diff --git a/.github/workflows/frontend-e2e-tests.yml b/.github/workflows/frontend-e2e-tests.yml index df6c88e0d2..3747ceb209 100644 --- a/.github/workflows/frontend-e2e-tests.yml +++ b/.github/workflows/frontend-e2e-tests.yml @@ -33,6 +33,9 @@ jobs: steps: - name: Check out repository uses: actions/checkout@v4 + with: + sparse-checkout: | + packages/e2e - name: print environment_url and BRANCH_NAME env: BASE_URL: "https://${{ needs.wait-for-deployment.outputs.environment_url }}" @@ -54,14 +57,14 @@ jobs: - name: Install Playwright run: | echo "$GITHUB_OUTPUT" - yarn --cwd packages/web install --frozen-lockfile && npx playwright install --with-deps chromium + yarn --cwd packages/e2e install --frozen-lockfile && npx playwright install --with-deps chromium - name: Run Swap Pair tests env: BASE_URL: "https://${{ needs.wait-for-deployment.outputs.environment_url }}" PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY }} WALLET_ID: ${{ secrets.TEST_WALLET_ID }} run: | - cd packages/web + cd packages/e2e npx playwright test -g "Test Swap feature" - name: upload Swap test results if: failure() @@ -69,7 +72,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: preview-swap-test-results - path: packages/web/playwright-report + path: packages/e2e/playwright-report preview-portfolio-trx-tests: timeout-minutes: 10 @@ -78,6 +81,9 @@ jobs: steps: - name: Check out repository uses: actions/checkout@v4 + with: + sparse-checkout: | + packages/e2e - name: Setup Node.js uses: actions/setup-node@v4 with: @@ -91,14 +97,14 @@ jobs: ${{ runner.OS }}-20.x- - name: Install Playwright run: | - yarn --cwd packages/web install --frozen-lockfile && npx playwright install --with-deps chromium + yarn --cwd packages/e2e install --frozen-lockfile && npx playwright install --with-deps chromium - name: Run Portfolio tests env: BASE_URL: "https://${{ needs.wait-for-deployment.outputs.environment_url }}" PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY }} WALLET_ID: ${{ secrets.TEST_WALLET_ID }} run: | - cd packages/web + cd packages/e2e npx playwright test portfolio transactions - name: upload Portfolio and transactions test results if: failure() @@ -106,7 +112,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: preview-portfolio-trx-test-results - path: packages/web/playwright-report + path: packages/e2e/playwright-report preview-pools-and-select-pair-tests: timeout-minutes: 10 @@ -115,6 +121,9 @@ jobs: steps: - name: Check out repository uses: actions/checkout@v4 + with: + sparse-checkout: | + packages/e2e - name: Setup Node.js uses: actions/setup-node@v4 with: @@ -128,12 +137,12 @@ jobs: ${{ runner.OS }}-20.x- - name: Install Playwright run: | - yarn --cwd packages/web install --frozen-lockfile && npx playwright install --with-deps chromium + yarn --cwd packages/e2e install --frozen-lockfile && npx playwright install --with-deps chromium - name: Run Pools tests env: BASE_URL: "https://${{ needs.wait-for-deployment.outputs.environment_url }}" run: | - cd packages/web + cd packages/e2e npx playwright test pools select - name: upload pools test results if: failure() @@ -141,7 +150,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: preview-pools-test-results - path: packages/web/playwright-report + path: packages/e2e/playwright-report preview-trade-tests: timeout-minutes: 10 @@ -150,6 +159,9 @@ jobs: steps: - name: Check out repository uses: actions/checkout@v4 + with: + sparse-checkout: | + packages/e2e - name: Setup Node.js uses: actions/setup-node@v4 with: @@ -164,14 +176,14 @@ jobs: - name: Install Playwright run: | echo "$GITHUB_OUTPUT" - yarn --cwd packages/web install --frozen-lockfile && npx playwright install --with-deps chromium + yarn --cwd packages/e2e install --frozen-lockfile && npx playwright install --with-deps chromium - name: Run Swap Pair tests env: BASE_URL: "https://${{ needs.wait-for-deployment.outputs.environment_url }}" PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY }} WALLET_ID: ${{ secrets.TEST_WALLET_ID }} run: | - cd packages/web + cd packages/e2e npx playwright test trade - name: upload Trade test results if: failure() @@ -179,7 +191,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: preview-trade-test-results - path: packages/web/playwright-report + path: packages/e2e/playwright-report preview-claim-tests: timeout-minutes: 10 @@ -188,6 +200,9 @@ jobs: steps: - name: Check out repository uses: actions/checkout@v4 + with: + sparse-checkout: | + packages/e2e - name: Setup Node.js uses: actions/setup-node@v4 with: @@ -202,14 +217,14 @@ jobs: - name: Install Playwright run: | echo "$GITHUB_OUTPUT" - yarn --cwd packages/web install --frozen-lockfile && npx playwright install --with-deps chromium + yarn --cwd packages/e2e install --frozen-lockfile && npx playwright install --with-deps chromium - name: Run Swap Pair tests env: BASE_URL: "https://${{ needs.wait-for-deployment.outputs.environment_url }}" PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY }} WALLET_ID: ${{ secrets.TEST_WALLET_ID }} run: | - cd packages/web + cd packages/e2e npx playwright test claim - name: upload Claim test results if: failure() @@ -217,4 +232,4 @@ jobs: uses: actions/upload-artifact@v4 with: name: preview-claim-test-results - path: packages/web/playwright-report + path: packages/e2e/playwright-report diff --git a/.github/workflows/jest-tests.yml b/.github/workflows/jest-tests.yml index 7ae1495147..63de6b26ca 100644 --- a/.github/workflows/jest-tests.yml +++ b/.github/workflows/jest-tests.yml @@ -19,6 +19,7 @@ jobs: "bridge", "tx", "proto-codecs", + "unit", ] steps: diff --git a/.github/workflows/monitoring-claim-orders .yml b/.github/workflows/monitoring-claim-orders .yml index 9eacbb8e8c..b7d2623389 100644 --- a/.github/workflows/monitoring-claim-orders .yml +++ b/.github/workflows/monitoring-claim-orders .yml @@ -25,13 +25,13 @@ jobs: ${{ runner.OS }}-20.x- - name: Install Playwright run: | - yarn --cwd packages/web install --frozen-lockfile && npx playwright install --with-deps chromium + yarn --cwd packages/e2e install --frozen-lockfile && npx playwright install --with-deps chromium - name: Run Swap tests in US env: BASE_URL: "https://app.osmosis.zone" PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY_1 }} run: | - cd packages/web + cd packages/e2e npx playwright test claim - name: upload test results if: failure() @@ -39,7 +39,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: claim1-test-results - path: packages/web/playwright-report + path: packages/e2e/playwright-report fe-claim2-tests: timeout-minutes: 10 @@ -60,13 +60,13 @@ jobs: ${{ runner.OS }}-20.x- - name: Install Playwright run: | - yarn --cwd packages/web install --frozen-lockfile && npx playwright install --with-deps chromium + yarn --cwd packages/e2e install --frozen-lockfile && npx playwright install --with-deps chromium - name: Run Claim tests env: BASE_URL: "https://app.osmosis.zone" PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY_2 }} run: | - cd packages/web + cd packages/e2e npx playwright test claim - name: upload claim2 test results if: failure() @@ -74,7 +74,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: claim2-test-results - path: packages/web/playwright-report + path: packages/e2e/playwright-report delete-deployments: runs-on: ubuntu-latest diff --git a/.github/workflows/monitoring-e2e-tests.yml b/.github/workflows/monitoring-e2e-tests.yml index e78431e575..34dba2532d 100644 --- a/.github/workflows/monitoring-e2e-tests.yml +++ b/.github/workflows/monitoring-e2e-tests.yml @@ -101,6 +101,9 @@ jobs: run: curl -L "https://ipinfo.io" -s - name: Check out repository uses: actions/checkout@v4 + with: + sparse-checkout: | + packages/e2e - name: Setup Node.js uses: actions/setup-node@v4 with: @@ -114,12 +117,12 @@ jobs: ${{ runner.OS }}-20.x- - name: Install Playwright run: | - yarn --cwd packages/web install --frozen-lockfile && npx playwright install --with-deps chromium + yarn --cwd packages/e2e install --frozen-lockfile && npx playwright install --with-deps chromium - name: Run Swap tests on ${{ matrix.env }} env: BASE_URL: ${{ matrix.base-url }} run: | - cd packages/web + cd packages/e2e npx playwright test pools - name: upload test results if: failure() @@ -127,7 +130,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: ${{ matrix.env }}-quote-test-results - path: packages/web/playwright-report + path: packages/e2e/playwright-report delete-deployments: runs-on: ubuntu-latest diff --git a/.github/workflows/monitoring-limit-geo-e2e-tests.yml b/.github/workflows/monitoring-limit-geo-e2e-tests.yml index c53c4451a4..79ed993bb0 100644 --- a/.github/workflows/monitoring-limit-geo-e2e-tests.yml +++ b/.github/workflows/monitoring-limit-geo-e2e-tests.yml @@ -1,18 +1,60 @@ -name: Synthetic Limit Orders Geo Monitoring Frontend tests +name: Synthetic Geo Monitoring Frontend tests on: workflow_dispatch: schedule: - - cron: "4 * * * *" + - cron: "1 * * * *" jobs: - fe-trade-eu-tests: - timeout-minutes: 12 - name: prod-fe-trade-eu-tests + fe-swap-us: + timeout-minutes: 10 + name: prod-fe-swap-us + runs-on: macos-latest + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + sparse-checkout: | + packages/e2e + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20.x + - name: Cache dependencies + uses: actions/cache@v4 + with: + path: "**/node_modules" + key: ${{ runner.OS }}-20.x-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.OS }}-20.x- + - name: Install Playwright + run: | + yarn --cwd packages/e2e install --frozen-lockfile && npx playwright install --with-deps chromium + - name: Run Swap tests in US + env: + BASE_URL: "https://app.osmosis.zone" + PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY_3 }} + run: | + cd packages/e2e + npx playwright test monitoring.swap + - name: upload test results + if: failure() + id: e2e-test-results + uses: actions/upload-artifact@v4 + with: + name: us-swap-test-results-${{ github.run_id }} + path: packages/e2e/playwright-report + + fe-swap-eu: + timeout-minutes: 15 + name: prod-fe-swap-eu runs-on: macos-latest steps: - name: Check out repository uses: actions/checkout@v4 + with: + sparse-checkout: | + packages/e2e - name: Setup Node.js uses: actions/setup-node@v4 with: @@ -26,17 +68,106 @@ jobs: ${{ runner.OS }}-20.x- - name: Install Playwright run: | - yarn --cwd packages/web install --frozen-lockfile && npx playwright install --with-deps chromium + yarn --cwd packages/e2e install --frozen-lockfile && npx playwright install --with-deps chromium - name: Run Swap tests in EU env: BASE_URL: "https://app.osmosis.zone" TEST_PROXY: "http://138.68.112.16:8888" TEST_PROXY_USERNAME: ${{ secrets.TEST_PROXY_USERNAME }} TEST_PROXY_PASSWORD: ${{ secrets.TEST_PROXY_PASSWORD }} + PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY_2 }} + USE_TEST_PROXY: "use" + run: | + cd packages/e2e + npx playwright test monitoring.swap + - name: upload test results + if: failure() + id: e2e-test-results + uses: actions/upload-artifact@v4 + with: + name: eu-swap-test-results-${{ github.run_id }} + path: packages/e2e/playwright-report + + fe-swap-sg: + timeout-minutes: 15 + name: prod-fe-swap-sg + runs-on: macos-latest + steps: + - name: Echo IP + run: curl -L "https://ipinfo.io" -s + - name: Check out repository + uses: actions/checkout@v4 + with: + sparse-checkout: | + packages/e2e + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20.x + - name: Cache dependencies + uses: actions/cache@v4 + with: + path: "**/node_modules" + key: ${{ runner.OS }}-20.x-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.OS }}-20.x- + - name: Install Playwright + run: | + yarn --cwd packages/e2e install --frozen-lockfile && npx playwright install --with-deps chromium + - name: Run Swap tests in SG + env: + BASE_URL: "https://app.osmosis.zone" + TEST_PROXY: "http://139.59.218.19:8888" + TEST_PROXY_USERNAME: ${{ secrets.TEST_PROXY_USERNAME }} + TEST_PROXY_PASSWORD: ${{ secrets.TEST_PROXY_PASSWORD }} PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY_1 }} USE_TEST_PROXY: "use" run: | - cd packages/web + cd packages/e2e + npx playwright test monitoring.swap + - name: upload test results + if: failure() + id: e2e-test-results + uses: actions/upload-artifact@v4 + with: + name: sg-swap-test-results-${{ github.run_id }} + path: packages/e2e/playwright-report + + fe-trade-eu: + timeout-minutes: 12 + needs: fe-swap-eu + name: prod-fe-trade-eu + runs-on: macos-latest + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + sparse-checkout: | + packages/e2e + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20.x + - name: Cache dependencies + uses: actions/cache@v4 + with: + path: "**/node_modules" + key: ${{ runner.OS }}-20.x-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.OS }}-20.x- + - name: Install Playwright + run: | + yarn --cwd packages/e2e install --frozen-lockfile && npx playwright install --with-deps chromium + - name: Run Swap tests in EU + env: + BASE_URL: "https://app.osmosis.zone" + TEST_PROXY: "http://138.68.112.16:8888" + TEST_PROXY_USERNAME: ${{ secrets.TEST_PROXY_USERNAME }} + TEST_PROXY_PASSWORD: ${{ secrets.TEST_PROXY_PASSWORD }} + PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY_2 }} + USE_TEST_PROXY: "use" + run: | + cd packages/e2e npx playwright test monitoring.market --timeout 180000 - name: upload monitoring test results if: failure() @@ -44,16 +175,19 @@ jobs: uses: actions/upload-artifact@v4 with: name: eu-trade-test-results-${{ github.run_id }} - path: packages/web/playwright-report + path: packages/e2e/playwright-report - fe-limit-eu-tests: - timeout-minutes: 12 - name: prod-fe-limit-eu-tests - needs: fe-trade-eu-tests + fe-limit-eu: + timeout-minutes: 15 + name: prod-fe-limit-eu + needs: fe-trade-eu runs-on: macos-latest steps: - name: Check out repository uses: actions/checkout@v4 + with: + sparse-checkout: | + packages/e2e - name: Setup Node.js uses: actions/setup-node@v4 with: @@ -67,17 +201,17 @@ jobs: ${{ runner.OS }}-20.x- - name: Install Playwright run: | - yarn --cwd packages/web install --frozen-lockfile && npx playwright install --with-deps chromium + yarn --cwd packages/e2e install --frozen-lockfile && npx playwright install --with-deps chromium - name: Run Limit tests in EU env: BASE_URL: "https://app.osmosis.zone" TEST_PROXY: "http://138.68.112.16:8888" TEST_PROXY_USERNAME: ${{ secrets.TEST_PROXY_USERNAME }} TEST_PROXY_PASSWORD: ${{ secrets.TEST_PROXY_PASSWORD }} - PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY_1 }} + PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY_2 }} USE_TEST_PROXY: "use" run: | - cd packages/web + cd packages/e2e npx playwright test monitoring.limit --timeout 180000 - name: upload monitoring test results if: failure() @@ -85,15 +219,19 @@ jobs: uses: actions/upload-artifact@v4 with: name: eu-limit-test-results-${{ github.run_id }} - path: packages/web/playwright-report + path: packages/e2e/playwright-report - fe-trade-sg-tests: + fe-trade-sg: timeout-minutes: 12 - name: prod-fe-trade-sg-tests + needs: fe-swap-sg + name: prod-fe-trade-sg runs-on: macos-latest steps: - name: Check out repository uses: actions/checkout@v4 + with: + sparse-checkout: | + packages/e2e - name: Setup Node.js uses: actions/setup-node@v4 with: @@ -107,17 +245,17 @@ jobs: ${{ runner.OS }}-20.x- - name: Install Playwright run: | - yarn --cwd packages/web install --frozen-lockfile && npx playwright install --with-deps chromium + yarn --cwd packages/e2e install --frozen-lockfile && npx playwright install --with-deps chromium - name: Run Swap tests in SG env: BASE_URL: "https://app.osmosis.zone" TEST_PROXY: "http://139.59.218.19:8888" TEST_PROXY_USERNAME: ${{ secrets.TEST_PROXY_USERNAME }} TEST_PROXY_PASSWORD: ${{ secrets.TEST_PROXY_PASSWORD }} - PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY_2 }} + PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY_1 }} USE_TEST_PROXY: "use" run: | - cd packages/web + cd packages/e2e npx playwright test monitoring.market --timeout 90000 - name: upload monitoring test results if: failure() @@ -125,15 +263,19 @@ jobs: uses: actions/upload-artifact@v4 with: name: sg-trade-test-results-${{ github.run_id }} - path: packages/web/playwright-report + path: packages/e2e/playwright-report - fe-trade-us-tests: + fe-trade-us: timeout-minutes: 10 - name: prod-fe-trade-us-tests + needs: fe-swap-us + name: prod-fe-trade-us runs-on: macos-latest steps: - name: Check out repository uses: actions/checkout@v4 + with: + sparse-checkout: | + packages/e2e - name: Setup Node.js uses: actions/setup-node@v4 with: @@ -147,14 +289,14 @@ jobs: ${{ runner.OS }}-20.x- - name: Install Playwright run: | - yarn --cwd packages/web install --frozen-lockfile && npx playwright install --with-deps chromium + yarn --cwd packages/e2e install --frozen-lockfile && npx playwright install --with-deps chromium - name: Run Swap tests in US id: run-us env: BASE_URL: "https://app.osmosis.zone" PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY_3 }} run: | - cd packages/web + cd packages/e2e npx playwright test monitoring.market --timeout 90000 - name: upload monitoring test results if: failure() @@ -162,16 +304,19 @@ jobs: uses: actions/upload-artifact@v4 with: name: us-trade-test-results-${{ github.run_id }} - path: packages/web/playwright-report + path: packages/e2e/playwright-report - fe-limit-us-tests: - timeout-minutes: 10 - needs: fe-trade-us-tests - name: prod-fe-limit-us-tests + fe-limit-us: + timeout-minutes: 15 + needs: fe-trade-us + name: prod-fe-limit-us runs-on: macos-latest steps: - name: Check out repository uses: actions/checkout@v4 + with: + sparse-checkout: | + packages/e2e - name: Setup Node.js uses: actions/setup-node@v4 with: @@ -185,14 +330,14 @@ jobs: ${{ runner.OS }}-20.x- - name: Install Playwright run: | - yarn --cwd packages/web install --frozen-lockfile && npx playwright install --with-deps chromium + yarn --cwd packages/e2e install --frozen-lockfile && npx playwright install --with-deps chromium - name: Run Limit tests in US id: run-us env: BASE_URL: "https://app.osmosis.zone" PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY_3 }} run: | - cd packages/web + cd packages/e2e npx playwright test monitoring.limit --timeout 180000 - name: upload monitoring test results if: failure() @@ -200,18 +345,18 @@ jobs: uses: actions/upload-artifact@v4 with: name: us-limit-test-results-${{ github.run_id }} - path: packages/web/playwright-report + path: packages/e2e/playwright-report fe-bot-alert: runs-on: ubuntu-latest needs: [ - fe-trade-eu-tests, - fe-trade-us-tests, - fe-trade-sg-tests, - fe-trade-us-tests, - fe-limit-us-tests, - fe-limit-eu-tests, + fe-trade-eu, + fe-trade-us, + fe-trade-sg, + fe-trade-us, + fe-limit-us, + fe-limit-eu, ] if: failure() steps: @@ -247,13 +392,13 @@ jobs: if: always() needs: [ - fe-trade-eu-tests, - fe-trade-us-tests, - fe-trade-sg-tests, + fe-trade-eu, + fe-trade-us, + fe-trade-sg, fe-bot-alert, - fe-trade-us-tests, - fe-limit-us-tests, - fe-limit-eu-tests, + fe-trade-us, + fe-limit-us, + fe-limit-eu, ] steps: - name: Delete Previous deployments diff --git a/.github/workflows/monitoring-quote-geo-e2e-tests.yml b/.github/workflows/monitoring-quote-geo-e2e-tests.yml new file mode 100644 index 0000000000..66efec6c00 --- /dev/null +++ b/.github/workflows/monitoring-quote-geo-e2e-tests.yml @@ -0,0 +1,124 @@ +name: Synthetic Quote Geo Monitoring Frontend tests + +on: + workflow_dispatch: + schedule: + - cron: "*/30 * * * *" + +jobs: + setup-matrix: + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + steps: + - id: set-matrix + run: | + echo "matrix={\"include\":[{\"test-proxy\":\"use\", \"server-url\":\"http://138.68.112.16:8888\", \"env\": \"prod-fra1\"}, {\"test-proxy\":\"use\", \"server-url\":\"http://139.59.218.19:8888\", \"env\": \"prod-sgp1\"}, {\"test-proxy\":\"no\", \"server-url\":\"http://139.59.218.19:8888\", \"env\": \"prod-usa1\"}]}" >> "$GITHUB_OUTPUT" + + fe-quote-tests: + timeout-minutes: 15 + name: ${{ matrix.env }}-fe-quote-tests + needs: setup-matrix + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: ${{fromJson(needs.setup-matrix.outputs.matrix)}} + steps: + - name: Echo IP + run: curl -L "https://ipinfo.io" -s + - name: Check out repository + uses: actions/checkout@v4 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20.x + - name: Cache dependencies + uses: actions/cache@v4 + with: + path: "**/node_modules" + key: ${{ runner.OS }}-20.x-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.OS }}-20.x- + - name: Install Playwright + run: | + yarn --cwd packages/e2e install --frozen-lockfile && npx playwright install --with-deps chromium + - name: Run Swap tests on ${{ matrix.env }} + env: + BASE_URL: "https://app.osmosis.zone" + TEST_PROXY: ${{ matrix.server-url }} + TEST_PROXY_USERNAME: ${{secrets.TEST_PROXY_USERNAME}} + TEST_PROXY_PASSWORD: ${{secrets.TEST_PROXY_PASSWORD}} + USE_TEST_PROXY: ${{ matrix.test-proxy }} + run: | + cd packages/e2e + npx playwright test select pools + - name: upload test results + if: failure() + id: e2e-test-results + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.env }}-quote-test-results + path: packages/e2e/playwright-report + + fe-bot-alert: + runs-on: ubuntu-latest + needs: [fe-quote-tests] + if: failure() + steps: + - name: Send Slack alert if test fails + id: slack + uses: slackapi/slack-github-action@v1.26.0 + with: + payload: | + { + "blocks": [ + { + "type": "header", + "text": { + "type": "plain_text", + "text": "🚨 Synthetic Prod Swap Monitoring Tests Failure Alert 🚨" + } + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "Click here to view the run: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|GitHub Actions Run>" + } + } + ] + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.SERVER_E2E_TESTS_SLACK_WEBHOOK_URL }} + SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK + + delete-deployments: + runs-on: ubuntu-latest + if: always() + needs: [fe-quote-tests, fe-bot-alert] + steps: + - name: Delete Previous deployments + uses: actions/github-script@v7 + with: + debug: true + script: | + const deployments = await github.rest.repos.listDeployments({ + owner: context.repo.owner, + repo: context.repo.repo, + sha: context.sha + }); + await Promise.all( + deployments.data.map(async (deployment) => { + await github.rest.repos.createDeploymentStatus({ + owner: context.repo.owner, + repo: context.repo.repo, + deployment_id: deployment.id, + state: 'inactive' + }); + return github.rest.repos.deleteDeployment({ + owner: context.repo.owner, + repo: context.repo.repo, + deployment_id: deployment.id + }); + }) + ); diff --git a/.github/workflows/monitoring-swap-geo-e2e-tests.yml b/.github/workflows/monitoring-swap-geo-e2e-tests.yml deleted file mode 100644 index 185896520a..0000000000 --- a/.github/workflows/monitoring-swap-geo-e2e-tests.yml +++ /dev/null @@ -1,253 +0,0 @@ -name: Synthetic Swaps Geo Monitoring Frontend tests - -on: - workflow_dispatch: - schedule: - - cron: "*/30 * * * *" - -jobs: - setup-matrix: - runs-on: ubuntu-latest - outputs: - matrix: ${{ steps.set-matrix.outputs.matrix }} - steps: - - id: set-matrix - run: | - echo "matrix={\"include\":[{\"test-proxy\":\"use\", \"server-url\":\"http://138.68.112.16:8888\", \"env\": \"prod-fra1\"}, {\"test-proxy\":\"use\", \"server-url\":\"http://139.59.218.19:8888\", \"env\": \"prod-sgp1\"}, {\"test-proxy\":\"no\", \"server-url\":\"http://139.59.218.19:8888\", \"env\": \"prod-usa1\"}]}" >> "$GITHUB_OUTPUT" - - fe-quote-tests: - timeout-minutes: 15 - name: ${{ matrix.env }}-fe-quote-tests - needs: setup-matrix - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: ${{fromJson(needs.setup-matrix.outputs.matrix)}} - steps: - - name: Echo IP - run: curl -L "https://ipinfo.io" -s - - name: Check out repository - uses: actions/checkout@v4 - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: 20.x - - name: Cache dependencies - uses: actions/cache@v4 - with: - path: "**/node_modules" - key: ${{ runner.OS }}-20.x-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.OS }}-20.x- - - name: Install Playwright - run: | - yarn --cwd packages/web install --frozen-lockfile && npx playwright install --with-deps chromium - - name: Run Swap tests on ${{ matrix.env }} - env: - BASE_URL: "https://app.osmosis.zone" - TEST_PROXY: ${{ matrix.server-url }} - TEST_PROXY_USERNAME: ${{secrets.TEST_PROXY_USERNAME}} - TEST_PROXY_PASSWORD: ${{secrets.TEST_PROXY_PASSWORD}} - USE_TEST_PROXY: ${{ matrix.test-proxy }} - run: | - cd packages/web - npx playwright test select pools - - name: upload test results - if: failure() - id: e2e-test-results - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.env }}-quote-test-results - path: packages/web/playwright-report - - fe-swap-us-tests: - timeout-minutes: 10 - name: prod-fe-swap-us-tests - runs-on: macos-latest - steps: - - name: Echo IP - run: curl -L "https://ipinfo.io" -s - - name: Check out repository - uses: actions/checkout@v4 - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: 20.x - - name: Cache dependencies - uses: actions/cache@v4 - with: - path: "**/node_modules" - key: ${{ runner.OS }}-20.x-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.OS }}-20.x- - - name: Install Playwright - run: | - yarn --cwd packages/web install --frozen-lockfile && npx playwright install --with-deps chromium - - name: Run Swap tests in US - env: - BASE_URL: "https://app.osmosis.zone" - PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY_1 }} - run: | - cd packages/web - npx playwright test -g "Test Swap Stables feature" - - name: upload test results - if: failure() - id: e2e-test-results - uses: actions/upload-artifact@v4 - with: - name: us-swap-test-results-${{ github.run_id }} - path: packages/web/playwright-report - - fe-swap-eu-tests: - timeout-minutes: 15 - name: prod-fe-swap-eu-tests - runs-on: macos-latest - steps: - - name: Echo IP - run: curl -L "https://ipinfo.io" -s - - name: Check out repository - uses: actions/checkout@v4 - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: 20.x - - name: Cache dependencies - uses: actions/cache@v4 - with: - path: "**/node_modules" - key: ${{ runner.OS }}-20.x-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.OS }}-20.x- - - name: Install Playwright - run: | - yarn --cwd packages/web install --frozen-lockfile && npx playwright install --with-deps chromium - - name: Run Swap tests in EU - env: - BASE_URL: "https://app.osmosis.zone" - TEST_PROXY: "http://138.68.112.16:8888" - TEST_PROXY_USERNAME: ${{ secrets.TEST_PROXY_USERNAME }} - TEST_PROXY_PASSWORD: ${{ secrets.TEST_PROXY_PASSWORD }} - PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY_2 }} - USE_TEST_PROXY: "use" - run: | - cd packages/web - npx playwright test -g "Test Swap Stables feature" - - name: upload test results - if: failure() - id: e2e-test-results - uses: actions/upload-artifact@v4 - with: - name: eu-swap-test-results-${{ github.run_id }} - path: packages/web/playwright-report - - fe-swap-sg-tests: - timeout-minutes: 15 - name: prod-fe-swap-sg-tests - runs-on: macos-latest - steps: - - name: Echo IP - run: curl -L "https://ipinfo.io" -s - - name: Check out repository - uses: actions/checkout@v4 - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: 20.x - - name: Cache dependencies - uses: actions/cache@v4 - with: - path: "**/node_modules" - key: ${{ runner.OS }}-20.x-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.OS }}-20.x- - - name: Install Playwright - run: | - yarn --cwd packages/web install --frozen-lockfile && npx playwright install --with-deps chromium - - name: Run Swap tests in SG - env: - BASE_URL: "https://app.osmosis.zone" - TEST_PROXY: "http://139.59.218.19:8888" - TEST_PROXY_USERNAME: ${{ secrets.TEST_PROXY_USERNAME }} - TEST_PROXY_PASSWORD: ${{ secrets.TEST_PROXY_PASSWORD }} - PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY_3 }} - USE_TEST_PROXY: "use" - run: | - cd packages/web - npx playwright test -g "Test Swap Stables feature" - - name: upload test results - if: failure() - id: e2e-test-results - uses: actions/upload-artifact@v4 - with: - name: sg-swap-test-results-${{ github.run_id }} - path: packages/web/playwright-report - - fe-bot-alert: - runs-on: ubuntu-latest - needs: [fe-swap-us-tests, fe-swap-eu-tests, fe-swap-sg-tests] - if: failure() - steps: - - name: Send Slack alert if test fails - id: slack - uses: slackapi/slack-github-action@v1.26.0 - with: - payload: | - { - "blocks": [ - { - "type": "header", - "text": { - "type": "plain_text", - "text": "🚨 Synthetic Prod Swap Monitoring Tests Failure Alert 🚨" - } - }, - { - "type": "section", - "text": { - "type": "mrkdwn", - "text": "Click here to view the run: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|GitHub Actions Run>" - } - } - ] - } - env: - SLACK_WEBHOOK_URL: ${{ secrets.SERVER_E2E_TESTS_SLACK_WEBHOOK_URL }} - SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK - - delete-deployments: - runs-on: ubuntu-latest - if: always() - needs: - [ - fe-quote-tests, - fe-swap-us-tests, - fe-swap-sg-tests, - fe-swap-eu-tests, - fe-bot-alert, - ] - steps: - - name: Delete Previous deployments - uses: actions/github-script@v7 - with: - debug: true - script: | - const deployments = await github.rest.repos.listDeployments({ - owner: context.repo.owner, - repo: context.repo.repo, - sha: context.sha - }); - await Promise.all( - deployments.data.map(async (deployment) => { - await github.rest.repos.createDeploymentStatus({ - owner: context.repo.owner, - repo: context.repo.repo, - deployment_id: deployment.id, - state: 'inactive' - }); - return github.rest.repos.deleteDeployment({ - owner: context.repo.owner, - repo: context.repo.repo, - deployment_id: deployment.id - }); - }) - ); diff --git a/.github/workflows/prod-frontend-e2e-tests.yml b/.github/workflows/prod-frontend-e2e-tests.yml index 25aeb62722..2b81ca22f9 100644 --- a/.github/workflows/prod-frontend-e2e-tests.yml +++ b/.github/workflows/prod-frontend-e2e-tests.yml @@ -52,14 +52,14 @@ jobs: ${{ runner.OS }}-20.x- - name: Install Playwright run: | - yarn --cwd packages/web install --frozen-lockfile && npx playwright install --with-deps chromium + yarn --cwd packages/e2e install --frozen-lockfile && npx playwright install --with-deps chromium - name: Run Swap Pair tests on Master env: BASE_URL: "https://app.osmosis.zone" PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY }} WALLET_ID: ${{ secrets.TEST_WALLET_ID }} run: | - cd packages/web + cd packages/e2e npx playwright test transactions portfolio swap.wallet - name: upload test results if: always() @@ -67,7 +67,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: prod-e2e-test-results-${{ github.run_id }} - path: packages/web/playwright-report + path: packages/e2e/playwright-report - name: Send Slack alert if test fails id: slack if: failure() @@ -111,6 +111,9 @@ jobs: steps: - name: Check out repository uses: actions/checkout@v4 + with: + sparse-checkout: | + packages/e2e - name: Setup Node.js uses: actions/setup-node@v4 with: @@ -124,12 +127,12 @@ jobs: ${{ runner.OS }}-20.x- - name: Install Playwright run: | - yarn --cwd packages/web install --frozen-lockfile && npx playwright install --with-deps chromium + yarn --cwd packages/e2e install --frozen-lockfile && npx playwright install --with-deps chromium - name: Run Pools tests env: BASE_URL: "https://app.osmosis.zone" run: | - cd packages/web + cd packages/e2e npx playwright test pools select - name: upload pools test results if: failure() @@ -137,4 +140,4 @@ jobs: uses: actions/upload-artifact@v4 with: name: prod-pools-test-results-${{ github.run_id }} - path: packages/web/playwright-report + path: packages/e2e/playwright-report diff --git a/.gitignore b/.gitignore index 0b2aa46414..643cdffbed 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,7 @@ packages/web/e2e/keplr-extension-manifest .*.swp .*.swo packages/web/e2e/metamask-extension-manifest/ +packages/e2e/keplr-extension-manifest/ +packages/e2e/playwright-report/ +packages/e2e/test-results/ +packages/e2e/.env diff --git a/package.json b/package.json index 15bcbcd151..01102c0b7b 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ ] }, "scripts": { - "dev": "turbo dev --concurrency 14", + "dev": "turbo dev --concurrency 15", "dev:testnet": "dotenv -v NEXT_PUBLIC_IS_TESTNET=true -- yarn dev", "start": "turbo start", "start:testnet": "dotenv -v NEXT_PUBLIC_IS_TESTNET=true -- yarn start", @@ -29,7 +29,7 @@ "pre-commit": "lerna run pre-commit --concurrency false", "publish:libs": "lerna publish", "machine-translate": "inlang machine translate -f --project ./project.inlang && yarn lint:fix", - "lint:workspace": "npx sherif@latest --ignore-package ./packages/keplr-hooks --ignore-package ./packages/keplr-stores", + "lint:workspace": "npx sherif@latest --ignore-package ./packages/keplr-hooks --ignore-package ./packages/keplr-stores --ignore-package ./packages/e2e", "lint:workspace:fix": "yarn lint:workspace -f", "postinstall": "yarn lint:workspace" }, @@ -80,7 +80,6 @@ "@keplr-wallet/cosmos": "0.10.24-ibc.go.v7.hot.fix", "@keplr-wallet/proto-types": "0.10.24-ibc.go.v7.hot.fix", "@keplr-wallet/router": "0.10.24-ibc.go.v7.hot.fix", - "@keplr-wallet/types": "0.10.24-ibc.go.v7.hot.fix", - "@keplr-wallet/unit": "0.10.24-ibc.go.v7.hot.fix" + "@keplr-wallet/types": "0.10.24-ibc.go.v7.hot.fix" } } diff --git a/packages/bridge/package.json b/packages/bridge/package.json index 30b14a7ac1..86129d8f8e 100644 --- a/packages/bridge/package.json +++ b/packages/bridge/package.json @@ -29,11 +29,11 @@ "@axelar-network/axelarjs-sdk": "0.17.0", "@cosmjs/encoding": "0.32.3", "@cosmjs/proto-signing": "0.32.3", - "@keplr-wallet/unit": "0.10.24-ibc.go.v7.hot.fix", "@osmosis-labs/proto-codecs": "^5.1.0", "@osmosis-labs/server": "^1.0.0", "@osmosis-labs/tx": "^1.0.0", "@osmosis-labs/types": "^1.0.0", + "@osmosis-labs/unit": "0.10.24-ibc.go.v7.hot.fix", "@osmosis-labs/utils": "^1.0.0", "base-x": "^5.0.0", "cachified": "^3.5.4", diff --git a/packages/bridge/src/axelar/index.ts b/packages/bridge/src/axelar/index.ts index 4a33c9aab8..9994526392 100644 --- a/packages/bridge/src/axelar/index.ts +++ b/packages/bridge/src/axelar/index.ts @@ -3,9 +3,9 @@ import type { AxelarQueryAPI, } from "@axelar-network/axelarjs-sdk"; import type { Registry } from "@cosmjs/proto-signing"; -import { CoinPretty, Dec, IntPretty } from "@keplr-wallet/unit"; import { estimateGasFee, makeIBCTransferMsg } from "@osmosis-labs/tx"; import type { IbcTransferMethod } from "@osmosis-labs/types"; +import { CoinPretty, Dec, IntPretty } from "@osmosis-labs/unit"; import { EthereumChainInfo, getAssetFromAssetList, diff --git a/packages/bridge/src/interface.ts b/packages/bridge/src/interface.ts index 33a8395980..bf9d8f808e 100644 --- a/packages/bridge/src/interface.ts +++ b/packages/bridge/src/interface.ts @@ -1,6 +1,6 @@ import { EncodeObject } from "@cosmjs/proto-signing"; -import { RatePretty } from "@keplr-wallet/unit"; import type { AssetList, Chain } from "@osmosis-labs/types"; +import { RatePretty } from "@osmosis-labs/unit"; import type { CacheEntry } from "cachified"; import type { LRUCache } from "lru-cache"; import { Address, Hex } from "viem"; diff --git a/packages/bridge/src/nomic/index.ts b/packages/bridge/src/nomic/index.ts index a7928d7c67..cc234cbf64 100644 --- a/packages/bridge/src/nomic/index.ts +++ b/packages/bridge/src/nomic/index.ts @@ -1,5 +1,4 @@ import type { Registry } from "@cosmjs/proto-signing"; -import { Dec, RatePretty } from "@keplr-wallet/unit"; import { getRouteTokenOutGivenIn } from "@osmosis-labs/server"; import { estimateGasFee, @@ -8,6 +7,7 @@ import { SkipSwapIbcHookContractAddress, } from "@osmosis-labs/tx"; import { IbcTransferMethod } from "@osmosis-labs/types"; +import { Dec, RatePretty } from "@osmosis-labs/unit"; import { deriveCosmosAddress, getAllBtcMinimalDenom, diff --git a/packages/bridge/src/squid/index.ts b/packages/bridge/src/squid/index.ts index e98b6d3a46..016999cf0b 100644 --- a/packages/bridge/src/squid/index.ts +++ b/packages/bridge/src/squid/index.ts @@ -6,12 +6,12 @@ import { type TokensResponse, type TransactionRequest, } from "@0xsquid/sdk"; -import { Dec } from "@keplr-wallet/unit"; import { makeExecuteCosmwasmContractMsg, makeIBCTransferMsg, } from "@osmosis-labs/tx"; import { CosmosCounterparty, EVMCounterparty } from "@osmosis-labs/types"; +import { Dec } from "@osmosis-labs/unit"; import { apiClient, ApiClientError, diff --git a/packages/web/e2e/README.md b/packages/e2e/README.md similarity index 100% rename from packages/web/e2e/README.md rename to packages/e2e/README.md diff --git a/packages/e2e/biome.json b/packages/e2e/biome.json new file mode 100644 index 0000000000..b249ffcd19 --- /dev/null +++ b/packages/e2e/biome.json @@ -0,0 +1,58 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.8.3/schema.json", + "files": { + "include": ["pages/**/*", "tests/**/*"] + }, + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + }, + "formatter": { + "enabled": true, + "formatWithErrors": false, + "indentStyle": "space", + "indentWidth": 2, + "lineEnding": "lf", + "lineWidth": 80, + "attributePosition": "auto" + }, + "organizeImports": { "enabled": true }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "correctness": { + "noUnusedImports": "error", + "noUnusedVariables": "warn" + }, + "suspicious": { + "noArrayIndexKey": "off", + "noExplicitAny": "warn" + }, + "a11y": { + "useKeyWithClickEvents": "off", + "noSvgWithoutTitle": "off", + "useButtonType": "off" + }, + "style": { + "noInferrableTypes": "off", + "useNumberNamespace": "off", + "noNonNullAssertion": "off" + } + } + }, + "javascript": { + "formatter": { + "jsxQuoteStyle": "single", + "quoteProperties": "asNeeded", + "trailingCommas": "all", + "semicolons": "asNeeded", + "arrowParentheses": "always", + "bracketSpacing": true, + "bracketSameLine": false, + "quoteStyle": "single", + "attributePosition": "auto" + } + } +} diff --git a/packages/web/e2e/keplr-extension-manifest-v3-v0.12.125.zip b/packages/e2e/keplr-extension-manifest-v3-v0.12.156.zip similarity index 70% rename from packages/web/e2e/keplr-extension-manifest-v3-v0.12.125.zip rename to packages/e2e/keplr-extension-manifest-v3-v0.12.156.zip index e34f005604..61f6feae31 100644 Binary files a/packages/web/e2e/keplr-extension-manifest-v3-v0.12.125.zip and b/packages/e2e/keplr-extension-manifest-v3-v0.12.156.zip differ diff --git a/packages/e2e/package.json b/packages/e2e/package.json new file mode 100644 index 0000000000..6706b57782 --- /dev/null +++ b/packages/e2e/package.json @@ -0,0 +1,22 @@ +{ + "name": "app-osmosis-e2e", + "version": "0.1.0", + "private": true, + "scripts": { + "clean": "rm -rf node_modules; rm -rf .next", + "lint": "biome check --write", + "lint:fix": "biome check --fix --unsafe", + "test": "npx playwright test", + "setup": "yarn install && npx playwright install --with-deps chromium" + }, + "dependencies": { + "@playwright/test": "1.49.0", + "decompress": "4.2.1", + "dotenv": "16.4.5" + }, + "devDependencies": { + "@biomejs/biome": "1.9.4", + "@types/node": "22.7.5", + "typescript": "5.6.3" + } +} diff --git a/packages/e2e/pages/base-page.ts b/packages/e2e/pages/base-page.ts new file mode 100644 index 0000000000..3ce89e5f44 --- /dev/null +++ b/packages/e2e/pages/base-page.ts @@ -0,0 +1,57 @@ +import { type Locator, type Page, expect } from '@playwright/test' + +export class BasePage { + readonly page: Page + readonly connectWalletBtn: Locator + readonly kepltWalletBtn: Locator + readonly portfolioLink: Locator + readonly poolsLink: Locator + + constructor(page: Page) { + this.page = page + this.connectWalletBtn = page + .getByRole('button', { name: 'Connect wallet', exact: true }) + .first() + this.kepltWalletBtn = page.locator('button').filter({ hasText: /^Keplr$/ }) + this.portfolioLink = page.getByText('Portfolio') + this.poolsLink = page.getByText('Pools') + } + + async connectWallet() { + await this.connectWalletBtn.click() + // This is needed to handle a wallet popup + const pagePromise = this.page.context().waitForEvent('page') + await this.kepltWalletBtn.click() + await this.page.waitForTimeout(1000) + // Handle Pop-up page -> + const newPage = await pagePromise + await newPage.waitForLoadState('load', { timeout: 10000 }) + const pageTitle = await newPage.title() + console.log(`Title of the new page: ${pageTitle}`) + await newPage.getByRole('button', { name: 'Approve' }).click() + // PopUp page is auto-closed + // Handle Pop-up page <- + const wallet = this.page.locator('//button/div/span[@title]') + await this.page.waitForTimeout(4000) + // Verify that wallet modal loaded correctly + const isWalletVisible = await wallet.isVisible({ timeout: 5000 }) + expect(isWalletVisible).toBeTruthy() + console.log('Wallet is connected.') + } + + async gotoPortfolio() { + await this.portfolioLink.click() + // we expect that after 2 seconds tokens are loaded and any failure after this point should be considered a bug. + await this.page.waitForTimeout(2000) + await this.printUrl() + } + + async gotoPools() { + await this.poolsLink.click() + } + + async printUrl() { + const currentUrl = this.page.url() + console.log(`FE opened at: ${currentUrl}`) + } +} diff --git a/packages/e2e/pages/keplr-page.ts b/packages/e2e/pages/keplr-page.ts new file mode 100644 index 0000000000..1d6f5cb1b6 --- /dev/null +++ b/packages/e2e/pages/keplr-page.ts @@ -0,0 +1,75 @@ +import { type Locator, type Page, expect } from '@playwright/test' + +export class WalletPage { + readonly page: Page + readonly importWalletBtn: Locator + readonly useRecoveryBtn: Locator + readonly privateKeyBtn: Locator + readonly privateKeyInput: Locator + readonly importBtn: Locator + readonly walletNameInput: Locator + readonly walletPassInput: Locator + readonly walletRePassInput: Locator + readonly nextBtn: Locator + readonly allCheckbox: Locator + readonly saveBtn: Locator + readonly finishBtn: Locator + + constructor(page: Page) { + this.page = page + this.importWalletBtn = page.getByText('Import an existing wallet') + this.useRecoveryBtn = page.getByText('Use recovery phrase or private key') + this.privateKeyBtn = page.getByRole('button', { + name: 'Private key', + exact: true, + }) + this.privateKeyInput = page.locator('input[type="password"]') + this.importBtn = page.getByRole('button', { name: 'Import', exact: true }) + this.walletNameInput = page.locator('input[name="name"]') + this.walletPassInput = page.locator('input[name="password"]') + this.walletRePassInput = page.locator("input[name='confirmPassword']") + this.nextBtn = page.getByRole('button', { name: 'Next', exact: true }) + this.allCheckbox = page.locator('input[type="checkbox"]').first() + this.saveBtn = page.getByRole('button', { name: 'Save', exact: true }) + this.finishBtn = page.getByRole('button', { name: 'Finish', exact: true }) + } + + async goto(extensionId: string) { + await this.page.goto(`chrome-extension://${extensionId}/register.html#`) + // IMO, it is better to assert navigation is successful + await expect(this.page.getByText('Your Interchain Gateway')).toBeVisible() + } + + async importWalletWithPrivateKey(privateKey: string) { + await this.importWalletBtn.click() + await this.useRecoveryBtn.click() + await this.privateKeyBtn.click() + await this.privateKeyInput.fill(privateKey) + await this.importBtn.click() + } + + async setWalletNameAndPassword(name: string, password = 'TestPassword2024.') { + await this.walletNameInput.fill(name) + await this.walletPassInput.fill(password) + await this.walletRePassInput.fill(password) + await this.nextBtn.click() + } + + async selectChainsAndSave() { + await this.allCheckbox.check() + await this.saveBtn.click() + // IMO, it is better to assert default action is successful. Unless a failure is possible. + await expect(this.page.getByText('Account Created!')).toBeVisible() + } + + async takeScreenshot() { + await this.page.screenshot({ + path: 'screenshot-wallet-setup.png', + fullPage: true, + }) + } + + async finish() { + await this.finishBtn.click() + } +} diff --git a/packages/e2e/pages/pool-page.ts b/packages/e2e/pages/pool-page.ts new file mode 100644 index 0000000000..e178249d71 --- /dev/null +++ b/packages/e2e/pages/pool-page.ts @@ -0,0 +1,36 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import type { Locator, Page } from '@playwright/test' + +import { BasePage } from './base-page' + +import { SwapPage } from './swap-page' + +export class PoolPage extends BasePage { + readonly page: Page + readonly viewMore: Locator + readonly poolsLink: Locator + readonly balance: Locator + readonly tradeBtn: Locator + + constructor(page: Page) { + super(page) + this.page = page + this.viewMore = page.getByText('View more') + this.poolsLink = page.locator('//a//div[contains(text(), "Pools")]') + this.balance = page.locator( + '//span[.="Total balance"]/..//h4[contains(@class, "text-osmoverse-100")]', + ) + this.tradeBtn = page.locator('//button/span[.="Trade Pair"]') + } + + async getBalance() { + const totalBalance: string = await this.balance.innerText() + console.log(`Total Balance for a Pool [${totalBalance}]`) + return totalBalance + } + + async getTradeModal() { + await this.tradeBtn.click() + return new SwapPage(this.page) + } +} diff --git a/packages/e2e/pages/pools-page.ts b/packages/e2e/pages/pools-page.ts new file mode 100644 index 0000000000..5aae46887a --- /dev/null +++ b/packages/e2e/pages/pools-page.ts @@ -0,0 +1,99 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import type { Locator, Page } from '@playwright/test' + +import { BasePage } from './base-page' + +import { PoolPage } from './pool-page' + +export class PoolsPage extends BasePage { + readonly page: Page + readonly viewMore: Locator + readonly poolsLink: Locator + readonly balance: Locator + readonly searchInput: Locator + + constructor(page: Page) { + super(page) + this.page = page + this.viewMore = page.getByText('View more') + this.poolsLink = page.locator('//a//div[contains(text(), "Pools")]') + this.balance = page.locator( + '//span[.="Total balance"]/..//h4[contains(@class, "text-osmoverse-100")]', + ) + this.searchInput = page.locator('//input[@id="search-input"]') + } + + async goto() { + await this.page.goto('/') + await this.page.waitForTimeout(2000) + await this.poolsLink.click() + await this.page.waitForTimeout(2000) + // Sometimes pools take longer to load + // we expect that after 10 seconds tokens are loaded and any failure after this point should be considered a bug. + // 1464 is an OSMO/USDC pool + const locRows = '//tr/td/a[contains(@href, "pool/1464")]/../..' + await this.page.locator(locRows).hover({ timeout: 10000 }) + await super.printUrl() + } + + async viewPool(id: number, pair: string) { + await this.page + .locator(`//table//td/a[@href="/pool/${id}"]//span[.="${pair}"]`) + .click() + // we expect that after 2 seconds tokens are loaded and any failure after this point should be considered a bug. + await this.page.waitForTimeout(2000) + await super.printUrl() + return new PoolPage(this.page) + } + + async searchForPool(poolName: string) { + await this.searchInput.fill(poolName) + // we expect that after 2 seconds tokens are loaded and any failure after this point should be considered a bug. + await this.page.waitForTimeout(2000) + } + + async getPoolsNumber() { + const loc = '//tr/td//a[contains(@href, "/pool/")]/../..' + const num = await this.page.locator(loc).count() + console.log(`Pools Count: ${num}`) + return num + } + + async getTopTenPoolsByLiquidity() { + const loc = '//tr/td//a[contains(@href, "/pool/")]/../..' + const liquidityList = [] + for (let i = 0; i < 10; i++) { + const tt = this.page.locator(loc).nth(i).locator('//td').nth(2) + const text: string = await tt.innerText() + const n: number = Number(text.replace(/[^0-9.-]+/g, '')) + liquidityList.push(n) + } + console.log(`Top 10 pools Liquidity: ${liquidityList}`) + return liquidityList + } + + async getTopTenPoolsByVolume() { + const loc = '//tr/td//a[contains(@href, "/pool/")]/../..' + const volumeList = [] + for (let i = 0; i < 10; i++) { + const tt = this.page.locator(loc).nth(i).locator('//td').nth(1) + const text: string = await tt.innerText() + const n: number = Number(text.replace(/[^0-9.-]+/g, '')) + volumeList.push(n) + } + console.log(`Top 10 pools Volume: ${volumeList}`) + return volumeList + } + + async getTopTenPoolsByAPR() { + const loc = '//tr/td//a[contains(@href, "/pool/")]/../..' + const aprList = [] + for (let i = 0; i < 10; i++) { + const tt = this.page.locator(loc).nth(i).locator('//td').nth(3) + const text: string = await tt.innerText() + aprList.push(text) + } + console.log(`Top 10 pools APRs: ${aprList}`) + return aprList + } +} diff --git a/packages/e2e/pages/portfolio-page.ts b/packages/e2e/pages/portfolio-page.ts new file mode 100644 index 0000000000..e09864ec1e --- /dev/null +++ b/packages/e2e/pages/portfolio-page.ts @@ -0,0 +1,71 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import type { Locator, Page } from '@playwright/test' + +import { BasePage } from './base-page' +import { TransactionsPage } from './transactions-page' + +export class PortfolioPage extends BasePage { + readonly hideZeros: Locator + readonly viewMore: Locator + readonly portfolioLink: Locator + readonly viewTransactions: Locator + readonly searchInput: Locator + + constructor(page: Page) { + super(page) + this.hideZeros = page.locator( + '//label[.="Hide zero balances"]/following-sibling::button', + ) + this.viewMore = page.getByText('View more') + this.portfolioLink = page.locator('//a//div[contains(text(), "Portfolio")]') + this.viewTransactions = page.locator('//div/a[.="View all"]') + this.searchInput = page.locator('//input[@id="search-input"]') + } + + async goto() { + await this.page.goto('/') + await this.portfolioLink.click() + // we expect that after 2 seconds tokens are loaded and any failure after this point should be considered a bug. + await this.page.waitForTimeout(2000) + const currentUrl = this.page.url() + console.log(`FE opened at: ${currentUrl}`) + } + + async getBalanceFor(token: string) { + await this.page.evaluate(() => window.scrollBy(0, 250)) + const bal = this.page + .locator(`//tbody/tr//a[contains(@href, "/assets/${token}")]`) + .nth(1) + const tokenBalance: string = await bal.innerText() + console.log(`Balance for ${token}: ${tokenBalance}`) + return tokenBalance + } + + async viewTransactionsPage() { + await this.viewTransactions.click() + await this.page.waitForTimeout(1000) + return new TransactionsPage(this.page) + } + + async hideZeroBalances() { + const isVisible = await this.hideZeros.isVisible({ timeout: 2000 }) + if (isVisible) { + await this.hideZeros.click() + await this.page.waitForTimeout(1000) + } + } + + async viewMoreBalances() { + const isVisible = await this.viewMore.isVisible({ timeout: 2000 }) + if (isVisible) { + await this.viewMore.click() + await this.page.waitForTimeout(1000) + } + } + + async searchForToken(tokenName: string) { + await this.searchInput.fill(tokenName) + // we expect that after 2 seconds tokens are loaded and any failure after this point should be considered a bug. + await this.page.waitForTimeout(2000) + } +} diff --git a/packages/e2e/pages/swap-page.ts b/packages/e2e/pages/swap-page.ts new file mode 100644 index 0000000000..721be13bf0 --- /dev/null +++ b/packages/e2e/pages/swap-page.ts @@ -0,0 +1,215 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import { + type BrowserContext, + type Locator, + type Page, + expect, +} from '@playwright/test' + +import { BasePage } from './base-page' + +export class SwapPage extends BasePage { + readonly page: Page + readonly swapBtn: Locator + readonly swapMaxBtn: Locator + readonly swapInput: Locator + readonly flipAssetsBtn: Locator + readonly exchangeRate: Locator + readonly trxSuccessful: Locator + readonly trxBroadcasting: Locator + readonly trxLink: Locator + + constructor(page: Page) { + super(page) + this.page = page + this.swapBtn = page.getByRole('button', { name: 'Swap', exact: true }) + this.swapMaxBtn = page.getByRole('button', { name: 'MAX', exact: true }) + this.swapInput = page.locator('//input[@data-testid="trade-input-swap"]') + this.flipAssetsBtn = page.locator( + '//div/button[contains(@class, "ease-bounce")]', + ) + this.exchangeRate = page.locator('//span[@data-testid="token-price"]') + this.trxSuccessful = page.locator('//h6[.="Transaction Succesful"]') + this.trxLink = page.getByText('View explorer') + this.trxBroadcasting = page.locator('//h6[.="Transaction Broadcasting"]') + } + + async goto() { + const assetPromise = this.page.waitForRequest('**/assets.json') + await this.page.goto('/') + const request = await assetPromise + expect(request).toBeTruthy() + // we expect that after 2 seconds tokens are loaded and any failure after this point should be considered a bug. + await this.page.waitForTimeout(2000) + const currentUrl = this.page.url() + console.log(`FE opened at: ${currentUrl}`) + } + + async flipTokenPair() { + await this.flipAssetsBtn.click() + await this.page.waitForTimeout(2000) + console.log('Fliped token pair.') + } + + async enterAmount(amount: string) { + // Just enter an amount for the swap and wait for a quote + await this.swapInput.fill(amount, { timeout: 2000 }) + await this.page.waitForTimeout(2000) + await expect(this.swapInput).toHaveValue(amount, { timeout: 3000 }) + const exchangeRate = await this.getExchangeRate() + console.log(`Swap ${amount} with rate: ${exchangeRate}`) + } + + async swapAndGetWalletMsg(context: BrowserContext) { + // Make sure to have sufficient balance and swap button is enabled + expect( + await this.isInsufficientBalance(), + 'Insufficient balance for the swap!', + ).toBeFalsy() + await expect(this.swapBtn).toBeEnabled({ timeout: 7000 }) + // Handle Pop-up page -> + const pageApprove = context.waitForEvent('page') + await this.swapBtn.click() + const approvePage = await pageApprove + await approvePage.waitForLoadState() + const approvePageTitle = approvePage.url() + console.log(`Approve page is opened at: ${approvePageTitle}`) + const approveBtn = approvePage.getByRole('button', { + name: 'Approve', + }) + await expect(approveBtn).toBeEnabled() + const msgContentAmount = await approvePage + .getByText('type: osmosis/poolmanager/') + .textContent() + console.log(`Wallet is approving this msg: \n${msgContentAmount}`) + // Approve trx + await approveBtn.click() + // wait for trx confirmation + await this.page.waitForTimeout(4000) + //await approvePage.close(); + // Handle Pop-up page <- + return { msgContentAmount } + } + + async selectPair(from: string, to: string) { + // Filter does not show already selected tokens + console.log(`Select pair ${from} to ${to}`) + const tokenLocator = + '//img[@alt="token icon"]/../..//h5 | //img[@alt="token icon"]/../..//span[@class="subtitle1"]' + const fromToken = this.page.locator(tokenLocator).nth(0) + const toToken = this.page.locator(tokenLocator).nth(1) + + const fromTokenText = await fromToken.innerText() + const toTokenText = await toToken.innerText() + console.log(`Current pair: ${fromTokenText} / ${toTokenText}`) + + if (fromTokenText === from && toTokenText === to) { + console.log( + `Current pair: ${fromTokenText}${toTokenText} is already matching.`, + ) + return + } + + if (fromTokenText === to && toTokenText === from) { + await this.flipTokenPair() + console.log(`Current pair: ${fromTokenText}${toTokenText} is fliped.`) + return + } + + if (from === toTokenText || to === fromTokenText) { + await this.flipTokenPair() + } + + if (fromTokenText !== from && toTokenText !== from) { + await fromToken.click() + // we expect that after 1 second token filter is displayed. + await this.page.waitForTimeout(1000) + await this.page.getByPlaceholder('Search').fill(from) + const fromLocator = this.page.locator( + `//div/button[@data-testid]//h6[.='${from}']`, + ) + await fromLocator.click() + } + + if (toTokenText !== to && fromTokenText !== to) { + await toToken.click() + // we expect that after 1 second token filter is displayed. + await this.page.waitForTimeout(1000) + await this.page.getByPlaceholder('Search').fill(to) + const toLocator = this.page.locator( + `//div/button[@data-testid]//h6[.='${to}']`, + ) + await toLocator.click() + } + // we expect that after 2 seconds exchange rate is populated. + await this.page.waitForTimeout(2000) + expect(await this.getExchangeRate()).toContain(from) + expect(await this.getExchangeRate()).toContain(to) + } + + async getExchangeRate() { + return await this.exchangeRate.innerText() + } + + async isTransactionSuccesful(delay = 7) { + console.log('Wait for a transaction success for 7 seconds.') + return await this.trxSuccessful.isVisible({ + timeout: delay * 1000, + }) + } + + async getTransactionUrl() { + const trxUrl = await this.trxLink.getAttribute('href') + console.log(`Trx url: ${trxUrl}`) + return trxUrl + } + + async isTransactionBroadcasted(delay = 5) { + console.log('Wait for a transaction broadcasting for 5 seconds.') + return await this.trxBroadcasting.isVisible({ timeout: delay * 1000 }) + } + + async isInsufficientBalance() { + const issufBalanceBtn = this.page.locator( + '//button[.="Insufficient balance"]', + ) + return await issufBalanceBtn.isVisible({ timeout: 2000 }) + } + + async isError() { + const errorBtn = this.page.locator('//button[.="Error"]') + return await errorBtn.isVisible({ timeout: 2000 }) + } + + async showSwapInfo() { + const swapInfo = this.page.locator("//button//span[.='Show details']") + await swapInfo.click() + console.log(`Price Impact: ${await this.getPriceInpact()}`) + } + + async getPriceInpact() { + const priceInpactSpan = this.page.locator( + '//span[.="Price Impact"]/..//span[@class="text-bullish-400"]', + ) + return await priceInpactSpan.textContent() + } + + async takeScreenshot(name: string) { + await this.page.screenshot({ + path: `screenshot-swap-${name}.png`, + fullPage: true, + }) + } + + async getSelectedPair() { + const tokenLocator = + '//img[@alt="token icon"]/../..//h5 | //img[@alt="token icon"]/../..//span[@class="subtitle1"]' + const fromToken = this.page.locator(tokenLocator).nth(0) + const toToken = this.page.locator(tokenLocator).nth(1) + + const fromTokenText = await fromToken.innerText() + const toTokenText = await toToken.innerText() + console.log(`Current pair: ${fromTokenText}/${toTokenText}`) + return `${fromTokenText}/${toTokenText}` + } +} diff --git a/packages/e2e/pages/trade-page.ts b/packages/e2e/pages/trade-page.ts new file mode 100644 index 0000000000..32c14d9298 --- /dev/null +++ b/packages/e2e/pages/trade-page.ts @@ -0,0 +1,352 @@ +import { + type BrowserContext, + type Locator, + type Page, + expect, +} from '@playwright/test' + +import { BasePage } from './base-page' + +export class TradePage extends BasePage { + readonly page: Page + readonly swapBtn: Locator + readonly swapMaxBtn: Locator + readonly flipAssetsBtn: Locator + readonly exchangeRate: Locator + readonly trxSuccessful: Locator + readonly trxBroadcasting: Locator + readonly trxLink: Locator + readonly inputAmount: Locator + readonly confirmSwapBtn: Locator + readonly buyTabBtn: Locator + readonly buyBtn: Locator + readonly sellTabBtn: Locator + readonly sellBtn: Locator + readonly limitTabBtn: Locator + readonly orderHistoryLink: Locator + readonly limitPrice: Locator + + constructor(page: Page) { + super(page) + this.page = page + this.swapBtn = page.locator('//button[@data-testid="trade-button-swap"]') + this.buyTabBtn = page.locator('//div[@class]/button[.="Buy"]/p[@class]/..') + this.buyBtn = page.locator('//div[@class]/button[@class]/h6[.="Buy"]/..') + this.sellBtn = page.locator('//div[@class]/button[@class]/h6[.="Sell"]/..') + this.sellTabBtn = page.locator( + '//div[@class]/button[.="Sell"]/p[@class]/..', + ) + this.confirmSwapBtn = page.locator('//div[@class]/button[.="Confirm"]') + this.swapMaxBtn = page.locator('//span[.="Max"]') + this.flipAssetsBtn = page.locator( + '//div/button[contains(@class, "ease-bounce")]', + ) + this.exchangeRate = page.locator('//span[@data-testid="token-price"]') + this.trxSuccessful = page.getByText('Transaction Successful') + this.trxLink = page.getByText('View explorer') + this.trxBroadcasting = page.locator('//h6[.="Transaction Broadcasting"]') + this.inputAmount = page.locator( + "//input[contains(@data-testid, 'trade-input')]", + ) + this.limitTabBtn = page.locator('//div[@class="w-full"]/button[.="Limit"]') + this.orderHistoryLink = page.getByText('Order history') + this.limitPrice = page.locator("//div/input[@type='text']") + } + + async goto() { + const assetPromise = this.page.waitForRequest('**/assets.json') + await this.page.goto('/') + const request = await assetPromise + expect(request).toBeTruthy() + // we expect that after 2 seconds tokens are loaded and any failure after this point should be considered a bug. + await this.page.waitForTimeout(2000) + const currentUrl = this.page.url() + console.log(`FE opened at: ${currentUrl}`) + } + + async gotoOrdersHistory(timeout = 1) { + await this.page.waitForTimeout(1000) + await this.orderHistoryLink.click() + await this.page.waitForTimeout(1000) + await new Promise((f) => setTimeout(f, timeout * 1000)) + const currentUrl = this.page.url() + console.log(`FE opened at: ${currentUrl}`) + } + + async openBuyTab() { + await this.buyTabBtn.click() + } + + async openSellTab() { + await this.sellTabBtn.click() + } + + async openLimit() { + await this.limitTabBtn.click() + await this.page.waitForTimeout(1000) + } + + async getLimitPrice() { + const lp = await this.limitPrice.inputValue() + console.log(`Current limit price is: ${lp}`) + return lp + } + + async setLimitPriceChange(change: string) { + const locator = `//button/span[contains(@class, "body2") and .="${change}"]` + await this.page.locator(locator).click() + await this.page.waitForTimeout(1000) + } + + async setLimitPrice(price: string) { + console.log(`Set Order Limit Price to: ${price}`) + await this.limitPrice.fill(price, { timeout: 2000 }) + } + + async flipTokenPair() { + await this.flipAssetsBtn.click() + await this.page.waitForTimeout(2000) + console.log('Fliped token pair.') + } + + async clickMaxAmountButton() { + await this.swapMaxBtn.click({ timeout: 2000 }) + await this.page.waitForTimeout(1000) + console.log('Clicked Max token amount button.') + } + + async enterAmount(amount: string) { + // Just enter an amount for the swap and wait for a quote + await this.inputAmount.fill(amount, { timeout: 2000 }) + await this.page.waitForTimeout(1000) + await expect(this.inputAmount).toHaveValue(amount, { timeout: 1000 }) + const exchangeRate = await this.getExchangeRate() + console.log(`Swap ${amount} with rate: ${exchangeRate}`) + } + + async swapAndGetWalletMsg(context: BrowserContext) { + // Make sure to have sufficient balance and swap button is enabled + expect( + await this.isInsufficientBalanceForSwap(), + 'Insufficient balance for the swap!', + ).toBeFalsy() + await expect(this.swapBtn).toBeEnabled({ timeout: 7000 }) + // Handle Pop-up page -> + await this.swapBtn.click() + const pageApprove = context.waitForEvent('page') + await this.confirmSwapBtn.click() + const approvePage = await pageApprove + await approvePage.waitForLoadState() + const approvePageTitle = approvePage.url() + console.log(`Approve page is opened at: ${approvePageTitle}`) + const approveBtn = approvePage.getByRole('button', { + name: 'Approve', + }) + await expect(approveBtn).toBeEnabled() + const msgContentAmount = await approvePage + .getByText('type: osmosis/poolmanager/') + .textContent() + console.log(`Wallet is approving this msg: \n${msgContentAmount}`) + // Approve trx + await approveBtn.click() + // wait for trx confirmation + await this.page.waitForTimeout(4000) + //await approvePage.close(); + // Handle Pop-up page <- + return { msgContentAmount } + } + + async selectAsset(token: string) { + const tokenLocator = '//div//button[@type]//img[@alt]' + const fromToken = this.page.locator(tokenLocator).nth(0) + await fromToken.click() + // we expect that after 1 second token filter is displayed. + await this.page.waitForTimeout(1000) + await this.page.getByPlaceholder('Search').fill(token) + const fromLocator = this.page.locator( + `//div/button[@data-testid='token-select-asset']//span[.='${token}']`, + ) + await fromLocator.click() + } + + async selectPair(from: string, to: string) { + // Filter does not show already selected tokens + console.log(`Select pair ${from} to ${to}`) + const fromToken = this.page.locator( + "//div//button[@data-testid='token-in']//img[@alt]", + ) + const toToken = this.page.locator( + "//div//button[@data-testid='token-out']//img[@alt]", + ) + // Select From Token + await fromToken.click({ timeout: 4000 }) + // we expect that after 1 second token filter is displayed. + await this.page.waitForTimeout(1000) + await this.page.getByPlaceholder('Search').fill(from) + const fromLocator = this.page + .locator( + `//div/button[@data-testid='token-select-asset']//span[.='${from}']`, + ) + .first() + await fromLocator.click({ timeout: 4000 }) + // Select To Token + await toToken.click({ timeout: 4000 }) + // we expect that after 1 second token filter is displayed. + await this.page.waitForTimeout(1000) + await this.page.getByPlaceholder('Search').fill(to) + const toLocator = this.page + .locator( + `//div/button[@data-testid='token-select-asset']//span[.='${to}']`, + ) + .first() + await toLocator.click() + // we expect that after 2 seconds exchange rate is populated. + await this.page.waitForTimeout(2000) + expect(await this.getExchangeRate()).toContain(from) + expect(await this.getExchangeRate()).toContain(to) + } + + async getExchangeRate() { + return await this.exchangeRate.innerText() + } + + async isTransactionSuccesful(delay = 7) { + console.log(`Wait for a transaction success for ${delay} seconds.`) + await expect(this.trxSuccessful).toBeVisible({ + timeout: delay * 1000, + visible: true, + }) + } + + async getTransactionUrl() { + const trxUrl = await this.trxLink.getAttribute('href') + console.log(`Trx url: ${trxUrl}`) + await this.page.reload() + return trxUrl + } + + async isTransactionBroadcasted(delay = 5) { + console.log(`Wait for a transaction broadcasting for ${delay} seconds.`) + return await this.trxBroadcasting.isVisible({ timeout: delay * 1000 }) + } + + async isInsufficientBalance() { + const issufBalanceBtn = this.page.locator( + '//span[.="Insufficient balance"]', + ) + return await issufBalanceBtn.isVisible({ timeout: 2000 }) + } + + async isInsufficientBalanceForSwap() { + const issufBalanceBtn = this.page.locator( + '//button[.="Insufficient balance"]', + ) + return await issufBalanceBtn.isVisible({ timeout: 2000 }) + } + + async isSufficientBalanceForTrade() { + // Make sure to have sufficient balance for a trade + expect( + await this.isInsufficientBalance(), + 'Insufficient balance for the swap!', + ).toBeFalsy() + } + + async isError() { + const errorBtn = this.page.locator('//button[.="Error"]') + return await errorBtn.isVisible({ timeout: 2000 }) + } + + async showSwapInfo() { + const swapInfo = this.page.locator("//button//span[.='Show details']") + await swapInfo.click({ timeout: 2000 }) + } + + async getPriceInpact() { + const priceInpactSpan = this.page.locator( + '//span[.="Price Impact"]/..//span[@class="text-bullish-400"]', + ) + return await priceInpactSpan.textContent() + } + + async takeScreenshot(name: string) { + await this.page.screenshot({ + path: `screenshot-trade-${name}.png`, + fullPage: true, + }) + } + + async getSelectedSwapPair() { + const tokenLocator = '//div//button[@type]//img[@alt]/../h5' + const fromToken = this.page.locator(tokenLocator).nth(0) + const toToken = this.page.locator(tokenLocator).nth(1) + await expect(fromToken).toBeVisible({ timeout: 2000 }) + const fromTokenText = await fromToken.innerText() + const toTokenText = await toToken.innerText() + console.log(`Current pair: ${fromTokenText}/${toTokenText}`) + return `${fromTokenText}/${toTokenText}` + } + + async buyAndGetWalletMsg(context: BrowserContext, limit = false) { + await expect(this.buyBtn, 'Buy button is disabled!').toBeEnabled({ + timeout: 9000, + }) + // Handle Pop-up page -> + await this.buyBtn.click() + const pageApprove = context.waitForEvent('page') + await this.confirmSwapBtn.click() + await this.page.waitForTimeout(200) + const approvePage = await pageApprove + await approvePage.waitForLoadState() + const approveBtn = approvePage.getByRole('button', { + name: 'Approve', + }) + await expect(approveBtn).toBeEnabled() + let msgTextLocator = 'type: osmosis/poolmanager/' + if (limit) { + msgTextLocator = 'Execute contract' + } + const msgContentAmount = await approvePage + .getByText(msgTextLocator) + .textContent() + console.log(`Wallet is approving this msg: \n${msgContentAmount}`) + // Approve trx + await approveBtn.click() + // wait for trx confirmation + await this.page.waitForTimeout(2000) + // Handle Pop-up page <- + return { msgContentAmount } + } + + async sellAndGetWalletMsg(context: BrowserContext, limit = false) { + // Make sure Sell button is enabled + await expect(this.sellBtn, 'Sell button is disabled!').toBeEnabled({ + timeout: 9000, + }) + // Handle Pop-up page -> + await this.sellBtn.click() + const pageApprove = context.waitForEvent('page') + await this.confirmSwapBtn.click() + await this.page.waitForTimeout(200) + const approvePage = await pageApprove + await approvePage.waitForLoadState() + const approveBtn = approvePage.getByRole('button', { + name: 'Approve', + }) + await expect(approveBtn).toBeEnabled() + let msgTextLocator = 'type: osmosis/poolmanager/' + if (limit) { + msgTextLocator = 'Execute contract' + } + const msgContentAmount = await approvePage + .getByText(msgTextLocator) + .textContent() + console.log(`Wallet is approving this msg: \n${msgContentAmount}`) + // Approve trx + await approveBtn.click() + // wait for trx confirmation + await this.page.waitForTimeout(2000) + // Handle Pop-up page <- + return { msgContentAmount } + } +} diff --git a/packages/e2e/pages/transactions-page.ts b/packages/e2e/pages/transactions-page.ts new file mode 100644 index 0000000000..89c60b8216 --- /dev/null +++ b/packages/e2e/pages/transactions-page.ts @@ -0,0 +1,177 @@ +import { + type BrowserContext, + type Locator, + type Page, + expect, +} from '@playwright/test' + +import { BasePage } from './base-page' +const TRANSACTION_CONFIRMATION_TIMEOUT = 2000 + +export class TransactionsPage extends BasePage { + readonly transactionRow: Locator + readonly viewExplorerLink: Locator + readonly closeTransactionBtn: Locator + readonly page: Page + readonly claimAndClose: Locator + readonly claimAllBtn: Locator + + constructor(page: Page) { + super(page) + this.page = page + this.transactionRow = page.locator('//div/p[.="Swapped"]') + this.viewExplorerLink = page.locator('//a/span["View on explorer"]/..') + this.closeTransactionBtn = page.locator('//button[@data-testid="close"]') + this.claimAndClose = page.getByRole('button', { + name: 'Claim and close', + exact: true, + }) + this.claimAllBtn = page.getByRole('button', { + name: 'Claim all', + exact: true, + }) + } + + async open() { + await this.page.goto('/transactions') + return this + } + + async viewTransactionByNumber(number: number) { + await this.transactionRow.nth(number).click() + await this.page.waitForTimeout(1000) + } + + async viewBySwapAmount(amount: string | number) { + // Transactions need some time to get loaded, wait for 30 seconds. + await this.page.waitForTimeout(30000) + await this.page.reload() + const loc = `//div/div[@class="subtitle1 text-osmoverse-100" and contains(text(), "${amount}")]` + const isTransactionVisible = await this.page + .locator(loc) + .isVisible({ timeout: 3000 }) + if (!isTransactionVisible) { + await this.page.waitForTimeout(30000) + await this.page.reload() + } + await this.page.waitForTimeout(1000) + await this.page.locator(loc).click({ timeout: 3000 }) + } + + async closeTransaction() { + await this.closeTransactionBtn.click() + } + + async viewOnExplorerIsVisible() { + await expect(this.viewExplorerLink).toBeVisible() + } + + async getOnExplorerLink() { + const trxUrl = await this.viewExplorerLink.getAttribute('href') + console.log(`Trx url: ${trxUrl}`) + return trxUrl + } + + async takeScreenshot(name: string) { + await this.page.screenshot({ + path: `screenshot-transactions-${name}.png`, + fullPage: true, + }) + } + + async cancelLimitOrder( + amount: string, + price: string, + context: BrowserContext, + ) { + const cancelBtn = `//td//span[.='${amount}']/../../../../..//td//p[.='$${price}']/../../..//button` + console.log(`Use locator for a cancel btn: ${cancelBtn}`) + await this.page.locator(cancelBtn).first().click() + const pageApprove = context.waitForEvent('page') + const approvePage = await pageApprove + await approvePage.waitForLoadState() + const approveBtn = approvePage.getByRole('button', { + name: 'Approve', + }) + await expect(approveBtn).toBeEnabled() + const msgContentAmount = await approvePage + .getByText('Execute contract') + .textContent() + console.log(`Wallet is approving this msg: \n${msgContentAmount}`) + // Approve trx + await approveBtn.click() + // Expect that this is a cancel limit call + expect(msgContentAmount).toContain('cancel_limit') + // wait for trx confirmation + await this.page.waitForTimeout(TRANSACTION_CONFIRMATION_TIMEOUT) + } + + async isFilledByLimitPrice(price: string | number) { + const loc = `//td//span[.='Filled']/../../..//td//p[.='$${price}']` + console.log(`Use Limit Order locator: ${loc}`) + await expect(this.page.locator(loc).first()).toBeVisible({ + timeout: 120_000, + visible: true, + }) + } + + async claimAndCloseAny(context: BrowserContext) { + const isClaimable = await this.claimAndClose + .first() + .isVisible({ timeout: 3000 }) + if (!isClaimable) { + console.log('No partially filled orders to claim.') + return + } + await this.claimAndClose.first().click() + const pageApprove = context.waitForEvent('page') + const approvePage = await pageApprove + await approvePage.waitForLoadState() + const approveBtn = approvePage.getByRole('button', { + name: 'Approve', + }) + await expect(approveBtn).toBeEnabled() + const msgContentAmount1 = await approvePage + .getByText('Execute contract') + .first() + .textContent() + const msgContentAmount2 = await approvePage + .getByText('Execute contract') + .last() + .textContent() + console.log( + `Wallet is approving this msg: \n${msgContentAmount1}---- \n${msgContentAmount2}`, + ) + // Approve trx + await approveBtn.click() + expect(msgContentAmount1).toContain('claim_limit') + expect(msgContentAmount2).toContain('cancel_limit') + // wait for trx confirmation + await this.page.waitForTimeout(TRANSACTION_CONFIRMATION_TIMEOUT) + } + + async claimAll(context: BrowserContext) { + await this.claimAllBtn.click() + const pageApprove = context.waitForEvent('page') + const approvePage = await pageApprove + await approvePage.waitForLoadState() + const approveBtn = approvePage.getByRole('button', { + name: 'Approve', + }) + await expect(approveBtn).toBeEnabled() + // Approve trx + await approveBtn.click() + // wait for trx confirmation + await this.page.waitForTimeout(TRANSACTION_CONFIRMATION_TIMEOUT) + } + + async claimAllIfPresent(context: BrowserContext) { + const isClaimable = await this.claimAllBtn.isVisible({ timeout: 4000 }) + if (isClaimable) { + console.log('Claim All filled limit orders!') + await this.claimAll(context) + } else { + console.log('No Claim All button.') + } + } +} diff --git a/packages/web/playwright.config.ts b/packages/e2e/playwright.config.ts similarity index 73% rename from packages/web/playwright.config.ts rename to packages/e2e/playwright.config.ts index 81b27c50f7..c51d78a4a2 100644 --- a/packages/web/playwright.config.ts +++ b/packages/e2e/playwright.config.ts @@ -1,11 +1,7 @@ /* eslint-disable import/no-extraneous-dependencies */ import { defineConfig, devices } from "@playwright/test"; -/** - * Read environment variables from file. - * https://github.com/motdotla/dotenv - */ -// require('dotenv').config(); +import "dotenv/config"; /** * See https://playwright.dev/docs/test-configuration. @@ -15,24 +11,17 @@ export default defineConfig({ reporter: [ ["html", { open: "never" }], ["junit", { outputFile: "./playwright-report/test-results.xml" }], - [ - "monocart-reporter", - { - name: "Test Coverage Report", - outputFile: "./playwright-report/cov-report.html", - }, - ], ], timeout: 45000, - testDir: "./e2e/tests", - /* Run tests in files in parallel */ - fullyParallel: false, + testDir: "./tests", + /* Run tests in files in parallel. */ + fullyParallel: true, /* Fail the build on CI if you accidentally left test.only in the source code. */ forbidOnly: !!process.env.CI, /* Retry on CI only */ - retries: process.env.CI ? 2 : 0, + retries: process.env.CI ? 1 : 0, /* Opt out of parallel tests on CI. Multiple swaps on same account could be unsatble. Test execution will be batched per agent. */ - workers: process.env.CI ? 1 : undefined, + workers: 1, /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { baseURL: process.env.BASE_URL ?? "https://stage.osmosis.zone", diff --git a/packages/web/e2e/test-config.ts b/packages/e2e/test-config.ts similarity index 93% rename from packages/web/e2e/test-config.ts rename to packages/e2e/test-config.ts index a72bf1ff44..ea8c63562c 100644 --- a/packages/web/e2e/test-config.ts +++ b/packages/e2e/test-config.ts @@ -29,8 +29,9 @@ export class TestConfig { if (USE_PROXY) { console.info( - "Get Test Proxy configuration for server: " + + `Get Test Proxy configuration for server: ${ this.getProxyConfig().server + }` ); return { headless: headless, @@ -54,8 +55,9 @@ export class TestConfig { const viewport = { width: 1440, height: 1280 }; if (USE_PROXY) { console.info( - "Get Test Proxy configuration for server: " + + `Get Test Proxy configuration for server: ${ this.getProxyConfig().server + }` ); return { headless: headless, diff --git a/packages/e2e/tests/claim.spec.ts b/packages/e2e/tests/claim.spec.ts new file mode 100644 index 0000000000..b64af411c0 --- /dev/null +++ b/packages/e2e/tests/claim.spec.ts @@ -0,0 +1,58 @@ +import { type BrowserContext, chromium, test } from '@playwright/test' + +import { TransactionsPage } from '../pages/transactions-page' +import { TestConfig } from '../test-config' +import { UnzipExtension } from '../unzip-extension' + +import { WalletPage } from '../pages/keplr-page' +import { TradePage } from '../pages/trade-page' + +test.describe('Test Claim All Orders feature', () => { + let context: BrowserContext + const privateKey = process.env.PRIVATE_KEY ?? 'private_key' + let tradePage: TradePage + + test.beforeAll(async () => { + const pathToExtension = new UnzipExtension().getPathToExtension() + console.log('\nSetup Wallet Extension before tests.') + // Launch Chrome with a Keplr wallet extension + context = await chromium.launchPersistentContext( + '', + new TestConfig().getBrowserExtensionConfig(false, pathToExtension), + ) + // Get all new pages (including Extension) in the context and wait + const emptyPage = context.pages()[0] + await emptyPage.waitForTimeout(2000) + const page = context.pages()[1] + const walletPage = new WalletPage(page) + // Import existing Wallet (could be aggregated in one function). + await walletPage.importWalletWithPrivateKey(privateKey) + await walletPage.setWalletNameAndPassword('Claim All Orders') + await walletPage.selectChainsAndSave() + await walletPage.finish() + // Switch to Application + tradePage = new TradePage(context.pages()[0]) + await tradePage.goto() + await tradePage.connectWallet() + }) + + test.afterAll(async () => { + await context.close() + }) + + test('User should be able to Claim All filled limit orders', async () => { + await tradePage.goto() + await tradePage.gotoOrdersHistory(10) + const p = context.pages()[0] + const trxPage = new TransactionsPage(p) + await trxPage.claimAllIfPresent(context) + }) + + test('User should be able to Claim and Close partialy filled limit orders', async () => { + await tradePage.goto() + await tradePage.gotoOrdersHistory(10) + const p = context.pages()[0] + const trxPage = new TransactionsPage(p) + await trxPage.claimAndCloseAny(context) + }) +}) diff --git a/packages/e2e/tests/monitoring.limit.wallet.spec.ts b/packages/e2e/tests/monitoring.limit.wallet.spec.ts new file mode 100644 index 0000000000..a688f9e18e --- /dev/null +++ b/packages/e2e/tests/monitoring.limit.wallet.spec.ts @@ -0,0 +1,99 @@ +import { type BrowserContext, chromium, expect, test } from '@playwright/test' + +import { TransactionsPage } from '../pages/transactions-page' +import { TestConfig } from '../test-config' +import { UnzipExtension } from '../unzip-extension' + +import { WalletPage } from '../pages/keplr-page' +import { TradePage } from '../pages/trade-page' + +test.describe('Test Filled Limit Order feature', () => { + let context: BrowserContext + const privateKey = process.env.PRIVATE_KEY ?? 'private_key' + let tradePage: TradePage + + test.beforeAll(async () => { + const pathToExtension = new UnzipExtension().getPathToExtension() + console.log('\nSetup Wallet Extension before tests.') + // Launch Chrome with a Keplr wallet extension + context = await chromium.launchPersistentContext( + '', + new TestConfig().getBrowserExtensionConfig(false, pathToExtension), + ) + // Get all new pages (including Extension) in the context and wait + const emptyPage = context.pages()[0] + await emptyPage.waitForTimeout(2000) + const page = context.pages()[1] + const walletPage = new WalletPage(page) + // Import existing Wallet (could be aggregated in one function). + await walletPage.importWalletWithPrivateKey(privateKey) + await walletPage.setWalletNameAndPassword('Monitoring E2E Tests') + await walletPage.selectChainsAndSave() + await walletPage.finish() + // Switch to Application + tradePage = new TradePage(context.pages()[0]) + await tradePage.goto() + await tradePage.connectWallet() + expect(await tradePage.isError(), 'Swap is not available!').toBeFalsy() + }) + + test.afterAll(async () => { + await context.close() + }) + + // biome-ignore lint/correctness/noEmptyPattern: + test.afterEach(async ({}, testInfo) => { + console.log(`Test [${testInfo.title}] status: ${testInfo.status}`) + if (testInfo.status === 'failed') { + const name = testInfo.title + process.env.GITHUB_STEP_SUMMARY = `Test ${name} failed.` + } + }) + + test('User should be able to limit sell OSMO', async () => { + await tradePage.goto() + await tradePage.openSellTab() + await tradePage.openLimit() + await tradePage.selectAsset('OSMO') + await tradePage.enterAmount('1.08') + await tradePage.setLimitPriceChange('Market') + const { msgContentAmount } = await tradePage.sellAndGetWalletMsg( + context, + true, + ) + expect(msgContentAmount, 'No msg from the wallet!').toBeTruthy() + // now this is converted from USDC + expect(msgContentAmount).toContain('place_limit') + expect(msgContentAmount).toContain('"order_direction": "ask"') + await tradePage.isTransactionSuccesful() + await tradePage.getTransactionUrl() + }) + + test('User should be able to limit buy OSMO', async () => { + const PRICE_INCREASE_FACTOR = 1.07 // 7% increase for limit price + const ORDER_HISTORY_TIMEOUT = 30 // Seconds to wait for order history + await tradePage.goto() + await tradePage.openBuyTab() + await tradePage.openLimit() + await tradePage.selectAsset('OSMO') + await tradePage.enterAmount('1.04') + await tradePage.setLimitPriceChange('Market') + const limitPrice = Number(await tradePage.getLimitPrice()) + const highLimitPrice = (limitPrice * PRICE_INCREASE_FACTOR).toFixed(4) + await tradePage.setLimitPrice(String(highLimitPrice)) + const { msgContentAmount } = await tradePage.buyAndGetWalletMsg( + context, + true, + ) + expect(msgContentAmount, 'No msg from the wallet!').toBeTruthy() + expect(msgContentAmount).toContain('"quantity": "1040000"') + expect(msgContentAmount).toContain('place_limit') + expect(msgContentAmount).toContain('"order_direction": "bid"') + await tradePage.isTransactionSuccesful() + await tradePage.getTransactionUrl() + await tradePage.gotoOrdersHistory(ORDER_HISTORY_TIMEOUT) + const p = context.pages()[0] + const trxPage = new TransactionsPage(p) + await trxPage.isFilledByLimitPrice(highLimitPrice) + }) +}) diff --git a/packages/e2e/tests/monitoring.market.wallet.spec.ts b/packages/e2e/tests/monitoring.market.wallet.spec.ts new file mode 100644 index 0000000000..a14d0ad53b --- /dev/null +++ b/packages/e2e/tests/monitoring.market.wallet.spec.ts @@ -0,0 +1,98 @@ +import { type BrowserContext, chromium, expect, test } from '@playwright/test' + +import { TestConfig } from '../test-config' +import { UnzipExtension } from '../unzip-extension' + +import { WalletPage } from '../pages/keplr-page' +import { TradePage } from '../pages/trade-page' + +test.describe('Test Market Buy/Sell Order feature', () => { + let context: BrowserContext + const privateKey = process.env.PRIVATE_KEY ?? 'private_key' + let tradePage: TradePage + const TRX_SUCCESS_TIMEOUT = 10000 + + test.beforeAll(async () => { + const pathToExtension = new UnzipExtension().getPathToExtension() + console.log('\nSetup Wallet Extension before tests.') + // Launch Chrome with a Keplr wallet extension + context = await chromium.launchPersistentContext( + '', + new TestConfig().getBrowserExtensionConfig(false, pathToExtension), + ) + // Get all new pages (including Extension) in the context and wait + const emptyPage = context.pages()[0] + await emptyPage.waitForTimeout(2000) + const page = context.pages()[1] + const walletPage = new WalletPage(page) + // Import existing Wallet (could be aggregated in one function). + await walletPage.importWalletWithPrivateKey(privateKey) + await walletPage.setWalletNameAndPassword('Monitoring E2E Tests') + await walletPage.selectChainsAndSave() + await walletPage.finish() + // Switch to Application + tradePage = new TradePage(context.pages()[0]) + await tradePage.goto() + await tradePage.connectWallet() + expect(await tradePage.isError(), 'Swap is not available!').toBeFalsy() + }) + + test.afterAll(async () => { + await context.close() + }) + + // biome-ignore lint/correctness/noEmptyPattern: + test.afterEach(async ({}, testInfo) => { + console.log(`Test [${testInfo.title}] status: ${testInfo.status}`) + if (testInfo.status === 'failed') { + const name = testInfo.title + process.env.GITHUB_STEP_SUMMARY = `Test ${name} failed.` + } + }) + + // biome-ignore lint/complexity/noForEach: + ;[{ name: 'WBTC' }, { name: 'OSMO' }].forEach(({ name }) => { + test(`User should be able to Market Buy ${name}`, async () => { + await tradePage.goto() + await tradePage.openBuyTab() + await tradePage.selectAsset(name) + await tradePage.enterAmount('1.55') + await tradePage.isSufficientBalanceForTrade() + await tradePage.showSwapInfo() + const { msgContentAmount } = await tradePage.buyAndGetWalletMsg(context) + expect(msgContentAmount).toBeTruthy() + expect(msgContentAmount).toContain('type: osmosis/poolmanager/') + await tradePage.isTransactionSuccesful(TRX_SUCCESS_TIMEOUT) + await tradePage.getTransactionUrl() + }) + }) + + // unwrapped market sell tests just in case this affects anything. + test('User should be able to Market Sell WBTC', async () => { + await tradePage.goto() + await tradePage.openSellTab() + await tradePage.selectAsset('WBTC') + await tradePage.enterAmount('1.54') + await tradePage.isSufficientBalanceForTrade() + await tradePage.showSwapInfo() + const { msgContentAmount } = await tradePage.sellAndGetWalletMsg(context) + expect(msgContentAmount).toBeTruthy() + expect(msgContentAmount).toContain('type: osmosis/poolmanager/') + await tradePage.isTransactionSuccesful(TRX_SUCCESS_TIMEOUT) + await tradePage.getTransactionUrl() + }) + + test('User should be able to Market Sell OSMO', async () => { + await tradePage.goto() + await tradePage.openSellTab() + await tradePage.selectAsset('OSMO') + await tradePage.enterAmount('1.54') + await tradePage.isSufficientBalanceForTrade() + await tradePage.showSwapInfo() + const { msgContentAmount } = await tradePage.sellAndGetWalletMsg(context) + expect(msgContentAmount).toBeTruthy() + expect(msgContentAmount).toContain('type: osmosis/poolmanager/') + await tradePage.isTransactionSuccesful(TRX_SUCCESS_TIMEOUT) + await tradePage.getTransactionUrl() + }) +}) diff --git a/packages/e2e/tests/monitoring.swap.wallet.spec.ts b/packages/e2e/tests/monitoring.swap.wallet.spec.ts new file mode 100644 index 0000000000..5127f85525 --- /dev/null +++ b/packages/e2e/tests/monitoring.swap.wallet.spec.ts @@ -0,0 +1,101 @@ +import { type BrowserContext, chromium, expect, test } from '@playwright/test' + +import { WalletPage } from '../pages/keplr-page' +import { TradePage } from '../pages/trade-page' +import { TestConfig } from '../test-config' +import { UnzipExtension } from '../unzip-extension' + +test.describe('Test Swap Stables feature', () => { + let context: BrowserContext + const privateKey = process.env.PRIVATE_KEY ?? 'private_key' + let tradePage: TradePage + const USDC = + 'ibc/498A0751C798A0D9A389AA3691123DADA57DAA4FE165D5C75894505B876BA6E4' + const USDCa = + 'ibc/D189335C6E4A68B513C10AB227BF1C1D38C746766278BA3EEB4FB14124F1D858' + const allUSDT = + 'factory/osmo1em6xs47hd82806f5cxgyufguxrrc7l0aqx7nzzptjuqgswczk8csavdxek/alloyed/allUSDT' + const swapAmount = '0.55' + + test.beforeAll(async () => { + const pathToExtension = new UnzipExtension().getPathToExtension() + console.log('\nSetup Wallet Extension before tests.') + // Launch Chrome with a Keplr wallet extension + context = await chromium.launchPersistentContext( + '', + new TestConfig().getBrowserExtensionConfig(false, pathToExtension), + ) + // Get all new pages (including Extension) in the context and wait + const emptyPage = context.pages()[0] + await emptyPage.waitForTimeout(2000) + let page = context.pages()[1] + const walletPage = new WalletPage(page) + // Import existing Wallet (could be aggregated in one function). + await walletPage.importWalletWithPrivateKey(privateKey) + await walletPage.setWalletNameAndPassword('Test Stables') + await walletPage.selectChainsAndSave() + await walletPage.finish() + page = context.pages()[0] + tradePage = new TradePage(page) + + await tradePage.goto() + await tradePage.connectWallet() + expect(await tradePage.isError(), 'Swap is not available!').toBeFalsy() + }) + + test.afterAll(async () => { + await context.close() + }) + + test('User should be able to swap USDC to USDC.eth.axl', async () => { + await tradePage.goto() + await tradePage.selectPair('USDC', 'USDC.eth.axl') + await tradePage.enterAmount(swapAmount) + await tradePage.showSwapInfo() + const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) + expect(msgContentAmount).toBeTruthy() + expect(msgContentAmount).toContain(`denom: ${USDC}`) + expect(msgContentAmount).toContain(`token_out_denom: ${USDCa}`) + await tradePage.isTransactionSuccesful() + await tradePage.getTransactionUrl() + }) + + test('User should be able to swap USDC.eth.axl to USDC', async () => { + await tradePage.goto() + await tradePage.selectPair('USDC.eth.axl', 'USDC') + await tradePage.enterAmount(swapAmount) + await tradePage.showSwapInfo() + const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) + expect(msgContentAmount).toBeTruthy() + expect(msgContentAmount).toContain(`denom: ${USDCa}`) + expect(msgContentAmount).toContain(`token_out_denom: ${USDC}`) + await tradePage.isTransactionSuccesful() + await tradePage.getTransactionUrl() + }) + + test('User should be able to swap USDT to USDC', async () => { + await tradePage.goto() + await tradePage.selectPair('USDT', 'USDC') + await tradePage.enterAmount(swapAmount) + await tradePage.showSwapInfo() + const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) + expect(msgContentAmount).toBeTruthy() + expect(msgContentAmount).toContain(USDC) + expect(msgContentAmount).toContain(allUSDT) + await tradePage.isTransactionSuccesful() + await tradePage.getTransactionUrl() + }) + + test('User should be able to swap USDC to USDT', async () => { + await tradePage.goto() + await tradePage.selectPair('USDC', 'USDT') + await tradePage.enterAmount(swapAmount) + await tradePage.showSwapInfo() + const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) + expect(msgContentAmount).toBeTruthy() + expect(msgContentAmount).toContain(`denom: ${USDC}`) + expect(msgContentAmount).toContain(allUSDT) + await tradePage.isTransactionSuccesful() + await tradePage.getTransactionUrl() + }) +}) diff --git a/packages/e2e/tests/pools.spec.ts b/packages/e2e/tests/pools.spec.ts new file mode 100644 index 0000000000..73e9ad04e7 --- /dev/null +++ b/packages/e2e/tests/pools.spec.ts @@ -0,0 +1,77 @@ +import { + type BrowserContext, + type Page, + chromium, + expect, + test, +} from '@playwright/test' + +import { TestConfig } from '../test-config' + +import { PoolsPage } from '../pages/pools-page' + +test.describe('Test Select Pool feature', () => { + let context: BrowserContext + let poolsPage: PoolsPage + let page: Page + + test.beforeAll(async () => { + context = await chromium.launchPersistentContext( + '', + new TestConfig().getBrowserConfig(true), + ) + page = context.pages()[0] + poolsPage = new PoolsPage(page) + }) + + test.afterAll(async () => { + await context.close() + }) + + test('User should be able to see at least 10 pools', async () => { + await poolsPage.goto() + expect(await poolsPage.getPoolsNumber()).toBeGreaterThan(10) + const topLiquidity = await poolsPage.getTopTenPoolsByLiquidity() + topLiquidity.every((element) => { + expect(element).toBeGreaterThan(10_000) + }) + const topVolume = await poolsPage.getTopTenPoolsByVolume() + topVolume.every((element) => { + expect(element).toBeGreaterThan(10_000) + }) + const topAPR = await poolsPage.getTopTenPoolsByAPR() + topAPR.every((element) => { + expect(element).toContain('%') + }) + }) + + test('User should be able to select ATOM/USDC pool', async () => { + const poolName = 'ATOM/USDC' + await poolsPage.goto() + await poolsPage.searchForPool(poolName) + const poolPage = await poolsPage.viewPool(1282, poolName) + const balance = await poolPage.getBalance() + expect(balance).toEqual('$0') + const tradeModal = await poolPage.getTradeModal() + await tradeModal.enterAmount('1') + const rate = await tradeModal.getExchangeRate() + await tradeModal.showSwapInfo() + expect(rate).toContain('ATOM') + expect(rate).toContain('USDC') + }) + + test('User should be able to select OSMO/USDC pool', async () => { + const poolName = 'OSMO/USDC' + await poolsPage.goto() + await poolsPage.searchForPool(poolName) + const poolPage = await poolsPage.viewPool(1464, poolName) + const balance = await poolPage.getBalance() + expect(balance).toEqual('$0') + const tradeModal = await poolPage.getTradeModal() + await tradeModal.enterAmount('1') + const rate = await tradeModal.getExchangeRate() + await tradeModal.showSwapInfo() + expect(rate).toContain('OSMO') + expect(rate).toContain('USDC') + }) +}) diff --git a/packages/e2e/tests/portfolio.wallet.spec.ts b/packages/e2e/tests/portfolio.wallet.spec.ts new file mode 100644 index 0000000000..7ceba58f4b --- /dev/null +++ b/packages/e2e/tests/portfolio.wallet.spec.ts @@ -0,0 +1,85 @@ +import { + type BrowserContext, + type Page, + chromium, + expect, + test, +} from '@playwright/test' + +import { TestConfig } from '../test-config' +import { UnzipExtension } from '../unzip-extension' + +import { WalletPage } from '../pages/keplr-page' +import { PortfolioPage } from '../pages/portfolio-page' + +test.describe('Test Portfolio feature', () => { + let context: BrowserContext + const privateKey = process.env.PRIVATE_KEY ?? 'pk' + let portfolioPage: PortfolioPage + const dollarBalanceRegEx = /\$\d+/ + let page: Page + + test.beforeAll(async () => { + const pathToExtension = new UnzipExtension().getPathToExtension() + console.log('\nSetup Wallet Extension before tests.') + // Launch Chrome with a Keplr wallet extension + context = await chromium.launchPersistentContext( + '', + new TestConfig().getBrowserExtensionConfig(false, pathToExtension), + ) + // Get all new pages (including Extension) in the context and wait + const emptyPage = context.pages()[0] + await emptyPage.waitForTimeout(2000) + page = context.pages()[1] + const walletPage = new WalletPage(page) + // Import existing Wallet (could be aggregated in one function). + await walletPage.importWalletWithPrivateKey(privateKey) + await walletPage.setWalletNameAndPassword('Test Portfolio') + await walletPage.selectChainsAndSave() + await walletPage.finish() + // Switch to Application + page = context.pages()[0] + portfolioPage = new PortfolioPage(page) + await portfolioPage.goto() + await portfolioPage.connectWallet() + await portfolioPage.hideZeroBalances() + await portfolioPage.viewMoreBalances() + }) + + test.afterAll(async () => { + await context.close() + }) + + // biome-ignore lint/complexity/noForEach: + ;[ + { name: 'OSMO' }, + { name: 'ATOM' }, + { name: 'USDT' }, + { name: 'USDC' }, + { name: 'TIA' }, + { name: 'DAI' }, + ].forEach(({ name }) => { + test(`User should be able to see native balances for ${name}`, async () => { + await portfolioPage.searchForToken(name) + const osmoBalance = await portfolioPage.getBalanceFor(name) + expect(osmoBalance).toMatch(dollarBalanceRegEx) + }) + }) + + // biome-ignore lint/complexity/noForEach: + ;[ + { name: 'INJ' }, + { name: 'ETH.axl' }, + { name: 'SOL' }, + { name: 'milkTIA' }, + { name: 'BTC' }, + { name: 'WBTC' }, + { name: 'ETH' }, + ].forEach(({ name }) => { + test(`User should be able to see bridged balances for ${name}`, async () => { + await portfolioPage.searchForToken(name) + const osmoBalance = await portfolioPage.getBalanceFor(name) + expect(osmoBalance).toMatch(dollarBalanceRegEx) + }) + }) +}) diff --git a/packages/e2e/tests/select.spec.ts b/packages/e2e/tests/select.spec.ts new file mode 100644 index 0000000000..2356287647 --- /dev/null +++ b/packages/e2e/tests/select.spec.ts @@ -0,0 +1,109 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import { + type BrowserContext, + type Page, + chromium, + test, +} from '@playwright/test' + +import { TradePage } from '../pages/trade-page' +import { TestConfig } from '../test-config' + +// Pairs are selected from top 10 +test.describe('Test Select Swap Pair feature', () => { + let context: BrowserContext + let swapPage: TradePage + let page: Page + + test.beforeAll(async () => { + context = await chromium.launchPersistentContext( + '', + new TestConfig().getBrowserConfig(true), + ) + page = context.pages()[0] + swapPage = new TradePage(page) + await swapPage.goto() + }) + + test.afterAll(async () => { + console.log(test.info()) + await context.close() + }) + + // Price Impact-54.768% -> no liquidity + test('User should be able to select nBTC/USDC', async () => { + await swapPage.goto() + await swapPage.selectPair('nBTC', 'USDC') + await swapPage.enterAmount('0.01') + await swapPage.showSwapInfo() + }) + + test('User should be able to select WBTC/USDC', async () => { + await swapPage.goto() + await swapPage.selectPair('WBTC', 'USDC') + await swapPage.enterAmount('0.1') + await swapPage.showSwapInfo() + }) + + test('User should be able to select OSMO/USDC', async () => { + await swapPage.goto() + await swapPage.selectPair('OSMO', 'USDC') + await swapPage.enterAmount('1') + await swapPage.showSwapInfo() + }) + + test('User should be able to select INJ/USDC', async () => { + await swapPage.goto() + await swapPage.selectPair('INJ', 'USDC') + await swapPage.enterAmount('10') + await swapPage.showSwapInfo() + }) + + test('User should be able to select TIA/USDC', async () => { + await swapPage.goto() + await swapPage.selectPair('TIA', 'USDC') + await swapPage.enterAmount('100') + await swapPage.showSwapInfo() + }) + + test('User should be able to select ATOM/USDC', async () => { + await swapPage.selectPair('ATOM', 'USDC') + await swapPage.enterAmount('100') + }) + + test('User should be able to select USDT/USDC', async () => { + await swapPage.selectPair('USDT', 'USDC') + await swapPage.enterAmount('10000') + }) + + test('User should be able to select TIA/OSMO', async () => { + await swapPage.selectPair('TIA', 'OSMO') + await swapPage.enterAmount('100') + }) + + test('User should be able to select AKT/OSMO', async () => { + await swapPage.selectPair('AKT', 'OSMO') + await swapPage.enterAmount('100') + }) + + test('User should be able to select PICA/OSMO', async () => { + await swapPage.selectPair('PICA', 'OSMO') + await swapPage.enterAmount('100') + }) + + test('User should be able to select USDT/OSMO', async () => { + await swapPage.selectPair('USDT', 'OSMO') + await swapPage.enterAmount('100') + }) + + test('User should be able to select TIA/BOOT', async () => { + // Just to verify some odd pair + await swapPage.selectPair('TIA', 'BOOT') + await swapPage.enterAmount('100') + }) + + test('User should be able to select stATOM/USDC', async () => { + await swapPage.selectPair('stATOM', 'USDC') + await swapPage.enterAmount('100') + }) +}) diff --git a/packages/e2e/tests/swap.wallet.spec.ts b/packages/e2e/tests/swap.wallet.spec.ts new file mode 100644 index 0000000000..394b6fbe4c --- /dev/null +++ b/packages/e2e/tests/swap.wallet.spec.ts @@ -0,0 +1,234 @@ +import { type BrowserContext, chromium, expect, test } from '@playwright/test' + +import { TestConfig } from '../test-config' +import { UnzipExtension } from '../unzip-extension' + +import { WalletPage } from '../pages/keplr-page' +import { TradePage } from '../pages/trade-page' + +test.describe('Test Swap feature', () => { + let context: BrowserContext + const walletId = + process.env.WALLET_ID ?? 'osmo1qyc8u7cn0zjxcu9dvrjz5zwfnn0ck92v62ak9l' + const privateKey = process.env.PRIVATE_KEY ?? 'private_key' + let tradePage: TradePage + const USDC = + 'ibc/498A0751C798A0D9A389AA3691123DADA57DAA4FE165D5C75894505B876BA6E4' + const ATOM = + 'ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2' + const TIA = + 'ibc/D79E7D83AB399BFFF93433E54FAA480C191248FC556924A2A8351AE2638B3877' + const INJ = + 'ibc/64BA6E31FE887D66C6F8F31C7B1A80C7CA179239677B4088BB55F5EA07DBE273' + const AKT = + 'ibc/1480B8FD20AD5FCAE81EA87584D269547DD4D436843C1D20F15E00EB64743EF4' + + test.beforeAll(async () => { + const pathToExtension = new UnzipExtension().getPathToExtension() + console.log('\nSetup Wallet Extension before tests.') + // Launch Chrome with a Keplr wallet extension + context = await chromium.launchPersistentContext( + '', + new TestConfig().getBrowserExtensionConfig(false, pathToExtension), + ) + // Get all new pages (including Extension) in the context and wait + const emptyPage = context.pages()[0] + await emptyPage.waitForTimeout(2000) + const page = context.pages()[1] + const walletPage = new WalletPage(page) + // Import existing Wallet (could be aggregated in one function). + await walletPage.importWalletWithPrivateKey(privateKey) + await walletPage.setWalletNameAndPassword('Test Swaps') + await walletPage.selectChainsAndSave() + await walletPage.finish() + // Switch to Application + tradePage = new TradePage(context.pages()[0]) + await tradePage.goto() + await tradePage.connectWallet() + expect(await tradePage.isError(), 'Swap is not available!').toBeFalsy() + }) + + test.afterAll(async () => { + await context.close() + }) + + test('User should be able to swap OSMO to ATOM', async () => { + await tradePage.goto() + await tradePage.selectPair('OSMO', 'ATOM') + await tradePage.enterAmount('0.2') + const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) + expect(msgContentAmount).toBeTruthy() + expect(msgContentAmount).toContain(`token_out_denom: ${ATOM}`) + expect(msgContentAmount).toContain(`sender: ${walletId}`) + expect(msgContentAmount).toContain('denom: uosmo') + await tradePage.isTransactionSuccesful() + await tradePage.getTransactionUrl() + }) + + test('User should be able to swap ATOM to OSMO', async () => { + await tradePage.goto() + await tradePage.selectPair('ATOM', 'OSMO') + await tradePage.enterAmount('0.01') + await tradePage.showSwapInfo() + const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) + expect(msgContentAmount).toBeTruthy() + expect(msgContentAmount).toContain(`denom: ${ATOM}`) + expect(msgContentAmount).toContain(`sender: ${walletId}`) + expect(msgContentAmount).toContain('token_out_denom: uosmo') + await tradePage.isTransactionSuccesful() + await tradePage.getTransactionUrl() + }) + + test('User should be able to swap OSMO to USDC', async () => { + await tradePage.goto() + await tradePage.selectPair('OSMO', 'USDC') + await tradePage.enterAmount('0.2') + await tradePage.showSwapInfo() + const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) + expect(msgContentAmount).toBeTruthy() + expect(msgContentAmount).toContain(`token_out_denom: ${USDC}`) + expect(msgContentAmount).toContain(`sender: ${walletId}`) + expect(msgContentAmount).toContain('denom: uosmo') + await tradePage.isTransactionSuccesful() + await tradePage.getTransactionUrl() + }) + + test('User should be able to swap OSMO to WBTC', async () => { + await tradePage.goto() + await tradePage.selectPair('OSMO', 'WBTC') + await tradePage.enterAmount('0.9') + await tradePage.showSwapInfo() + const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) + expect(msgContentAmount).toBeTruthy() + expect(msgContentAmount).toContain(`sender: ${walletId}`) + expect(msgContentAmount).toContain('denom: uosmo') + await tradePage.isTransactionSuccesful() + await tradePage.getTransactionUrl() + }) + + test('User should be able to swap USDC to OSMO', async () => { + await tradePage.goto() + await tradePage.selectPair('USDC', 'OSMO') + await tradePage.enterAmount('0.1') + await tradePage.showSwapInfo() + const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) + expect(msgContentAmount).toBeTruthy() + expect(msgContentAmount).toContain('token_out_denom: uosmo') + expect(msgContentAmount).toContain(`sender: ${walletId}`) + expect(msgContentAmount).toContain(`denom: ${USDC}`) + await tradePage.isTransactionSuccesful() + await tradePage.getTransactionUrl() + }) + + test('User should be able to swap ATOM to USDC', async () => { + await tradePage.goto() + await tradePage.selectPair('ATOM', 'USDC') + await tradePage.enterAmount('0.015') + await tradePage.showSwapInfo() + const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) + expect(msgContentAmount).toBeTruthy() + expect(msgContentAmount).toContain(`denom: ${ATOM}`) + expect(msgContentAmount).toContain(`sender: ${walletId}`) + expect(msgContentAmount).toContain(`token_out_denom: ${USDC}`) + await tradePage.isTransactionSuccesful() + await tradePage.getTransactionUrl() + }) + + test('User should be able to swap USDC to ATOM', async () => { + await tradePage.goto() + await tradePage.selectPair('USDC', 'ATOM') + await tradePage.enterAmount('0.1') + await tradePage.showSwapInfo() + const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) + expect(msgContentAmount).toBeTruthy() + expect(msgContentAmount).toContain(`denom: ${USDC}`) + expect(msgContentAmount).toContain(`sender: ${walletId}`) + expect(msgContentAmount).toContain(`token_out_denom: ${ATOM}`) + await tradePage.isTransactionSuccesful() + await tradePage.getTransactionUrl() + }) + + test('User should be able to swap USDC to TIA', async () => { + await tradePage.goto() + await tradePage.selectPair('USDC', 'TIA') + await tradePage.enterAmount('0.1') + await tradePage.showSwapInfo() + const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) + expect(msgContentAmount).toBeTruthy() + expect(msgContentAmount).toContain(`denom: ${USDC}`) + expect(msgContentAmount).toContain(`sender: ${walletId}`) + expect(msgContentAmount).toContain(`token_out_denom: ${TIA}`) + await tradePage.isTransactionSuccesful() + await tradePage.getTransactionUrl() + }) + + test('User should be able to swap TIA to USDC', async () => { + await tradePage.goto() + await tradePage.selectPair('TIA', 'USDC') + await tradePage.enterAmount('0.02') + await tradePage.showSwapInfo() + const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) + expect(msgContentAmount).toBeTruthy() + expect(msgContentAmount).toContain(`denom: ${TIA}`) + expect(msgContentAmount).toContain(`sender: ${walletId}`) + expect(msgContentAmount).toContain(`token_out_denom: ${USDC}`) + await tradePage.isTransactionSuccesful() + await tradePage.getTransactionUrl() + }) + + test('User should be able to swap USDC to INJ', async () => { + await tradePage.goto() + await tradePage.selectPair('USDC', 'INJ') + await tradePage.enterAmount('0.2') + await tradePage.showSwapInfo() + const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) + expect(msgContentAmount).toBeTruthy() + expect(msgContentAmount).toContain(`denom: ${USDC}`) + expect(msgContentAmount).toContain(`sender: ${walletId}`) + expect(msgContentAmount).toContain(`token_out_denom: ${INJ}`) + await tradePage.isTransactionSuccesful() + await tradePage.getTransactionUrl() + }) + + test('User should be able to swap INJ to USDC', async () => { + await tradePage.goto() + await tradePage.selectPair('INJ', 'USDC') + await tradePage.enterAmount('0.01') + await tradePage.showSwapInfo() + const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) + expect(msgContentAmount).toBeTruthy() + expect(msgContentAmount).toContain(`denom: ${INJ}`) + expect(msgContentAmount).toContain(`sender: ${walletId}`) + expect(msgContentAmount).toContain(`token_out_denom: ${USDC}`) + await tradePage.isTransactionSuccesful() + await tradePage.getTransactionUrl() + }) + + test('User should be able to swap USDC to AKT', async () => { + await tradePage.goto() + await tradePage.selectPair('USDC', 'AKT') + await tradePage.enterAmount('0.1') + await tradePage.showSwapInfo() + const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) + expect(msgContentAmount).toBeTruthy() + expect(msgContentAmount).toContain(`denom: ${USDC}`) + expect(msgContentAmount).toContain(`sender: ${walletId}`) + expect(msgContentAmount).toContain(`token_out_denom: ${AKT}`) + await tradePage.isTransactionSuccesful() + await tradePage.getTransactionUrl() + }) + + test('User should be able to swap AKT to USDC', async () => { + await tradePage.goto() + await tradePage.selectPair('AKT', 'USDC') + await tradePage.enterAmount('0.025') + await tradePage.showSwapInfo() + const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) + expect(msgContentAmount).toBeTruthy() + expect(msgContentAmount).toContain(`denom: ${AKT}`) + expect(msgContentAmount).toContain(`sender: ${walletId}`) + expect(msgContentAmount).toContain(`token_out_denom: ${USDC}`) + await tradePage.isTransactionSuccesful() + await tradePage.getTransactionUrl() + }) +}) diff --git a/packages/e2e/tests/trade.wallet.spec.ts b/packages/e2e/tests/trade.wallet.spec.ts new file mode 100644 index 0000000000..84125c9a6a --- /dev/null +++ b/packages/e2e/tests/trade.wallet.spec.ts @@ -0,0 +1,127 @@ +import { type BrowserContext, chromium, expect, test } from '@playwright/test' + +import { TransactionsPage } from '../pages/transactions-page' +import { TestConfig } from '../test-config' +import { UnzipExtension } from '../unzip-extension' + +import { WalletPage } from '../pages/keplr-page' +import { TradePage } from '../pages/trade-page' + +test.describe('Test Trade feature', () => { + let context: BrowserContext + const privateKey = process.env.PRIVATE_KEY ?? 'private_key' + let tradePage: TradePage + const USDC = + 'ibc/498A0751C798A0D9A389AA3691123DADA57DAA4FE165D5C75894505B876BA6E4' + const ATOM = + 'ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2' + + test.beforeAll(async () => { + const pathToExtension = new UnzipExtension().getPathToExtension() + console.log('\nSetup Keplr Wallet Extension before tests.') + // Launch Chrome with a Keplr wallet extension + context = await chromium.launchPersistentContext( + '', + new TestConfig().getBrowserExtensionConfig(false, pathToExtension), + ) + // Get all new pages (including Extension) in the context and wait + const emptyPage = context.pages()[0] + await emptyPage.waitForTimeout(2000) + const page = context.pages()[1] + const walletPage = new WalletPage(page) + // Import existing Wallet (could be aggregated in one function). + await walletPage.importWalletWithPrivateKey(privateKey) + await walletPage.setWalletNameAndPassword('Test Trades') + await walletPage.selectChainsAndSave() + await walletPage.finish() + // Switch to Application + tradePage = new TradePage(context.pages()[0]) + await tradePage.goto() + await tradePage.connectWallet() + expect(await tradePage.isError(), 'Swap is not available!').toBeFalsy() + }) + + test.afterAll(async () => { + await context.close() + }) + + test('User should be able to Buy ATOM', async () => { + await tradePage.goto() + await tradePage.openBuyTab() + await tradePage.selectAsset('ATOM') + await tradePage.enterAmount('1.12') + const { msgContentAmount } = await tradePage.buyAndGetWalletMsg(context) + expect(msgContentAmount).toBeTruthy() + expect(msgContentAmount).toContain(`denom: ${ATOM}`) + expect(msgContentAmount).toContain('type: osmosis/poolmanager/') + expect(msgContentAmount).toContain(`denom: ${USDC}`) + await tradePage.isTransactionSuccesful() + await tradePage.getTransactionUrl() + }) + + test('User should be able to Sell ATOM', async () => { + await tradePage.goto() + await tradePage.openSellTab() + await tradePage.selectAsset('ATOM') + await tradePage.enterAmount('1.11') + const { msgContentAmount } = await tradePage.sellAndGetWalletMsg(context) + expect(msgContentAmount).toBeTruthy() + expect(msgContentAmount).toContain(`denom: ${USDC}`) + expect(msgContentAmount).toContain('type: osmosis/poolmanager/') + expect(msgContentAmount).toContain(`denom: ${ATOM}`) + await tradePage.isTransactionSuccesful() + await tradePage.getTransactionUrl() + }) + + test('User should be able to limit sell ATOM', async () => { + await tradePage.goto() + const amount = '1.01' + await tradePage.openSellTab() + await tradePage.openLimit() + await tradePage.selectAsset('ATOM') + await tradePage.enterAmount(amount) + await tradePage.setLimitPriceChange('5%') + const limitPrice = await tradePage.getLimitPrice() + const { msgContentAmount } = await tradePage.sellAndGetWalletMsg( + context, + true, + ) + expect(msgContentAmount).toBeTruthy() + //expect(msgContentAmount).toContain(amount + " ATOM (Cosmos Hub/channel-0)"); + expect(msgContentAmount).toContain('place_limit') + expect(msgContentAmount).toContain('"order_direction": "ask"') + await tradePage.isTransactionSuccesful() + await tradePage.getTransactionUrl() + await tradePage.gotoOrdersHistory() + const trxPage = new TransactionsPage(context.pages()[0]) + await trxPage.cancelLimitOrder(`Sell $${amount} of`, limitPrice, context) + await tradePage.isTransactionSuccesful() + await tradePage.getTransactionUrl() + }) + + test('User should be able to cancel limit sell OSMO', async () => { + await tradePage.goto() + const amount = '1.01' + await tradePage.openSellTab() + await tradePage.openLimit() + await tradePage.selectAsset('OSMO') + await tradePage.enterAmount(amount) + await tradePage.setLimitPriceChange('10%') + const limitPrice = await tradePage.getLimitPrice() + const { msgContentAmount } = await tradePage.sellAndGetWalletMsg( + context, + true, + ) + expect(msgContentAmount).toBeTruthy() + //expect(msgContentAmount).toContain(`${amount} OSMO`); + expect(msgContentAmount).toContain('place_limit') + expect(msgContentAmount).toContain('"order_direction": "ask"') + await tradePage.isTransactionSuccesful() + await tradePage.getTransactionUrl() + await tradePage.gotoOrdersHistory() + const trxPage = new TransactionsPage(context.pages()[0]) + await trxPage.cancelLimitOrder(`Sell $${amount} of`, limitPrice, context) + await tradePage.isTransactionSuccesful() + await tradePage.getTransactionUrl() + }) +}) diff --git a/packages/e2e/tests/transactions.wallet.spec.ts b/packages/e2e/tests/transactions.wallet.spec.ts new file mode 100644 index 0000000000..393cad0994 --- /dev/null +++ b/packages/e2e/tests/transactions.wallet.spec.ts @@ -0,0 +1,92 @@ +import { + type BrowserContext, + type Page, + chromium, + expect, + test, +} from '@playwright/test' + +import { WalletPage } from '../pages/keplr-page' +import { PortfolioPage } from '../pages/portfolio-page' +import { SwapPage } from '../pages/swap-page' +import { TransactionsPage } from '../pages/transactions-page' +import { TestConfig } from '../test-config' +import { UnzipExtension } from '../unzip-extension' + +test.describe('Test Transactions feature', () => { + let context: BrowserContext + let page: Page + const walletId = + process.env.WALLET_ID ?? 'osmo1qyc8u7cn0zjxcu9dvrjz5zwfnn0ck92v62ak9l' + const privateKey = process.env.PRIVATE_KEY ?? 'pk' + let portfolioPage: PortfolioPage + let transactionsPage: TransactionsPage + let swapPage: SwapPage + + test.beforeAll(async () => { + const pathToExtension = new UnzipExtension().getPathToExtension() + console.log('\nSetup Wallet Extension before tests.') + // Launch Chrome with a Keplr wallet extension + context = await chromium.launchPersistentContext( + '', + new TestConfig().getBrowserExtensionConfig(false, pathToExtension), + ) + // Get all new pages (including Extension) in the context and wait + const emptyPage = context.pages()[0] + await emptyPage.waitForTimeout(2000) + page = context.pages()[1] + const walletPage = new WalletPage(page) + // Import existing Wallet (could be aggregated in one function). + await walletPage.importWalletWithPrivateKey(privateKey) + await walletPage.setWalletNameAndPassword('Test Transactions') + await walletPage.selectChainsAndSave() + await walletPage.finish() + // Switch to Application + page = context.pages()[0] + portfolioPage = new PortfolioPage(page) + await portfolioPage.goto() + await portfolioPage.connectWallet() + transactionsPage = await new TransactionsPage(page).open() + }) + + test.afterAll(async () => { + await context.close() + }) + + test('User should be able to see old transactions', async () => { + await transactionsPage.viewTransactionByNumber(10) + await transactionsPage.viewOnExplorerIsVisible() + await transactionsPage.closeTransaction() + await transactionsPage.viewTransactionByNumber(20) + await transactionsPage.viewOnExplorerIsVisible() + await transactionsPage.closeTransaction() + await transactionsPage.viewTransactionByNumber(35) + await transactionsPage.viewOnExplorerIsVisible() + await transactionsPage.closeTransaction() + }) + + test.skip('User should be able to see a new transaction', async () => { + swapPage = new SwapPage(context.pages()[0]) + await swapPage.goto() + await swapPage.selectPair('USDC', 'USDT') + const rndInt = Math.floor(Math.random() * 99) + 1 + const swapAmount = `0.1${rndInt}` + await swapPage.enterAmount(swapAmount) + const { msgContentAmount } = await swapPage.swapAndGetWalletMsg(context) + expect(msgContentAmount).toBeTruthy() + expect(msgContentAmount).toContain(`sender: ${walletId}`) + expect(msgContentAmount).toContain( + 'denom: ibc/498A0751C798A0D9A389AA3691123DADA57DAA4FE165D5C75894505B876BA6E4', + ) + expect(swapPage.isTransactionBroadcasted(10)) + expect(swapPage.isTransactionSuccesful(10)) + const swapTrxUrl = await swapPage.getTransactionUrl() + await swapPage.gotoPortfolio() + await portfolioPage.viewTransactionsPage() + await transactionsPage.viewBySwapAmount(swapAmount) + await transactionsPage.viewOnExplorerIsVisible() + const trxUrl = await transactionsPage.getOnExplorerLink() + expect(trxUrl).toContain(swapTrxUrl) + await transactionsPage.closeTransaction() + }) +}) diff --git a/packages/e2e/tsconfig.json b/packages/e2e/tsconfig.json new file mode 100644 index 0000000000..0872abf237 --- /dev/null +++ b/packages/e2e/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES6", // Specify ECMAScript target version + "module": "commonjs", // Specify module code generation + "strict": true, // Enable all strict type-checking options + "esModuleInterop": true, // Enables emit interoperability between CommonJS and ES Modules + "skipLibCheck": true, // Skip type checking of declaration files + "forceConsistentCasingInFileNames": true, // Disallow inconsistently-cased references to the same file + "types": ["node"] // Include Node.js type definitions + }, + "include": [ + "pages/**/*", + "tests/**/*", + "test-config.ts", + "unzip-extension.ts", + "playwright.config.ts" + ], + "exclude": ["node_modules"] +} diff --git a/packages/e2e/unzip-extension.ts b/packages/e2e/unzip-extension.ts new file mode 100644 index 0000000000..79bedeb1cf --- /dev/null +++ b/packages/e2e/unzip-extension.ts @@ -0,0 +1,16 @@ +import decompress from "decompress"; +import path from "node:path"; + +export class UnzipExtension { + getPathToExtension() { + console.log("Unzip Wallet Extension before tests."); + // Unzip keplr-extension-manifest + const pathToZip = path.join( + __dirname, + "./keplr-extension-manifest-v3-v0.12.156.zip" + ); + const pathToExtension = path.join(__dirname, "./keplr-extension-manifest"); + decompress(pathToZip, pathToExtension); + return pathToExtension; + } +} diff --git a/packages/keplr-hooks/package.json b/packages/keplr-hooks/package.json index c81f2901d4..b3e8ff4f93 100644 --- a/packages/keplr-hooks/package.json +++ b/packages/keplr-hooks/package.json @@ -40,7 +40,7 @@ "@keplr-wallet/popup": "0.10.24-ibc.go.v7.hot.fix", "@keplr-wallet/proto-types": "0.10.24-ibc.go.v7.hot.fix", "@keplr-wallet/types": "0.10.24-ibc.go.v7.hot.fix", - "@keplr-wallet/unit": "0.10.24-ibc.go.v7.hot.fix", + "@osmosis-labs/unit": "0.10.24-ibc.go.v7.hot.fix", "@osmosis-labs/keplr-stores": "0.10.24-ibc.go.v7.hot.fix", "axios": "^0.27.2", "long": "^4.0.0", diff --git a/packages/keplr-hooks/src/tx/amount.ts b/packages/keplr-hooks/src/tx/amount.ts index 37d697ecf4..ecda1e2c23 100644 --- a/packages/keplr-hooks/src/tx/amount.ts +++ b/packages/keplr-hooks/src/tx/amount.ts @@ -15,7 +15,7 @@ import { NegativeAmountError, ZeroAmountError, } from "./errors"; -import { CoinPretty, Dec, DecUtils } from "@keplr-wallet/unit"; +import { CoinPretty, Dec, DecUtils } from "@osmosis-labs/unit"; import { useState } from "react"; export class AmountConfig extends TxChainSetter implements IAmountConfig { diff --git a/packages/keplr-hooks/src/tx/fee.ts b/packages/keplr-hooks/src/tx/fee.ts index 8880a49956..2d2c0f7d81 100644 --- a/packages/keplr-hooks/src/tx/fee.ts +++ b/packages/keplr-hooks/src/tx/fee.ts @@ -12,7 +12,7 @@ import { IQueriesStore, } from "@osmosis-labs/keplr-stores"; import { action, computed, makeObservable, observable } from "mobx"; -import { Coin, CoinPretty, Dec, DecUtils, Int } from "@keplr-wallet/unit"; +import { Coin, CoinPretty, Dec, DecUtils, Int } from "@osmosis-labs/unit"; import { Currency } from "@keplr-wallet/types"; import { computedFn } from "mobx-utils"; import type { StdFee } from "@cosmjs/launchpad"; diff --git a/packages/keplr-hooks/src/tx/staked-amount.ts b/packages/keplr-hooks/src/tx/staked-amount.ts index 17213a3f4a..22a12d4757 100644 --- a/packages/keplr-hooks/src/tx/staked-amount.ts +++ b/packages/keplr-hooks/src/tx/staked-amount.ts @@ -5,7 +5,7 @@ import { IQueriesStore, } from "@osmosis-labs/keplr-stores"; import { override } from "mobx"; -import { Dec, CoinPretty } from "@keplr-wallet/unit"; +import { Dec, CoinPretty } from "@osmosis-labs/unit"; import { useState } from "react"; import { AmountConfig } from "./amount"; import { Staking as StakingType } from "@osmosis-labs/keplr-stores"; diff --git a/packages/keplr-hooks/src/tx/types.ts b/packages/keplr-hooks/src/tx/types.ts index e5fc9e6555..175b551319 100644 --- a/packages/keplr-hooks/src/tx/types.ts +++ b/packages/keplr-hooks/src/tx/types.ts @@ -1,6 +1,6 @@ import { AppCurrency, Currency } from "@keplr-wallet/types"; import type { StdFee } from "@cosmjs/launchpad"; -import { CoinPretty } from "@keplr-wallet/unit"; +import { CoinPretty } from "@osmosis-labs/unit"; import { CoinPrimitive } from "@osmosis-labs/keplr-stores"; export interface ITxChainSetter { diff --git a/packages/keplr-stores/package.json b/packages/keplr-stores/package.json index 3f044b62a4..6a07873144 100644 --- a/packages/keplr-stores/package.json +++ b/packages/keplr-stores/package.json @@ -39,7 +39,7 @@ "@keplr-wallet/proto-types": "0.10.24-ibc.go.v7.hot.fix", "@keplr-wallet/router": "0.10.24-ibc.go.v7.hot.fix", "@keplr-wallet/types": "0.10.24-ibc.go.v7.hot.fix", - "@keplr-wallet/unit": "0.10.24-ibc.go.v7.hot.fix", + "@osmosis-labs/unit": "0.10.24-ibc.go.v7.hot.fix", "@osmosis-labs/types": "^1.0.0", "axios": "^0.27.2", "buffer": "^6.0.3", @@ -60,6 +60,6 @@ "@keplr-wallet/proto-types": "0.10.24-ibc.go.v7.hot.fix", "@keplr-wallet/router": "0.10.24-ibc.go.v7.hot.fix", "@keplr-wallet/types": "0.10.24-ibc.go.v7.hot.fix", - "@keplr-wallet/unit": "0.10.24-ibc.go.v7.hot.fix" + "@osmosis-labs/unit": "0.10.24-ibc.go.v7.hot.fix" } } diff --git a/packages/keplr-stores/src/account/cosmos.ts b/packages/keplr-stores/src/account/cosmos.ts index c6685142ab..a7f43a5b8d 100644 --- a/packages/keplr-stores/src/account/cosmos.ts +++ b/packages/keplr-stores/src/account/cosmos.ts @@ -2,7 +2,7 @@ import { AccountSetBaseSuper, MsgOpt, WalletStatus } from "./base"; import { AppCurrency, Keplr, KeplrSignOptions } from "@keplr-wallet/types"; import type { BroadcastMode, Msg, StdFee, StdSignDoc } from "@cosmjs/launchpad"; import { DenomHelper, escapeHTML } from "@keplr-wallet/common"; -import { Dec, DecUtils, Int } from "@keplr-wallet/unit"; +import { Dec, DecUtils, Int } from "@osmosis-labs/unit"; import { Any } from "@keplr-wallet/proto-types/google/protobuf/any"; import { AuthInfo, diff --git a/packages/keplr-stores/src/account/cosmwasm.ts b/packages/keplr-stores/src/account/cosmwasm.ts index fa7c5fb6fa..5f2890688b 100644 --- a/packages/keplr-stores/src/account/cosmwasm.ts +++ b/packages/keplr-stores/src/account/cosmwasm.ts @@ -3,7 +3,7 @@ import { CosmwasmQueries, IQueriesStore, QueriesSetBase } from "../query"; import { ChainGetter, CoinPrimitive } from "../common"; import type { StdFee } from "@cosmjs/launchpad"; import { DenomHelper } from "@keplr-wallet/common"; -import { Dec, DecUtils } from "@keplr-wallet/unit"; +import { Dec, DecUtils } from "@osmosis-labs/unit"; import { AppCurrency, KeplrSignOptions } from "@keplr-wallet/types"; import { DeepPartial, DeepReadonly, Optional } from "utility-types"; import { MsgExecuteContract } from "@keplr-wallet/proto-types/cosmwasm/wasm/v1/tx"; diff --git a/packages/keplr-stores/src/account/types.ts b/packages/keplr-stores/src/account/types.ts index c9ee3eaa04..2c0ceed5aa 100644 --- a/packages/keplr-stores/src/account/types.ts +++ b/packages/keplr-stores/src/account/types.ts @@ -1,6 +1,6 @@ import type { Msg, StdFee } from "@cosmjs/launchpad"; import type { Any } from "@keplr-wallet/proto-types/google/protobuf/any"; -import { Dec } from "@keplr-wallet/unit"; +import { Dec } from "@osmosis-labs/unit"; import type { KeplrSignOptions } from "@keplr-wallet/types"; export type ProtoMsgsOrWithAminoMsgs = { diff --git a/packages/keplr-stores/src/common/utils/index.ts b/packages/keplr-stores/src/common/utils/index.ts index 7a7b31ddec..914a17798e 100644 --- a/packages/keplr-stores/src/common/utils/index.ts +++ b/packages/keplr-stores/src/common/utils/index.ts @@ -1,6 +1,6 @@ import { Currency } from "@keplr-wallet/types"; import { CoinPrimitive } from "../types"; -import { CoinPretty, Dec, Int } from "@keplr-wallet/unit"; +import { CoinPretty, Dec, Int } from "@osmosis-labs/unit"; export class StoreUtils { public static getBalancesFromCurrencies( diff --git a/packages/keplr-stores/src/price/index.ts b/packages/keplr-stores/src/price/index.ts index 1510ae0da0..fee3618d3c 100644 --- a/packages/keplr-stores/src/price/index.ts +++ b/packages/keplr-stores/src/price/index.ts @@ -2,7 +2,7 @@ import { ObservableQuery, QueryResponse } from "../common"; import { CoinGeckoSimplePrice } from "./types"; import Axios from "axios"; import { KVStore, toGenerator } from "@keplr-wallet/common"; -import { Dec, CoinPretty, Int, PricePretty } from "@keplr-wallet/unit"; +import { Dec, CoinPretty, Int, PricePretty } from "@osmosis-labs/unit"; import { FiatCurrency } from "@keplr-wallet/types"; import { DeepReadonly } from "utility-types"; import deepmerge from "deepmerge"; diff --git a/packages/keplr-stores/src/query/balances.ts b/packages/keplr-stores/src/query/balances.ts index b95575cf89..a805c68ee9 100644 --- a/packages/keplr-stores/src/query/balances.ts +++ b/packages/keplr-stores/src/query/balances.ts @@ -2,7 +2,7 @@ import { ObservableChainQuery } from "./chain-query"; import { DenomHelper, KVStore } from "@keplr-wallet/common"; import { ChainGetter } from "../common"; import { computed, makeObservable, observable, runInAction } from "mobx"; -import { CoinPretty, Dec, Int } from "@keplr-wallet/unit"; +import { CoinPretty, Dec, Int } from "@osmosis-labs/unit"; import { AppCurrency } from "@keplr-wallet/types"; import { HasMapStore } from "../common"; import { computedFn } from "mobx-utils"; diff --git a/packages/keplr-stores/src/query/cosmos/balance/balances.ts b/packages/keplr-stores/src/query/cosmos/balance/balances.ts index 2bdf635ca6..b79d556b4d 100644 --- a/packages/keplr-stores/src/query/cosmos/balance/balances.ts +++ b/packages/keplr-stores/src/query/cosmos/balance/balances.ts @@ -1,7 +1,7 @@ import { DenomHelper, KVStore } from "@keplr-wallet/common"; import { ChainGetter, QueryResponse } from "../../../common"; import { computed, makeObservable, override } from "mobx"; -import { CoinPretty, Int } from "@keplr-wallet/unit"; +import { CoinPretty, Int } from "@osmosis-labs/unit"; import { StoreUtils } from "../../../common"; import { BalanceRegistry, ObservableQueryBalanceInner } from "../../balances"; import { ObservableChainQuery } from "../../chain-query"; @@ -119,10 +119,8 @@ export class ObservableQueryCosmosBalances extends ObservableChainQuery = new Map(); + protected nativeBalances: Map = + new Map(); constructor(protected readonly kvStore: KVStore) {} diff --git a/packages/keplr-stores/src/query/cosmos/balance/spendable.ts b/packages/keplr-stores/src/query/cosmos/balance/spendable.ts index f65e25cc66..e2ded0d285 100644 --- a/packages/keplr-stores/src/query/cosmos/balance/spendable.ts +++ b/packages/keplr-stores/src/query/cosmos/balance/spendable.ts @@ -5,7 +5,7 @@ import { ObservableChainQueryMap, } from "../../chain-query"; import { ChainGetter } from "../../../common"; -import { CoinPretty } from "@keplr-wallet/unit"; +import { CoinPretty } from "@osmosis-labs/unit"; import { computed } from "mobx"; export class ObservableChainQuerySpendableBalances extends ObservableChainQuery { diff --git a/packages/keplr-stores/src/query/cosmos/distribution/params.ts b/packages/keplr-stores/src/query/cosmos/distribution/params.ts index 178fa5b906..5d9004e6c7 100644 --- a/packages/keplr-stores/src/query/cosmos/distribution/params.ts +++ b/packages/keplr-stores/src/query/cosmos/distribution/params.ts @@ -3,7 +3,7 @@ import { DistributionParams } from "./types"; import { KVStore } from "@keplr-wallet/common"; import { ChainGetter } from "../../../common"; import { computed, makeObservable } from "mobx"; -import { RatePretty } from "@keplr-wallet/unit"; +import { RatePretty } from "@osmosis-labs/unit"; export class ObservableQueryDistributionParams extends ObservableChainQuery { constructor(kvStore: KVStore, chainId: string, chainGetter: ChainGetter) { diff --git a/packages/keplr-stores/src/query/cosmos/governance/proposal.ts b/packages/keplr-stores/src/query/cosmos/governance/proposal.ts index a8d5e5350e..5fcd40e8d3 100644 --- a/packages/keplr-stores/src/query/cosmos/governance/proposal.ts +++ b/packages/keplr-stores/src/query/cosmos/governance/proposal.ts @@ -4,7 +4,7 @@ import { KVStore } from "@keplr-wallet/common"; import { ChainGetter } from "../../../common"; import { computed, makeObservable } from "mobx"; import { DeepReadonly } from "utility-types"; -import { CoinPretty, Dec, DecUtils, Int, IntPretty } from "@keplr-wallet/unit"; +import { CoinPretty, Dec, DecUtils, Int, IntPretty } from "@osmosis-labs/unit"; import { ObservableQueryGovernance } from "./proposals"; export class ObservableQueryProposal extends ObservableChainQuery { diff --git a/packages/keplr-stores/src/query/cosmos/governance/proposals.ts b/packages/keplr-stores/src/query/cosmos/governance/proposals.ts index c13c85d766..9515aceb1f 100644 --- a/packages/keplr-stores/src/query/cosmos/governance/proposals.ts +++ b/packages/keplr-stores/src/query/cosmos/governance/proposals.ts @@ -9,7 +9,7 @@ import { import { KVStore } from "@keplr-wallet/common"; import { ChainGetter } from "../../../common"; import { DeepReadonly } from "utility-types"; -import { Dec, DecUtils, Int, IntPretty } from "@keplr-wallet/unit"; +import { Dec, DecUtils, Int, IntPretty } from "@osmosis-labs/unit"; import { computedFn } from "mobx-utils"; import { ObservableQueryProposal } from "./proposal"; import { ObservableQueryStakingPool } from "../staking"; @@ -125,9 +125,9 @@ export class ObservableQueryGovernance extends ObservableChainQuery - | undefined => { - return this.proposals.find((proposal) => proposal.id === id); - }); + readonly getProposal = computedFn( + (id: string): DeepReadonly | undefined => { + return this.proposals.find((proposal) => proposal.id === id); + } + ); } diff --git a/packages/keplr-stores/src/query/cosmos/staking/delegations.ts b/packages/keplr-stores/src/query/cosmos/staking/delegations.ts index 6ef67f94fb..fb381ec3cc 100644 --- a/packages/keplr-stores/src/query/cosmos/staking/delegations.ts +++ b/packages/keplr-stores/src/query/cosmos/staking/delegations.ts @@ -5,7 +5,7 @@ import { import { Delegation, Delegations } from "./types"; import { KVStore } from "@keplr-wallet/common"; import { ChainGetter } from "../../../common"; -import { CoinPretty, Int } from "@keplr-wallet/unit"; +import { CoinPretty, Int } from "@osmosis-labs/unit"; import { computed, makeObservable } from "mobx"; import { computedFn } from "mobx-utils"; @@ -89,8 +89,9 @@ export class ObservableQueryDelegationsInner extends ObservableChainQuery { const delegations = this.delegations; - const stakeCurrency = this.chainGetter.getChain(this.chainId) - .stakeCurrency; + const stakeCurrency = this.chainGetter.getChain( + this.chainId + ).stakeCurrency; if (!this.response) { return new CoinPretty(stakeCurrency, new Int(0)).ready(false); diff --git a/packages/keplr-stores/src/query/cosmos/staking/pool.ts b/packages/keplr-stores/src/query/cosmos/staking/pool.ts index 0b5ef8e1e5..de60f2c4a3 100644 --- a/packages/keplr-stores/src/query/cosmos/staking/pool.ts +++ b/packages/keplr-stores/src/query/cosmos/staking/pool.ts @@ -3,7 +3,7 @@ import { StakingPool } from "./types"; import { KVStore } from "@keplr-wallet/common"; import { ChainGetter } from "../../../common"; import { computed, makeObservable } from "mobx"; -import { CoinPretty } from "@keplr-wallet/unit"; +import { CoinPretty } from "@osmosis-labs/unit"; export class ObservableQueryStakingPool extends ObservableChainQuery { constructor(kvStore: KVStore, chainId: string, chainGetter: ChainGetter) { diff --git a/packages/keplr-stores/src/query/cosmos/staking/rewards.ts b/packages/keplr-stores/src/query/cosmos/staking/rewards.ts index 7d2b7eaf84..ac23e5e2c2 100644 --- a/packages/keplr-stores/src/query/cosmos/staking/rewards.ts +++ b/packages/keplr-stores/src/query/cosmos/staking/rewards.ts @@ -6,7 +6,7 @@ import { } from "../../chain-query"; import { ChainGetter } from "../../../common"; import { computed, makeObservable } from "mobx"; -import { CoinPretty, Dec, Int } from "@keplr-wallet/unit"; +import { CoinPretty, Dec, Int } from "@osmosis-labs/unit"; import { Currency } from "@keplr-wallet/types"; import { StoreUtils } from "../../../common"; import { computedFn } from "mobx-utils"; diff --git a/packages/keplr-stores/src/query/cosmos/staking/unbonding-delegations.ts b/packages/keplr-stores/src/query/cosmos/staking/unbonding-delegations.ts index e358fc4179..8e4ba5294f 100644 --- a/packages/keplr-stores/src/query/cosmos/staking/unbonding-delegations.ts +++ b/packages/keplr-stores/src/query/cosmos/staking/unbonding-delegations.ts @@ -5,7 +5,7 @@ import { import { UnbondingDelegation, UnbondingDelegations } from "./types"; import { KVStore } from "@keplr-wallet/common"; import { ChainGetter } from "../../../common"; -import { CoinPretty, Int } from "@keplr-wallet/unit"; +import { CoinPretty, Int } from "@osmosis-labs/unit"; import { computed, makeObservable } from "mobx"; export class ObservableQueryUnbondingDelegationsInner extends ObservableChainQuery { diff --git a/packages/keplr-stores/src/query/cosmos/staking/validators.ts b/packages/keplr-stores/src/query/cosmos/staking/validators.ts index 5424cd937c..9db9ac4401 100644 --- a/packages/keplr-stores/src/query/cosmos/staking/validators.ts +++ b/packages/keplr-stores/src/query/cosmos/staking/validators.ts @@ -9,7 +9,7 @@ import { computed, makeObservable, observable, runInAction } from "mobx"; import { ObservableQuery, QueryResponse } from "../../../common"; import Axios from "axios"; import PQueue from "p-queue"; -import { CoinPretty, Dec } from "@keplr-wallet/unit"; +import { CoinPretty, Dec } from "@osmosis-labs/unit"; import { computedFn } from "mobx-utils"; import { BondStatus } from "@osmosis-labs/types"; diff --git a/packages/keplr-stores/src/query/cosmos/status/index.ts b/packages/keplr-stores/src/query/cosmos/status/index.ts index c203fc0322..0c9c471798 100644 --- a/packages/keplr-stores/src/query/cosmos/status/index.ts +++ b/packages/keplr-stores/src/query/cosmos/status/index.ts @@ -1,7 +1,7 @@ import { KVStore } from "@keplr-wallet/common"; import { ChainGetter } from "../../../common"; import { ObservableChainQueryRPC } from "../../chain-rpc-query"; -import { Int } from "@keplr-wallet/unit"; +import { Int } from "@osmosis-labs/unit"; export class ObservableQueryRPCStatus extends ObservableChainQueryRPC<{ jsonrpc: "2.0"; diff --git a/packages/keplr-stores/src/query/cosmos/supply/inflation.ts b/packages/keplr-stores/src/query/cosmos/supply/inflation.ts index a8278bfa62..e5fbc529a4 100644 --- a/packages/keplr-stores/src/query/cosmos/supply/inflation.ts +++ b/packages/keplr-stores/src/query/cosmos/supply/inflation.ts @@ -1,5 +1,5 @@ import { computed, makeObservable } from "mobx"; -import { Dec, DecUtils, Int, IntPretty } from "@keplr-wallet/unit"; +import { Dec, DecUtils, Int, IntPretty } from "@osmosis-labs/unit"; import { ObservableQuerySupplyTotal } from "./supply"; import { MintingInflation } from "./types"; import { ObservableChainQuery } from "../../chain-query"; diff --git a/packages/keplr-stores/src/query/cosmos/supply/osmosis/epoch-provisions.ts b/packages/keplr-stores/src/query/cosmos/supply/osmosis/epoch-provisions.ts index e67f772e26..762f7132aa 100644 --- a/packages/keplr-stores/src/query/cosmos/supply/osmosis/epoch-provisions.ts +++ b/packages/keplr-stores/src/query/cosmos/supply/osmosis/epoch-provisions.ts @@ -3,7 +3,7 @@ import { ObservableChainQuery } from "../../../chain-query"; import { EpochProvisions } from "./types"; import { KVStore } from "@keplr-wallet/common"; import { computed, makeObservable } from "mobx"; -import { CoinPretty, Int } from "@keplr-wallet/unit"; +import { CoinPretty, Int } from "@osmosis-labs/unit"; import { ObservableQueryOsmosisMintParmas } from "./params"; export class ObservableQueryOsmosisEpochProvisions extends ObservableChainQuery { diff --git a/packages/keplr-stores/src/query/cosmos/supply/osmosis/params.ts b/packages/keplr-stores/src/query/cosmos/supply/osmosis/params.ts index 331132135a..e8b1c426f3 100644 --- a/packages/keplr-stores/src/query/cosmos/supply/osmosis/params.ts +++ b/packages/keplr-stores/src/query/cosmos/supply/osmosis/params.ts @@ -3,7 +3,7 @@ import { ObservableChainQuery } from "../../../chain-query"; import { MintParmas } from "./types"; import { KVStore } from "@keplr-wallet/common"; import { computed, makeObservable } from "mobx"; -import { Dec } from "@keplr-wallet/unit"; +import { Dec } from "@osmosis-labs/unit"; export class ObservableQueryOsmosisMintParmas extends ObservableChainQuery { constructor(kvStore: KVStore, chainId: string, chainGetter: ChainGetter) { diff --git a/packages/keplr-stores/src/query/cosmwasm/cw20-balance.ts b/packages/keplr-stores/src/query/cosmwasm/cw20-balance.ts index ad8a8312be..15bad0e9d6 100644 --- a/packages/keplr-stores/src/query/cosmwasm/cw20-balance.ts +++ b/packages/keplr-stores/src/query/cosmwasm/cw20-balance.ts @@ -1,7 +1,7 @@ import { computed, makeObservable, override } from "mobx"; import { DenomHelper, KVStore } from "@keplr-wallet/common"; import { ChainGetter } from "../../common"; -import { CoinPretty, Int } from "@keplr-wallet/unit"; +import { CoinPretty, Int } from "@osmosis-labs/unit"; import { BalanceRegistry, ObservableQueryBalanceInner } from "../balances"; import { Cw20ContractBalance } from "./types"; import { ObservableCosmwasmContractChainQuery } from "./contract-query"; diff --git a/packages/math/README.md b/packages/math/README.md index 8c67dbd72a..75594499a7 100644 --- a/packages/math/README.md +++ b/packages/math/README.md @@ -2,4 +2,4 @@ Math functions related to Osmosis AMM. Useful for estimating state changes to propose reasonable min/max amounts in transactions. -Relies on `@keplr-wallet/unit` (`Dec`, `Int`) objects for operations. `*Pretty` objects for display to user. +Relies on `@osmosis-labs/unit` (`Dec`, `Int`) objects for operations. `*Pretty` objects for display to user. diff --git a/packages/math/package.json b/packages/math/package.json index ea2749274b..e3aeb309ab 100644 --- a/packages/math/package.json +++ b/packages/math/package.json @@ -38,7 +38,7 @@ }, "dependencies": { "@keplr-wallet/types": "0.10.24-ibc.go.v7.hot.fix", - "@keplr-wallet/unit": "0.10.24-ibc.go.v7.hot.fix", + "@osmosis-labs/unit": "0.10.24-ibc.go.v7.hot.fix", "big-integer": "^1.6.48" }, "devDependencies": { diff --git a/packages/math/src/big-dec.ts b/packages/math/src/big-dec.ts index 7a67dffccd..152156a6da 100644 --- a/packages/math/src/big-dec.ts +++ b/packages/math/src/big-dec.ts @@ -1,4 +1,4 @@ -import { CoinUtils, Dec, Int } from "@keplr-wallet/unit"; +import { CoinUtils, Dec, Int } from "@osmosis-labs/unit"; import bigInteger from "big-integer"; export class BigDec { diff --git a/packages/math/src/pool/__tests__/stable.spec.ts b/packages/math/src/pool/__tests__/stable.spec.ts index 7bb4156476..dda0cfa49d 100644 --- a/packages/math/src/pool/__tests__/stable.spec.ts +++ b/packages/math/src/pool/__tests__/stable.spec.ts @@ -1,4 +1,4 @@ -import { Coin, Dec, DecUtils, Int } from "@keplr-wallet/unit"; +import { Coin, Dec, DecUtils, Int } from "@osmosis-labs/unit"; import { BigDec } from "../../big-dec"; import { checkMultiplicativeErrorTolerance } from "../../rounding"; diff --git a/packages/math/src/pool/__tests__/weighted.spec.ts b/packages/math/src/pool/__tests__/weighted.spec.ts index 13302a000c..5d3730bec8 100644 --- a/packages/math/src/pool/__tests__/weighted.spec.ts +++ b/packages/math/src/pool/__tests__/weighted.spec.ts @@ -1,4 +1,4 @@ -import { Dec } from "@keplr-wallet/unit"; +import { Dec } from "@osmosis-labs/unit"; import assert from "assert"; import { pow } from "../../utils"; diff --git a/packages/math/src/pool/concentrated/__tests__/math.spec.ts b/packages/math/src/pool/concentrated/__tests__/math.spec.ts index d9e7b2d34c..b38c47414f 100644 --- a/packages/math/src/pool/concentrated/__tests__/math.spec.ts +++ b/packages/math/src/pool/concentrated/__tests__/math.spec.ts @@ -1,4 +1,4 @@ -import { Dec } from "@keplr-wallet/unit"; +import { Dec } from "@osmosis-labs/unit"; import { BigDec } from "../../../big-dec"; import { checkMultiplicativeErrorTolerance } from "../../../rounding"; diff --git a/packages/math/src/pool/concentrated/__tests__/quotes.spec.ts b/packages/math/src/pool/concentrated/__tests__/quotes.spec.ts index 971362b710..4509c31443 100644 --- a/packages/math/src/pool/concentrated/__tests__/quotes.spec.ts +++ b/packages/math/src/pool/concentrated/__tests__/quotes.spec.ts @@ -1,4 +1,4 @@ -import { Coin, Dec, Int } from "@keplr-wallet/unit"; +import { Coin, Dec, Int } from "@osmosis-labs/unit"; import { BigDec } from "../../../big-dec"; import { maxTick } from "../const"; diff --git a/packages/math/src/pool/concentrated/__tests__/tick.spec.ts b/packages/math/src/pool/concentrated/__tests__/tick.spec.ts index 9ce7caae5c..b79381aaaa 100644 --- a/packages/math/src/pool/concentrated/__tests__/tick.spec.ts +++ b/packages/math/src/pool/concentrated/__tests__/tick.spec.ts @@ -1,4 +1,4 @@ -import { Dec, Int } from "@keplr-wallet/unit"; +import { Dec, Int } from "@osmosis-labs/unit"; // eslint-disable-next-line import/no-extraneous-dependencies import cases from "jest-in-case"; diff --git a/packages/math/src/pool/concentrated/const.ts b/packages/math/src/pool/concentrated/const.ts index 838b660b2b..a1df7d3298 100644 --- a/packages/math/src/pool/concentrated/const.ts +++ b/packages/math/src/pool/concentrated/const.ts @@ -1,4 +1,4 @@ -import { Dec, Int } from "@keplr-wallet/unit"; +import { Dec, Int } from "@osmosis-labs/unit"; import { BigDec } from "../../big-dec"; diff --git a/packages/math/src/pool/concentrated/math.ts b/packages/math/src/pool/concentrated/math.ts index d8d6f26830..7f179703dc 100644 --- a/packages/math/src/pool/concentrated/math.ts +++ b/packages/math/src/pool/concentrated/math.ts @@ -1,13 +1,13 @@ -import { Dec, Int } from "@keplr-wallet/unit"; +import { Dec, Int } from "@osmosis-labs/unit"; import { BigDec } from "../../big-dec"; import { tickToSqrtPrice } from "./tick"; -/** The `@keplr-wallet/unit` `Dec` object doesn't have the `mulRoundUp()` function +/** The `@osmosis-labs/unit` `Dec` object doesn't have the `mulRoundUp()` function * as seen in Cosmos SDK `Dec` object. To adapt, we extend Dec and add the function. * * Create a custom Dec object if it's needed in more places than below. - * TODO: If we manage to update `@keplr-wallet/unit` to have `mulRoundUp()` function, we can remove this. + * TODO: If we manage to update `@osmosis-labs/unit` to have `mulRoundUp()` function, we can remove this. * Proposed in PR: https://github.com/chainapsis/keplr-wallet/pull/721 */ class DecWithMulRoundUp extends Dec { diff --git a/packages/math/src/pool/concentrated/one-for-zero.ts b/packages/math/src/pool/concentrated/one-for-zero.ts index 08153d8ad0..75d29fb242 100644 --- a/packages/math/src/pool/concentrated/one-for-zero.ts +++ b/packages/math/src/pool/concentrated/one-for-zero.ts @@ -1,4 +1,4 @@ -import { Dec } from "@keplr-wallet/unit"; +import { Dec } from "@osmosis-labs/unit"; import { BigDec } from "../../big-dec"; import { maxSpotPrice } from "./const"; diff --git a/packages/math/src/pool/concentrated/quotes.ts b/packages/math/src/pool/concentrated/quotes.ts index 4db2075af6..aaa7a7d00c 100644 --- a/packages/math/src/pool/concentrated/quotes.ts +++ b/packages/math/src/pool/concentrated/quotes.ts @@ -1,4 +1,4 @@ -import { Dec, Int } from "@keplr-wallet/unit"; +import { Dec, Int } from "@osmosis-labs/unit"; import { BigDec } from "../../big-dec"; import { approxSqrt } from "../../utils"; diff --git a/packages/math/src/pool/concentrated/swap-strategy.ts b/packages/math/src/pool/concentrated/swap-strategy.ts index 1713ab9edf..738eabc937 100644 --- a/packages/math/src/pool/concentrated/swap-strategy.ts +++ b/packages/math/src/pool/concentrated/swap-strategy.ts @@ -1,4 +1,4 @@ -import { Dec } from "@keplr-wallet/unit"; +import { Dec } from "@osmosis-labs/unit"; import { BigDec } from "../../big-dec"; import { OneForZeroStrategy } from "./one-for-zero"; diff --git a/packages/math/src/pool/concentrated/tick.ts b/packages/math/src/pool/concentrated/tick.ts index bd10c3e859..41940f4897 100644 --- a/packages/math/src/pool/concentrated/tick.ts +++ b/packages/math/src/pool/concentrated/tick.ts @@ -1,4 +1,4 @@ -import { Dec, DecUtils, Int } from "@keplr-wallet/unit"; +import { Dec, DecUtils, Int } from "@osmosis-labs/unit"; import { BigDec } from "../../big-dec"; import { approxSqrt } from "../../utils"; @@ -20,48 +20,7 @@ const nine = new Dec(9); If tickIndex is zero, the function returns new Dec(1). */ export function tickToSqrtPrice(tickIndex: Int): Dec { - if (tickIndex.isZero()) { - return new Dec(1); - } - - const geometricExponentIncrementDistanceInTicks = nine.mul( - powTenBigDec(new Int(exponentAtPriceOne).neg()).toDec() - ); - - if (tickIndex.lt(minTick) || tickIndex.gt(maxTick)) { - throw new Error( - `tickIndex is out of range: ${tickIndex.toString()}, min: ${minTick.toString()}, max: ${maxTick.toString()}` - ); - } - - const geometricExponentDelta = new Dec(tickIndex) - .quoTruncate(new Dec(geometricExponentIncrementDistanceInTicks.truncate())) - .truncate(); - - let exponentAtCurTick = new Int(exponentAtPriceOne).add( - geometricExponentDelta - ); - if (tickIndex.lt(new Int(0))) { - exponentAtCurTick = exponentAtCurTick.sub(new Int(1)); - } - - const currentAdditiveIncrementInTicks = powTenBigDec(exponentAtCurTick); - - const numAdditiveTicks = tickIndex.sub( - geometricExponentDelta.mul( - geometricExponentIncrementDistanceInTicks.truncate() - ) - ); - - const price = powTenBigDec(geometricExponentDelta) - .add(new BigDec(numAdditiveTicks).mul(currentAdditiveIncrementInTicks)) - .toDec(); - - if (price.gt(maxSpotPrice) || price.lt(minSpotPrice)) { - throw new Error( - `price is out of range: ${price.toString()}, min: ${minSpotPrice.toString()}, max: ${maxSpotPrice.toString()}` - ); - } + const price = tickToPrice(tickIndex); return approxSqrt(price); } diff --git a/packages/math/src/pool/concentrated/types.ts b/packages/math/src/pool/concentrated/types.ts index 3fb280f1c9..d4a280e421 100644 --- a/packages/math/src/pool/concentrated/types.ts +++ b/packages/math/src/pool/concentrated/types.ts @@ -1,4 +1,4 @@ -import { Coin, Dec, Int } from "@keplr-wallet/unit"; +import { Coin, Dec, Int } from "@osmosis-labs/unit"; import { BigDec } from "../../big-dec"; diff --git a/packages/math/src/pool/concentrated/zero-for-one.ts b/packages/math/src/pool/concentrated/zero-for-one.ts index e49b9949ee..ebe5b2e72b 100644 --- a/packages/math/src/pool/concentrated/zero-for-one.ts +++ b/packages/math/src/pool/concentrated/zero-for-one.ts @@ -1,4 +1,4 @@ -import { Dec } from "@keplr-wallet/unit"; +import { Dec } from "@osmosis-labs/unit"; import { BigDec } from "../../big-dec"; import { minSpotPrice } from "./const"; diff --git a/packages/math/src/pool/general.ts b/packages/math/src/pool/general.ts index f836b63f94..d6823f2de7 100644 --- a/packages/math/src/pool/general.ts +++ b/packages/math/src/pool/general.ts @@ -1,4 +1,4 @@ -import { Dec, Int } from "@keplr-wallet/unit"; +import { Dec, Int } from "@osmosis-labs/unit"; /** Use the before spot price, in amount, and slippage setting to get the min out amount received. */ export function calcPriceImpactWithAmount( diff --git a/packages/math/src/pool/share-quotes.ts b/packages/math/src/pool/share-quotes.ts index 450385882c..f241d13401 100644 --- a/packages/math/src/pool/share-quotes.ts +++ b/packages/math/src/pool/share-quotes.ts @@ -6,7 +6,7 @@ import { DecUtils, Int, IntPretty, -} from "@keplr-wallet/unit"; +} from "@osmosis-labs/unit"; import { StableSwapMath } from "./stable"; import { WeightedPoolMath } from "./weighted"; diff --git a/packages/math/src/pool/stable.ts b/packages/math/src/pool/stable.ts index 6faee2c7de..58eca237cc 100644 --- a/packages/math/src/pool/stable.ts +++ b/packages/math/src/pool/stable.ts @@ -1,4 +1,4 @@ -import { Coin, Dec, DecUtils } from "@keplr-wallet/unit"; +import { Coin, Dec, DecUtils } from "@osmosis-labs/unit"; import { BigDec } from "../big-dec"; import { checkMultiplicativeErrorTolerance } from "../rounding"; diff --git a/packages/math/src/pool/weighted.ts b/packages/math/src/pool/weighted.ts index 6d63022f32..57d5c84f19 100644 --- a/packages/math/src/pool/weighted.ts +++ b/packages/math/src/pool/weighted.ts @@ -1,4 +1,4 @@ -import { Dec } from "@keplr-wallet/unit"; +import { Dec } from "@osmosis-labs/unit"; import { pow } from "../utils"; diff --git a/packages/math/src/utils.ts b/packages/math/src/utils.ts index 7919fdb63e..f0079f7516 100644 --- a/packages/math/src/utils.ts +++ b/packages/math/src/utils.ts @@ -1,4 +1,4 @@ -import { Dec, Int } from "@keplr-wallet/unit"; +import { Dec, Int } from "@osmosis-labs/unit"; import { smallestDec } from "./pool/concentrated/const"; diff --git a/packages/mobile/package.json b/packages/mobile/package.json new file mode 100644 index 0000000000..086b7755ea --- /dev/null +++ b/packages/mobile/package.json @@ -0,0 +1,5 @@ +{ + "name": "mobile", + "version": "0.0.0", + "private": true +} \ No newline at end of file diff --git a/packages/pools/package.json b/packages/pools/package.json index 2104132193..31cee64da6 100644 --- a/packages/pools/package.json +++ b/packages/pools/package.json @@ -37,9 +37,9 @@ ] }, "dependencies": { - "@keplr-wallet/unit": "0.10.24-ibc.go.v7.hot.fix", "@osmosis-labs/math": "^5.1.0", - "@osmosis-labs/types": "^1.0.0" + "@osmosis-labs/types": "^1.0.0", + "@osmosis-labs/unit": "0.10.24-ibc.go.v7.hot.fix" }, "devDependencies": { "deepmerge": "" diff --git a/packages/pools/src/__tests__/concentrated.spec.ts b/packages/pools/src/__tests__/concentrated.spec.ts index e240aeb46e..deff86fb42 100644 --- a/packages/pools/src/__tests__/concentrated.spec.ts +++ b/packages/pools/src/__tests__/concentrated.spec.ts @@ -1,5 +1,5 @@ -import { Dec, Int } from "@keplr-wallet/unit"; import { BigDec, LiquidityDepth } from "@osmosis-labs/math"; +import { Dec, Int } from "@osmosis-labs/unit"; import { ConcentratedLiquidityPool, diff --git a/packages/pools/src/concentrated/fetch-tick-data-provider.ts b/packages/pools/src/concentrated/fetch-tick-data-provider.ts index 985536c698..8cff2782d8 100644 --- a/packages/pools/src/concentrated/fetch-tick-data-provider.ts +++ b/packages/pools/src/concentrated/fetch-tick-data-provider.ts @@ -1,4 +1,3 @@ -import { Dec, Int } from "@keplr-wallet/unit"; import { BigDec, estimateInitialTickBound, @@ -6,6 +5,7 @@ import { maxTick, minTick, } from "@osmosis-labs/math"; +import { Dec, Int } from "@osmosis-labs/unit"; import { ConcentratedLiquidityPool, diff --git a/packages/pools/src/concentrated/pool.ts b/packages/pools/src/concentrated/pool.ts index 4c3043b0d5..7dd8447874 100644 --- a/packages/pools/src/concentrated/pool.ts +++ b/packages/pools/src/concentrated/pool.ts @@ -1,9 +1,9 @@ -import { Coin, Dec, Int } from "@keplr-wallet/unit"; import { BigDec, ConcentratedLiquidityMath, LiquidityDepth, } from "@osmosis-labs/math"; +import { Coin, Dec, Int } from "@osmosis-labs/unit"; import { NotEnoughLiquidityError, diff --git a/packages/pools/src/cosmwasm/transmuter.ts b/packages/pools/src/cosmwasm/transmuter.ts index 12967231f9..c7ae5ce9f7 100644 --- a/packages/pools/src/cosmwasm/transmuter.ts +++ b/packages/pools/src/cosmwasm/transmuter.ts @@ -1,4 +1,4 @@ -import { Dec, Int } from "@keplr-wallet/unit"; +import { Dec, Int } from "@osmosis-labs/unit"; import { NotEnoughLiquidityError, validateDenoms } from "../errors"; import { BasePool } from "../interface"; diff --git a/packages/pools/src/interface.ts b/packages/pools/src/interface.ts index 137d5adbba..893a533f7a 100644 --- a/packages/pools/src/interface.ts +++ b/packages/pools/src/interface.ts @@ -1,4 +1,4 @@ -import { Dec, Int } from "@keplr-wallet/unit"; +import { Dec, Int } from "@osmosis-labs/unit"; import { PoolType } from "./types"; diff --git a/packages/pools/src/router/__tests__/pool.ts b/packages/pools/src/router/__tests__/pool.ts index 6727f38736..ade60a2efa 100644 --- a/packages/pools/src/router/__tests__/pool.ts +++ b/packages/pools/src/router/__tests__/pool.ts @@ -1,4 +1,4 @@ -import { Dec, Int } from "@keplr-wallet/unit"; +import { Dec, Int } from "@osmosis-labs/unit"; // eslint-disable-next-line import/no-extraneous-dependencies import deepmerge from "deepmerge"; diff --git a/packages/pools/src/router/__tests__/routes.spec.ts b/packages/pools/src/router/__tests__/routes.spec.ts index d51b086063..cc9f452fb7 100644 --- a/packages/pools/src/router/__tests__/routes.spec.ts +++ b/packages/pools/src/router/__tests__/routes.spec.ts @@ -1,4 +1,4 @@ -import { Int } from "@keplr-wallet/unit"; +import { Int } from "@osmosis-labs/unit"; import { NotEnoughLiquidityError } from "../../errors"; import { RouteWithInAmount } from "../route"; diff --git a/packages/pools/src/router/route.ts b/packages/pools/src/router/route.ts index 35dafe6463..a786dfb982 100644 --- a/packages/pools/src/router/route.ts +++ b/packages/pools/src/router/route.ts @@ -1,5 +1,5 @@ -import { Dec, Int } from "@keplr-wallet/unit"; import { Currency } from "@osmosis-labs/types"; +import { Dec, Int } from "@osmosis-labs/unit"; import { PoolType } from "../types"; diff --git a/packages/pools/src/router/routes.ts b/packages/pools/src/router/routes.ts index 00a9340e15..7cf62e5960 100644 --- a/packages/pools/src/router/routes.ts +++ b/packages/pools/src/router/routes.ts @@ -1,4 +1,4 @@ -import { Dec, Int } from "@keplr-wallet/unit"; +import { Dec, Int } from "@osmosis-labs/unit"; import { NotEnoughLiquidityError, NotEnoughQuotedError } from "../errors"; import { NoRouteError } from "./errors"; diff --git a/packages/pools/src/router/types.ts b/packages/pools/src/router/types.ts index 452c1ed2e0..033fc81220 100644 --- a/packages/pools/src/router/types.ts +++ b/packages/pools/src/router/types.ts @@ -1,4 +1,4 @@ -import { Dec, Int } from "@keplr-wallet/unit"; +import { Dec, Int } from "@osmosis-labs/unit"; import { RouteWithInAmount, RouteWithOutAmount } from "./route"; diff --git a/packages/pools/src/stable.ts b/packages/pools/src/stable.ts index 1c2e5b2511..ecc2a41b0e 100644 --- a/packages/pools/src/stable.ts +++ b/packages/pools/src/stable.ts @@ -1,5 +1,5 @@ -import { Coin, Dec, Int } from "@keplr-wallet/unit"; import { StableSwapMath, StableSwapToken } from "@osmosis-labs/math"; +import { Coin, Dec, Int } from "@osmosis-labs/unit"; import { NotEnoughLiquidityError } from "./errors"; import { SharePool } from "./interface"; diff --git a/packages/pools/src/weighted.ts b/packages/pools/src/weighted.ts index 805fb53aa3..2a6d3e087b 100644 --- a/packages/pools/src/weighted.ts +++ b/packages/pools/src/weighted.ts @@ -1,5 +1,5 @@ -import { Dec, Int } from "@keplr-wallet/unit"; import { WeightedPoolMath } from "@osmosis-labs/math"; +import { Dec, Int } from "@osmosis-labs/unit"; import { NotEnoughQuotedError } from "./errors"; import { SharePool } from "./interface"; diff --git a/packages/server/package.json b/packages/server/package.json index ce9de07747..a3d25ff480 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -30,11 +30,11 @@ }, "dependencies": { "@keplr-wallet/types": "0.10.24-ibc.go.v7.hot.fix", - "@keplr-wallet/unit": "0.10.24-ibc.go.v7.hot.fix", "@opentelemetry/api": "^1.9.0", "@osmosis-labs/math": "^5.1.0", "@osmosis-labs/pools": "^5.1.0", "@osmosis-labs/types": "^1.0.0", + "@osmosis-labs/unit": "0.10.24-ibc.go.v7.hot.fix", "@osmosis-labs/utils": "^1.0.0", "@upstash/redis": "^1.31.5", "axios": "^0.27.2", diff --git a/packages/server/src/env.ts b/packages/server/src/env.ts index 4f7339e67f..4e78f71370 100644 --- a/packages/server/src/env.ts +++ b/packages/server/src/env.ts @@ -18,10 +18,9 @@ export const ASSET_LIST_COMMIT_HASH = process.env.ASSET_LIST_COMMIT_HASH; // data services export const TIMESERIES_DATA_URL = process.env.NEXT_PUBLIC_TIMESERIES_DATA_URL ?? - "https://stage-proxy-data-api.osmosis-labs.workers.dev"; + "https://data.stage.osmosis.zone"; export const INDEXER_DATA_URL = - process.env.NEXT_PUBLIC_INDEXER_DATA_URL ?? - "https://stage-proxy-data-indexer.osmosis-labs.workers.dev"; + process.env.NEXT_PUBLIC_INDEXER_DATA_URL ?? "https://data.stage.osmosis.zone"; export const NUMIA_BASE_URL = process.env.NEXT_PUBLIC_NUMIA_BASE_URL ?? "https://public-osmosis-api.numia.xyz"; diff --git a/packages/server/src/queries/complex/assets/index.ts b/packages/server/src/queries/complex/assets/index.ts index 26d9144b4d..452c6030dd 100644 --- a/packages/server/src/queries/complex/assets/index.ts +++ b/packages/server/src/queries/complex/assets/index.ts @@ -1,9 +1,9 @@ -import { CoinPretty } from "@keplr-wallet/unit"; import { Asset as AssetListAsset, AssetList, MinimalAsset, } from "@osmosis-labs/types"; +import { CoinPretty } from "@osmosis-labs/unit"; import { makeMinimalAsset } from "@osmosis-labs/utils"; import { z } from "zod"; diff --git a/packages/server/src/queries/complex/assets/market.ts b/packages/server/src/queries/complex/assets/market.ts index a1cb955898..7f54da58a5 100644 --- a/packages/server/src/queries/complex/assets/market.ts +++ b/packages/server/src/queries/complex/assets/market.ts @@ -1,5 +1,5 @@ -import { CoinPretty, Dec, PricePretty, RatePretty } from "@keplr-wallet/unit"; import { AssetList, Chain, MinimalAsset } from "@osmosis-labs/types"; +import { CoinPretty, Dec, PricePretty, RatePretty } from "@osmosis-labs/unit"; import cachified, { CacheEntry } from "cachified"; import { LRUCache } from "lru-cache"; diff --git a/packages/server/src/queries/complex/assets/price/index.ts b/packages/server/src/queries/complex/assets/price/index.ts index d05ea20884..63fa78ffe2 100644 --- a/packages/server/src/queries/complex/assets/price/index.ts +++ b/packages/server/src/queries/complex/assets/price/index.ts @@ -1,5 +1,5 @@ -import { CoinPretty, Dec, DecUtils, Int } from "@keplr-wallet/unit"; import { Asset, AssetList, Chain } from "@osmosis-labs/types"; +import { CoinPretty, Dec, DecUtils, Int } from "@osmosis-labs/unit"; import cachified, { CacheEntry } from "cachified"; import { LRUCache } from "lru-cache"; diff --git a/packages/server/src/queries/complex/assets/price/providers/coingecko.ts b/packages/server/src/queries/complex/assets/price/providers/coingecko.ts index 046648362a..198c2f425a 100644 --- a/packages/server/src/queries/complex/assets/price/providers/coingecko.ts +++ b/packages/server/src/queries/complex/assets/price/providers/coingecko.ts @@ -1,5 +1,5 @@ -import { Dec } from "@keplr-wallet/unit"; import { Asset } from "@osmosis-labs/types"; +import { Dec } from "@osmosis-labs/unit"; import cachified, { CacheEntry } from "cachified"; import { LRUCache } from "lru-cache"; diff --git a/packages/server/src/queries/complex/assets/price/providers/sidecar.ts b/packages/server/src/queries/complex/assets/price/providers/sidecar.ts index 3d192ff395..8fa1163529 100644 --- a/packages/server/src/queries/complex/assets/price/providers/sidecar.ts +++ b/packages/server/src/queries/complex/assets/price/providers/sidecar.ts @@ -1,5 +1,5 @@ -import { Dec } from "@keplr-wallet/unit"; import { Asset } from "@osmosis-labs/types"; +import { Dec } from "@osmosis-labs/unit"; import { isNil } from "@osmosis-labs/utils"; import cachified, { CacheEntry } from "cachified"; import { LRUCache } from "lru-cache"; diff --git a/packages/server/src/queries/complex/assets/user.ts b/packages/server/src/queries/complex/assets/user.ts index 3f42768e6c..8a0075e943 100644 --- a/packages/server/src/queries/complex/assets/user.ts +++ b/packages/server/src/queries/complex/assets/user.ts @@ -1,5 +1,5 @@ -import { CoinPretty, PricePretty } from "@keplr-wallet/unit"; import { AssetList, Chain, MinimalAsset } from "@osmosis-labs/types"; +import { CoinPretty, PricePretty } from "@osmosis-labs/unit"; import { aggregateCoinsByDenom, isNil, diff --git a/packages/server/src/queries/complex/concentrated-liquidity/__tests__/concentrated-liquidity.spec.ts b/packages/server/src/queries/complex/concentrated-liquidity/__tests__/concentrated-liquidity.spec.ts index 9031303e5b..ba512b052b 100644 --- a/packages/server/src/queries/complex/concentrated-liquidity/__tests__/concentrated-liquidity.spec.ts +++ b/packages/server/src/queries/complex/concentrated-liquidity/__tests__/concentrated-liquidity.spec.ts @@ -1,4 +1,4 @@ -import { CoinPretty, Dec, Int } from "@keplr-wallet/unit"; +import { CoinPretty, Dec, Int } from "@osmosis-labs/unit"; import cases from "jest-in-case"; import { calcPositionStatus, getPriceFromSqrtPrice, getTickPrice } from ".."; diff --git a/packages/server/src/queries/complex/concentrated-liquidity/index.ts b/packages/server/src/queries/complex/concentrated-liquidity/index.ts index e91af6e0f3..67fe721b71 100644 --- a/packages/server/src/queries/complex/concentrated-liquidity/index.ts +++ b/packages/server/src/queries/complex/concentrated-liquidity/index.ts @@ -1,3 +1,5 @@ +import { BigDec, maxTick, minTick, tickToPrice } from "@osmosis-labs/math"; +import { AssetList, Chain } from "@osmosis-labs/types"; import { CoinPretty, Dec, @@ -5,9 +7,7 @@ import { Int, PricePretty, RatePretty, -} from "@keplr-wallet/unit"; -import { BigDec, maxTick, minTick, tickToSqrtPrice } from "@osmosis-labs/math"; -import { AssetList, Chain } from "@osmosis-labs/types"; +} from "@osmosis-labs/unit"; import { aggregateCoinsByDenom, timeout } from "@osmosis-labs/utils"; import cachified, { CacheEntry } from "cachified"; import { LRUCache } from "lru-cache"; @@ -154,6 +154,22 @@ export function getPriceFromSqrtPrice({ return price; } +export function getDisplayPriceFromPrice({ + price, + baseCoin, + quoteCoin, +}: { + baseCoin: CoinPretty; + quoteCoin: CoinPretty; + price: Dec; +}) { + const multiplicationQuoteOverBase = DecUtils.getTenExponentN( + baseCoin.currency.coinDecimals - quoteCoin.currency.coinDecimals + ); + const displayPrice = price.mul(multiplicationQuoteOverBase); + return displayPrice; +} + export function getTickPrice({ tick, baseCoin, @@ -163,11 +179,11 @@ export function getTickPrice({ baseCoin: CoinPretty; quoteCoin: CoinPretty; }) { - const sqrtPrice = tickToSqrtPrice(tick); - return getPriceFromSqrtPrice({ + const price = tickToPrice(tick); + return getDisplayPriceFromPrice({ baseCoin, quoteCoin, - sqrtPrice, + price, }); } diff --git a/packages/server/src/queries/complex/earn/strategies.ts b/packages/server/src/queries/complex/earn/strategies.ts index e414217194..b817cb5279 100644 --- a/packages/server/src/queries/complex/earn/strategies.ts +++ b/packages/server/src/queries/complex/earn/strategies.ts @@ -1,5 +1,5 @@ -import { Dec, PricePretty, RatePretty } from "@keplr-wallet/unit"; import { AssetList, MinimalAsset } from "@osmosis-labs/types"; +import { Dec, PricePretty, RatePretty } from "@osmosis-labs/unit"; import cachified, { CacheEntry } from "cachified"; import { LRUCache } from "lru-cache"; diff --git a/packages/server/src/queries/complex/get-timeout-height.ts b/packages/server/src/queries/complex/get-timeout-height.ts index 0650f4c6af..9cb8a48074 100644 --- a/packages/server/src/queries/complex/get-timeout-height.ts +++ b/packages/server/src/queries/complex/get-timeout-height.ts @@ -1,5 +1,5 @@ -import { Int } from "@keplr-wallet/unit"; import { Chain } from "@osmosis-labs/types"; +import { Int } from "@osmosis-labs/unit"; import { ChainIdHelper, getChain } from "@osmosis-labs/utils"; import { queryRPCStatus } from "../../queries/cosmos"; diff --git a/packages/server/src/queries/complex/orderbooks/active-orders.ts b/packages/server/src/queries/complex/orderbooks/active-orders.ts index 6b1fa9d618..a6930d86ac 100644 --- a/packages/server/src/queries/complex/orderbooks/active-orders.ts +++ b/packages/server/src/queries/complex/orderbooks/active-orders.ts @@ -1,6 +1,6 @@ -import { Dec, Int } from "@keplr-wallet/unit"; import { tickToPrice } from "@osmosis-labs/math"; import { AssetList, Chain } from "@osmosis-labs/types"; +import { Dec, Int } from "@osmosis-labs/unit"; import { getAssetFromAssetList } from "@osmosis-labs/utils"; import cachified, { CacheEntry } from "cachified"; import dayjs from "dayjs"; diff --git a/packages/server/src/queries/complex/orderbooks/historical-orders.ts b/packages/server/src/queries/complex/orderbooks/historical-orders.ts index 4a539e98bc..5e050bcb62 100644 --- a/packages/server/src/queries/complex/orderbooks/historical-orders.ts +++ b/packages/server/src/queries/complex/orderbooks/historical-orders.ts @@ -1,6 +1,6 @@ -import { Dec, Int } from "@keplr-wallet/unit"; import { tickToPrice } from "@osmosis-labs/math"; import { AssetList, Chain } from "@osmosis-labs/types"; +import { Dec, Int } from "@osmosis-labs/unit"; import { getAssetFromAssetList } from "@osmosis-labs/utils"; import cachified, { CacheEntry } from "cachified"; import dayjs from "dayjs"; diff --git a/packages/server/src/queries/complex/orderbooks/maker-fee.ts b/packages/server/src/queries/complex/orderbooks/maker-fee.ts index bac557dc62..d1600982cd 100644 --- a/packages/server/src/queries/complex/orderbooks/maker-fee.ts +++ b/packages/server/src/queries/complex/orderbooks/maker-fee.ts @@ -1,5 +1,5 @@ -import { Dec } from "@keplr-wallet/unit"; import { Chain } from "@osmosis-labs/types"; +import { Dec } from "@osmosis-labs/unit"; import cachified, { CacheEntry } from "cachified"; import { LRUCache } from "lru-cache"; diff --git a/packages/server/src/queries/complex/orderbooks/types.ts b/packages/server/src/queries/complex/orderbooks/types.ts index da555ce8b0..1f18671bea 100644 --- a/packages/server/src/queries/complex/orderbooks/types.ts +++ b/packages/server/src/queries/complex/orderbooks/types.ts @@ -1,4 +1,4 @@ -import type { Dec } from "@keplr-wallet/unit"; +import type { Dec } from "@osmosis-labs/unit"; import { getAssetFromAssetList } from "@osmosis-labs/utils"; import type { LimitOrder } from "../../osmosis"; diff --git a/packages/server/src/queries/complex/pools/bonding.ts b/packages/server/src/queries/complex/pools/bonding.ts index d972bb0eca..bfb4a7bbf7 100644 --- a/packages/server/src/queries/complex/pools/bonding.ts +++ b/packages/server/src/queries/complex/pools/bonding.ts @@ -1,5 +1,5 @@ -import { CoinPretty, PricePretty, RatePretty } from "@keplr-wallet/unit"; import { AssetList, Chain } from "@osmosis-labs/types"; +import { CoinPretty, PricePretty, RatePretty } from "@osmosis-labs/unit"; import type { Duration } from "dayjs/plugin/duration"; import { dayjs } from "../../../utils/dayjs"; diff --git a/packages/server/src/queries/complex/pools/incentives.ts b/packages/server/src/queries/complex/pools/incentives.ts index 69b0e83bf3..287a57cba0 100644 --- a/packages/server/src/queries/complex/pools/incentives.ts +++ b/packages/server/src/queries/complex/pools/incentives.ts @@ -1,5 +1,5 @@ -import { Dec, RatePretty } from "@keplr-wallet/unit"; import { Chain } from "@osmosis-labs/types"; +import { Dec, RatePretty } from "@osmosis-labs/unit"; import cachified, { CacheEntry } from "cachified"; import dayjs from "dayjs"; import duration from "dayjs/plugin/duration"; diff --git a/packages/server/src/queries/complex/pools/index.ts b/packages/server/src/queries/complex/pools/index.ts index c625c144d8..0aec90c773 100644 --- a/packages/server/src/queries/complex/pools/index.ts +++ b/packages/server/src/queries/complex/pools/index.ts @@ -1,5 +1,5 @@ -import { CoinPretty, Dec, PricePretty, RatePretty } from "@keplr-wallet/unit"; import { AssetList, Chain } from "@osmosis-labs/types"; +import { CoinPretty, Dec, PricePretty, RatePretty } from "@osmosis-labs/unit"; import { z } from "zod"; import { IS_TESTNET } from "../../../env"; diff --git a/packages/server/src/queries/complex/pools/providers/sidecar.ts b/packages/server/src/queries/complex/pools/providers/sidecar.ts index c4a5670920..795aa0d812 100644 --- a/packages/server/src/queries/complex/pools/providers/sidecar.ts +++ b/packages/server/src/queries/complex/pools/providers/sidecar.ts @@ -1,5 +1,5 @@ -import { CoinPretty, Dec, PricePretty, RatePretty } from "@keplr-wallet/unit"; import { AssetList, Chain } from "@osmosis-labs/types"; +import { CoinPretty, Dec, PricePretty, RatePretty } from "@osmosis-labs/unit"; import { timeout } from "@osmosis-labs/utils"; import cachified, { CacheEntry } from "cachified"; import { LRUCache } from "lru-cache"; diff --git a/packages/server/src/queries/complex/pools/share.ts b/packages/server/src/queries/complex/pools/share.ts index 916a7a94a2..3ad70d6900 100644 --- a/packages/server/src/queries/complex/pools/share.ts +++ b/packages/server/src/queries/complex/pools/share.ts @@ -1,6 +1,6 @@ -import { CoinPretty, Dec, Int, RatePretty } from "@keplr-wallet/unit"; import { estimateExitSwap } from "@osmosis-labs/math"; import { AssetList, Chain, Currency } from "@osmosis-labs/types"; +import { CoinPretty, Dec, Int, RatePretty } from "@osmosis-labs/unit"; import { StablePoolRawResponse, WeightedPoolRawResponse } from "../../osmosis"; import { getLockableDurations } from "../pools/incentives"; diff --git a/packages/server/src/queries/complex/pools/transmuter.ts b/packages/server/src/queries/complex/pools/transmuter.ts index 5faaca9137..72fe9f96f8 100644 --- a/packages/server/src/queries/complex/pools/transmuter.ts +++ b/packages/server/src/queries/complex/pools/transmuter.ts @@ -1,5 +1,5 @@ -import { CoinPretty, Dec, DecUtils, RatePretty } from "@keplr-wallet/unit"; import { AssetList, Chain, MinimalAsset } from "@osmosis-labs/types"; +import { CoinPretty, Dec, DecUtils, RatePretty } from "@osmosis-labs/unit"; import cachified, { CacheEntry } from "cachified"; import { LRUCache } from "lru-cache"; diff --git a/packages/server/src/queries/complex/pools/user.ts b/packages/server/src/queries/complex/pools/user.ts index 0e6369521f..30d0d2af04 100644 --- a/packages/server/src/queries/complex/pools/user.ts +++ b/packages/server/src/queries/complex/pools/user.ts @@ -1,5 +1,5 @@ -import { Dec, IntPretty, PricePretty } from "@keplr-wallet/unit"; import { AssetList, Chain } from "@osmosis-labs/types"; +import { Dec, IntPretty, PricePretty } from "@osmosis-labs/unit"; import { aggregateRawCoinsByDenom, timeout } from "@osmosis-labs/utils"; import { diff --git a/packages/server/src/queries/complex/portfolio/assets.ts b/packages/server/src/queries/complex/portfolio/assets.ts index fadd377815..b7409a5676 100644 --- a/packages/server/src/queries/complex/portfolio/assets.ts +++ b/packages/server/src/queries/complex/portfolio/assets.ts @@ -1,6 +1,6 @@ -import { CoinPretty, PricePretty } from "@keplr-wallet/unit"; -import { Dec, RatePretty } from "@keplr-wallet/unit"; import { AssetList, MinimalAsset } from "@osmosis-labs/types"; +import { CoinPretty, PricePretty } from "@osmosis-labs/unit"; +import { Dec, RatePretty } from "@osmosis-labs/unit"; import { sort } from "@osmosis-labs/utils"; import { captureIfError } from "../../../utils"; diff --git a/packages/server/src/queries/complex/price/index.ts b/packages/server/src/queries/complex/price/index.ts index c53aa7617a..22924b394e 100644 --- a/packages/server/src/queries/complex/price/index.ts +++ b/packages/server/src/queries/complex/price/index.ts @@ -1,4 +1,4 @@ -import { Dec, PricePretty } from "@keplr-wallet/unit"; +import { Dec, PricePretty } from "@osmosis-labs/unit"; import { DEFAULT_VS_CURRENCY } from "../../../queries/complex/assets/config"; diff --git a/packages/server/src/queries/complex/staking/apr.ts b/packages/server/src/queries/complex/staking/apr.ts index 70f2e908cd..bfa3b72be5 100644 --- a/packages/server/src/queries/complex/staking/apr.ts +++ b/packages/server/src/queries/complex/staking/apr.ts @@ -1,4 +1,4 @@ -import { Dec } from "@keplr-wallet/unit"; +import { Dec } from "@osmosis-labs/unit"; import cachified, { CacheEntry } from "cachified"; import { LRUCache } from "lru-cache"; diff --git a/packages/server/src/queries/complex/staking/superfluid.ts b/packages/server/src/queries/complex/staking/superfluid.ts index f60f29b28a..bc8004246c 100644 --- a/packages/server/src/queries/complex/staking/superfluid.ts +++ b/packages/server/src/queries/complex/staking/superfluid.ts @@ -1,5 +1,5 @@ -import { CoinPretty, Dec, DecUtils } from "@keplr-wallet/unit"; import { AssetList, Chain } from "@osmosis-labs/types"; +import { CoinPretty, Dec, DecUtils } from "@osmosis-labs/unit"; import cachified, { CacheEntry } from "cachified"; import { LRUCache } from "lru-cache"; diff --git a/packages/server/src/queries/complex/staking/user.ts b/packages/server/src/queries/complex/staking/user.ts index bf70275633..bc376f24f5 100644 --- a/packages/server/src/queries/complex/staking/user.ts +++ b/packages/server/src/queries/complex/staking/user.ts @@ -1,5 +1,5 @@ -import { CoinPretty } from "@keplr-wallet/unit"; import { AssetList, Chain } from "@osmosis-labs/types"; +import { CoinPretty } from "@osmosis-labs/unit"; import { getChainStakeTokenSourceDenom } from "@osmosis-labs/utils"; import { queryDelegations, queryUndelegations } from "../../cosmos"; diff --git a/packages/server/src/queries/complex/staking/validator.ts b/packages/server/src/queries/complex/staking/validator.ts index ae6b99a63a..b560b888e3 100644 --- a/packages/server/src/queries/complex/staking/validator.ts +++ b/packages/server/src/queries/complex/staking/validator.ts @@ -1,5 +1,5 @@ -import { Dec, RatePretty } from "@keplr-wallet/unit"; import { BondStatus, Chain } from "@osmosis-labs/types"; +import { Dec, RatePretty } from "@osmosis-labs/unit"; import cachified, { CacheEntry } from "cachified"; import { LRUCache } from "lru-cache"; diff --git a/packages/server/src/queries/complex/swap.ts b/packages/server/src/queries/complex/swap.ts index b79b546a82..a1b50baa1c 100644 --- a/packages/server/src/queries/complex/swap.ts +++ b/packages/server/src/queries/complex/swap.ts @@ -1,6 +1,6 @@ -import { CoinPretty, Int, RatePretty } from "@keplr-wallet/unit"; import { SplitTokenInQuote, SplitTokenOutQuote } from "@osmosis-labs/pools"; import { AssetList } from "@osmosis-labs/types"; +import { CoinPretty, Int, RatePretty } from "@osmosis-labs/unit"; import { z } from "zod"; import { captureIfError } from "../../utils"; diff --git a/packages/server/src/queries/complex/transactions/transactions.ts b/packages/server/src/queries/complex/transactions/transactions.ts index d24852bd58..66c0062956 100644 --- a/packages/server/src/queries/complex/transactions/transactions.ts +++ b/packages/server/src/queries/complex/transactions/transactions.ts @@ -1,5 +1,5 @@ -import { CoinPretty, PricePretty } from "@keplr-wallet/unit"; import { AssetList } from "@osmosis-labs/types"; +import { CoinPretty, PricePretty } from "@osmosis-labs/unit"; import cachified, { CacheEntry } from "cachified"; import { LRUCache } from "lru-cache"; diff --git a/packages/server/src/queries/data-services/earn.ts b/packages/server/src/queries/data-services/earn.ts index 21a7ab51f4..18208119a4 100644 --- a/packages/server/src/queries/data-services/earn.ts +++ b/packages/server/src/queries/data-services/earn.ts @@ -1,5 +1,5 @@ -import { PricePretty, RatePretty } from "@keplr-wallet/unit"; import { MinimalAsset } from "@osmosis-labs/types"; +import { PricePretty, RatePretty } from "@osmosis-labs/unit"; import { apiClient } from "@osmosis-labs/utils"; export const EarnStrategyCategories = [ diff --git a/packages/server/src/queries/sidecar/router.ts b/packages/server/src/queries/sidecar/router.ts index 62eff6a8bb..022a0c3c79 100644 --- a/packages/server/src/queries/sidecar/router.ts +++ b/packages/server/src/queries/sidecar/router.ts @@ -1,4 +1,3 @@ -import { Dec, Int } from "@keplr-wallet/unit"; import { NotEnoughLiquidityError, NotEnoughQuotedError, @@ -10,6 +9,7 @@ import { SplitTokenOutQuote, Token, } from "@osmosis-labs/pools/build/router"; +import { Dec, Int } from "@osmosis-labs/unit"; import { apiClient } from "@osmosis-labs/utils"; import { SIDECAR_BASE_URL } from "../../env"; diff --git a/packages/server/src/utils/superjson.ts b/packages/server/src/utils/superjson.ts index e5fc8cc170..7874bbe398 100644 --- a/packages/server/src/utils/superjson.ts +++ b/packages/server/src/utils/superjson.ts @@ -1,4 +1,5 @@ import { FiatCurrency } from "@keplr-wallet/types"; +import { Currency } from "@osmosis-labs/types"; import { CoinPretty, CoinPrettyOptions, @@ -8,8 +9,7 @@ import { PricePrettyOptions, RatePretty, RatePrettyOptions, -} from "@keplr-wallet/unit"; -import { Currency } from "@osmosis-labs/types"; +} from "@osmosis-labs/unit"; import dayjs from "dayjs"; import duration, { type Duration } from "dayjs/plugin/duration"; import superjson from "superjson"; diff --git a/packages/stores/package.json b/packages/stores/package.json index f3cabc5079..43180d0a06 100644 --- a/packages/stores/package.json +++ b/packages/stores/package.json @@ -61,7 +61,6 @@ "@keplr-wallet/crypto": "0.12.48", "@keplr-wallet/proto-types": "0.10.24-ibc.go.v7.hot.fix", "@keplr-wallet/types": "0.10.24-ibc.go.v7.hot.fix", - "@keplr-wallet/unit": "0.10.24-ibc.go.v7.hot.fix", "@osmosis-labs/bridge": "^1.0.0", "@osmosis-labs/keplr-hooks": "0.10.24-ibc.go.v7.hot.fix", "@osmosis-labs/keplr-stores": "0.10.24-ibc.go.v7.hot.fix", @@ -71,6 +70,7 @@ "@osmosis-labs/server": "^1.0.0", "@osmosis-labs/tx": "^1.0.0", "@osmosis-labs/types": "^1.0.0", + "@osmosis-labs/unit": "0.10.24-ibc.go.v7.hot.fix", "@osmosis-labs/utils": "^1.0.0", "axios": "^0.27.2", "buffer": "^6.0.3", diff --git a/packages/stores/src/account/__tests_e2e__/join-pool.spec.ts b/packages/stores/src/account/__tests_e2e__/join-pool.spec.ts index 39007b3981..7b697b465f 100644 --- a/packages/stores/src/account/__tests_e2e__/join-pool.spec.ts +++ b/packages/stores/src/account/__tests_e2e__/join-pool.spec.ts @@ -1,5 +1,5 @@ /* eslint-disable */ -import { Dec, DecUtils, CoinPretty } from "@keplr-wallet/unit"; +import { Dec, DecUtils, CoinPretty } from "@osmosis-labs/unit"; import { deepContained, getEventFromTx, diff --git a/packages/stores/src/account/__tests_e2e__/positions.spec.ts b/packages/stores/src/account/__tests_e2e__/positions.spec.ts index bbfb863559..c34f69fcff 100644 --- a/packages/stores/src/account/__tests_e2e__/positions.spec.ts +++ b/packages/stores/src/account/__tests_e2e__/positions.spec.ts @@ -7,9 +7,9 @@ import { waitAccountLoaded, } from "../../tests/test-env"; import { maxTick, minTick, priceToTick } from "@osmosis-labs/math"; -import { Int, Dec } from "@keplr-wallet/unit"; +import { Int, Dec } from "@osmosis-labs/unit"; import { TestOsmosisChainId } from "../../tests/mock-data"; -// import { Int } from "@keplr-wallet/unit"; +// import { Int } from "@osmosis-labs/unit"; describe("Create CL Positions Txs", () => { const { accountStore, queriesStore, chainStore } = new RootStore(); diff --git a/packages/stores/src/account/__tests_e2e__/swap-exact-in-positions.spec.ts b/packages/stores/src/account/__tests_e2e__/swap-exact-in-positions.spec.ts index ecc0cf5fcd..3ce2eb2444 100644 --- a/packages/stores/src/account/__tests_e2e__/swap-exact-in-positions.spec.ts +++ b/packages/stores/src/account/__tests_e2e__/swap-exact-in-positions.spec.ts @@ -1,5 +1,4 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ -import { Dec, Int } from "@keplr-wallet/unit"; import { maxTick, minTick } from "@osmosis-labs/math"; import { BigDec } from "@osmosis-labs/math/src/big-dec"; import { @@ -12,6 +11,7 @@ import { ConcentratedLiquidityPool, NotEnoughLiquidityError, } from "@osmosis-labs/pools"; +import { Dec, Int } from "@osmosis-labs/unit"; import { ObservableQueryPool } from "../../queries-external/pools"; import { TestOsmosisChainId } from "../../tests/mock-data"; diff --git a/packages/stores/src/account/__tests_e2e__/swap-exact-in.spec.ts b/packages/stores/src/account/__tests_e2e__/swap-exact-in.spec.ts index 2d45549e24..25e1dc2b79 100644 --- a/packages/stores/src/account/__tests_e2e__/swap-exact-in.spec.ts +++ b/packages/stores/src/account/__tests_e2e__/swap-exact-in.spec.ts @@ -1,8 +1,8 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ import { Currency } from "@keplr-wallet/types"; -import { Coin, Dec, DecUtils, Int, IntPretty } from "@keplr-wallet/unit"; import { estimateSwapExactAmountIn } from "@osmosis-labs/math"; import { OptimizedRoutes } from "@osmosis-labs/pools"; +import { Coin, Dec, DecUtils, Int, IntPretty } from "@osmosis-labs/unit"; import { ObservableQueryPool } from "../../queries-external/pools"; import { TestOsmosisChainId } from "../../tests/mock-data"; diff --git a/packages/stores/src/account/__tests_e2e__/swap-exact-out.spec.ts b/packages/stores/src/account/__tests_e2e__/swap-exact-out.spec.ts index c0a47376b5..c5cfec331e 100644 --- a/packages/stores/src/account/__tests_e2e__/swap-exact-out.spec.ts +++ b/packages/stores/src/account/__tests_e2e__/swap-exact-out.spec.ts @@ -7,7 +7,7 @@ import { RootStore, waitAccountLoaded, } from "../../tests/test-env"; -import { Dec, Int, Coin, DecUtils, IntPretty } from "@keplr-wallet/unit"; +import { Dec, Int, Coin, DecUtils, IntPretty } from "@osmosis-labs/unit"; import { Currency } from "@keplr-wallet/types"; import { estimateSwapExactAmountOut } from "@osmosis-labs/math"; import { ObservableQueryPool } from "../../queries-external/pools"; diff --git a/packages/stores/src/account/base.ts b/packages/stores/src/account/base.ts index 48ac2c410f..41ec926f7d 100644 --- a/packages/stores/src/account/base.ts +++ b/packages/stores/src/account/base.ts @@ -17,7 +17,6 @@ import { KVStore } from "@keplr-wallet/common"; import { BaseAccount } from "@keplr-wallet/cosmos"; import { Hash, PrivKeySecp256k1 } from "@keplr-wallet/crypto"; import { SignDoc } from "@keplr-wallet/proto-types/cosmos/tx/v1beta1/tx"; -import { Dec } from "@keplr-wallet/unit"; import { ChainedFunctionifyTuple, ChainGetter, @@ -35,6 +34,7 @@ import { TxTracer, } from "@osmosis-labs/tx"; import type { AssetList, Chain } from "@osmosis-labs/types"; +import { Dec } from "@osmosis-labs/unit"; import { apiClient, ApiClientError, diff --git a/packages/stores/src/account/cosmos.ts b/packages/stores/src/account/cosmos.ts index bdc0affe85..fb2fff7a03 100644 --- a/packages/stores/src/account/cosmos.ts +++ b/packages/stores/src/account/cosmos.ts @@ -1,6 +1,5 @@ import { ChainIdHelper } from "@keplr-wallet/cosmos"; import { AppCurrency } from "@keplr-wallet/types"; -import { Dec, DecUtils, Int } from "@keplr-wallet/unit"; import { ChainGetter, CosmosQueries, @@ -8,6 +7,7 @@ import { txEventsWithPreOnFulfill, } from "@osmosis-labs/keplr-stores"; import { makeIBCTransferMsg } from "@osmosis-labs/tx"; +import { Dec, DecUtils, Int } from "@osmosis-labs/unit"; import { AccountStore, diff --git a/packages/stores/src/account/osmosis/index.ts b/packages/stores/src/account/osmosis/index.ts index 31afc81845..cfd1b708ac 100644 --- a/packages/stores/src/account/osmosis/index.ts +++ b/packages/stores/src/account/osmosis/index.ts @@ -1,7 +1,6 @@ import type { StdFee } from "@cosmjs/amino"; import type { EncodeObject } from "@cosmjs/proto-signing"; import { AppCurrency, Currency } from "@keplr-wallet/types"; -import { Coin, CoinPretty, Dec, DecUtils, Int } from "@keplr-wallet/unit"; import { ChainGetter, CosmosQueries, @@ -40,6 +39,7 @@ import { makeWithdrawPositionMsg, } from "@osmosis-labs/tx"; import { BondStatus } from "@osmosis-labs/types"; +import { Coin, CoinPretty, Dec, DecUtils, Int } from "@osmosis-labs/unit"; import Long from "long"; import { AccountStore, CosmosAccount, CosmwasmAccount } from "../../account"; diff --git a/packages/stores/src/derived-data/pool/bonding.ts b/packages/stores/src/derived-data/pool/bonding.ts index eea871672d..d1c6646d2b 100644 --- a/packages/stores/src/derived-data/pool/bonding.ts +++ b/packages/stores/src/derived-data/pool/bonding.ts @@ -1,15 +1,15 @@ +import { + ChainGetter, + HasMapStore, + IQueriesStore, +} from "@osmosis-labs/keplr-stores"; import { CoinPretty, Dec, IntPretty, PricePretty, RatePretty, -} from "@keplr-wallet/unit"; -import { - ChainGetter, - HasMapStore, - IQueriesStore, -} from "@osmosis-labs/keplr-stores"; +} from "@osmosis-labs/unit"; import dayjs from "dayjs"; import { Duration } from "dayjs/plugin/duration"; import { computed, makeObservable } from "mobx"; diff --git a/packages/stores/src/derived-data/pool/concentrated.ts b/packages/stores/src/derived-data/pool/concentrated.ts index 23c30c1c8b..d90a136850 100644 --- a/packages/stores/src/derived-data/pool/concentrated.ts +++ b/packages/stores/src/derived-data/pool/concentrated.ts @@ -1,12 +1,12 @@ import { FiatCurrency } from "@keplr-wallet/types"; +import { HasMapStore, IQueriesStore } from "@osmosis-labs/keplr-stores"; import { CoinPretty, Dec, DecUtils, PricePretty, RatePretty, -} from "@keplr-wallet/unit"; -import { HasMapStore, IQueriesStore } from "@osmosis-labs/keplr-stores"; +} from "@osmosis-labs/unit"; import { computed, makeObservable } from "mobx"; import { AccountStore } from "../../account"; diff --git a/packages/stores/src/derived-data/pool/share-pool-details.ts b/packages/stores/src/derived-data/pool/share-pool-details.ts index b05f23e94f..58eaa93dbf 100644 --- a/packages/stores/src/derived-data/pool/share-pool-details.ts +++ b/packages/stores/src/derived-data/pool/share-pool-details.ts @@ -1,6 +1,6 @@ import { FiatCurrency } from "@keplr-wallet/types"; -import { CoinPretty, Dec, PricePretty, RatePretty } from "@keplr-wallet/unit"; import { HasMapStore, IQueriesStore } from "@osmosis-labs/keplr-stores"; +import { CoinPretty, Dec, PricePretty, RatePretty } from "@osmosis-labs/unit"; import dayjs from "dayjs"; import { Duration } from "dayjs/plugin/duration"; import { computed, makeObservable } from "mobx"; diff --git a/packages/stores/src/derived-data/pool/superfluid.ts b/packages/stores/src/derived-data/pool/superfluid.ts index 4589bbff39..f7efcfb913 100644 --- a/packages/stores/src/derived-data/pool/superfluid.ts +++ b/packages/stores/src/derived-data/pool/superfluid.ts @@ -1,11 +1,11 @@ import { FiatCurrency } from "@keplr-wallet/types"; -import { CoinPretty, Dec, RatePretty } from "@keplr-wallet/unit"; import { CosmosQueries, HasMapStore, IQueriesStore, } from "@osmosis-labs/keplr-stores"; import { BondStatus } from "@osmosis-labs/types"; +import { CoinPretty, Dec, RatePretty } from "@osmosis-labs/unit"; import dayjs from "dayjs"; import { computed, makeObservable } from "mobx"; import { computedFn } from "mobx-utils"; diff --git a/packages/stores/src/derived-data/pool/types.ts b/packages/stores/src/derived-data/pool/types.ts index 945bdd791c..83afaba613 100644 --- a/packages/stores/src/derived-data/pool/types.ts +++ b/packages/stores/src/derived-data/pool/types.ts @@ -1,4 +1,4 @@ -import { CoinPretty, PricePretty, RatePretty } from "@keplr-wallet/unit"; +import { CoinPretty, PricePretty, RatePretty } from "@osmosis-labs/unit"; import { Duration } from "dayjs/plugin/duration"; /** Non OSMO gauge. */ diff --git a/packages/stores/src/price/pool.ts b/packages/stores/src/price/pool.ts index e20f4d60be..913210432d 100644 --- a/packages/stores/src/price/pool.ts +++ b/packages/stores/src/price/pool.ts @@ -1,8 +1,8 @@ import { KVStore } from "@keplr-wallet/common"; import { FiatCurrency } from "@keplr-wallet/types"; -import { CoinPretty, Dec, PricePretty } from "@keplr-wallet/unit"; import { ChainGetter, CoinGeckoPriceStore } from "@osmosis-labs/keplr-stores"; import { Asset } from "@osmosis-labs/types"; +import { CoinPretty, Dec, PricePretty } from "@osmosis-labs/unit"; import { computedFn } from "mobx-utils"; import { ObservableQueryPoolGetter } from "../queries-external/pools"; diff --git a/packages/stores/src/price/types.ts b/packages/stores/src/price/types.ts index 2927d191dc..dbc230fb08 100644 --- a/packages/stores/src/price/types.ts +++ b/packages/stores/src/price/types.ts @@ -1,5 +1,5 @@ import { FiatCurrency } from "@keplr-wallet/types"; -import { CoinPretty, PricePretty } from "@keplr-wallet/unit"; +import { CoinPretty, PricePretty } from "@osmosis-labs/unit"; // TODO: Move to @keplr-wallet export interface IPriceStore { diff --git a/packages/stores/src/queries-external/concentrated-liquidity/pool-avg-apr.ts b/packages/stores/src/queries-external/concentrated-liquidity/pool-avg-apr.ts index a1ccc11927..36e01c7c27 100644 --- a/packages/stores/src/queries-external/concentrated-liquidity/pool-avg-apr.ts +++ b/packages/stores/src/queries-external/concentrated-liquidity/pool-avg-apr.ts @@ -1,6 +1,6 @@ import { KVStore } from "@keplr-wallet/common"; -import { RatePretty } from "@keplr-wallet/unit"; import { HasMapStore } from "@osmosis-labs/keplr-stores"; +import { RatePretty } from "@osmosis-labs/unit"; import { computed, makeObservable } from "mobx"; import { IMPERATOR_INDEXER_DEFAULT_BASEURL } from ".."; diff --git a/packages/stores/src/queries-external/concentrated-liquidity/range-aprs.ts b/packages/stores/src/queries-external/concentrated-liquidity/range-aprs.ts index e90eb897f9..842440e588 100644 --- a/packages/stores/src/queries-external/concentrated-liquidity/range-aprs.ts +++ b/packages/stores/src/queries-external/concentrated-liquidity/range-aprs.ts @@ -1,7 +1,7 @@ import { KVStore } from "@keplr-wallet/common"; -import { Int, RatePretty } from "@keplr-wallet/unit"; import { HasMapStore } from "@osmosis-labs/keplr-stores"; import { maxTick, minTick } from "@osmosis-labs/math"; +import { Int, RatePretty } from "@osmosis-labs/unit"; import { computed, makeObservable } from "mobx"; import { IMPERATOR_INDEXER_DEFAULT_BASEURL } from ".."; diff --git a/packages/stores/src/queries-external/numia/pool-apr.ts b/packages/stores/src/queries-external/numia/pool-apr.ts index 98b8891acb..1c6dc78ace 100644 --- a/packages/stores/src/queries-external/numia/pool-apr.ts +++ b/packages/stores/src/queries-external/numia/pool-apr.ts @@ -1,5 +1,5 @@ import { KVStore } from "@keplr-wallet/common"; -import { Dec, RatePretty } from "@keplr-wallet/unit"; +import { Dec, RatePretty } from "@osmosis-labs/unit"; import { computed, makeObservable } from "mobx"; import { computedFn } from "mobx-utils"; diff --git a/packages/stores/src/queries-external/pool-rewards/index.ts b/packages/stores/src/queries-external/pool-rewards/index.ts index e6844ea875..ce924d8f77 100644 --- a/packages/stores/src/queries-external/pool-rewards/index.ts +++ b/packages/stores/src/queries-external/pool-rewards/index.ts @@ -1,6 +1,6 @@ import { KVStore } from "@keplr-wallet/common"; -import { Dec, PricePretty } from "@keplr-wallet/unit"; import { HasMapStore } from "@osmosis-labs/keplr-stores"; +import { Dec, PricePretty } from "@osmosis-labs/unit"; import { makeObservable } from "mobx"; import { computedFn } from "mobx-utils"; diff --git a/packages/stores/src/queries-external/pool-rewards/types.ts b/packages/stores/src/queries-external/pool-rewards/types.ts index 12117955f3..35c6746a60 100644 --- a/packages/stores/src/queries-external/pool-rewards/types.ts +++ b/packages/stores/src/queries-external/pool-rewards/types.ts @@ -1,4 +1,4 @@ -import { PricePretty } from "@keplr-wallet/unit"; +import { PricePretty } from "@osmosis-labs/unit"; export interface PoolsRewards { pools: { diff --git a/packages/stores/src/queries-external/pools/pool.ts b/packages/stores/src/queries-external/pools/pool.ts index f1103c4d58..eed7abeed8 100644 --- a/packages/stores/src/queries-external/pools/pool.ts +++ b/packages/stores/src/queries-external/pools/pool.ts @@ -1,13 +1,5 @@ import { KVStore } from "@keplr-wallet/common"; import { AppCurrency, Currency } from "@keplr-wallet/types"; -import { - CoinPretty, - Dec, - DecUtils, - IntPretty, - PricePretty, - RatePretty, -} from "@keplr-wallet/unit"; import { ChainGetter, ObservableQueryBalances, @@ -30,6 +22,14 @@ import { WEIGHTED_POOL_TYPE, WeightedPool, } from "@osmosis-labs/pools"; +import { + CoinPretty, + Dec, + DecUtils, + IntPretty, + PricePretty, + RatePretty, +} from "@osmosis-labs/unit"; import dayjs from "dayjs"; import { Duration } from "dayjs/plugin/duration"; import { action, computed, makeObservable, observable } from "mobx"; diff --git a/packages/stores/src/queries-external/position-performance/index.ts b/packages/stores/src/queries-external/position-performance/index.ts index d654ffbf4a..9ddcd482d9 100644 --- a/packages/stores/src/queries-external/position-performance/index.ts +++ b/packages/stores/src/queries-external/position-performance/index.ts @@ -1,6 +1,6 @@ import { KVStore } from "@keplr-wallet/common"; -import { CoinPretty, PricePretty, RatePretty } from "@keplr-wallet/unit"; import { ChainGetter, HasMapStore } from "@osmosis-labs/keplr-stores"; +import { CoinPretty, PricePretty, RatePretty } from "@osmosis-labs/unit"; import { computed, makeObservable } from "mobx"; import { computedFn } from "mobx-utils"; diff --git a/packages/stores/src/queries-external/token-historical-chart/index.ts b/packages/stores/src/queries-external/token-historical-chart/index.ts index 80f79b85b9..1ecece72e8 100644 --- a/packages/stores/src/queries-external/token-historical-chart/index.ts +++ b/packages/stores/src/queries-external/token-historical-chart/index.ts @@ -1,6 +1,6 @@ import { KVStore } from "@keplr-wallet/common"; -import { Dec, PricePretty } from "@keplr-wallet/unit"; import { HasMapStore } from "@osmosis-labs/keplr-stores"; +import { Dec, PricePretty } from "@osmosis-labs/unit"; import { computed, makeObservable } from "mobx"; import { IPriceStore } from "../../price"; diff --git a/packages/stores/src/queries-external/token-market-cap/index.ts b/packages/stores/src/queries-external/token-market-cap/index.ts index 40019bb917..606ee81ea4 100644 --- a/packages/stores/src/queries-external/token-market-cap/index.ts +++ b/packages/stores/src/queries-external/token-market-cap/index.ts @@ -1,5 +1,5 @@ import { KVStore } from "@keplr-wallet/common"; -import { Dec, PricePretty } from "@keplr-wallet/unit"; +import { Dec, PricePretty } from "@osmosis-labs/unit"; import { makeObservable } from "mobx"; import { computedFn } from "mobx-utils"; diff --git a/packages/stores/src/queries/concentrated-liquidity/account-positions.ts b/packages/stores/src/queries/concentrated-liquidity/account-positions.ts index 5479bcd33b..0d283cc1f9 100644 --- a/packages/stores/src/queries/concentrated-liquidity/account-positions.ts +++ b/packages/stores/src/queries/concentrated-liquidity/account-positions.ts @@ -1,11 +1,11 @@ import { KVStore } from "@keplr-wallet/common"; -import { CoinPretty } from "@keplr-wallet/unit"; import { ChainGetter, ObservableChainQuery, ObservableChainQueryMap, QueryResponse, } from "@osmosis-labs/keplr-stores"; +import { CoinPretty } from "@osmosis-labs/unit"; import { computed, makeObservable } from "mobx"; import { computedFn } from "mobx-utils"; diff --git a/packages/stores/src/queries/concentrated-liquidity/liquidity-net-in-direction.ts b/packages/stores/src/queries/concentrated-liquidity/liquidity-net-in-direction.ts index ad5ad14a61..9d914ba28a 100644 --- a/packages/stores/src/queries/concentrated-liquidity/liquidity-net-in-direction.ts +++ b/packages/stores/src/queries/concentrated-liquidity/liquidity-net-in-direction.ts @@ -1,7 +1,7 @@ import { KVStore } from "@keplr-wallet/common"; -import { Dec, Int } from "@keplr-wallet/unit"; import { ChainGetter, ObservableChainQuery } from "@osmosis-labs/keplr-stores"; import { BigDec, LiquidityDepth, maxTick, minTick } from "@osmosis-labs/math"; +import { Dec, Int } from "@osmosis-labs/unit"; import { computed, makeObservable, observable } from "mobx"; import { LiquidityNetInDirection } from "./types"; diff --git a/packages/stores/src/queries/concentrated-liquidity/params.ts b/packages/stores/src/queries/concentrated-liquidity/params.ts index 3d7734c63d..322369803b 100644 --- a/packages/stores/src/queries/concentrated-liquidity/params.ts +++ b/packages/stores/src/queries/concentrated-liquidity/params.ts @@ -1,6 +1,6 @@ import { KVStore } from "@keplr-wallet/common"; -import { Dec } from "@keplr-wallet/unit"; import { ChainGetter, ObservableChainQuery } from "@osmosis-labs/keplr-stores"; +import { Dec } from "@osmosis-labs/unit"; import { computed } from "mobx"; export type ConcentratedLiquidityParams = { diff --git a/packages/stores/src/queries/concentrated-liquidity/position-by-id.ts b/packages/stores/src/queries/concentrated-liquidity/position-by-id.ts index ce3e986b87..c84f691010 100644 --- a/packages/stores/src/queries/concentrated-liquidity/position-by-id.ts +++ b/packages/stores/src/queries/concentrated-liquidity/position-by-id.ts @@ -1,5 +1,4 @@ import { KVStore } from "@keplr-wallet/common"; -import { CoinPretty, Dec, DecUtils, Int } from "@keplr-wallet/unit"; import { ChainGetter, ObservableChainQuery, @@ -7,6 +6,7 @@ import { QueryResponse, } from "@osmosis-labs/keplr-stores"; import { maxTick, minTick, tickToSqrtPrice } from "@osmosis-labs/math"; +import { CoinPretty, Dec, DecUtils, Int } from "@osmosis-labs/unit"; import { action, computed, makeObservable, observable } from "mobx"; import { LiquidityPosition } from "./types"; diff --git a/packages/stores/src/queries/concentrated-liquidity/tick-data-provider.ts b/packages/stores/src/queries/concentrated-liquidity/tick-data-provider.ts index 8be89d5ba2..093eec502c 100644 --- a/packages/stores/src/queries/concentrated-liquidity/tick-data-provider.ts +++ b/packages/stores/src/queries/concentrated-liquidity/tick-data-provider.ts @@ -1,4 +1,3 @@ -import { Dec, Int } from "@keplr-wallet/unit"; import { estimateInitialTickBound } from "@osmosis-labs/math"; import { ConcentratedLiquidityPool, @@ -6,6 +5,7 @@ import { TickDataProvider, TickDepths, } from "@osmosis-labs/pools"; +import { Dec, Int } from "@osmosis-labs/unit"; import { ObservableQueryLiquiditiesNetInDirection } from "./liquidity-net-in-direction"; diff --git a/packages/stores/src/queries/incentives/gauge-by-id.ts b/packages/stores/src/queries/incentives/gauge-by-id.ts index 53890dd29a..8db8b7a332 100644 --- a/packages/stores/src/queries/incentives/gauge-by-id.ts +++ b/packages/stores/src/queries/incentives/gauge-by-id.ts @@ -1,11 +1,11 @@ import { KVStore } from "@keplr-wallet/common"; -import { CoinPretty, Dec } from "@keplr-wallet/unit"; import { ChainGetter, ObservableChainQuery, ObservableChainQueryMap, QueryResponse, } from "@osmosis-labs/keplr-stores"; +import { CoinPretty, Dec } from "@osmosis-labs/unit"; import dayjs from "dayjs"; import { Duration } from "dayjs/plugin/duration"; import { action, computed, makeObservable, observable } from "mobx"; diff --git a/packages/stores/src/queries/lockup/account-locked.ts b/packages/stores/src/queries/lockup/account-locked.ts index dbc556d88b..50581c8e7e 100644 --- a/packages/stores/src/queries/lockup/account-locked.ts +++ b/packages/stores/src/queries/lockup/account-locked.ts @@ -1,12 +1,12 @@ import { KVStore } from "@keplr-wallet/common"; import { AppCurrency } from "@keplr-wallet/types"; -import { CoinPretty, Dec } from "@keplr-wallet/unit"; import { ChainGetter, ObservableChainQuery, ObservableChainQueryMap, QueryResponse, } from "@osmosis-labs/keplr-stores"; +import { CoinPretty, Dec } from "@osmosis-labs/unit"; import dayjs from "dayjs"; import { Duration } from "dayjs/plugin/duration"; import { computed, makeObservable } from "mobx"; diff --git a/packages/stores/src/queries/lockup/locked-coins.ts b/packages/stores/src/queries/lockup/locked-coins.ts index bfb1ab48f5..a98905c813 100644 --- a/packages/stores/src/queries/lockup/locked-coins.ts +++ b/packages/stores/src/queries/lockup/locked-coins.ts @@ -1,11 +1,11 @@ import { KVStore } from "@keplr-wallet/common"; -import { CoinPretty, Dec } from "@keplr-wallet/unit"; import { ChainGetter, ObservableChainQuery, ObservableChainQueryMap, QueryResponse, } from "@osmosis-labs/keplr-stores"; +import { CoinPretty, Dec } from "@osmosis-labs/unit"; import { computed, makeObservable } from "mobx"; import { AccountLockedCoins } from "./types"; diff --git a/packages/stores/src/queries/lockup/unlocking-coins.ts b/packages/stores/src/queries/lockup/unlocking-coins.ts index 0b6fa2f6a8..9c40531dd4 100644 --- a/packages/stores/src/queries/lockup/unlocking-coins.ts +++ b/packages/stores/src/queries/lockup/unlocking-coins.ts @@ -1,11 +1,11 @@ import { KVStore } from "@keplr-wallet/common"; -import { CoinPretty, Dec } from "@keplr-wallet/unit"; import { ChainGetter, ObservableChainQuery, ObservableChainQueryMap, QueryResponse, } from "@osmosis-labs/keplr-stores"; +import { CoinPretty, Dec } from "@osmosis-labs/unit"; import { computed, makeObservable } from "mobx"; import { AccountUnlockingCoins } from "./types"; diff --git a/packages/stores/src/queries/mint/epoch-provisions.ts b/packages/stores/src/queries/mint/epoch-provisions.ts index 1d77d5d793..d767e009cf 100644 --- a/packages/stores/src/queries/mint/epoch-provisions.ts +++ b/packages/stores/src/queries/mint/epoch-provisions.ts @@ -1,6 +1,6 @@ import { KVStore } from "@keplr-wallet/common"; -import { CoinPretty, Dec } from "@keplr-wallet/unit"; import { ChainGetter, ObservableChainQuery } from "@osmosis-labs/keplr-stores"; +import { CoinPretty, Dec } from "@osmosis-labs/unit"; import { computed, makeObservable } from "mobx"; import { ObservableQueryMintParmas } from "./params"; diff --git a/packages/stores/src/queries/mint/params.ts b/packages/stores/src/queries/mint/params.ts index f9f62b3c72..fb02a51e8b 100644 --- a/packages/stores/src/queries/mint/params.ts +++ b/packages/stores/src/queries/mint/params.ts @@ -1,6 +1,6 @@ import { KVStore } from "@keplr-wallet/common"; -import { Dec } from "@keplr-wallet/unit"; import { ChainGetter, ObservableChainQuery } from "@osmosis-labs/keplr-stores"; +import { Dec } from "@osmosis-labs/unit"; import { computed, makeObservable } from "mobx"; import { MintParmas } from "./types"; diff --git a/packages/stores/src/queries/pool-creation-fee/index.ts b/packages/stores/src/queries/pool-creation-fee/index.ts index 7b43629164..642932edd3 100644 --- a/packages/stores/src/queries/pool-creation-fee/index.ts +++ b/packages/stores/src/queries/pool-creation-fee/index.ts @@ -1,6 +1,6 @@ import { KVStore } from "@keplr-wallet/common"; -import { CoinPretty, Dec } from "@keplr-wallet/unit"; import { ChainGetter, ObservableChainQuery } from "@osmosis-labs/keplr-stores"; +import { CoinPretty, Dec } from "@osmosis-labs/unit"; import { computed, makeObservable } from "mobx"; export type Params = { diff --git a/packages/stores/src/queries/pool-incentives/distr-info.ts b/packages/stores/src/queries/pool-incentives/distr-info.ts index e7e2f87b32..9a44db59c3 100644 --- a/packages/stores/src/queries/pool-incentives/distr-info.ts +++ b/packages/stores/src/queries/pool-incentives/distr-info.ts @@ -1,6 +1,6 @@ import { KVStore } from "@keplr-wallet/common"; -import { Int } from "@keplr-wallet/unit"; import { ChainGetter, ObservableChainQuery } from "@osmosis-labs/keplr-stores"; +import { Int } from "@osmosis-labs/unit"; import { computed, makeObservable } from "mobx"; import { computedFn } from "mobx-utils"; diff --git a/packages/stores/src/queries/pool-incentives/incentivized-pools.ts b/packages/stores/src/queries/pool-incentives/incentivized-pools.ts index 202dd74e39..d878b5dac4 100644 --- a/packages/stores/src/queries/pool-incentives/incentivized-pools.ts +++ b/packages/stores/src/queries/pool-incentives/incentivized-pools.ts @@ -1,7 +1,7 @@ import { KVStore } from "@keplr-wallet/common"; import { FiatCurrency } from "@keplr-wallet/types"; -import { CoinPretty, Dec, Int, RatePretty } from "@keplr-wallet/unit"; import { ChainGetter, ObservableChainQuery } from "@osmosis-labs/keplr-stores"; +import { CoinPretty, Dec, Int, RatePretty } from "@osmosis-labs/unit"; import dayjs from "dayjs"; import { Duration } from "dayjs/plugin/duration"; import { computed, makeObservable } from "mobx"; diff --git a/packages/stores/src/queries/pool-incentives/pool-gauges.ts b/packages/stores/src/queries/pool-incentives/pool-gauges.ts index 2e727dcbe9..3b0afceba1 100644 --- a/packages/stores/src/queries/pool-incentives/pool-gauges.ts +++ b/packages/stores/src/queries/pool-incentives/pool-gauges.ts @@ -1,10 +1,10 @@ import { KVStore } from "@keplr-wallet/common"; -import { Dec } from "@keplr-wallet/unit"; import { ChainGetter, HasMapStore, ObservableChainQuery, } from "@osmosis-labs/keplr-stores"; +import { Dec } from "@osmosis-labs/unit"; import dayjs from "dayjs"; import { Duration } from "dayjs/plugin/duration"; import { computed, makeObservable } from "mobx"; diff --git a/packages/stores/src/queries/pool-share/index.ts b/packages/stores/src/queries/pool-share/index.ts index 4d480b84bd..33eda830aa 100644 --- a/packages/stores/src/queries/pool-share/index.ts +++ b/packages/stores/src/queries/pool-share/index.ts @@ -1,4 +1,5 @@ import { AppCurrency, Currency, FiatCurrency } from "@keplr-wallet/types"; +import { ObservableQueryBalances } from "@osmosis-labs/keplr-stores"; import { CoinPretty, Dec, @@ -6,8 +7,7 @@ import { IntPretty, PricePretty, RatePretty, -} from "@keplr-wallet/unit"; -import { ObservableQueryBalances } from "@osmosis-labs/keplr-stores"; +} from "@osmosis-labs/unit"; import { Duration } from "dayjs/plugin/duration"; import { computedFn } from "mobx-utils"; diff --git a/packages/stores/src/queries/superfluid-pools/asset-multiplier.ts b/packages/stores/src/queries/superfluid-pools/asset-multiplier.ts index 85c11b78d5..98043e4c09 100644 --- a/packages/stores/src/queries/superfluid-pools/asset-multiplier.ts +++ b/packages/stores/src/queries/superfluid-pools/asset-multiplier.ts @@ -1,10 +1,10 @@ import { KVStore } from "@keplr-wallet/common"; -import { Dec } from "@keplr-wallet/unit"; import { ChainGetter, ObservableChainQuery, ObservableChainQueryMap, } from "@osmosis-labs/keplr-stores"; +import { Dec } from "@osmosis-labs/unit"; import { computed, makeObservable } from "mobx"; import { SuperfluidAssetMultiplier } from "./types"; diff --git a/packages/stores/src/queries/superfluid-pools/delegated-positions.ts b/packages/stores/src/queries/superfluid-pools/delegated-positions.ts index c170374840..7c7c49bf8f 100644 --- a/packages/stores/src/queries/superfluid-pools/delegated-positions.ts +++ b/packages/stores/src/queries/superfluid-pools/delegated-positions.ts @@ -1,10 +1,10 @@ import { KVStore } from "@keplr-wallet/common"; -import { CoinPretty } from "@keplr-wallet/unit"; import { ChainGetter, ObservableChainQuery, ObservableChainQueryMap, } from "@osmosis-labs/keplr-stores"; +import { CoinPretty } from "@osmosis-labs/unit"; import { computed, makeObservable } from "mobx"; import { computedFn } from "mobx-utils"; diff --git a/packages/stores/src/queries/superfluid-pools/delegations.ts b/packages/stores/src/queries/superfluid-pools/delegations.ts index a5df94b426..65dfc94415 100644 --- a/packages/stores/src/queries/superfluid-pools/delegations.ts +++ b/packages/stores/src/queries/superfluid-pools/delegations.ts @@ -1,11 +1,11 @@ import { KVStore } from "@keplr-wallet/common"; import { Currency } from "@keplr-wallet/types"; -import { CoinPretty, Int } from "@keplr-wallet/unit"; import { ChainGetter, ObservableChainQuery, ObservableChainQueryMap, } from "@osmosis-labs/keplr-stores"; +import { CoinPretty, Int } from "@osmosis-labs/unit"; import { makeObservable } from "mobx"; import { computedFn } from "mobx-utils"; diff --git a/packages/stores/src/queries/superfluid-pools/osmo-equivalent.ts b/packages/stores/src/queries/superfluid-pools/osmo-equivalent.ts index 14ad5c4fe0..1936877c95 100644 --- a/packages/stores/src/queries/superfluid-pools/osmo-equivalent.ts +++ b/packages/stores/src/queries/superfluid-pools/osmo-equivalent.ts @@ -1,6 +1,6 @@ import { AppCurrency } from "@keplr-wallet/types"; -import { CoinPretty, Dec, DecUtils } from "@keplr-wallet/unit"; import { ChainGetter } from "@osmosis-labs/keplr-stores"; +import { CoinPretty, Dec, DecUtils } from "@osmosis-labs/unit"; import { computedFn } from "mobx-utils"; import { ObservableQueryPoolGetter } from "../../queries-external/pools"; diff --git a/packages/stores/src/queries/superfluid-pools/params.ts b/packages/stores/src/queries/superfluid-pools/params.ts index e42f8709d0..07a6c4f377 100644 --- a/packages/stores/src/queries/superfluid-pools/params.ts +++ b/packages/stores/src/queries/superfluid-pools/params.ts @@ -1,6 +1,6 @@ import { KVStore } from "@keplr-wallet/common"; -import { Dec } from "@keplr-wallet/unit"; import { ChainGetter, ObservableChainQuery } from "@osmosis-labs/keplr-stores"; +import { Dec } from "@osmosis-labs/unit"; import { computed, makeObservable } from "mobx"; import { SuperfluidParams } from "./types"; diff --git a/packages/stores/src/queries/superfluid-pools/types.ts b/packages/stores/src/queries/superfluid-pools/types.ts index da071a555a..86bc21a0b2 100644 --- a/packages/stores/src/queries/superfluid-pools/types.ts +++ b/packages/stores/src/queries/superfluid-pools/types.ts @@ -1,4 +1,4 @@ -import { CoinPretty } from "@keplr-wallet/unit"; +import { CoinPretty } from "@osmosis-labs/unit"; import { Duration } from "dayjs/plugin/duration"; export type SuperfluidParams = { diff --git a/packages/stores/src/queries/superfluid-pools/undelegating-positions.ts b/packages/stores/src/queries/superfluid-pools/undelegating-positions.ts index 227191e95c..ae1e4bf6a2 100644 --- a/packages/stores/src/queries/superfluid-pools/undelegating-positions.ts +++ b/packages/stores/src/queries/superfluid-pools/undelegating-positions.ts @@ -1,10 +1,10 @@ import { KVStore } from "@keplr-wallet/common"; -import { CoinPretty } from "@keplr-wallet/unit"; import { ChainGetter, ObservableChainQuery, ObservableChainQueryMap, } from "@osmosis-labs/keplr-stores"; +import { CoinPretty } from "@osmosis-labs/unit"; import { computed, makeObservable } from "mobx"; import { computedFn } from "mobx-utils"; diff --git a/packages/stores/src/queries/superfluid-pools/undelegations.ts b/packages/stores/src/queries/superfluid-pools/undelegations.ts index 4238d93e18..a434caa921 100644 --- a/packages/stores/src/queries/superfluid-pools/undelegations.ts +++ b/packages/stores/src/queries/superfluid-pools/undelegations.ts @@ -1,11 +1,11 @@ import { KVStore } from "@keplr-wallet/common"; import { Currency } from "@keplr-wallet/types"; -import { CoinPretty, Dec } from "@keplr-wallet/unit"; import { ChainGetter, ObservableChainQuery, ObservableChainQueryMap, } from "@osmosis-labs/keplr-stores"; +import { CoinPretty, Dec } from "@osmosis-labs/unit"; import dayjs from "dayjs"; import { makeObservable } from "mobx"; import { computedFn } from "mobx-utils"; diff --git a/packages/stores/src/tests/test-env.ts b/packages/stores/src/tests/test-env.ts index 2c8742990c..6a6191448f 100644 --- a/packages/stores/src/tests/test-env.ts +++ b/packages/stores/src/tests/test-env.ts @@ -1,13 +1,13 @@ /* eslint-disable import/no-extraneous-dependencies */ import { WalletStatus } from "@cosmos-kit/core"; import { MemoryKVStore } from "@keplr-wallet/common"; -import { Coin, Int } from "@keplr-wallet/unit"; import { CosmosQueries, CosmwasmQueries, IQueriesStore, QueriesStore, } from "@osmosis-labs/keplr-stores"; +import { Coin, Int } from "@osmosis-labs/unit"; import { when } from "mobx"; import WebSocket from "ws"; diff --git a/packages/stores/src/ui-config/create-pool.ts b/packages/stores/src/ui-config/create-pool.ts index ed72df5d6b..3d895a7cd6 100644 --- a/packages/stores/src/ui-config/create-pool.ts +++ b/packages/stores/src/ui-config/create-pool.ts @@ -1,6 +1,5 @@ import { Bech32Address } from "@keplr-wallet/cosmos"; import { AppCurrency } from "@keplr-wallet/types"; -import { Dec, RatePretty } from "@keplr-wallet/unit"; import { IFeeConfig, InvalidNumberAmountError, @@ -12,6 +11,7 @@ import { IQueriesStore, ObservableQueryBalances, } from "@osmosis-labs/keplr-stores"; +import { Dec, RatePretty } from "@osmosis-labs/unit"; import { action, computed, diff --git a/packages/stores/src/ui-config/fake-fee-config.ts b/packages/stores/src/ui-config/fake-fee-config.ts index 0a82a7d999..3aa0baf39b 100644 --- a/packages/stores/src/ui-config/fake-fee-config.ts +++ b/packages/stores/src/ui-config/fake-fee-config.ts @@ -1,12 +1,12 @@ import type { StdFee } from "@cosmjs/amino"; import { Currency } from "@keplr-wallet/types"; -import { CoinPretty, Dec, Int } from "@keplr-wallet/unit"; import { DefaultGasPriceStep, FeeType, IFeeConfig, } from "@osmosis-labs/keplr-hooks"; import { ChainGetter, CoinPrimitive } from "@osmosis-labs/keplr-stores"; +import { CoinPretty, Dec, Int } from "@osmosis-labs/unit"; import { action, computed, makeObservable, observable } from "mobx"; import { computedFn } from "mobx-utils"; diff --git a/packages/stores/src/ui-config/manage-liquidity/add-liquidity.ts b/packages/stores/src/ui-config/manage-liquidity/add-liquidity.ts index 423c4234f7..ddb39fbdd2 100644 --- a/packages/stores/src/ui-config/manage-liquidity/add-liquidity.ts +++ b/packages/stores/src/ui-config/manage-liquidity/add-liquidity.ts @@ -1,11 +1,3 @@ -import { - CoinPretty, - Dec, - DecUtils, - Int, - IntPretty, - RatePretty, -} from "@keplr-wallet/unit"; import { AmountConfig } from "@osmosis-labs/keplr-hooks"; import { ChainGetter, @@ -13,6 +5,14 @@ import { ObservableQueryBalances, } from "@osmosis-labs/keplr-stores"; import type { Currency } from "@osmosis-labs/types"; +import { + CoinPretty, + Dec, + DecUtils, + Int, + IntPretty, + RatePretty, +} from "@osmosis-labs/unit"; import { action, computed, makeObservable, observable } from "mobx"; import { ObservableQueryPoolShare } from "../../queries"; diff --git a/packages/stores/src/ui-config/manage-liquidity/base.ts b/packages/stores/src/ui-config/manage-liquidity/base.ts index 0387c1190b..c34df6ff39 100644 --- a/packages/stores/src/ui-config/manage-liquidity/base.ts +++ b/packages/stores/src/ui-config/manage-liquidity/base.ts @@ -1,5 +1,5 @@ -import { CoinPretty } from "@keplr-wallet/unit"; import { ChainGetter, IQueriesStore } from "@osmosis-labs/keplr-stores"; +import { CoinPretty } from "@osmosis-labs/unit"; import { action, makeObservable, observable } from "mobx"; import { ObservableQueryPoolShare } from "../../queries"; diff --git a/packages/stores/src/ui-config/manage-liquidity/remove-concentrated-liquidity.ts b/packages/stores/src/ui-config/manage-liquidity/remove-concentrated-liquidity.ts index 3152398484..0e94480e07 100644 --- a/packages/stores/src/ui-config/manage-liquidity/remove-concentrated-liquidity.ts +++ b/packages/stores/src/ui-config/manage-liquidity/remove-concentrated-liquidity.ts @@ -1,6 +1,6 @@ -import { CoinPretty, Dec, DecUtils } from "@keplr-wallet/unit"; import { EmptyAmountError } from "@osmosis-labs/keplr-hooks"; import { ChainGetter } from "@osmosis-labs/keplr-stores"; +import { CoinPretty, Dec, DecUtils } from "@osmosis-labs/unit"; import { action, computed, makeObservable, observable } from "mobx"; type Position = { diff --git a/packages/stores/src/ui-config/price.ts b/packages/stores/src/ui-config/price.ts index f0f1765b8a..d946d0514b 100644 --- a/packages/stores/src/ui-config/price.ts +++ b/packages/stores/src/ui-config/price.ts @@ -1,5 +1,5 @@ import { AppCurrency } from "@keplr-wallet/types"; -import { Dec, DecUtils } from "@keplr-wallet/unit"; +import { Dec, DecUtils } from "@osmosis-labs/unit"; import { action, computed, makeObservable, observable } from "mobx"; import { computedFn } from "mobx-utils"; diff --git a/packages/stores/src/ui-config/slippage-config.ts b/packages/stores/src/ui-config/slippage-config.ts index 862c49e29a..0e5ba16910 100644 --- a/packages/stores/src/ui-config/slippage-config.ts +++ b/packages/stores/src/ui-config/slippage-config.ts @@ -1,4 +1,4 @@ -import { Dec, DecUtils, RatePretty } from "@keplr-wallet/unit"; +import { Dec, DecUtils, RatePretty } from "@osmosis-labs/unit"; import { action, computed, makeObservable, observable } from "mobx"; import { InvalidSlippageError, NegativeSlippageError } from "./errors"; diff --git a/packages/trpc/package.json b/packages/trpc/package.json index 45069ae914..a23ec569f2 100644 --- a/packages/trpc/package.json +++ b/packages/trpc/package.json @@ -30,12 +30,12 @@ }, "dependencies": { "@keplr-wallet/types": "0.10.24-ibc.go.v7.hot.fix", - "@keplr-wallet/unit": "0.10.24-ibc.go.v7.hot.fix", "@opentelemetry/api": "^1.9.0", "@osmosis-labs/math": "^5.1.0", "@osmosis-labs/pools": "^5.1.0", "@osmosis-labs/server": "^1.0.0", "@osmosis-labs/types": "^1.0.0", + "@osmosis-labs/unit": "0.10.24-ibc.go.v7.hot.fix", "@osmosis-labs/utils": "^1.0.0", "@trpc/client": "^10.45.1", "@trpc/server": "^10.45.1", diff --git a/packages/trpc/src/__tests_e2e__/swap-router.spec.ts b/packages/trpc/src/__tests_e2e__/swap-router.spec.ts index 275f72c263..13bb4acb44 100644 --- a/packages/trpc/src/__tests_e2e__/swap-router.spec.ts +++ b/packages/trpc/src/__tests_e2e__/swap-router.spec.ts @@ -4,9 +4,9 @@ * production data from the SQS Osmosis API to ensure * functionality and stability. */ -import { CoinPretty, Dec, DecUtils, Int, RatePretty } from "@keplr-wallet/unit"; import { getAssetPrice, getPools, superjson } from "@osmosis-labs/server"; import { Asset } from "@osmosis-labs/types"; +import { CoinPretty, Dec, DecUtils, Int, RatePretty } from "@osmosis-labs/unit"; import { getAssetFromAssetList, isNumeric, diff --git a/packages/trpc/src/assets.ts b/packages/trpc/src/assets.ts index 8df816c203..9be03650cd 100644 --- a/packages/trpc/src/assets.ts +++ b/packages/trpc/src/assets.ts @@ -1,4 +1,3 @@ -import { PricePretty } from "@keplr-wallet/unit"; import { AssetFilterSchema, AvailableRangeValues, @@ -29,6 +28,7 @@ import { TimeDuration, TimeFrame, } from "@osmosis-labs/server"; +import { PricePretty } from "@osmosis-labs/unit"; import { compareCommon, getAllBtcMinimalDenom, diff --git a/packages/trpc/src/balances.ts b/packages/trpc/src/balances.ts index ff8125a9e5..e231afdc75 100644 --- a/packages/trpc/src/balances.ts +++ b/packages/trpc/src/balances.ts @@ -1,4 +1,3 @@ -import { CoinPretty } from "@keplr-wallet/unit"; import { captureIfError, getAsset, @@ -6,6 +5,7 @@ import { makeGammShareCurrency, queryBalances, } from "@osmosis-labs/server"; +import { CoinPretty } from "@osmosis-labs/unit"; import z from "zod"; import { createTRPCRouter, publicProcedure } from "./api"; diff --git a/packages/trpc/src/one-click-trading.ts b/packages/trpc/src/one-click-trading.ts index b2282db361..53280cc455 100644 --- a/packages/trpc/src/one-click-trading.ts +++ b/packages/trpc/src/one-click-trading.ts @@ -1,4 +1,3 @@ -import { Dec, DecUtils, PricePretty } from "@keplr-wallet/unit"; import { DEFAULT_VS_CURRENCY, getAsset, @@ -7,6 +6,7 @@ import { queryAuthenticatorSpendLimit, } from "@osmosis-labs/server"; import { OneClickTradingTransactionParams } from "@osmosis-labs/types"; +import { Dec, DecUtils, PricePretty } from "@osmosis-labs/unit"; import { OneClickTradingMaxGasLimit } from "@osmosis-labs/utils"; import { TRPCError } from "@trpc/server"; import { z } from "zod"; diff --git a/packages/trpc/src/orderbook-router.ts b/packages/trpc/src/orderbook-router.ts index be7b0d5064..e675b106aa 100644 --- a/packages/trpc/src/orderbook-router.ts +++ b/packages/trpc/src/orderbook-router.ts @@ -1,4 +1,3 @@ -import { Dec, Int } from "@keplr-wallet/unit"; import { tickToPrice } from "@osmosis-labs/math"; import { CursorPaginationSchema, @@ -12,6 +11,7 @@ import { maybeCachePaginatedItems, OrderStatus, } from "@osmosis-labs/server"; +import { Dec, Int } from "@osmosis-labs/unit"; import { getAssetFromAssetList } from "@osmosis-labs/utils"; import { z } from "zod"; diff --git a/packages/tx/package.json b/packages/tx/package.json index 7244bb5c7f..a6a384bef0 100644 --- a/packages/tx/package.json +++ b/packages/tx/package.json @@ -27,10 +27,10 @@ "dependencies": { "@cosmjs/proto-signing": "0.32.3", "@cosmjs/stargate": "0.32.3", - "@keplr-wallet/unit": "0.10.24-ibc.go.v7.hot.fix", "@osmosis-labs/proto-codecs": "^5.1.0", "@osmosis-labs/server": "^1.0.0", "@osmosis-labs/types": "^1.0.0", + "@osmosis-labs/unit": "0.10.24-ibc.go.v7.hot.fix", "@osmosis-labs/utils": "^1.0.0", "buffer": "^6.0.3", "cachified": "^3.5.4", diff --git a/packages/tx/src/__tests__/gas.spec.ts b/packages/tx/src/__tests__/gas.spec.ts index 79159f8a87..1be5ddb869 100644 --- a/packages/tx/src/__tests__/gas.spec.ts +++ b/packages/tx/src/__tests__/gas.spec.ts @@ -1,4 +1,3 @@ -import { Dec } from "@keplr-wallet/unit"; import { BaseAccountTypeStr, queryBalances, @@ -9,6 +8,7 @@ import { queryFeeTokenSpotPrice, sendTxSimulate, } from "@osmosis-labs/server"; +import { Dec } from "@osmosis-labs/unit"; import { ApiClientError } from "@osmosis-labs/utils"; import type { Any } from "cosmjs-types/google/protobuf/any"; diff --git a/packages/tx/src/events.ts b/packages/tx/src/events.ts index 09d569e3aa..bc61bed57d 100644 --- a/packages/tx/src/events.ts +++ b/packages/tx/src/events.ts @@ -1,5 +1,5 @@ -import { Int } from "@keplr-wallet/unit"; import { TxEvent } from "@osmosis-labs/server"; +import { Int } from "@osmosis-labs/unit"; /** Reliably use the bank module's `coin_spent` event attribute to extract the combined * sum of coins spent in a transaction for a given spender. */ diff --git a/packages/tx/src/gas.ts b/packages/tx/src/gas.ts index 9dd4a118f2..9781923ac4 100644 --- a/packages/tx/src/gas.ts +++ b/packages/tx/src/gas.ts @@ -1,4 +1,3 @@ -import { Dec, Int } from "@keplr-wallet/unit"; import { BaseAccount, BaseAccountTypeStr, @@ -13,6 +12,7 @@ import { VestingAccount, } from "@osmosis-labs/server"; import type { Chain } from "@osmosis-labs/types"; +import { Dec, Int } from "@osmosis-labs/unit"; import { ApiClientError } from "@osmosis-labs/utils"; import { Buffer } from "buffer/"; import cachified, { CacheEntry } from "cachified"; diff --git a/packages/tx/src/message-composers/complex/swap.ts b/packages/tx/src/message-composers/complex/swap.ts index 78ad23ed13..e15b2669b3 100644 --- a/packages/tx/src/message-composers/complex/swap.ts +++ b/packages/tx/src/message-composers/complex/swap.ts @@ -1,8 +1,8 @@ -import { Dec, DecUtils } from "@keplr-wallet/unit"; import type { getRouteTokenInGivenOut, getRouteTokenOutGivenIn, } from "@osmosis-labs/server"; +import { Dec, DecUtils } from "@osmosis-labs/unit"; import { isNil } from "@osmosis-labs/utils"; import { diff --git a/packages/types/package.json b/packages/types/package.json index 68a4686f9b..af76728314 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@keplr-wallet/types": "0.10.24-ibc.go.v7.hot.fix", - "@keplr-wallet/unit": "0.10.24-ibc.go.v7.hot.fix", + "@osmosis-labs/unit": "0.10.24-ibc.go.v7.hot.fix", "dayjs": "^1.10.7" }, "lint-staged": { diff --git a/packages/types/src/one-click-trading-types.ts b/packages/types/src/one-click-trading-types.ts index 2485410aa7..53741f9e4d 100644 --- a/packages/types/src/one-click-trading-types.ts +++ b/packages/types/src/one-click-trading-types.ts @@ -1,4 +1,4 @@ -import type { PricePretty } from "@keplr-wallet/unit"; +import type { PricePretty } from "@osmosis-labs/unit"; export type AvailableOneClickTradingMessages = | "/osmosis.poolmanager.v1beta1.MsgSwapExactAmountIn" diff --git a/packages/unit/.eslintignore b/packages/unit/.eslintignore new file mode 100644 index 0000000000..2f348080dc --- /dev/null +++ b/packages/unit/.eslintignore @@ -0,0 +1,2 @@ +build/* +.DS_Store diff --git a/packages/unit/.eslintrc.js b/packages/unit/.eslintrc.js new file mode 100644 index 0000000000..8012c968f5 --- /dev/null +++ b/packages/unit/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require("../../.eslintrc.base.js"); diff --git a/packages/unit/.prettierignore b/packages/unit/.prettierignore new file mode 100644 index 0000000000..2f348080dc --- /dev/null +++ b/packages/unit/.prettierignore @@ -0,0 +1,2 @@ +build/* +.DS_Store diff --git a/packages/unit/LICENSE b/packages/unit/LICENSE new file mode 100644 index 0000000000..7e7f92da98 --- /dev/null +++ b/packages/unit/LICENSE @@ -0,0 +1,203 @@ +License: Apache2.0 + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2020 Chainapsis, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/packages/unit/jest.config.js b/packages/unit/jest.config.js new file mode 100644 index 0000000000..42eb6623c3 --- /dev/null +++ b/packages/unit/jest.config.js @@ -0,0 +1,5 @@ +module.exports = { + preset: "ts-jest", + testEnvironment: "node", + testMatch: ["**/src/**/?(*.)+(spec|test).[jt]s?(x)"], +}; diff --git a/packages/unit/package.json b/packages/unit/package.json new file mode 100644 index 0000000000..59ac597bd4 --- /dev/null +++ b/packages/unit/package.json @@ -0,0 +1,33 @@ +{ + "name": "@osmosis-labs/unit", + "version": "0.10.24-ibc.go.v7.hot.fix", + "main": "build/index.js", + "author": "chainapsis", + "repository": { + "type": "git", + "url": "https://github.com/osmosis-labs/osmosis-frontend" + }, + "bugs": { + "url": "https://github.com/osmosis-labs/osmosis-frontend/issues" + }, + "keywords": [ + "osmosis" + ], + "private": false, + "publishConfig": { + "access": "public" + }, + "scripts": { + "clean": "rm -rf node_modules; rm -rf build; rm -f tsconfig.tsbuildinfo", + "build": "tsc", + "dev": "tsc -w", + "test": "jest --passWithNoTests", + "lint-test": "eslint \"src/**/*\" && prettier --check \"src/**/*\"", + "lint-fix": "eslint --fix \"src/**/*\" && prettier --write \"src/**/*\"" + }, + "dependencies": { + "@keplr-wallet/types": "0.10.24-ibc.go.v7.hot.fix", + "big-integer": "^1.6.48", + "utility-types": "^3.10.0" + } +} diff --git a/packages/unit/src/coin-pretty.spec.ts b/packages/unit/src/coin-pretty.spec.ts new file mode 100644 index 0000000000..101c38d614 --- /dev/null +++ b/packages/unit/src/coin-pretty.spec.ts @@ -0,0 +1,518 @@ +import { CoinPretty } from "./coin-pretty"; +import { CoinUtils } from "./coin-utils"; +import { DecUtils } from "./dec-utils"; +import { Dec } from "./decimal"; +import { Int } from "./int"; + +describe("Test CoinPretty", () => { + it("Test creation of CoinPretty", () => { + expect( + new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Int(1234) + ) + .toDec() + .equals(new Dec("0.001234")) + ).toBe(true); + expect( + new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Int(1234) + ).toString() + ).toBe("0.001234 ATOM"); + + expect( + new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + 1234 + ) + .toDec() + .equals(new Dec("0.001234")) + ).toBe(true); + expect( + new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + 1234 + ).toString() + ).toBe("0.001234 ATOM"); + + expect( + new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + "1234.5" + ) + .toDec() + .equals(new Dec("0.0012345")) + ).toBe(true); + expect( + new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + "1234.5" + ).toString() + ).toBe("0.001234 ATOM"); + + expect( + new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Dec("1234.5") + ) + .toDec() + .equals(new Dec("0.0012345")) + ).toBe(true); + expect( + new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Dec("1234.5") + ).toString() + ).toBe("0.001234 ATOM"); + }); + + it("Basic test for CoinPretty", () => { + const pretty = new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Int(1234) + ); + expect(pretty.toDec().equals(new Dec("0.001234"))).toBeTruthy(); + + expect(pretty.toString()).toBe("0.001234 ATOM"); + expect(pretty.separator("").toString()).toBe("0.001234ATOM"); + expect(pretty.increasePrecision(1).toString()).toBe("0.000123 ATOM"); + expect(pretty.decreasePrecision(1).toString()).toBe("0.012340 ATOM"); + expect(pretty.decreasePrecision(1).trim(true).toString()).toBe( + "0.01234 ATOM" + ); + expect(pretty.moveDecimalPointLeft(1).toString()).toBe("0.000123 ATOM"); + expect(pretty.moveDecimalPointRight(1).toString()).toBe("0.012340 ATOM"); + expect(pretty.moveDecimalPointRight(1).trim(true).toString()).toBe( + "0.01234 ATOM" + ); + + expect(pretty.maxDecimals(7).add(new Dec("0.1")).toString()).toBe( + "0.0012341 ATOM" + ); + expect(pretty.maxDecimals(7).sub(new Dec("0.1")).toString()).toBe( + "0.0012339 ATOM" + ); + expect(pretty.maxDecimals(7).mul(new Dec("0.1")).toString()).toBe( + "0.0001234 ATOM" + ); + expect(pretty.maxDecimals(7).quo(new Dec("0.1")).toString()).toBe( + "0.0123400 ATOM" + ); + + expect( + pretty + .add( + new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Int(1200000) + ) + ) + .toString() + ).toBe("1.201234 ATOM"); + expect( + pretty + .sub( + new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Int(1200000) + ) + ) + .toString() + ).toBe("-1.198766 ATOM"); + + // If target is `CoinPretty` and it has different denom, do nothing. + expect( + pretty + .add( + new CoinPretty( + { + coinDenom: "SCRT", + coinMinimalDenom: "uscrt", + coinDecimals: 6, + }, + new Int(1200000) + ) + ) + .toString() + ).toBe("0.001234 ATOM"); + // If target is `CoinPretty` and it has different denom, do nothing. + expect( + pretty + .sub( + new CoinPretty( + { + coinDenom: "SCRT", + coinMinimalDenom: "uscrt", + coinDecimals: 6, + }, + new Int(1200000) + ) + ) + .toString() + ).toBe("0.001234 ATOM"); + }); + + it("Basic test for CoinPretty 2", () => { + const pretty = new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Dec("12.1234") + ); + + expect(pretty.toString()).toBe("0.000012 ATOM"); + expect(pretty.maxDecimals(10).toString()).toBe("0.0000121234 ATOM"); + expect(pretty.increasePrecision(1).toString()).toBe("0.000001 ATOM"); + expect(pretty.decreasePrecision(1).toString()).toBe("0.000121 ATOM"); + expect(pretty.moveDecimalPointLeft(1).toString()).toBe("0.000001 ATOM"); + expect(pretty.moveDecimalPointRight(1).toString()).toBe("0.000121 ATOM"); + + expect(pretty.maxDecimals(7).add(new Dec("0.1")).toString()).toBe( + "0.0000122 ATOM" + ); + expect(pretty.maxDecimals(7).sub(new Dec("0.1")).toString()).toBe( + "0.0000120 ATOM" + ); + expect(pretty.maxDecimals(7).mul(new Dec("0.1")).toString()).toBe( + "0.0000012 ATOM" + ); + expect(pretty.maxDecimals(7).quo(new Dec("0.1")).toString()).toBe( + "0.0001212 ATOM" + ); + + expect( + pretty + .add( + new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Int(1200000) + ) + ) + .toString() + ).toBe("1.200012 ATOM"); + expect( + pretty + .sub( + new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Int(1200000) + ) + ) + .toString() + ).toBe("-1.199987 ATOM"); + }); + + it("Test toCoin() for CoinPretty", () => { + expect( + new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Dec("0.1234") + ).toCoin() + ).toStrictEqual({ + denom: "uatom", + amount: "0", + }); + + expect( + new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Dec("12.1234") + ).toCoin() + ).toStrictEqual({ + denom: "uatom", + amount: "12", + }); + + expect( + new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Dec("123456.1234") + ).toCoin() + ).toStrictEqual({ + denom: "uatom", + amount: "123456", + }); + + expect( + new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Int("12345600") + ).toCoin() + ).toStrictEqual({ + denom: "uatom", + amount: "12345600", + }); + }); + + it("Test CoinPretty's setCurrency", () => { + const pretty = new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Int("123456") + ); + + expect( + pretty + .setCurrency({ + coinDenom: "TEST", + coinMinimalDenom: "utest", + coinDecimals: 6, + }) + .toString() + ).toBe("0.123456 TEST"); + + expect( + pretty + .setCurrency({ + coinDenom: "TEST", + coinMinimalDenom: "utest", + coinDecimals: 3, + }) + .toString() + ).toBe("123.456000 TEST"); + + expect( + pretty + .setCurrency({ + coinDenom: "TEST", + coinMinimalDenom: "utest", + coinDecimals: 3, + }) + .moveDecimalPointLeft(2) + .moveDecimalPointRight(1) + .trim(true) + .toString() + ).toBe("12.3456 TEST"); + }); + + it("Test CoinPretty's toString()", () => { + const tests: { + base: CoinPretty; + pre: (pretty: CoinPretty) => CoinPretty; + res: string; + }[] = [ + { + base: new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Int("12345600") + ), + pre: (pretty) => pretty, + res: "12.345600 ATOM", + }, + { + base: new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Int("12345600") + ), + pre: (pretty) => pretty.hideDenom(true), + res: "12.345600", + }, + { + base: new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Int("12345600") + ), + pre: (pretty) => pretty.separator(""), + res: "12.345600ATOM", + }, + { + base: new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Int("12345600") + ), + pre: (pretty) => pretty.maxDecimals(3), + res: "12.345 ATOM", + }, + { + base: new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Int("12345600") + ), + pre: (pretty) => pretty.maxDecimals(3).separator(""), + res: "12.345ATOM", + }, + { + base: new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Int("12345600") + ), + pre: (pretty) => pretty.lowerCase(true), + res: "12.345600 atom", + }, + { + base: new CoinPretty( + { + coinDenom: "AtoM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Int("12345600") + ), + pre: (pretty) => pretty.upperCase(true), + res: "12.345600 ATOM", + }, + { + base: new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Int("1234560000") + ), + pre: (pretty) => pretty, + res: "1,234.560000 ATOM", + }, + { + base: new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Int("1234560000") + ), + pre: (pretty) => pretty.locale(false), + res: "1234.560000 ATOM", + }, + { + base: new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Int("1234560000") + ), + pre: (pretty) => pretty.shrink(true), + res: + CoinUtils.shrinkDecimals( + new Dec("1234560000").mul(DecUtils.getTenExponentN(-6)), + 0, + 6, + true + ) + " ATOM", + }, + { + base: new CoinPretty( + { + coinDenom: "ATOM", + coinMinimalDenom: "uatom", + coinDecimals: 6, + }, + new Int("1234560000") + ), + pre: (pretty) => pretty.locale(false).shrink(true), + res: + CoinUtils.shrinkDecimals( + new Dec("1234560000").mul(DecUtils.getTenExponentN(-6)), + 0, + 6, + false + ) + " ATOM", + }, + ]; + + for (const test of tests) { + expect(test.pre(test.base).toString()).toBe(test.res); + } + }); +}); diff --git a/packages/unit/src/coin-pretty.ts b/packages/unit/src/coin-pretty.ts new file mode 100644 index 0000000000..a688389600 --- /dev/null +++ b/packages/unit/src/coin-pretty.ts @@ -0,0 +1,289 @@ +import { AppCurrency } from "@keplr-wallet/types"; +import bigInteger from "big-integer"; +import { DeepReadonly } from "utility-types"; + +import { DecUtils } from "./dec-utils"; +import { Dec } from "./decimal"; +import { IntPretty, IntPrettyOptions } from "./int-pretty"; + +export type CoinPrettyOptions = { + separator: string; + upperCase: boolean; + lowerCase: boolean; + hideDenom: boolean; +}; + +export class CoinPretty { + protected intPretty: IntPretty; + + protected _options: CoinPrettyOptions = { + separator: " ", + upperCase: false, + lowerCase: false, + hideDenom: false, + }; + + constructor( + protected _currency: AppCurrency, + protected amount: Dec | { toDec(): Dec } | bigInteger.BigNumber + ) { + if (typeof this.amount === "object" && "toDec" in this.amount) { + this.amount = this.amount.toDec(); + } else if (!(this.amount instanceof Dec)) { + this.amount = new Dec(this.amount); + } + + this.intPretty = new IntPretty( + this.amount.quoTruncate( + DecUtils.getTenExponentNInPrecisionRange(_currency.coinDecimals) + ) + ).maxDecimals(_currency.coinDecimals); + } + + get options(): DeepReadonly { + return { + ...this._options, + ...this.intPretty.options, + }; + } + + get denom(): string { + return this.currency.coinDenom; + } + + get currency(): AppCurrency { + return this._currency; + } + + setCurrency(currency: AppCurrency): CoinPretty { + const pretty = this.clone(); + pretty.intPretty = this.intPretty.moveDecimalPointRight( + this._currency.coinDecimals - currency.coinDecimals + ); + pretty._currency = currency; + return pretty; + } + + separator(str: string): CoinPretty { + const pretty = this.clone(); + pretty._options.separator = str; + return pretty; + } + + upperCase(bool: boolean): CoinPretty { + const pretty = this.clone(); + pretty._options.upperCase = bool; + pretty._options.lowerCase = !bool; + return pretty; + } + + lowerCase(bool: boolean): CoinPretty { + const pretty = this.clone(); + pretty._options.lowerCase = bool; + pretty._options.upperCase = !bool; + return pretty; + } + + hideDenom(bool: boolean): CoinPretty { + const pretty = this.clone(); + pretty._options.hideDenom = bool; + return pretty; + } + + moveDecimalPointLeft(delta: number): CoinPretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.moveDecimalPointLeft(delta); + return pretty; + } + + moveDecimalPointRight(delta: number): CoinPretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.moveDecimalPointRight(delta); + return pretty; + } + + /** + * @deprecated Use`moveDecimalPointLeft` + */ + increasePrecision(delta: number): CoinPretty { + return this.moveDecimalPointLeft(delta); + } + + /** + * @deprecated Use`moveDecimalPointRight` + */ + decreasePrecision(delta: number): CoinPretty { + return this.moveDecimalPointRight(delta); + } + + maxDecimals(max: number): CoinPretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.maxDecimals(max); + return pretty; + } + + inequalitySymbol(bool: boolean): CoinPretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.inequalitySymbol(bool); + return pretty; + } + + inequalitySymbolSeparator(str: string): CoinPretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.inequalitySymbolSeparator(str); + return pretty; + } + + trim(bool: boolean): CoinPretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.trim(bool); + return pretty; + } + + shrink(bool: boolean): CoinPretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.shrink(bool); + return pretty; + } + + locale(locale: boolean): CoinPretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.locale(locale); + return pretty; + } + + /** + * Ready indicates the actual value is ready to show the users. + * Even if the ready option is false, it expects that the value can be shown to users (probably as 0). + * The method that returns prettied value may return `undefined` or `null` if the value is not ready. + * But, alternatively, it can return the 0 value that can be shown the users anyway, but indicates that the value is not ready. + * @param bool + */ + ready(bool: boolean): CoinPretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.ready(bool); + return pretty; + } + + get isReady(): boolean { + return this.intPretty.isReady; + } + + add(target: Dec | { toDec(): Dec } | CoinPretty): CoinPretty { + const isCoinPretty = target instanceof CoinPretty; + if (isCoinPretty) { + // If target is `CoinPretty` and it has different denom, do nothing. + if ( + "currency" in target && + this.currency.coinMinimalDenom !== target.currency.coinMinimalDenom + ) { + return this.clone(); + } + } + + if ("toDec" in target) { + target = target.toDec(); + } + + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.add( + isCoinPretty + ? target + : target.mul( + DecUtils.getTenExponentNInPrecisionRange( + -this._currency.coinDecimals + ) + ) + ); + return pretty; + } + + sub(target: Dec | { toDec(): Dec } | CoinPretty): CoinPretty { + const isCoinPretty = target instanceof CoinPretty; + if (isCoinPretty) { + // If target is `CoinPretty` and it has different denom, do nothing. + if ( + "currency" in target && + this.currency.coinMinimalDenom !== target.currency.coinMinimalDenom + ) { + return this.clone(); + } + } + + if ("toDec" in target) { + target = target.toDec(); + } + + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.sub( + isCoinPretty + ? target + : target.mul( + DecUtils.getTenExponentNInPrecisionRange( + -this._currency.coinDecimals + ) + ) + ); + return pretty; + } + + mul(target: Dec | { toDec(): Dec }): CoinPretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.mul(target); + return pretty; + } + + quo(target: Dec | { toDec(): Dec }): CoinPretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.quo(target); + return pretty; + } + + toDec(): Dec { + return this.intPretty.toDec(); + } + + toCoin(): { + denom: string; + amount: string; + } { + const amount = this.toDec() + .mulTruncate( + DecUtils.getTenExponentNInPrecisionRange(this.currency.coinDecimals) + ) + .truncate(); + + return { + denom: this.currency.coinMinimalDenom, + amount: amount.toString(), + }; + } + + toString(): string { + let denom = this.denom; + if (this._options.upperCase) { + denom = denom.toUpperCase(); + } + if (this._options.lowerCase) { + denom = denom.toLowerCase(); + } + + let separator = this._options.separator; + + if (this._options.hideDenom) { + denom = ""; + separator = ""; + } + + return this.intPretty.toStringWithSymbols("", `${separator}${denom}`); + } + + clone(): CoinPretty { + const pretty = new CoinPretty(this._currency, this.amount); + pretty._options = { + ...this._options, + }; + pretty.intPretty = this.intPretty.clone(); + return pretty; + } +} diff --git a/packages/unit/src/coin-utils.spec.ts b/packages/unit/src/coin-utils.spec.ts new file mode 100644 index 0000000000..7afa3dc284 --- /dev/null +++ b/packages/unit/src/coin-utils.spec.ts @@ -0,0 +1,47 @@ +import { CoinUtils } from "./coin-utils"; +import { Dec } from "./decimal"; + +describe("Test CoinUtils", () => { + it("Test integerStringToUSLocaleString", () => { + expect(CoinUtils.integerStringToUSLocaleString("123456789")).toBe( + "123,456,789" + ); + + expect(CoinUtils.integerStringToUSLocaleString("0")).toBe("0"); + + expect(CoinUtils.integerStringToUSLocaleString("123")).toBe("123"); + expect(CoinUtils.integerStringToUSLocaleString("12")).toBe("12"); + expect(CoinUtils.integerStringToUSLocaleString("1234")).toBe("1,234"); + + expect(CoinUtils.integerStringToUSLocaleString("-1234")).toBe("-1,234"); + expect(CoinUtils.integerStringToUSLocaleString("-123456789")).toBe( + "-123,456,789" + ); + }); + + it("Test shrink", () => { + expect(CoinUtils.shrinkDecimals(new Dec(1234.56789), 3, 6)).toBe( + "1234.567" + ); + expect(CoinUtils.shrinkDecimals(new Dec(1234.56789), 3, 6, true)).toBe( + "1,234.567" + ); + expect(CoinUtils.shrinkDecimals(new Dec(1234), 3, 6)).toBe("1234.000"); + + expect(CoinUtils.shrinkDecimals(new Dec(-1234.56789), 3, 6)).toBe( + "-1234.567" + ); + expect(CoinUtils.shrinkDecimals(new Dec(-1234.56789), 3, 6, true)).toBe( + "-1,234.567" + ); + + expect(CoinUtils.shrinkDecimals(new Dec(1234.56789), 0, 0)).toBe("1234"); + expect(CoinUtils.shrinkDecimals(new Dec(-1234.56789), 0, 0)).toBe("-1234"); + expect(CoinUtils.shrinkDecimals(new Dec(1234.56789), 1, 1)).toBe("1234.5"); + expect(CoinUtils.shrinkDecimals(new Dec(-1234.56789), 1, 1)).toBe( + "-1234.5" + ); + expect(CoinUtils.shrinkDecimals(new Dec(1234), 1, 1)).toBe("1234.0"); + expect(CoinUtils.shrinkDecimals(new Dec(-1234), 1, 1)).toBe("-1234.0"); + }); +}); diff --git a/packages/unit/src/coin-utils.ts b/packages/unit/src/coin-utils.ts new file mode 100644 index 0000000000..ec15db534f --- /dev/null +++ b/packages/unit/src/coin-utils.ts @@ -0,0 +1,188 @@ +import { Currency } from "@keplr-wallet/types"; + +import { Coin } from "./coin"; +import { DecUtils } from "./dec-utils"; +import { Dec } from "./decimal"; +import { Int } from "./int"; + +export class CoinUtils { + static createCoinsFromPrimitives( + coinPrimitives: { + denom: string; + amount: string; + }[] + ): Coin[] { + return coinPrimitives.map((primitive) => { + return new Coin(primitive.denom, primitive.amount); + }); + } + + static amountOf(coins: Coin[], denom: string): Int { + const coin = coins.find((coin) => { + return coin.denom === denom; + }); + + if (!coin) { + return new Int(0); + } else { + return coin.amount; + } + } + + static exclude(coins: Coin[], demons: string[]): Coin[] { + return coins.filter((coin) => { + return demons.indexOf(coin.denom) === 0; + }); + } + + static concat(...coins: Coin[]): Coin[] { + if (coins.length === 0) { + return []; + } + + const arr = coins.slice(); + const reducer = (accumulator: Coin[], coin: Coin) => { + // Find the duplicated denom. + const find = accumulator.find((c) => c.denom === coin.denom); + // If duplicated coin exists, add the amount to duplicated one. + if (find) { + const newCoin = new Coin(find.denom, find.amount.add(coin.amount)); + accumulator.push(newCoin); + } else { + const newCoin = new Coin(coin.denom, coin.amount); + accumulator.push(newCoin); + } + + return accumulator; + }; + + return arr.reduce(reducer, []); + } + + static getCoinFromDecimals( + currencies: Currency[], + decAmountStr: string, + denom: string + ): Coin { + const currency = currencies.find((currency) => { + return currency.coinDenom === denom; + }); + if (!currency) { + throw new Error("Invalid currency"); + } + + let precision = new Dec(1); + for (let i = 0; i < currency.coinDecimals; i++) { + precision = precision.mul(new Dec(10)); + } + + let decAmount = new Dec(decAmountStr); + decAmount = decAmount.mul(precision); + + if (!new Dec(decAmount.truncate()).equals(decAmount)) { + throw new Error("Can't divide anymore"); + } + + return new Coin(currency.coinMinimalDenom, decAmount.truncate()); + } + + static parseDecAndDenomFromCoin( + currencies: Currency[], + coin: Coin + ): { amount: string; denom: string } { + let currency = currencies.find((currency) => { + return currency.coinMinimalDenom === coin.denom; + }); + if (!currency) { + // If the currency is unknown, just use the raw currency. + currency = { + coinDecimals: 0, + coinDenom: coin.denom, + coinMinimalDenom: coin.denom, + }; + } + + let precision = new Dec(1); + for (let i = 0; i < currency.coinDecimals; i++) { + precision = precision.mul(new Dec(10)); + } + + const decAmount = new Dec(coin.amount).quoTruncate(precision); + return { + amount: decAmount.toString(currency.coinDecimals), + denom: currency.coinDenom, + }; + } + + static shrinkDecimals( + dec: Dec, + minDecimals: number, + maxDecimals: number, + locale: boolean = false + ): string { + if (dec.equals(new Dec(0))) { + return "0"; + } + + const isNeg = dec.isNegative(); + + const integer = dec.abs().truncate(); + const fraction = dec.abs().sub(new Dec(integer)); + + const decimals = Math.max( + maxDecimals - integer.toString().length + 1, + minDecimals + ); + + const fractionStr = + decimals === 0 ? "" : fraction.toString(decimals).replace("0.", ""); + + const integerStr = locale + ? CoinUtils.integerStringToUSLocaleString(integer.toString()) + : integer.toString(); + + return ( + (isNeg ? "-" : "") + + integerStr + + (fractionStr.length > 0 ? "." : "") + + fractionStr + ); + } + + /** + * Change the non-locale integer string to locale string. + * Only support en-US format. + * This method uses the BigInt if the environment supports the BigInt. + * @param numberStr + */ + static integerStringToUSLocaleString(numberStr: string): string { + if (numberStr.indexOf(".") >= 0) { + throw new Error(`${numberStr} is not integer`); + } + + if (typeof BigInt !== "undefined") { + return BigInt(numberStr).toLocaleString("en-US"); + } + + const integer = numberStr; + + const chunks: string[] = []; + for (let i = integer.length; i > 0; i -= 3) { + chunks.push(integer.slice(Math.max(0, i - 3), i)); + } + + return chunks.reverse().join(","); + } + + static coinToTrimmedString( + coin: Coin, + currency: Currency, + separator: string = " " + ): string { + const dec = new Dec(coin.amount).quoTruncate( + DecUtils.getPrecisionDec(currency.coinDecimals) + ); + + return `${DecUtils.trim(dec)}${separator}${currency.coinDenom}`; + } +} diff --git a/packages/unit/src/coin.spec.ts b/packages/unit/src/coin.spec.ts new file mode 100644 index 0000000000..92957df6b2 --- /dev/null +++ b/packages/unit/src/coin.spec.ts @@ -0,0 +1,40 @@ +import { Coin } from "./coin"; + +describe("Test coin", () => { + it("coin parsed from str properly", () => { + let coin = Coin.parse("1000test"); + + expect(coin.denom).toBe("test"); + expect(coin.amount.toString()).toBe("1000"); + expect(coin.toString()).toBe("1000test"); + + coin = Coin.parse("1000tesT"); + + expect(coin.denom).toBe("tesT"); + expect(coin.amount.toString()).toBe("1000"); + expect(coin.toString()).toBe("1000tesT"); + + coin = Coin.parse("1000TEST"); + + expect(coin.denom).toBe("TEST"); + expect(coin.amount.toString()).toBe("1000"); + expect(coin.toString()).toBe("1000TEST"); + + coin = Coin.parse("1000 TEST"); + + expect(coin.denom).toBe("TEST"); + expect(coin.amount.toString()).toBe("1000"); + expect(coin.toString()).toBe("1000TEST"); + + coin = Coin.parse("1000 TEST"); + + expect(coin.denom).toBe("TEST"); + expect(coin.amount.toString()).toBe("1000"); + expect(coin.toString()).toBe("1000TEST"); + + expect(() => Coin.parse("ascasc")).toThrow(); + expect(() => Coin.parse("ascasc asd")).toThrow(); + expect(() => Coin.parse("100 ascasc asd")).toThrow(); + expect(() => Coin.parse("asd 100")).toThrow(); + }); +}); diff --git a/packages/unit/src/coin.ts b/packages/unit/src/coin.ts new file mode 100644 index 0000000000..d4565f379b --- /dev/null +++ b/packages/unit/src/coin.ts @@ -0,0 +1,29 @@ +import bigInteger from "big-integer"; + +import { Int } from "./int"; + +export class Coin { + public static parse(str: string): Coin { + const re = new RegExp("([0-9]+)[ ]*([a-zA-Z]+)$"); + const execed = re.exec(str); + if (!execed || execed.length !== 3) { + throw new Error("Invalid coin str"); + } + const denom = execed[2]; + const amount = execed[1]; + return new Coin(denom, amount); + } + + public denom: string; + + public amount: Int; + + constructor(denom: string, amount: Int | bigInteger.BigNumber) { + this.denom = denom; + this.amount = amount instanceof Int ? amount : new Int(amount); + } + + public toString(): string { + return `${this.amount.toString()}${this.denom}`; + } +} diff --git a/packages/unit/src/dec-utils.spec.ts b/packages/unit/src/dec-utils.spec.ts new file mode 100644 index 0000000000..df1c97b37d --- /dev/null +++ b/packages/unit/src/dec-utils.spec.ts @@ -0,0 +1,76 @@ +import { DecUtils } from "./dec-utils"; +import { Dec } from "./decimal"; + +describe("Test DecUtils", () => { + it("Test trim in DecUtils", () => { + expect(DecUtils.trim("0.00100")).toBe("0.001"); + expect(DecUtils.trim("0.00")).toBe("0"); + expect(DecUtils.trim("-0.00100")).toBe("-0.001"); + expect(DecUtils.trim("-0.00")).toBe("-0"); + }); + + it("getPrecisionDec should return the (10^precision)", () => { + expect(DecUtils.getPrecisionDec(-1).toString()).toBe( + new Dec("0.1").toString() + ); + expect(DecUtils.getPrecisionDec(-5).toString()).toBe( + new Dec("0.00001").toString() + ); + + expect(DecUtils.getPrecisionDec(0).toString()).toBe(new Dec(1).toString()); + expect(DecUtils.getPrecisionDec(1).toString()).toBe(new Dec(10).toString()); + expect(DecUtils.getPrecisionDec(5).toString()).toBe( + new Dec(100000).toString() + ); + }); + + it("getPrecisionDec can have maximum 18 precision", () => { + expect(() => { + DecUtils.getPrecisionDec(18); + }).not.toThrow(); + + expect(() => { + DecUtils.getPrecisionDec(19); + }).toThrow(); + + expect(() => { + DecUtils.getPrecisionDec(-18); + }).not.toThrow(); + + expect(() => { + DecUtils.getPrecisionDec(-19); + }).toThrow(); + }); + + it("getTenExponentN should return same cached result", () => { + for (let i = 0; i < 3; i++) { + expect(DecUtils.getTenExponentN(5).toString()).toBe( + new Dec(100000).toString() + ); + } + }); + + it("Test getTenExponentN", () => { + expect(DecUtils.getTenExponentN(0).toString()).toBe( + new Dec("1").toString() + ); + + expect(DecUtils.getTenExponentN(1).toString()).toBe( + new Dec("10").toString() + ); + + expect(DecUtils.getTenExponentN(10).toString()).toBe( + new Dec("10000000000").toString() + ); + + expect(DecUtils.getTenExponentN(20).toString()).toBe( + new Dec("100000000000000000000").toString() + ); + + expect(DecUtils.getTenExponentN(-18).toString()).toBe( + new Dec("0.000000000000000001").toString() + ); + + expect(() => DecUtils.getTenExponentN(-19)).toThrow(); + }); +}); diff --git a/packages/unit/src/dec-utils.ts b/packages/unit/src/dec-utils.ts new file mode 100644 index 0000000000..60dbbbeac0 --- /dev/null +++ b/packages/unit/src/dec-utils.ts @@ -0,0 +1,62 @@ +import { Dec } from "./decimal"; +import { Int } from "./int"; + +export class DecUtils { + public static trim(dec: Dec | string): string { + let decStr = typeof dec === "string" ? dec : dec.toString(); + + if (decStr.indexOf(".") < 0) { + return decStr; + } + + for (let i = decStr.length - 1; i >= 0; i--) { + if (decStr[i] === "0") { + decStr = decStr.slice(0, i); + } else { + break; + } + } + + if (decStr.length > 0) { + if (decStr[decStr.length - 1] === ".") { + decStr = decStr.slice(0, decStr.length - 1); + } + } + + return decStr; + } + + protected static tenExponentNs: { [n: string]: Dec } = {}; + + public static getTenExponentN(n: number): Dec { + if (n < -Dec.precision) { + // Dec can only handle up to precision 18. + // Anything less than 18 precision is 0, so there is a high probability of an error. + throw new Error("Too little precision"); + } + + if (DecUtils.tenExponentNs[n.toString()]) { + return DecUtils.tenExponentNs[n.toString()]; + } + + const dec = new Dec(10).pow(new Int(n)); + DecUtils.tenExponentNs[n.toString()] = dec; + + return dec; + } + + public static getTenExponentNInPrecisionRange(n: number): Dec { + if (n > Dec.precision) { + throw new Error("Too much precision"); + } + + return DecUtils.getTenExponentN(n); + } + + /** + * @deprecated Use`getTenExponentNInPrecisionRange` + */ + public static getPrecisionDec(precision: number): Dec { + return DecUtils.getTenExponentNInPrecisionRange(precision); + } +} diff --git a/packages/unit/src/decimal.spec.ts b/packages/unit/src/decimal.spec.ts new file mode 100644 index 0000000000..37192d2b8a --- /dev/null +++ b/packages/unit/src/decimal.spec.ts @@ -0,0 +1,690 @@ +/* eslint-disable @typescript-eslint/no-loss-of-precision */ +import { Dec } from "./decimal"; +import { Int } from "./int"; + +describe("Test decimals", () => { + // (2 ** (256 + 60) - 1) / (10 ** 18) + const maxDec = + "133499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535"; + // maxDec + 0.000000000000000001 + const overflowedDec = + "133499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433536"; + + it("dec should be parsed properly", () => { + expect(() => new Dec(1, 0)).not.toThrow(); + expect(() => new Dec(1, -1)).toThrow(); + expect(() => new Dec(1, Dec.precision)).not.toThrow(); + expect(() => new Dec(1, Dec.precision + 1)).toThrow(); + + let dec = new Dec("10.009"); + expect(dec.toString()).toBe("10.009000000000000000"); + expect(dec.toString(2)).toBe("10.00"); + + dec = new Dec("-123.45678900"); + expect(dec.toString()).toBe("-123.456789000000000000"); + expect(dec.toString(3)).toBe("-123.456"); + + dec = new Dec("10"); + expect(dec.toString()).toBe("10.000000000000000000"); + + dec = new Dec(10); + expect(dec.toString()).toBe("10.000000000000000000"); + + dec = new Dec(10.009); + expect(dec.toString()).toBe("10.009000000000000000"); + expect(dec.toString(2)).toBe("10.00"); + + dec = new Dec(-123.456789); + expect(dec.toString()).toBe("-123.456789000000000000"); + expect(dec.toString(3)).toBe("-123.456"); + + expect(() => { + new Dec(""); + }).toThrow(); + expect(() => { + new Dec("0.-75"); + }).toThrow(); + expect(() => { + new Dec("0.489234893284938249348923849283408"); + }).not.toThrow(); + expect(() => { + new Dec("foobar"); + }).toThrow(); + expect(() => { + new Dec("0.foobar"); + }).toThrow(); + expect(() => { + new Dec("foobar.0"); + }).toThrow(); + }); + + it("Test Dec overflow", () => { + expect(new Dec(maxDec).toString()).toBe(maxDec); + expect(new Dec("-" + maxDec).toString()).toBe("-" + maxDec); + + expect(() => new Dec(overflowedDec)).toThrow(); + expect(() => new Dec("-" + overflowedDec)).toThrow(); + + const max = new Dec(maxDec); + expect(() => max.add(new Dec(1, Dec.precision))).toThrow(); + + const min = new Dec("-" + maxDec); + expect(() => min.sub(new Dec(1, Dec.precision))).toThrow(); + }); + + it("Test Dec neg/abs", () => { + expect(new Dec(1).neg().toString()).toBe("-1.000000000000000000"); + expect(new Dec(1).neg().equals(new Dec(-1))).toBe(true); + + expect(new Dec(-1).neg().toString()).toBe("1.000000000000000000"); + expect(new Dec(-1).neg().equals(new Dec(1))).toBe(true); + + expect(new Dec(1).abs().toString()).toBe("1.000000000000000000"); + expect(new Dec(1).abs().equals(new Dec(1))).toBe(true); + + expect(new Dec(-1).abs().toString()).toBe("1.000000000000000000"); + expect(new Dec(-1).abs().equals(new Dec(1))).toBe(true); + }); + + it("Test Dec isPositive/isNegative/isInteger/isZero", () => { + expect(new Dec(1).isPositive()).toBe(true); + expect(new Dec(-1).isPositive()).toBe(false); + + expect(new Dec(1).isNegative()).toBe(false); + expect(new Dec(-1).isNegative()).toBe(true); + + expect(new Dec(1).isInteger()).toBe(true); + expect(new Dec(-1).isInteger()).toBe(true); + + expect(new Dec(1.1).isInteger()).toBe(false); + expect(new Dec(-1.1).isInteger()).toBe(false); + + expect(new Dec(0).isZero()).toBe(true); + expect(new Dec(-0).isZero()).toBe(true); + expect(new Dec(-1.1).isZero()).toBe(false); + expect(new Dec(1.1).isZero()).toBe(false); + }); + + it("Test Dec comparison", () => { + const dec1 = new Dec(1); + const dec2 = new Dec(2); + + expect(dec1.gt(dec2)).toBe(false); + expect(dec1.gte(dec1)).toBe(true); + + expect(dec1.lt(dec2)).toBe(true); + expect(dec1.lte(dec1)).toBe(true); + + expect(dec1.equals(dec2)).toBe(false); + expect(dec1.equals(dec1)).toBe(true); + }); + + it("Test Dec power", () => { + const tests: { + d1: Dec; + i1: Int; + exp: Dec; + }[] = [ + { + d1: new Dec(0), + i1: new Int(12), + exp: new Dec(0), + }, + { + d1: new Dec(0), + i1: new Int(0), + exp: new Dec(1), + }, + { + d1: new Dec(12), + i1: new Int(0), + exp: new Dec(1), + }, + { + d1: new Dec(-12), + i1: new Int(0), + exp: new Dec(1), + }, + { + d1: new Dec(-12), + i1: new Int(1), + exp: new Dec(-12), + }, + { + d1: new Dec(-12), + i1: new Int(2), + exp: new Dec(144), + }, + { + d1: new Dec(12), + i1: new Int(3), + exp: new Dec(1728), + }, + { + d1: new Dec(12), + i1: new Int(-1), + exp: new Dec("0.083333333333333333"), + }, + { + d1: new Dec(12), + i1: new Int(-2), + exp: new Dec("0.006944444444444444"), + }, + { + d1: new Dec(12), + i1: new Int(-3), + exp: new Dec("0.000578703703703704"), + }, + { + d1: new Dec(10), + i1: new Int(4), + exp: new Dec("10000"), + }, + { + d1: new Dec(10), + i1: new Int(5), + exp: new Dec("100000"), + }, + { + d1: new Dec(10), + i1: new Int(-5), + exp: new Dec("0.00001"), + }, + ]; + + for (const test of tests) { + const res = test.d1.pow(test.i1); + + expect(res.toString()).toBe(test.exp.toString()); + } + }); + + it("dec should be caculated properly", () => { + const tests: { + d1: Dec; + d2: Dec; + expMul: Dec; + expMulTruncate: Dec; + expQuo: Dec; + expQuoRoundUp: Dec; + expQuoTruncate: Dec; + expAdd: Dec; + expSub: Dec; + }[] = [ + { + d1: new Dec(0), + d2: new Dec(0), + expMul: new Dec(0), + expMulTruncate: new Dec(0), + expQuo: new Dec(0), + expQuoRoundUp: new Dec(0), + expQuoTruncate: new Dec(0), + expAdd: new Dec(0), + expSub: new Dec(0), + }, + { + d1: new Dec(0), + d2: new Dec(1), + expMul: new Dec(0), + expMulTruncate: new Dec(0), + expQuo: new Dec(0), + expQuoRoundUp: new Dec(0), + expQuoTruncate: new Dec(0), + expAdd: new Dec(1), + expSub: new Dec(-1), + }, + { + d1: new Dec(-1), + d2: new Dec(0), + expMul: new Dec(0), + expMulTruncate: new Dec(0), + expQuo: new Dec(0), + expQuoRoundUp: new Dec(0), + expQuoTruncate: new Dec(0), + expAdd: new Dec(-1), + expSub: new Dec(-1), + }, + { + d1: new Dec(-1), + d2: new Dec(1), + expMul: new Dec(-1), + expMulTruncate: new Dec(-1), + expQuo: new Dec(-1), + expQuoRoundUp: new Dec(-1), + expQuoTruncate: new Dec(-1), + expAdd: new Dec(0), + expSub: new Dec(-2), + }, + { + d1: new Dec(3), + d2: new Dec(7), + expMul: new Dec(21), + expMulTruncate: new Dec(21), + expQuo: new Dec("428571428571428571", 18), + expQuoRoundUp: new Dec("428571428571428572", 18), + expQuoTruncate: new Dec("428571428571428571", 18), + expAdd: new Dec(10), + expSub: new Dec(-4), + }, + { + d1: new Dec(100), + d2: new Dec(100), + expMul: new Dec(10000), + expMulTruncate: new Dec(10000), + expQuo: new Dec(1), + expQuoRoundUp: new Dec(1), + expQuoTruncate: new Dec(1), + expAdd: new Dec(200), + expSub: new Dec(0), + }, + { + d1: new Dec(3333, 4), + d2: new Dec(333, 4), + expMul: new Dec(1109889, 8), + expMulTruncate: new Dec(1109889, 8), + expQuo: new Dec("10.009009009009009009"), + expQuoRoundUp: new Dec("10.009009009009009010"), + expQuoTruncate: new Dec("10.009009009009009009"), + expAdd: new Dec(3666, 4), + expSub: new Dec(3, 1), + }, + ]; + + for (const test of tests) { + const resAdd = test.d1.add(test.d2); + const resSub = test.d1.sub(test.d2); + const resMul = test.d1.mul(test.d2); + const resMulTruncate = test.d1.mulTruncate(test.d2); + + // invalid result of add + expect(resAdd.toString()).toBe(test.expAdd.toString()); + // invalid result of sub + expect(resSub.toString()).toBe(test.expSub.toString()); + // invalid result of mul + expect(resMul.toString()).toBe(test.expMul.toString()); + // invalid result of mul + expect(resMulTruncate.toString()).toBe(test.expMulTruncate.toString()); + + if (test.d2.isZero()) { + expect(() => { + test.d1.quo(test.d2); + }).toThrow(); + } else { + const resQuo = test.d1.quo(test.d2); + const resQuoRoundUp = test.d1.quoRoundUp(test.d2); + const resQuoTruncate = test.d1.quoTruncate(test.d2); + + // invalid result of quo + expect(resQuo.toString()).toBe(test.expQuo.toString()); + // invalid result of quo round up + expect(resQuoRoundUp.toString()).toBe(test.expQuoRoundUp.toString()); + // invalid result of quo truncate + expect(resQuoTruncate.toString()).toBe(test.expQuoTruncate.toString()); + } + } + }); + + it("dec should be round up properly", () => { + const tests: { + d1: Dec; + exp: Int; + }[] = [ + { + d1: new Dec("0.25"), + exp: new Int("1"), + }, + { + d1: new Dec("0"), + exp: new Int("0"), + }, + { + d1: new Dec("1"), + exp: new Int("1"), + }, + { + d1: new Dec("0.75"), + exp: new Int("1"), + }, + { + d1: new Dec("0.5"), + exp: new Int("1"), + }, + { + d1: new Dec("7.5"), + exp: new Int("8"), + }, + { + d1: new Dec("0.545"), + exp: new Int("1"), + }, + { + d1: new Dec("1.545"), + exp: new Int("2"), + }, + { + d1: new Dec("-1.545"), + exp: new Int("-1"), + }, + { + d1: new Dec("-0.545"), + exp: new Int("0"), + }, + ]; + + for (const test of tests) { + const resPos = test.d1.roundUp(); + expect(resPos.toString()).toBe(test.exp.toString()); + + const resPosDec = test.d1.roundUpDec(); + expect(resPosDec.toString()).toBe( + test.exp.toString() + ".000000000000000000" + ); + } + }); + + it("dec should be round properly", () => { + const tests: { + d1: Dec; + exp: Int; + }[] = [ + { + d1: new Dec("0.25"), + exp: new Int("0"), + }, + { + d1: new Dec("0"), + exp: new Int("0"), + }, + { + d1: new Dec("1"), + exp: new Int("1"), + }, + { + d1: new Dec("0.75"), + exp: new Int("1"), + }, + { + d1: new Dec("0.5"), + exp: new Int("0"), + }, + { + d1: new Dec("7.5"), + exp: new Int("8"), + }, + { + d1: new Dec("0.545"), + exp: new Int("1"), + }, + { + d1: new Dec("1.545"), + exp: new Int("2"), + }, + ]; + + for (const test of tests) { + const resNeg = test.d1.neg().round(); + expect(resNeg.toString()).toBe(test.exp.neg().toString()); + + const resNegDec = test.d1.neg().roundDec(); + expect(resNegDec.toString()).toBe( + test.exp.neg().toString() + ".000000000000000000" + ); + + const resPos = test.d1.round(); + expect(resPos.toString()).toBe(test.exp.toString()); + + const resPosDec = test.d1.roundDec(); + expect(resPosDec.toString()).toBe( + test.exp.toString() + ".000000000000000000" + ); + } + }); + + it("dec should be truncated properly", () => { + const tests: { + d1: Dec; + exp: Int; + }[] = [ + { + d1: new Dec("0"), + exp: new Int("0"), + }, + { + d1: new Dec("0.25"), + exp: new Int("0"), + }, + { + d1: new Dec("0.75"), + exp: new Int("0"), + }, + { + d1: new Dec("1"), + exp: new Int("1"), + }, + { + d1: new Dec("7.5"), + exp: new Int("7"), + }, + { + d1: new Dec("7.6"), + exp: new Int("7"), + }, + { + d1: new Dec("8.5"), + exp: new Int("8"), + }, + { + d1: new Dec("100.000000001"), + exp: new Int("100"), + }, + ]; + + for (const test of tests) { + const resNeg = test.d1.neg().truncate(); + expect(resNeg.toString()).toBe(test.exp.neg().toString()); + + const resNegDec = test.d1.neg().truncateDec(); + expect(resNegDec.toString()).toBe( + test.exp.neg().toString() + ".000000000000000000" + ); + + const resPos = test.d1.truncate(); + expect(resPos.toString()).toBe(test.exp.toString()); + + const resPosDec = test.d1.truncateDec(); + expect(resPosDec.toString()).toBe( + test.exp.toString() + ".000000000000000000" + ); + } + }); + + it("dec should be parsed to string properly", () => { + const tests: { + d1: Dec; + precision: number; + exp: string; + }[] = [ + { + d1: new Dec("0"), + precision: 0, + exp: "0", + }, + { + d1: new Dec("1.25"), + precision: 0, + exp: "1", + }, + { + d1: new Dec("0.75"), + precision: 1, + exp: "0.7", + }, + { + d1: new Dec("1"), + precision: 5, + exp: "1.00000", + }, + { + d1: new Dec(new Int("1")), + precision: 5, + exp: "1.00000", + }, + { + d1: new Dec("7.5"), + precision: 3, + exp: "7.500", + }, + { + d1: new Dec("100.000000001"), + precision: 0, + exp: "100", + }, + { + d1: new Dec(100.000000001), + precision: 0, + exp: "100", + }, + { + d1: new Dec("-0.25"), + precision: 0, + exp: "0", + }, + { + d1: new Dec("-1.25"), + precision: 0, + exp: "-1", + }, + { + d1: new Dec("-0.75"), + precision: 1, + exp: "-0.7", + }, + { + d1: new Dec("-1"), + precision: 5, + exp: "-1.00000", + }, + { + d1: new Dec(-1), + precision: 5, + exp: "-1.00000", + }, + { + d1: new Dec("-7.5"), + precision: 3, + exp: "-7.500", + }, + { + d1: new Dec(-7.5), + precision: 3, + exp: "-7.500", + }, + { + d1: new Dec("-100.000000001"), + precision: 0, + exp: "-100", + }, + { + d1: new Dec(-100.000000001), + precision: 0, + exp: "-100", + }, + ]; + + for (const test of tests) { + const res = test.d1.toString(test.precision); + expect(res).toBe(test.exp); + } + }); + + it("Test case that input decimals exceeds 18", () => { + const tests: { + input: number | string; + res: Dec; + resStr: string; + }[] = [ + { + input: "0.489234893284938249348923849283408", + res: new Dec("0.489234893284938249"), + resStr: "0.489234893284938249", + }, + { + input: 0.0000010000000249348, + res: new Dec("0.000001000000024934"), + resStr: "0.000001000000024934", + }, + { + input: "0.0000000000000000001", + res: new Dec("0"), + resStr: "0.000000000000000000", + }, + { + input: 0.0000000000000000001, + res: new Dec("0"), + resStr: "0.000000000000000000", + }, + ]; + + for (const test of tests) { + const dec = new Dec(test.input); + + expect(dec.equals(test.res)).toBe(true); + expect(dec.toString()).toBe(test.resStr); + } + }); + + it("Test Int/Uint from exponent number", () => { + const tests: { + num: number; + str: string; + expect: Dec; + }[] = [ + { + num: 12345678901234567890123, + str: "1.2345678901234568e+22", + expect: new Dec("12345678901234568000000"), + }, + { + num: -12345678901234567890123, + str: "-1.2345678901234568e+22", + expect: new Dec("-12345678901234568000000"), + }, + { + num: 0.0000000000001, + str: "1e-13", + expect: new Dec("0.0000000000001"), + }, + { + num: 0.000000000000123, + str: "1.23e-13", + expect: new Dec("0.000000000000123"), + }, + { + num: 0.000000000000000001, + str: "1e-18", + expect: new Dec("0.000000000000000001"), + }, + { + num: 0.0000000000000000001, + str: "1e-19", + expect: new Dec("0"), + }, + { + num: 0.00000000000000000123, + str: "1.23e-18", + expect: new Dec("0.000000000000000001"), + }, + { + num: 0.000000000000000000123, + str: "1.23e-19", + expect: new Dec("0"), + }, + ]; + + for (const test of tests) { + expect(test.num.toString()).toBe(test.str); + + expect(new Dec(test.num).equals(test.expect)).toBe(true); + } + }); +}); diff --git a/packages/unit/src/decimal.ts b/packages/unit/src/decimal.ts new file mode 100644 index 0000000000..c2fa836a3d --- /dev/null +++ b/packages/unit/src/decimal.ts @@ -0,0 +1,374 @@ +import bigInteger from "big-integer"; + +import { CoinUtils } from "./coin-utils"; +import { + exponentDecStringToDecString, + isExponentDecString, + isValidDecimalString, +} from "./etc"; +import { Int } from "./int"; + +export class Dec { + public static readonly precision = 18; + // Bytes required to represent the above precision is 18. + // Ceiling[Log2[999 999 999 999 999 999]] + protected static readonly decimalPrecisionBits = 60; + // Max bit length for `Dec` is 256 + 60(decimalPrecisionBits) + // The int in the `Dec` is handled as integer assuming that it has 18 precision. + // (2 ** (256 + 60) - 1) + protected static readonly maxDec = bigInteger( + "133499189745056880149688856635597007162669032647290798121690100488888732861290034376435130433535" + ); + + protected static readonly precisionMultipliers: { + [key: string]: bigInteger.BigInteger | undefined; + } = {}; + protected static calcPrecisionMultiplier( + prec: number + ): bigInteger.BigInteger { + if (prec < 0) { + throw new Error("Invalid prec"); + } + if (prec > Dec.precision) { + throw new Error("Too much precision"); + } + if (Dec.precisionMultipliers[prec.toString()]) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return Dec.precisionMultipliers[prec.toString()]!; + } + + const zerosToAdd = Dec.precision - prec; + const multiplier = bigInteger(10).pow(zerosToAdd); + Dec.precisionMultipliers[prec.toString()] = multiplier; + return multiplier; + } + + protected static reduceDecimalsFromString(str: string): { + res: string; + isDownToZero: boolean; + } { + const decimalPointIndex = str.indexOf("."); + if (decimalPointIndex < 0) { + return { + res: str, + isDownToZero: false, + }; + } + + const exceededDecimals = str.length - 1 - decimalPointIndex - Dec.precision; + if (exceededDecimals <= 0) { + return { + res: str, + isDownToZero: false, + }; + } + + const res = str.slice(0, str.length - exceededDecimals); + return { + res, + isDownToZero: /^[0.]*$/.test(res), + }; + } + + protected int: bigInteger.BigInteger; + + /** + * Create a new Dec from integer with decimal place at prec + * @param int - Parse a number | bigInteger | string into a Dec. + * If int is string and contains dot(.), prec is ignored and automatically calculated. + * @param prec - Precision + */ + constructor(int: bigInteger.BigNumber | Int, prec: number = 0) { + if (typeof int === "number") { + int = int.toString(); + } + + if (typeof int === "string") { + if (int.length === 0) { + throw new Error("empty string"); + } + if (!isValidDecimalString(int)) { + if (isExponentDecString(int)) { + int = exponentDecStringToDecString(int); + } else { + throw new Error(`invalid decimal: ${int}`); + } + } + // Even if an input with more than 18 decimals, it does not throw an error and ignores the rest. + const reduced = Dec.reduceDecimalsFromString(int); + if (reduced.isDownToZero) { + // However, as a result, if the input becomes 0, a problem may occur in mul or quo. In this case, print a warning. + console.log( + `WARNING: Got ${int}. Dec can only handle up to 18 decimals. However, since the decimal point of the input exceeds 18 digits, the remainder is discarded. As a result, input becomes 0.` + ); + } + int = reduced.res; + if (int.indexOf(".") >= 0) { + prec = int.length - int.indexOf(".") - 1; + int = int.replace(".", ""); + } + this.int = bigInteger(int); + } else if (int instanceof Int) { + this.int = bigInteger(int.toString()); + } else if (typeof int === "bigint") { + this.int = bigInteger(int); + } else { + this.int = bigInteger(int); + } + + this.int = this.int.multiply(Dec.calcPrecisionMultiplier(prec)); + + this.checkBitLen(); + } + + protected checkBitLen(): void { + if (this.int.abs().gt(Dec.maxDec)) { + throw new Error(`Integer out of range ${this.int.toString()}`); + } + } + + public isZero(): boolean { + return this.int.eq(bigInteger(0)); + } + + public isNegative(): boolean { + return this.int.isNegative(); + } + + public isPositive(): boolean { + return this.int.isPositive(); + } + + public equals(d2: Dec): boolean { + return this.int.eq(d2.int); + } + + /** + * Alias for the greater method. + */ + public gt(d2: Dec): boolean { + return this.int.gt(d2.int); + } + + /** + * Alias for the greaterOrEquals method. + */ + public gte(d2: Dec): boolean { + return this.int.geq(d2.int); + } + + /** + * Alias for the lesser method. + */ + public lt(d2: Dec): boolean { + return this.int.lt(d2.int); + } + + /** + * Alias for the lesserOrEquals method. + */ + public lte(d2: Dec): boolean { + return this.int.leq(d2.int); + } + + /** + * reverse the decimal sign. + */ + public neg(): Dec { + return new Dec(this.int.negate(), Dec.precision); + } + + /** + * Returns the absolute value of a decimals. + */ + public abs(): Dec { + return new Dec(this.int.abs(), Dec.precision); + } + + public add(d2: Dec): Dec { + return new Dec(this.int.add(d2.int), Dec.precision); + } + + public sub(d2: Dec): Dec { + return new Dec(this.int.subtract(d2.int), Dec.precision); + } + + public pow(n: Int): Dec { + if (n.isZero()) { + return new Dec(1); + } + + if (n.isNegative()) { + return new Dec(1).quo(this.pow(n.abs())); + } + + let base = new Dec(this.int, Dec.precision); + let tmp = new Dec(1); + + for (let i = n; i.gt(new Int(1)); i = i.div(new Int(2))) { + if (!i.mod(new Int(2)).isZero()) { + tmp = tmp.mul(base); + } + base = base.mul(base); + } + + return base.mul(tmp); + } + + public mul(d2: Dec): Dec { + return new Dec(this.mulRaw(d2).chopPrecisionAndRound(), Dec.precision); + } + + public mulTruncate(d2: Dec): Dec { + return new Dec(this.mulRaw(d2).chopPrecisionAndTruncate(), Dec.precision); + } + + protected mulRaw(d2: Dec): Dec { + return new Dec(this.int.multiply(d2.int), Dec.precision); + } + + public quo(d2: Dec): Dec { + return new Dec(this.quoRaw(d2).chopPrecisionAndRound(), Dec.precision); + } + + public quoTruncate(d2: Dec): Dec { + return new Dec(this.quoRaw(d2).chopPrecisionAndTruncate(), Dec.precision); + } + + public quoRoundUp(d2: Dec): Dec { + return new Dec(this.quoRaw(d2).chopPrecisionAndRoundUp(), Dec.precision); + } + + protected quoRaw(d2: Dec): Dec { + const precision = Dec.calcPrecisionMultiplier(0); + + // multiply precision twice + const mul = this.int.multiply(precision).multiply(precision); + return new Dec(mul.divide(d2.int), Dec.precision); + } + + public isInteger(): boolean { + const precision = Dec.calcPrecisionMultiplier(0); + return this.int.remainder(precision).equals(bigInteger(0)); + } + + /** + * Remove a Precision amount of rightmost digits and perform bankers rounding + * on the remainder (gaussian rounding) on the digits which have been removed. + */ + protected chopPrecisionAndRound(): bigInteger.BigInteger { + // Remove the negative and add it back when returning + if (this.isNegative()) { + const absoulteDec = this.abs(); + const choped = absoulteDec.chopPrecisionAndRound(); + return choped.negate(); + } + + const precision = Dec.calcPrecisionMultiplier(0); + const fivePrecision = precision.divide(bigInteger(2)); + + // Get the truncated quotient and remainder + const { quotient, remainder } = this.int.divmod(precision); + + // If remainder is zero + if (remainder.equals(bigInteger(0))) { + return quotient; + } + + if (remainder.lt(fivePrecision)) { + return quotient; + } else if (remainder.gt(fivePrecision)) { + return quotient.add(bigInteger(1)); + } else { + // always round to an even number + if (quotient.divide(bigInteger(2)).equals(bigInteger(0))) { + return quotient; + } else { + return quotient.add(bigInteger(1)); + } + } + } + + protected chopPrecisionAndRoundUp(): bigInteger.BigInteger { + // Remove the negative and add it back when returning + if (this.isNegative()) { + const absoulteDec = this.abs(); + // truncate since d is negative... + const choped = absoulteDec.chopPrecisionAndTruncate(); + return choped.negate(); + } + + const precision = Dec.calcPrecisionMultiplier(0); + + // Get the truncated quotient and remainder + const { quotient, remainder } = this.int.divmod(precision); + + // If remainder is zero + if (remainder.equals(bigInteger(0))) { + return quotient; + } + + return quotient.add(bigInteger(1)); + } + + /** + * Similar to chopPrecisionAndRound, but always rounds down + */ + protected chopPrecisionAndTruncate(): bigInteger.BigInteger { + const precision = Dec.calcPrecisionMultiplier(0); + return this.int.divide(precision); + } + + public toString( + prec: number = Dec.precision, + locale: boolean = false + ): string { + const precision = Dec.calcPrecisionMultiplier(0); + const int = this.int.abs(); + const { quotient: integer, remainder: fraction } = int.divmod(precision); + + let fractionStr = fraction.toString(10); + for (let i = 0, l = fractionStr.length; i < Dec.precision - l; i++) { + fractionStr = "0" + fractionStr; + } + fractionStr = fractionStr.substring(0, prec); + + const isNegative = + this.isNegative() && + !(integer.eq(bigInteger(0)) && fractionStr.length === 0); + + const integerStr = locale + ? // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + CoinUtils.integerStringToUSLocaleString(integer.toString()) + : integer.toString(); + + return `${isNegative ? "-" : ""}${integerStr}${ + fractionStr.length > 0 ? "." + fractionStr : "" + }`; + } + + public round(): Int { + return new Int(this.chopPrecisionAndRound()); + } + + public roundUp(): Int { + return new Int(this.chopPrecisionAndRoundUp()); + } + + public truncate(): Int { + return new Int(this.chopPrecisionAndTruncate()); + } + + public roundDec(): Dec { + return new Dec(this.chopPrecisionAndRound(), 0); + } + + public roundUpDec(): Dec { + return new Dec(this.chopPrecisionAndRoundUp(), 0); + } + + public truncateDec(): Dec { + return new Dec(this.chopPrecisionAndTruncate(), 0); + } +} diff --git a/packages/unit/src/etc.spec.ts b/packages/unit/src/etc.spec.ts new file mode 100644 index 0000000000..f47f504a21 --- /dev/null +++ b/packages/unit/src/etc.spec.ts @@ -0,0 +1,73 @@ +import { exponentDecStringToDecString } from "./etc"; + +describe("Test etc utils", () => { + it("Test exponentDecStringToDecString", () => { + expect(exponentDecStringToDecString("1e+0")).toBe("1"); + expect(exponentDecStringToDecString("1e+1")).toBe("10"); + expect(exponentDecStringToDecString("123e+1")).toBe("1230"); + expect(exponentDecStringToDecString("123e+2")).toBe("12300"); + expect(exponentDecStringToDecString("123e+3")).toBe("123000"); + expect(exponentDecStringToDecString("123e+4")).toBe("1230000"); + + expect(exponentDecStringToDecString("-1e+0")).toBe("-1"); + expect(exponentDecStringToDecString("-1e+1")).toBe("-10"); + expect(exponentDecStringToDecString("-123e+1")).toBe("-1230"); + expect(exponentDecStringToDecString("-123e+2")).toBe("-12300"); + expect(exponentDecStringToDecString("-123e+3")).toBe("-123000"); + expect(exponentDecStringToDecString("-123e+4")).toBe("-1230000"); + + expect(exponentDecStringToDecString("1.2e+0")).toBe("1.2"); + expect(exponentDecStringToDecString("1.2e+1")).toBe("12"); + expect(exponentDecStringToDecString("1.23e+1")).toBe("12.3"); + expect(exponentDecStringToDecString("1.23e+2")).toBe("123"); + expect(exponentDecStringToDecString("1.23e+3")).toBe("1230"); + expect(exponentDecStringToDecString("1.23e+4")).toBe("12300"); + + expect(exponentDecStringToDecString("-1.2e+0")).toBe("-1.2"); + expect(exponentDecStringToDecString("-1.2e+1")).toBe("-12"); + expect(exponentDecStringToDecString("-1.23e+1")).toBe("-12.3"); + expect(exponentDecStringToDecString("-1.23e+2")).toBe("-123"); + expect(exponentDecStringToDecString("-1.23e+3")).toBe("-1230"); + expect(exponentDecStringToDecString("-1.23e+4")).toBe("-12300"); + + expect(exponentDecStringToDecString("1e-0")).toBe("1"); + expect(exponentDecStringToDecString("1e-1")).toBe("0.1"); + expect(exponentDecStringToDecString("123e-1")).toBe("12.3"); + expect(exponentDecStringToDecString("123e-2")).toBe("1.23"); + expect(exponentDecStringToDecString("123e-3")).toBe("0.123"); + expect(exponentDecStringToDecString("123e-4")).toBe("0.0123"); + + expect(exponentDecStringToDecString("-1e-0")).toBe("-1"); + expect(exponentDecStringToDecString("-1e-1")).toBe("-0.1"); + expect(exponentDecStringToDecString("-123e-1")).toBe("-12.3"); + expect(exponentDecStringToDecString("-123e-2")).toBe("-1.23"); + expect(exponentDecStringToDecString("-123e-3")).toBe("-0.123"); + expect(exponentDecStringToDecString("-123e-4")).toBe("-0.0123"); + + expect(exponentDecStringToDecString("1.2e-0")).toBe("1.2"); + expect(exponentDecStringToDecString("1.2e-1")).toBe("0.12"); + expect(exponentDecStringToDecString("1.23e-1")).toBe("0.123"); + expect(exponentDecStringToDecString("1.23e-2")).toBe("0.0123"); + expect(exponentDecStringToDecString("1.23e-3")).toBe("0.00123"); + expect(exponentDecStringToDecString("1.23e-4")).toBe("0.000123"); + + expect(exponentDecStringToDecString("-1.2e-0")).toBe("-1.2"); + expect(exponentDecStringToDecString("-1.2e-1")).toBe("-0.12"); + expect(exponentDecStringToDecString("-1.23e-1")).toBe("-0.123"); + expect(exponentDecStringToDecString("-1.23e-2")).toBe("-0.0123"); + expect(exponentDecStringToDecString("-1.23e-3")).toBe("-0.00123"); + expect(exponentDecStringToDecString("-1.23e-4")).toBe("-0.000123"); + + expect(exponentDecStringToDecString("0.00123e+1")).toBe("0.0123"); + expect(exponentDecStringToDecString("0.00123e-1")).toBe("0.000123"); + expect(exponentDecStringToDecString("0.00123e+4")).toBe("12.3"); + expect(exponentDecStringToDecString("0.00123e-4")).toBe("0.000000123"); + expect(exponentDecStringToDecString("1234.567e+2")).toBe("123456.7"); + expect(exponentDecStringToDecString("1234.567e+3")).toBe("1234567"); + expect(exponentDecStringToDecString("1234.567e+4")).toBe("12345670"); + expect(exponentDecStringToDecString("1234.567e+10")).toBe("12345670000000"); + + expect(exponentDecStringToDecString("-0.00123e+1")).toBe("-0.0123"); + expect(exponentDecStringToDecString("-0.00123e-1")).toBe("-0.000123"); + }); +}); diff --git a/packages/unit/src/etc.ts b/packages/unit/src/etc.ts new file mode 100644 index 0000000000..d5387665c7 --- /dev/null +++ b/packages/unit/src/etc.ts @@ -0,0 +1,73 @@ +const regexIntString = /^-?\d+$/; +const regexDecString = /^-?\d+.?\d*$/; +const regexExponentDecString = /^(-?)([\d.]+)e([-+])([\d]+)$/; + +export function isValidIntegerString(str: string): boolean { + return regexIntString.test(str); +} + +export function isValidDecimalString(str: string): boolean { + return regexDecString.test(str); +} + +export function isExponentDecString(str: string): boolean { + return regexExponentDecString.test(str); +} + +function makeZerosStr(len: number): string { + let r = ""; + for (let i = 0; i < len; i++) { + r += "0"; + } + return r; +} + +function removeHeadZeros(str: string): string { + while (str.length > 0 && str[0] === "0") { + str = str.slice(1); + } + if (str.length === 0 || str[0] === ".") { + return "0" + str; + } + return str; +} + +export function exponentDecStringToDecString(str: string): string { + const split = str.split(regexExponentDecString); + if (split.length !== 6) { + return str; + } + + const isNeg = split[1] === "-"; + let numStr = split[2]; + const numStrFractionIndex = numStr.indexOf("."); + + const exponentStr = split[4]; + let exponent = parseInt(exponentStr) * (split[3] === "-" ? -1 : 1); + + if (numStrFractionIndex >= 0) { + const fractionLen = numStr.length - numStrFractionIndex - 1; + exponent = exponent - fractionLen; + + numStr = removeHeadZeros(numStr.replace(".", "")); + } + + const prefix = isNeg ? "-" : ""; + + if (exponent < 0) { + if (numStr.length > -exponent) { + const fractionPosition = numStr.length + exponent; + + return ( + prefix + + (numStr.slice(0, fractionPosition) + + "." + + numStr.slice(fractionPosition)) + ); + } + + return prefix + "0." + makeZerosStr(-(numStr.length + exponent)) + numStr; + } else { + return prefix + numStr + makeZerosStr(exponent); + } +} diff --git a/packages/unit/src/index.ts b/packages/unit/src/index.ts new file mode 100644 index 0000000000..ce4d4952dc --- /dev/null +++ b/packages/unit/src/index.ts @@ -0,0 +1,9 @@ +export * from "./coin"; +export * from "./coin-pretty"; +export * from "./coin-utils"; +export * from "./dec-utils"; +export * from "./decimal"; +export * from "./int"; +export * from "./int-pretty"; +export * from "./price-pretty"; +export * from "./rate-pretty"; diff --git a/packages/unit/src/int-pretty.spec.ts b/packages/unit/src/int-pretty.spec.ts new file mode 100644 index 0000000000..2e9ce19b24 --- /dev/null +++ b/packages/unit/src/int-pretty.spec.ts @@ -0,0 +1,729 @@ +import { Dec } from "./decimal"; +import { Int } from "./int"; +import { IntPretty } from "./int-pretty"; + +describe("Test IntPretty", () => { + it("Test creation of IntPretty", () => { + expect(new IntPretty(new Dec("1.1")).toDec().equals(new Dec("1.1"))).toBe( + true + ); + expect(new IntPretty(new Dec("1.1")).maxDecimals(2).toString()).toBe( + "1.10" + ); + expect(new IntPretty(new Dec("5")).toString()).toBe("5"); + expect(new IntPretty(new Dec("5.0")).toString()).toBe("5"); + + expect(new IntPretty("1.1").toDec().equals(new Dec("1.1"))).toBe(true); + expect(new IntPretty("1.1").maxDecimals(2).toString()).toBe("1.10"); + + expect(new IntPretty(1.1).toDec().equals(new Dec("1.1"))).toBe(true); + expect(new IntPretty(1.1).maxDecimals(2).toString()).toBe("1.10"); + expect(new IntPretty(1.1234).maxDecimals(2).toString()).toBe("1.12"); + expect(new IntPretty(0.1234).maxDecimals(2).toString()).toBe("0.12"); + expect(new IntPretty(0.003).maxDecimals(2).toString()).toBe("0.00"); + expect(new IntPretty(0.00003456).toString()).toBe("0.00003456"); + + expect(new IntPretty(new Int(1)).toDec().equals(new Dec("1.0"))).toBe(true); + expect(new IntPretty(new Int(1)).maxDecimals(2).toString()).toBe("1.00"); + }); + + it("Test the maxDecimals of IntPretty", () => { + const params: { + arg: Dec | Int; + maxDecimals: number; + dec: Dec; + str: string; + }[] = [ + { + arg: new Int(0), + maxDecimals: 0, + dec: new Dec(0), + str: "0", + }, + { + arg: new Dec(0), + maxDecimals: 0, + dec: new Dec(0), + str: "0", + }, + { + arg: new Int(100), + maxDecimals: 0, + dec: new Dec(100), + str: "100", + }, + { + arg: new Dec(100), + maxDecimals: 0, + dec: new Dec(100), + str: "100", + }, + { + arg: new Dec("0.01"), + maxDecimals: 2, + dec: new Dec("0.01"), + str: "0.01", + }, + { + arg: new Dec("-0.01"), + maxDecimals: 2, + dec: new Dec("-0.01"), + str: "-0.01", + }, + { + arg: new Dec("1.01"), + maxDecimals: 2, + dec: new Dec("1.01"), + str: "1.01", + }, + { + arg: new Dec("-1.01"), + maxDecimals: 2, + dec: new Dec("-1.01"), + str: "-1.01", + }, + { + arg: new Dec("10.01"), + maxDecimals: 2, + dec: new Dec("10.01"), + str: "10.01", + }, + { + arg: new Dec("-10.01"), + maxDecimals: 2, + dec: new Dec("-10.01"), + str: "-10.01", + }, + { + arg: new Dec("10.0100"), + maxDecimals: 2, + dec: new Dec("10.01"), + str: "10.01", + }, + { + arg: new Dec("-10.0100"), + maxDecimals: 2, + dec: new Dec("-10.01"), + str: "-10.01", + }, + ]; + + for (const param of params) { + const pretty = new IntPretty(param.arg); + expect(pretty.options.maxDecimals).toBe(param.maxDecimals); + expect(pretty.toDec().equals(param.dec)).toBeTruthy(); + expect(pretty.toString()).toBe(param.str); + } + }); + + it("Test modifying the precision of IntPretty", () => { + const tests: { + base: Dec; + delta: number; + right: boolean; + res: Dec; + resStr: string; + otherTest?: (int: IntPretty) => void; + }[] = [ + { + base: new Dec("10.001"), + delta: 0, + right: false, + res: new Dec("10.001"), + resStr: "10.001", + otherTest: (int) => { + expect(int.maxDecimals(4).toString()).toBe("10.0010"); + }, + }, + { + base: new Dec("10.001"), + delta: 1, + right: false, + res: new Dec("1.0001"), + resStr: "1.000", + otherTest: (int) => { + expect(int.maxDecimals(4).toString()).toBe("1.0001"); + }, + }, + { + base: new Dec("10.001"), + delta: 1, + right: true, + res: new Dec("100.010"), + resStr: "100.010", + otherTest: (int) => { + expect(int.maxDecimals(4).toString()).toBe("100.0100"); + }, + }, + { + base: new Dec("10.001"), + delta: 6, + right: true, + res: new Dec("10001000"), + resStr: "10,001,000.000", + }, + { + base: new Dec("0"), + delta: 3, + right: false, + res: new Dec("0"), + resStr: "0", + }, + { + base: new Dec("0"), + delta: 3, + right: true, + res: new Dec("0"), + resStr: "0", + }, + { + base: new Dec("100.01"), + delta: 20, + right: true, + res: new Dec("10001000000000000000000"), + resStr: "10,001,000,000,000,000,000,000.00", + }, + { + base: new Dec("100.01"), + delta: 20, + right: false, + res: new Dec("0.000000000000000001"), + resStr: "0.00", + otherTest: (int) => { + expect(int.trim(true).toString()).toBe("0"); + }, + }, + ]; + + for (const test of tests) { + let pretty = new IntPretty(test.base); + + if (test.right) { + pretty = pretty.moveDecimalPointRight(test.delta); + } else { + pretty = pretty.moveDecimalPointLeft(test.delta); + } + + expect(pretty.toDec().equals(test.res)).toBeTruthy(); + expect(pretty.toString()).toBe(test.resStr); + + if (test.otherTest) { + test.otherTest(pretty); + } + } + + for (const test of tests) { + let pretty = new IntPretty(test.base); + + if (test.right) { + pretty = pretty.decreasePrecision(test.delta); + } else { + pretty = pretty.increasePrecision(test.delta); + } + + expect(pretty.toDec().equals(test.res)).toBeTruthy(); + expect(pretty.toString()).toBe(test.resStr); + + if (test.otherTest) { + test.otherTest(pretty); + } + } + }); + + it("Test the add calcutation of IntPretty", () => { + const params: { + base: Dec | Int; + target: Dec | Int; + dec: Dec; + str: string; + }[] = [ + { + base: new Int(0), + target: new Int(0), + dec: new Dec(0), + str: "0", + }, + { + base: new Dec(0), + target: new Int(0), + dec: new Dec(0), + str: "0", + }, + { + base: new Int(0), + target: new Dec(0), + dec: new Dec(0), + str: "0", + }, + { + base: new Int(1), + target: new Dec(1), + dec: new Dec(2), + str: "2", + }, + { + base: new Int(1), + target: new Dec(-1), + dec: new Dec(0), + str: "0", + }, + { + base: new Int(100), + target: new Dec(-1), + dec: new Dec("99"), + str: "99", + }, + { + base: new Dec("100.001"), + target: new Dec(-1), + dec: new Dec("99.001"), + str: "99.001", + }, + { + base: new Dec("100.00100"), + target: new Dec("-1.001"), + dec: new Dec("99"), + // Max decimals should be remain + str: "99.000", + }, + { + base: new Dec("100.00100"), + target: new Dec("-0.00100"), + dec: new Dec("100"), + // Max decimals should be remain + str: "100.000", + }, + { + base: new Dec("0.00100"), + target: new Dec("-1.00100"), + dec: new Dec("-1"), + // Max decimals should be remain + str: "-1.000", + }, + { + base: new Dec("100.00100"), + target: new Dec("1.01"), + dec: new Dec("101.011"), + str: "101.011", + }, + ]; + + for (const param of params) { + const pretty = new IntPretty(param.base).add(new IntPretty(param.target)); + expect(pretty.toDec().equals(param.dec)).toBeTruthy(); + expect(pretty.toString()).toBe(param.str); + } + }); + + it("Test the sub calcutation of IntPretty", () => { + const params: { + base: Dec | Int; + target: Dec | Int; + dec: Dec; + str: string; + }[] = [ + { + base: new Int(0), + target: new Int(0), + dec: new Dec(0), + str: "0", + }, + { + base: new Dec(0), + target: new Int(0), + dec: new Dec(0), + str: "0", + }, + { + base: new Int(0), + target: new Dec(0), + dec: new Dec(0), + str: "0", + }, + { + base: new Int(1), + target: new Dec(1), + dec: new Dec(0), + str: "0", + }, + { + base: new Int(1), + target: new Dec(-1), + dec: new Dec(2), + str: "2", + }, + { + base: new Int(100), + target: new Dec(-1), + dec: new Dec("101"), + str: "101", + }, + { + base: new Dec("100.001"), + target: new Dec(-1), + dec: new Dec("101.001"), + str: "101.001", + }, + { + base: new Dec("100.00100"), + target: new Dec("1.001"), + dec: new Dec("99"), + // Max decimals should be remain + str: "99.000", + }, + { + base: new Dec("100.00100"), + target: new Dec("0.00100"), + dec: new Dec("100"), + // Max decimals should be remain + str: "100.000", + }, + { + base: new Dec("0.00100"), + target: new Dec("-1.00100"), + dec: new Dec("1.002"), + str: "1.002", + }, + { + base: new Dec("100.00100"), + target: new Dec("-1.01"), + dec: new Dec("101.011"), + str: "101.011", + }, + ]; + + for (const param of params) { + const pretty = new IntPretty(param.base).sub(new IntPretty(param.target)); + expect(pretty.toDec().equals(param.dec)).toBeTruthy(); + expect(pretty.toString()).toBe(param.str); + } + }); + + it("Test the mul calcutation of IntPretty", () => { + const params: { + base: Dec | Int; + target: Dec | Int; + dec: Dec; + str: string; + }[] = [ + { + base: new Int(0), + target: new Int(0), + dec: new Dec(0), + str: "0", + }, + { + base: new Dec(0), + target: new Int(0), + dec: new Dec(0), + str: "0", + }, + { + base: new Int(0), + target: new Dec(0), + dec: new Dec(0), + str: "0", + }, + { + base: new Int(1), + target: new Dec(1), + dec: new Dec(1), + str: "1", + }, + { + base: new Int(1), + target: new Dec(-1), + dec: new Dec(-1), + str: "-1", + }, + { + base: new Int(100), + target: new Dec(-1), + dec: new Dec("-100"), + str: "-100", + }, + { + base: new Dec("100.001"), + target: new Dec(-1), + dec: new Dec("-100.001"), + str: "-100.001", + }, + { + base: new Dec("100.00100"), + target: new Dec("1.001"), + dec: new Dec("100.101001"), + // Max decimals should be remain + str: "100.101", + }, + { + base: new Dec("100.00100"), + target: new Dec("0.00100"), + dec: new Dec("0.100001"), + // Max decimals should be remain + str: "0.100", + }, + { + base: new Dec("100.00100"), + target: new Dec("-1.00100"), + dec: new Dec("-100.101001"), + // Max decimals should be remain + str: "-100.101", + }, + { + base: new Dec("100.00100"), + target: new Dec("-0.00100"), + dec: new Dec("-0.100001"), + // Max decimals should be remain + str: "-0.100", + }, + ]; + + for (const param of params) { + const pretty = new IntPretty(param.base).mul(new IntPretty(param.target)); + expect(pretty.toDec().equals(param.dec)).toBeTruthy(); + expect(pretty.toString()).toBe(param.str); + } + }); + + it("Test the quo calcutation of IntPretty", () => { + expect(() => { + new IntPretty(new Dec("1")).quo(new IntPretty(new Int(0))); + }).toThrow(); + + const params: { + base: Dec | Int; + target: Dec | Int; + dec: Dec; + str: string; + }[] = [ + { + base: new Int(1), + target: new Dec(1), + dec: new Dec(1), + str: "1", + }, + { + base: new Int(1), + target: new Dec(-1), + dec: new Dec(-1), + str: "-1", + }, + { + base: new Int(100), + target: new Dec(-1), + dec: new Dec("-100"), + str: "-100", + }, + { + base: new Dec("100.001"), + target: new Dec(-1), + dec: new Dec("-100.001"), + str: "-100.001", + }, + { + base: new Dec("300.00300"), + target: new Dec("3"), + dec: new Dec("100.001"), + str: "100.001", + }, + { + base: new Dec("100.00500"), + target: new Dec("0.02"), + dec: new Dec("5000.25"), + // Max decimals should be remain + str: "5,000.250", + }, + { + base: new Dec("300.00300"), + target: new Dec("4"), + dec: new Dec("75.00075"), + // Max decimals should be remain + str: "75.000", + }, + ]; + + for (const param of params) { + const pretty = new IntPretty(param.base).quo(new IntPretty(param.target)); + expect(pretty.toDec().equals(param.dec)).toBeTruthy(); + expect(pretty.toString()).toBe(param.str); + } + }); + + it("Test toString() of IntPretty", () => { + let pretty = new IntPretty(new Dec("1234.123456")); + expect(pretty.toString()).toBe("1,234.123456"); + expect(pretty.locale(false).toString()).toBe("1234.123456"); + expect(pretty.maxDecimals(3).toString()).toBe("1,234.123"); + expect(pretty.maxDecimals(9).toString()).toBe("1,234.123456000"); + expect(pretty.maxDecimals(9).trim(true).toString()).toBe("1,234.123456"); + expect(pretty.shrink(true).toString()).toBe("1,234.123"); + + pretty = new IntPretty(new Dec("0.0123456")); + expect(pretty.toString()).toBe("0.0123456"); + expect(pretty.locale(false).toString()).toBe("0.0123456"); + expect(pretty.maxDecimals(3).toString()).toBe("0.012"); + expect(pretty.maxDecimals(9).toString()).toBe("0.012345600"); + expect(pretty.maxDecimals(9).trim(true).toString()).toBe("0.0123456"); + expect(pretty.shrink(true).toString()).toBe("0.0123456"); + }); + + it("Test inequalitySymbol of IntPretty", () => { + const tests: { + base: IntPretty; + maxDecimals: number; + inequalitySymbolSeparator: string; + resStr: string; + }[] = [ + { + base: new IntPretty(new Dec("0")), + maxDecimals: 3, + inequalitySymbolSeparator: " ", + resStr: "0.000", + }, + { + base: new IntPretty(new Dec("-0")), + maxDecimals: 3, + inequalitySymbolSeparator: " ", + resStr: "0.000", + }, + { + base: new IntPretty(new Dec("0.1")), + maxDecimals: 3, + inequalitySymbolSeparator: " ", + resStr: "0.100", + }, + { + base: new IntPretty(new Dec("1234.123456")), + maxDecimals: 3, + inequalitySymbolSeparator: " ", + resStr: "1,234.123", + }, + { + base: new IntPretty(new Dec("0.123456")), + maxDecimals: 3, + inequalitySymbolSeparator: " ", + resStr: "0.123", + }, + { + base: new IntPretty(new Dec("0.123456")).moveDecimalPointLeft(2), + maxDecimals: 3, + inequalitySymbolSeparator: " ", + resStr: "0.001", + }, + { + base: new IntPretty(new Dec("0.123456")).moveDecimalPointLeft(3), + maxDecimals: 3, + inequalitySymbolSeparator: " ", + resStr: "< 0.001", + }, + { + base: new IntPretty(new Dec("0.123456")), + maxDecimals: 0, + inequalitySymbolSeparator: " ", + resStr: "< 1", + }, + { + base: new IntPretty(new Dec("1.123456")), + maxDecimals: 0, + inequalitySymbolSeparator: " ", + resStr: "1", + }, + { + base: new IntPretty(new Dec("0.0001")), + maxDecimals: 3, + inequalitySymbolSeparator: " ", + resStr: "< 0.001", + }, + { + base: new IntPretty(new Dec("0.0001")), + maxDecimals: 3, + inequalitySymbolSeparator: "", + resStr: "<0.001", + }, + { + base: new IntPretty(new Dec("0.001")), + maxDecimals: 3, + inequalitySymbolSeparator: " ", + resStr: "0.001", + }, + { + base: new IntPretty(new Dec("-1234.123456")), + maxDecimals: 3, + inequalitySymbolSeparator: " ", + resStr: "-1,234.123", + }, + { + base: new IntPretty(new Dec("-0.123456")), + maxDecimals: 3, + inequalitySymbolSeparator: " ", + resStr: "-0.123", + }, + { + base: new IntPretty(new Dec("-0.0001")), + maxDecimals: 3, + inequalitySymbolSeparator: " ", + resStr: "> -0.001", + }, + { + base: new IntPretty(new Dec("-0.0001")), + maxDecimals: 3, + inequalitySymbolSeparator: "", + resStr: ">-0.001", + }, + { + base: new IntPretty(new Dec("-0.001")), + maxDecimals: 3, + inequalitySymbolSeparator: " ", + resStr: "-0.001", + }, + { + base: new IntPretty(new Dec("-0.123456")), + maxDecimals: 0, + inequalitySymbolSeparator: " ", + resStr: "> -1", + }, + { + base: new IntPretty(new Dec("-1.123456")), + maxDecimals: 0, + inequalitySymbolSeparator: " ", + resStr: "-1", + }, + ]; + + for (const test of tests) { + expect( + test.base + .maxDecimals(test.maxDecimals) + .inequalitySymbol(true) + .inequalitySymbolSeparator(test.inequalitySymbolSeparator) + .toString() + ).toBe(test.resStr); + } + }); + + it("Test toStringWithSymbols() of IntPretty", () => { + expect( + new IntPretty(new Dec(-123.45)).toStringWithSymbols("$", "SUFFIX") + ).toBe("-$123.45SUFFIX"); + + expect( + new IntPretty(new Dec(-123.45)) + .maxDecimals(0) + .toStringWithSymbols("$", "SUFFIX") + ).toBe("-$123SUFFIX"); + + expect( + new IntPretty(new Dec(-0.045)) + .maxDecimals(1) + .inequalitySymbol(true) + .toStringWithSymbols("$", "SUFFIX") + ).toBe("> -$0.1SUFFIX"); + + expect( + new IntPretty(new Dec(0.045)) + .maxDecimals(1) + .inequalitySymbol(true) + .toStringWithSymbols("$", "SUFFIX") + ).toBe("< $0.1SUFFIX"); + }); +}); diff --git a/packages/unit/src/int-pretty.ts b/packages/unit/src/int-pretty.ts new file mode 100644 index 0000000000..4b48315a3a --- /dev/null +++ b/packages/unit/src/int-pretty.ts @@ -0,0 +1,276 @@ +import bigInteger from "big-integer"; +import { DeepReadonly } from "utility-types"; + +import { CoinUtils } from "./coin-utils"; +import { DecUtils } from "./dec-utils"; +import { Dec } from "./decimal"; + +export type IntPrettyOptions = { + maxDecimals: number; + trim: boolean; + shrink: boolean; + ready: boolean; + locale: boolean; + // If this is true, toString() will return the string with prefix like < 0.001 if a value cannot be expressed with a max decimals. + inequalitySymbol: boolean; + inequalitySymbolSeparator: string; +}; + +export class IntPretty { + protected dec: Dec; + protected floatingDecimalPointRight = 0; + + protected _options: IntPrettyOptions = { + maxDecimals: 0, + trim: false, + shrink: false, + ready: true, + locale: true, + inequalitySymbol: false, + inequalitySymbolSeparator: " ", + }; + // note if you add another field, update clone() + + constructor(num: Dec | { toDec(): Dec } | bigInteger.BigNumber) { + if (typeof num === "object" && "toDec" in num) { + num = num.toDec(); + } else if (!(num instanceof Dec)) { + num = new Dec(num); + } + + if (num.isZero()) { + this.dec = num; + return; + } + + // Get string representation and find decimal position + const decStr = num.toString(); + const decimalIndex = decStr.indexOf('.'); + + // If no decimal point no precision needed + if (decimalIndex === -1) { + this.dec = num; + this._options.maxDecimals = 0; + return; + } + + // Count significant digits by walking backwards until non-zero digit + const decimalPart = decStr.slice(decimalIndex + 1); + let trailingZeros = 0; + for (let i = decimalPart.length - 1; i >= 0 && decimalPart[i] === '0'; i--) { + trailingZeros++; + } + const decPrecision = decimalPart.length - trailingZeros; + + this.dec = num; + this._options.maxDecimals = decPrecision; + } + + get options(): DeepReadonly { + return this._options; + } + + moveDecimalPointLeft(delta: number): IntPretty { + const pretty = this.clone(); + pretty.floatingDecimalPointRight += -delta; + return pretty; + } + + moveDecimalPointRight(delta: number): IntPretty { + const pretty = this.clone(); + pretty.floatingDecimalPointRight += delta; + return pretty; + } + + /** + * @deprecated Use`moveDecimalPointLeft` + */ + increasePrecision(delta: number): IntPretty { + return this.moveDecimalPointLeft(delta); + } + + /** + * @deprecated Use`moveDecimalPointRight` + */ + decreasePrecision(delta: number): IntPretty { + return this.moveDecimalPointRight(delta); + } + + maxDecimals(max: number): IntPretty { + const pretty = this.clone(); + pretty._options.maxDecimals = max; + return pretty; + } + + inequalitySymbol(bool: boolean): IntPretty { + const pretty = this.clone(); + pretty._options.inequalitySymbol = bool; + return pretty; + } + + inequalitySymbolSeparator(str: string): IntPretty { + const pretty = this.clone(); + pretty._options.inequalitySymbolSeparator = str; + return pretty; + } + + trim(bool: boolean): IntPretty { + const pretty = this.clone(); + pretty._options.trim = bool; + return pretty; + } + + shrink(bool: boolean): IntPretty { + const pretty = this.clone(); + pretty._options.shrink = bool; + return pretty; + } + + locale(locale: boolean): IntPretty { + const pretty = this.clone(); + pretty._options.locale = locale; + return pretty; + } + + /** + * Ready indicates the actual value is ready to show the users. + * Even if the ready option is false, it expects that the value can be shown to users (probably as 0). + * The method that returns prettied value may return `undefined` or `null` if the value is not ready. + * But, alternatively, it can return the 0 value that can be shown the users anyway, but indicates that the value is not ready. + * @param bool + */ + ready(bool: boolean): IntPretty { + const pretty = this.clone(); + pretty._options.ready = bool; + return pretty; + } + + get isReady(): boolean { + return this._options.ready; + } + + add(target: Dec | { toDec(): Dec }): IntPretty { + if (!(target instanceof Dec)) { + target = target.toDec(); + } + + const pretty = new IntPretty(this.toDec().add(target)); + pretty._options = { + ...this._options, + }; + return pretty; + } + + sub(target: Dec | { toDec(): Dec }): IntPretty { + if (!(target instanceof Dec)) { + target = target.toDec(); + } + + const pretty = new IntPretty(this.toDec().sub(target)); + pretty._options = { + ...this._options, + }; + return pretty; + } + + mul(target: Dec | { toDec(): Dec }): IntPretty { + if (!(target instanceof Dec)) { + target = target.toDec(); + } + + const pretty = new IntPretty(this.toDec().mul(target)); + pretty._options = { + ...this._options, + }; + return pretty; + } + + quo(target: Dec | { toDec(): Dec }): IntPretty { + if (!(target instanceof Dec)) { + target = target.toDec(); + } + + const pretty = new IntPretty(this.toDec().quo(target)); + pretty._options = { + ...this._options, + }; + return pretty; + } + + toDec(): Dec { + if (this.floatingDecimalPointRight === 0) { + return this.dec; + } else if (this.floatingDecimalPointRight > 0) { + return this.dec.mulTruncate( + DecUtils.getTenExponentN(this.floatingDecimalPointRight) + ); + } else { + // Since a decimal in Dec cannot exceed 18, it cannot be computed at once. + let i = -this.floatingDecimalPointRight; + let dec = this.dec; + while (i > 0) { + if (i >= Dec.precision) { + dec = dec.mulTruncate(DecUtils.getTenExponentN(-Dec.precision)); + i -= Dec.precision; + } else { + dec = dec.mulTruncate(DecUtils.getTenExponentN(-(i % Dec.precision))); + break; + } + } + return dec; + } + } + + toString(): string { + return this.toStringWithSymbols("", ""); + } + + toStringWithSymbols(prefix: string, suffix: string): string { + const dec = this.toDec(); + + if ( + this._options.inequalitySymbol && + !dec.isZero() && + dec.abs().lt(DecUtils.getTenExponentN(-this._options.maxDecimals)) + ) { + const isNeg = dec.isNegative(); + + return `${isNeg ? ">" : "<"}${this._options.inequalitySymbolSeparator}${ + isNeg ? "-" : "" + }${prefix}${DecUtils.getTenExponentN(-this._options.maxDecimals).toString( + this._options.maxDecimals, + this._options.locale + )}${suffix}`; + } + + let result: string; + if (!this._options.shrink) { + result = dec.toString(this._options.maxDecimals, this._options.locale); + } else { + result = CoinUtils.shrinkDecimals( + dec, + 0, + this._options.maxDecimals, + this._options.locale + ); + } + if (this._options.trim) { + result = DecUtils.trim(result); + } + + const isNeg = result.charAt(0) === "-"; + if (isNeg) { + result = result.slice(1); + } + + return `${isNeg ? "-" : ""}${prefix}${result}${suffix}`; + } + + clone(): IntPretty { + // doing a constructor call is slow, so we use this method instead + return Object.setPrototypeOf( + { dec: this.dec, floatingDecimalPointRight: this.floatingDecimalPointRight, _options: { ...this._options } }, + IntPretty.prototype + ); + } +} diff --git a/packages/unit/src/int.spec.ts b/packages/unit/src/int.spec.ts new file mode 100644 index 0000000000..1c6d569267 --- /dev/null +++ b/packages/unit/src/int.spec.ts @@ -0,0 +1,213 @@ +/* eslint-disable @typescript-eslint/no-loss-of-precision */ +import { Dec } from "./decimal"; +import { Int, Uint } from "./int"; + +describe("Test Int/Uint", () => { + // (2 ** 256) - 1 + const maxInt = + "115792089237316195423570985008687907853269984665640564039457584007913129639935"; + // 2 ** 256 + const overflowedInt = + "115792089237316195423570985008687907853269984665640564039457584007913129639936"; + + it("Test parsing Int", () => { + expect(new Int(0).toString()).toBe("0"); + expect(new Int(-0).toString()).toBe("0"); + expect(new Int(1).toString()).toBe("1"); + expect(new Int(-1).toString()).toBe("-1"); + expect(new Int("-123").toString()).toBe("-123"); + + expect(new Int(maxInt).toString()).toBe(maxInt); + expect(new Int("-" + maxInt).toString()).toBe("-" + maxInt); + + expect(() => new Int("1.1")).toThrow(); + expect(() => new Int("1.0")).toThrow(); + expect(() => new Int(1.1)).toThrow(); + expect(() => new Int("-1.1")).toThrow(); + + expect(() => new Int("str")).toThrow(); + }); + + it("Test Int/Uint toDec", () => { + expect(new Int(0).toDec().toString()).toBe(new Dec(0).toString()); + expect(new Uint(0).toDec().toString()).toBe(new Dec(0).toString()); + + expect(new Int(123).toDec().toString()).toBe(new Dec(123).toString()); + expect(new Uint(123).toDec().toString()).toBe(new Dec(123).toString()); + + expect(new Int(-123).toDec().toString()).toBe(new Dec(-123).toString()); + }); + + it("Test Int/Uint overflow", () => { + expect(() => new Int(overflowedInt)).toThrow(); + expect(() => new Int("-" + overflowedInt)).toThrow(); + + const max = new Int(maxInt); + expect(() => max.add(new Int(1))).toThrow(); + const min = new Int("-" + maxInt); + expect(() => min.sub(new Int(1))).toThrow(); + + expect(() => new Uint(overflowedInt)).toThrow(); + const uMax = new Uint(maxInt); + expect(() => uMax.add(new Uint(1))).toThrow(); + }); + + it("Test parsing UInt", () => { + expect(new Uint(0).toString()).toBe("0"); + expect(new Uint(-0).toString()).toBe("0"); + expect(new Uint(1).toString()).toBe("1"); + + expect(new Uint(maxInt).toString()).toBe(maxInt); + + expect(() => new Uint("1.1")).toThrow(); + expect(() => new Uint("1.0")).toThrow(); + expect(() => new Uint(1.1)).toThrow(); + expect(() => new Uint("-1.1")).toThrow(); + + expect(() => new Uint("str")).toThrow(); + }); + + it("Test UInt overflow", () => { + expect(() => new Int(overflowedInt)).toThrow(); + + const max = new Int(maxInt); + expect(() => max.add(new Int(1))).toThrow(); + }); + + it("Test Uint can not be negative", () => { + expect(() => new Uint(-1)).toThrow(); + expect(() => new Uint("-123")).toThrow(); + + const uint = new Uint(0); + expect(() => uint.sub(new Uint(1))).toThrow(); + }); + + it("Test Int isNegative/isPositive/isZero", () => { + expect(new Int(1).isPositive()).toBe(true); + expect(new Int(1).isNegative()).toBe(false); + + expect(new Int(-1).isPositive()).toBe(false); + expect(new Int(-1).isNegative()).toBe(true); + + expect(new Int(0).isZero()).toBe(true); + expect(new Int(1).isZero()).toBe(false); + expect(new Int(-1).isZero()).toBe(false); + }); + + it("Test Uint isZero", () => { + expect(new Uint(0).isZero()).toBe(true); + expect(new Uint(1).isZero()).toBe(false); + }); + + it("Test Int computation", () => { + const int1 = new Int(1); + const int2 = new Int(2); + const int3 = new Int(3); + + expect(int1.add(int2).toString()).toBe("3"); + + expect(int1.sub(int2).toString()).toBe("-1"); + expect(int2.sub(int1).toString()).toBe("1"); + + expect(int1.mul(int2).toString()).toBe("2"); + + expect(int1.div(int2).toString()).toBe("0"); + expect(int2.div(int1).toString()).toBe("2"); + expect(int3.div(int2).toString()).toBe("1"); + + expect(int1.mod(int2).toString()).toBe("1"); + expect(int2.mod(int1).toString()).toBe("0"); + expect(int3.mod(int2).toString()).toBe("1"); + + expect(int1.neg().toString()).toBe("-1"); + expect(int1.neg().abs().toString()).toBe("1"); + expect(int1.neg().absUInt().toString()).toBe("1"); + + expect(int1.pow(int3.absUInt()).toString()).toBe("1"); + expect(int2.pow(int3.absUInt()).toString()).toBe("8"); + }); + + it("Test Uint computation", () => { + const int1 = new Uint(1); + const int2 = new Uint(2); + const int3 = new Uint(3); + + expect(int1.add(int2).toString()).toBe("3"); + + expect(() => int1.sub(int2).toString()).toThrow(); + expect(int2.sub(int1).toString()).toBe("1"); + + expect(int1.mul(int2).toString()).toBe("2"); + + expect(int1.div(int2).toString()).toBe("0"); + expect(int2.div(int1).toString()).toBe("2"); + expect(int3.div(int2).toString()).toBe("1"); + + expect(int1.mod(int2).toString()).toBe("1"); + expect(int2.mod(int1).toString()).toBe("0"); + expect(int3.mod(int2).toString()).toBe("1"); + + expect(int1.pow(int3).toString()).toBe("1"); + expect(int2.pow(int3).toString()).toBe("8"); + }); + + it("Test Int/Uint comparison", () => { + const int1 = new Int(1); + const int2 = new Int(2); + + expect(int1.gt(int2)).toBe(false); + expect(int1.gte(int1)).toBe(true); + + expect(int1.lt(int2)).toBe(true); + expect(int1.lte(int1)).toBe(true); + + expect(int1.equals(int2)).toBe(false); + expect(int1.equals(int1)).toBe(true); + + const uint1 = new Uint(1); + const uint2 = new Uint(2); + + expect(uint1.gt(uint2)).toBe(false); + expect(uint1.gte(uint1)).toBe(true); + + expect(uint1.lt(uint2)).toBe(true); + expect(uint1.lte(uint1)).toBe(true); + + expect(uint1.equals(uint2)).toBe(false); + expect(uint1.equals(uint1)).toBe(true); + }); + + it("Test Int/Uint from exponent number", () => { + const tests: { + num: number; + str: string; + expect: Int | Uint; + }[] = [ + { + num: 12345678901234567890123, + str: "1.2345678901234568e+22", + expect: new Int("12345678901234568000000"), + }, + { + num: -12345678901234567890123, + str: "-1.2345678901234568e+22", + expect: new Int("-12345678901234568000000"), + }, + { + num: 12345678901234567890123, + str: "1.2345678901234568e+22", + expect: new Uint("12345678901234568000000"), + }, + ]; + + for (const test of tests) { + expect(test.num.toString()).toBe(test.str); + + if (test.expect instanceof Int) { + expect(new Int(test.num).equals(test.expect)).toBe(true); + } else { + expect(new Uint(test.num).equals(test.expect)).toBe(true); + } + } + }); +}); diff --git a/packages/unit/src/int.ts b/packages/unit/src/int.ts new file mode 100644 index 0000000000..02dde05eea --- /dev/null +++ b/packages/unit/src/int.ts @@ -0,0 +1,231 @@ +import bigInteger from "big-integer"; + +import { Dec } from "./decimal"; +import { + exponentDecStringToDecString, + isExponentDecString, + isValidIntegerString, +} from "./etc"; + +export class Int { + // (2 ** 256) - 1 + protected static maxInt = bigInteger( + "115792089237316195423570985008687907853269984665640564039457584007913129639935" + ); + + protected int: bigInteger.BigInteger; + + /** + * @param int - Parse a number | bigInteger | string into a bigInt. + */ + constructor(int: bigInteger.BigNumber) { + if (typeof int === "number") { + int = int.toString(); + } + + if (typeof int === "string") { + if (!isValidIntegerString(int)) { + if (isExponentDecString(int)) { + int = exponentDecStringToDecString(int); + } else { + throw new Error(`invalid integer: ${int}`); + } + } + + this.int = bigInteger(int); + } else if (typeof int === "bigint") { + this.int = bigInteger(int); + } else { + this.int = bigInteger(int); + } + + this.checkBitLen(); + } + + protected checkBitLen(): void { + if (this.int.abs().gt(Int.maxInt)) { + throw new Error(`Integer out of range ${this.int.toString()}`); + } + } + + public toString(): string { + return this.int.toString(10); + } + + public isNegative(): boolean { + return this.int.isNegative(); + } + + public isPositive(): boolean { + return this.int.isPositive(); + } + + public isZero(): boolean { + return this.int.eq(bigInteger(0)); + } + + public equals(i: Int): boolean { + return this.int.equals(i.int); + } + + public gt(i: Int): boolean { + return this.int.gt(i.int); + } + + public gte(i: Int): boolean { + return this.int.greaterOrEquals(i.int); + } + + public lt(i: Int): boolean { + return this.int.lt(i.int); + } + + public lte(i: Int): boolean { + return this.int.lesserOrEquals(i.int); + } + + public abs(): Int { + return new Int(this.int.abs()); + } + + public absUInt(): Uint { + return new Uint(this.int.abs()); + } + + public add(i: Int): Int { + return new Int(this.int.add(i.int)); + } + + public sub(i: Int): Int { + return new Int(this.int.subtract(i.int)); + } + + public mul(i: Int): Int { + return new Int(this.int.multiply(i.int)); + } + + public div(i: Int): Int { + return new Int(this.int.divide(i.int)); + } + + public mod(i: Int): Int { + return new Int(this.int.mod(i.int)); + } + + public neg(): Int { + return new Int(this.int.negate()); + } + + public pow(i: Uint): Int { + return new Int(this.int.pow(i.toBigNumber())); + } + + public toDec(): Dec { + return new Dec(this); + } + + public toBigNumber(): bigInteger.BigInteger { + return this.int; + } +} + +export class Uint { + protected uint: bigInteger.BigInteger; + + /** + * @param uint - Parse a number | bigInteger | string into a bigUint. + */ + constructor(uint: bigInteger.BigNumber) { + if (typeof uint === "number") { + uint = uint.toString(); + } + + if (typeof uint === "string") { + if (!isValidIntegerString(uint)) { + if (isExponentDecString(uint)) { + uint = exponentDecStringToDecString(uint); + } else { + throw new Error(`invalid integer: ${uint}`); + } + } + + this.uint = bigInteger(uint); + } else if (typeof uint === "bigint") { + this.uint = bigInteger(uint); + } else { + this.uint = bigInteger(uint); + } + + if (this.uint.isNegative()) { + throw new TypeError("Uint should not be negative"); + } + + this.checkBitLen(); + } + + protected checkBitLen(): void { + if (this.uint.abs().bitLength().gt(256)) { + throw new Error(`Integer out of range ${this.uint.toString()}`); + } + } + + public toString(): string { + return this.uint.toString(10); + } + + public isZero(): boolean { + return this.uint.eq(bigInteger(0)); + } + + public equals(i: Uint): boolean { + return this.uint.equals(i.uint); + } + + public gt(i: Uint): boolean { + return this.uint.gt(i.uint); + } + + public gte(i: Uint): boolean { + return this.uint.greaterOrEquals(i.uint); + } + + public lt(i: Uint): boolean { + return this.uint.lt(i.uint); + } + + public lte(i: Uint): boolean { + return this.uint.lesserOrEquals(i.uint); + } + + public add(i: Uint): Uint { + return new Uint(this.uint.add(i.uint)); + } + + public sub(i: Uint): Uint { + return new Uint(this.uint.subtract(i.uint)); + } + + public mul(i: Uint): Uint { + return new Uint(this.uint.multiply(i.uint)); + } + + public div(i: Uint): Uint { + return new Uint(this.uint.divide(i.uint)); + } + + public mod(i: Uint): Uint { + return new Uint(this.uint.mod(i.uint)); + } + + public pow(i: Uint): Uint { + return new Uint(this.uint.pow(i.toBigNumber())); + } + + public toDec(): Dec { + return new Dec(new Int(this.toString())); + } + + public toBigNumber(): bigInteger.BigInteger { + return this.uint; + } +} diff --git a/packages/unit/src/price-pretty.spec.ts b/packages/unit/src/price-pretty.spec.ts new file mode 100644 index 0000000000..4f6b7990a5 --- /dev/null +++ b/packages/unit/src/price-pretty.spec.ts @@ -0,0 +1,143 @@ +import { Dec } from "./decimal"; +import { PricePretty } from "./price-pretty"; + +describe("Test PricePretty", () => { + it("Basic test for PricePretty", () => { + const pretty = new PricePretty( + { + currency: "usd", + symbol: "$", + maxDecimals: 2, + locale: "en-US", + }, + new Dec("12.1234") + ); + + expect(pretty.toString()).toBe("$12.1"); + expect(pretty.increasePrecision(1).toString()).toBe("$1.21"); + expect(pretty.decreasePrecision(1).toString()).toBe("$121"); + expect(pretty.moveDecimalPointLeft(1).toString()).toBe("$1.21"); + expect(pretty.moveDecimalPointRight(1).toString()).toBe("$121"); + + expect(pretty.add(new Dec("0.1")).toString()).toBe("$12.2"); + expect(pretty.sub(new Dec("0.1")).toString()).toBe("$12"); + expect(pretty.mul(new Dec("0.1")).toString()).toBe("$1.21"); + expect(pretty.quo(new Dec("0.1")).toString()).toBe("$121"); + + expect( + new PricePretty( + { + currency: "usd", + symbol: "$", + maxDecimals: 2, + locale: "en-US", + }, + new Dec("0") + ).toString() + ).toBe("$0"); + + expect( + new PricePretty( + { + currency: "usd", + symbol: "$", + maxDecimals: 2, + locale: "en-US", + }, + new Dec("-0") + ).toString() + ).toBe("$0"); + + expect( + new PricePretty( + { + currency: "usd", + symbol: "$", + maxDecimals: 2, + locale: "en-US", + }, + new Dec("0.001") + ).toString() + ).toBe("< $0.01"); + + expect( + new PricePretty( + { + currency: "usd", + symbol: "$", + maxDecimals: 2, + locale: "en-US", + }, + new Dec("0.001") + ) + .inequalitySymbol(false) + .toString() + ).toBe("$0"); + + expect( + new PricePretty( + { + currency: "usd", + symbol: "$", + maxDecimals: 2, + locale: "en-US", + }, + new Dec("-0.001") + ).toString() + ).toBe("> -$0.01"); + + expect( + new PricePretty( + { + currency: "usd", + symbol: "$", + maxDecimals: 2, + locale: "en-US", + }, + new Dec("-0.001") + ) + .inequalitySymbol(false) + .toString() + // TODO: Delete the case of "-0". Return "0" + ).toBe("-$0"); + + expect( + new PricePretty( + { + currency: "usd", + symbol: "$", + maxDecimals: 3, + locale: "en-US", + }, + new Dec("0.001") + ).toString() + ).toBe("$0.001"); + + expect( + new PricePretty( + { + currency: "usd", + symbol: "$", + maxDecimals: 3, + locale: "en-US", + }, + new Dec("-0.001") + ).toString() + ).toBe("-$0.001"); + + // PricePretty's maxDecimals behave differently than IntPretty. + expect( + new PricePretty( + { + currency: "usd", + symbol: "$", + maxDecimals: 4, + locale: "en-US", + }, + new Dec("0.001") + ) + .trim(false) + .toString() + ).toBe("$0.001"); + }); +}); diff --git a/packages/unit/src/price-pretty.ts b/packages/unit/src/price-pretty.ts new file mode 100644 index 0000000000..1127dc6895 --- /dev/null +++ b/packages/unit/src/price-pretty.ts @@ -0,0 +1,232 @@ +import { FiatCurrency } from "@keplr-wallet/types"; +import bigInteger from "big-integer"; +import { DeepReadonly } from "utility-types"; + +import { DecUtils } from "./dec-utils"; +import { Dec } from "./decimal"; +import { IntPretty, IntPrettyOptions } from "./int-pretty"; + +export type PricePrettyOptions = { + separator: string; + upperCase: boolean; + lowerCase: boolean; + locale: string; +}; + +export class PricePretty { + protected intPretty: IntPretty; + + protected _options: PricePrettyOptions = { + separator: "", + upperCase: false, + lowerCase: false, + locale: "en-US", + }; + + constructor( + protected _fiatCurrency: FiatCurrency, + protected amount: Dec | { toDec(): Dec } | bigInteger.BigNumber + ) { + this.intPretty = new IntPretty(amount) + .maxDecimals(_fiatCurrency.maxDecimals) + .shrink(true) + .trim(true) + .locale(false) + .inequalitySymbol(true); + + this._options.locale = _fiatCurrency.locale; + } + + get options(): DeepReadonly< + Omit & PricePrettyOptions + > { + return { + ...this.intPretty.options, + ...this._options, + }; + } + + get symbol(): string { + return this._fiatCurrency.symbol; + } + + get fiatCurrency(): FiatCurrency { + return this._fiatCurrency; + } + + separator(str: string): PricePretty { + const pretty = this.clone(); + pretty._options.separator = str; + return pretty; + } + + upperCase(bool: boolean): PricePretty { + const pretty = this.clone(); + pretty._options.upperCase = bool; + pretty._options.lowerCase = !bool; + return pretty; + } + + lowerCase(bool: boolean): PricePretty { + const pretty = this.clone(); + pretty._options.lowerCase = bool; + pretty._options.upperCase = !bool; + return pretty; + } + + moveDecimalPointLeft(delta: number): PricePretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.moveDecimalPointLeft(delta); + return pretty; + } + + moveDecimalPointRight(delta: number): PricePretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.moveDecimalPointRight(delta); + return pretty; + } + + /** + * @deprecated Use`moveDecimalPointLeft` + */ + increasePrecision(delta: number): PricePretty { + return this.moveDecimalPointLeft(delta); + } + + /** + * @deprecated Use`moveDecimalPointRight` + */ + decreasePrecision(delta: number): PricePretty { + return this.moveDecimalPointRight(delta); + } + + maxDecimals(max: number): PricePretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.maxDecimals(max); + return pretty; + } + + inequalitySymbol(bool: boolean): PricePretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.inequalitySymbol(bool); + return pretty; + } + + inequalitySymbolSeparator(str: string): PricePretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.inequalitySymbolSeparator(str); + return pretty; + } + + trim(bool: boolean): PricePretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.trim(bool); + return pretty; + } + + shrink(bool: boolean): PricePretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.shrink(bool); + return pretty; + } + + locale(locale: string): PricePretty { + const pretty = this.clone(); + pretty._options.locale = locale; + return pretty; + } + + /** + * Ready indicates the actual value is ready to show the users. + * Even if the ready option is false, it expects that the value can be shown to users (probably as 0). + * The method that returns prettied value may return `undefined` or `null` if the value is not ready. + * But, alternatively, it can return the 0 value that can be shown the users anyway, but indicates that the value is not ready. + * @param bool + */ + ready(bool: boolean): PricePretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.ready(bool); + return pretty; + } + + get isReady(): boolean { + return this.intPretty.isReady; + } + + add(target: Dec | { toDec(): Dec }): PricePretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.add(target); + return pretty; + } + + sub(target: Dec | { toDec(): Dec }): PricePretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.sub(target); + return pretty; + } + + mul(target: Dec | { toDec(): Dec }): PricePretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.mul(target); + return pretty; + } + + quo(target: Dec | { toDec(): Dec }): PricePretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.quo(target); + return pretty; + } + + toDec(): Dec { + return this.intPretty.toDec(); + } + + toString(): string { + let symbol = this.symbol; + if (this._options.upperCase) { + symbol = symbol.toUpperCase(); + } + if (this._options.lowerCase) { + symbol = symbol.toLowerCase(); + } + + const dec = this.toDec(); + const options = this.options; + + if ( + options.inequalitySymbol && + !dec.isZero() && + dec.abs().lt(DecUtils.getTenExponentN(-options.maxDecimals)) + ) { + return this.intPretty.toStringWithSymbols( + `${symbol}${this._options.separator}`, + "" + ); + } + + let localeString = parseFloat(this.intPretty.toString()).toLocaleString( + options.locale, + { + maximumFractionDigits: options.maxDecimals, + } + ); + + const isNeg = localeString.charAt(0) === "-"; + if (isNeg) { + localeString = localeString.slice(1); + } + + return `${isNeg ? "-" : ""}${symbol}${ + this._options.separator + }${localeString}`; + } + + clone(): PricePretty { + const pretty = new PricePretty(this._fiatCurrency, this.amount); + pretty._options = { + ...this._options, + }; + pretty.intPretty = this.intPretty.clone(); + return pretty; + } +} diff --git a/packages/unit/src/rate-pretty.spec.ts b/packages/unit/src/rate-pretty.spec.ts new file mode 100644 index 0000000000..ca8e04489c --- /dev/null +++ b/packages/unit/src/rate-pretty.spec.ts @@ -0,0 +1,52 @@ +import { Dec } from "./decimal"; +import { RatePretty } from "./rate-pretty"; + +describe("Test RatePretty", () => { + it("Basic test for RatePretty", () => { + const pretty = new RatePretty(new Dec("0.3")); + + expect(pretty.toDec().equals(new Dec("0.3"))).toBe(true); + expect(pretty.toDec().toString(1)).toBe("0.3"); + + expect(pretty.toString()).toBe("30%"); + expect(pretty.moveDecimalPointLeft(1).toString()).toBe("3%"); + expect(pretty.moveDecimalPointRight(1).toString()).toBe("300%"); + + expect(pretty.add(new Dec("0.1")).toString()).toBe("40%"); + expect(pretty.add(new Dec("0.1")).toDec().toString(1)).toBe("0.4"); + expect(pretty.sub(new Dec("0.1")).toString()).toBe("20%"); + expect(pretty.sub(new Dec("0.1")).toDec().toString(1)).toBe("0.2"); + expect(pretty.mul(new Dec("0.1")).toString()).toBe("3%"); + expect(pretty.mul(new Dec("0.1")).toDec().toString(2)).toBe("0.03"); + expect(pretty.quo(new Dec("0.1")).toString()).toBe("300%"); + expect(pretty.quo(new Dec("0.1")).toDec().toString(1)).toBe("3.0"); + + expect(new RatePretty(new Dec("0.001")).toString()).toBe("0.1%"); + expect(new RatePretty(new Dec("0.00001")).toString()).toBe("0.001%"); + expect(new RatePretty(new Dec("0.000001")).toString()).toBe("< 0.001%"); + + expect(new RatePretty(new Dec("0")).toString()).toBe("0%"); + expect(new RatePretty(new Dec("-0")).toString()).toBe("0%"); + + expect( + new RatePretty(new Dec("0.000001")).separator(" ").symbol("?").toString() + ).toBe("< 0.001 ?"); + + expect( + new RatePretty(new Dec("0.000001")).inequalitySymbol(false).toString() + ).toBe("0%"); + expect( + new RatePretty(new Dec("0.000001")) + .inequalitySymbol(false) + .maxDecimals(4) + .toString() + ).toBe("0.0001%"); + + expect(new RatePretty(new Dec("-0.000001")).toString()).toBe("> -0.001%"); + + expect( + new RatePretty(new Dec("-0.000001")).inequalitySymbol(false).toString() + // TODO: Delete the case of "-0". Return "0" + ).toBe("-0%"); + }); +}); diff --git a/packages/unit/src/rate-pretty.ts b/packages/unit/src/rate-pretty.ts new file mode 100644 index 0000000000..fd113392d1 --- /dev/null +++ b/packages/unit/src/rate-pretty.ts @@ -0,0 +1,166 @@ +import bigInteger from "big-integer"; +import { DeepReadonly } from "utility-types"; + +import { Dec } from "./decimal"; +import { IntPretty, IntPrettyOptions } from "./int-pretty"; + +export type RatePrettyOptions = { + separator: string; + symbol: string; +}; + +/** + * RatePretty treats `Dec` in rate form for easy calculation, and displays it as a percentage to the user by using toString(). + * By default, if the value is less than maxDeciamls, it is displayed using an inequality sign (Ex. < 0.001%) + */ +export class RatePretty { + protected intPretty: IntPretty; + + protected _options: RatePrettyOptions = { + separator: "", + symbol: "%", + }; + + constructor(protected amount: Dec | { toDec(): Dec } | bigInteger.BigNumber) { + this.intPretty = new IntPretty(amount); + + this.intPretty = this.intPretty + .maxDecimals(3) + .shrink(false) + .trim(true) + .locale(true) + .inequalitySymbol(true); + } + + get options(): DeepReadonly< + Omit & RatePrettyOptions + > { + return { + ...this.intPretty.options, + ...this._options, + }; + } + + separator(str: string): RatePretty { + const pretty = this.clone(); + pretty._options.separator = str; + return pretty; + } + + symbol(str: string): RatePretty { + const pretty = this.clone(); + pretty._options.symbol = str; + return pretty; + } + + moveDecimalPointLeft(delta: number): RatePretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.moveDecimalPointLeft(delta); + return pretty; + } + + moveDecimalPointRight(delta: number): RatePretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.moveDecimalPointRight(delta); + return pretty; + } + + maxDecimals(max: number): RatePretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.maxDecimals(max); + return pretty; + } + + inequalitySymbol(bool: boolean): RatePretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.inequalitySymbol(bool); + return pretty; + } + + inequalitySymbolSeparator(str: string): RatePretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.inequalitySymbolSeparator(str); + return pretty; + } + + trim(bool: boolean): RatePretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.trim(bool); + return pretty; + } + + shrink(bool: boolean): RatePretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.shrink(bool); + return pretty; + } + + locale(locale: boolean): RatePretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.locale(locale); + return pretty; + } + + /** + * Ready indicates the actual value is ready to show the users. + * Even if the ready option is false, it expects that the value can be shown to users (probably as 0). + * The method that returns prettied value may return `undefined` or `null` if the value is not ready. + * But, alternatively, it can return the 0 value that can be shown the users anyway, but indicates that the value is not ready. + * @param bool + */ + ready(bool: boolean): RatePretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.ready(bool); + return pretty; + } + + get isReady(): boolean { + return this.intPretty.isReady; + } + + add(target: Dec | { toDec(): Dec }): RatePretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.add(target); + return pretty; + } + + sub(target: Dec | { toDec(): Dec }): RatePretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.sub(target); + return pretty; + } + + mul(target: Dec | { toDec(): Dec }): RatePretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.mul(target); + return pretty; + } + + quo(target: Dec | { toDec(): Dec }): RatePretty { + const pretty = this.clone(); + pretty.intPretty = pretty.intPretty.quo(target); + return pretty; + } + + toDec(): Dec { + return this.intPretty.toDec(); + } + + toString(): string { + return this.intPretty + .moveDecimalPointRight(2) + .toStringWithSymbols( + "", + `${this._options.separator}${this._options.symbol}` + ); + } + + clone(): RatePretty { + const pretty = new RatePretty(this.amount); + pretty._options = { + ...this._options, + }; + pretty.intPretty = this.intPretty.clone(); + return pretty; + } +} diff --git a/packages/unit/tsconfig.json b/packages/unit/tsconfig.json new file mode 100644 index 0000000000..0e28050606 --- /dev/null +++ b/packages/unit/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "baseUrl": ".", + "outDir": "build", + "declaration": true, + "rootDir": "src" + }, + "include": ["src/**/*"] +} diff --git a/packages/utils/package.json b/packages/utils/package.json index 982b3405d4..b1d67a0390 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -15,8 +15,8 @@ }, "dependencies": { "@cosmjs/encoding": "0.32.3", - "@keplr-wallet/unit": "0.10.24-ibc.go.v7.hot.fix", "@osmosis-labs/types": "^1.0.0", + "@osmosis-labs/unit": "0.10.24-ibc.go.v7.hot.fix", "bitcoinjs-lib": "^7.0.0-rc.0", "sha.js": "^2.4.11", "viem": "^2.21.19" diff --git a/packages/utils/src/__tests__/compare.spec.ts b/packages/utils/src/__tests__/compare.spec.ts index 0aadeade8b..989354d3f7 100644 --- a/packages/utils/src/__tests__/compare.spec.ts +++ b/packages/utils/src/__tests__/compare.spec.ts @@ -1,4 +1,4 @@ -import { Dec, Int } from "@keplr-wallet/unit"; +import { Dec, Int } from "@osmosis-labs/unit"; import cases from "jest-in-case"; import { diff --git a/packages/utils/src/__tests__/math.spec.ts b/packages/utils/src/__tests__/math.spec.ts index 7a322b1c52..10fddf1192 100644 --- a/packages/utils/src/__tests__/math.spec.ts +++ b/packages/utils/src/__tests__/math.spec.ts @@ -1,4 +1,4 @@ -import { Dec } from "@keplr-wallet/unit"; +import { Dec } from "@osmosis-labs/unit"; import cases from "jest-in-case"; import { sum } from "../math"; diff --git a/packages/utils/src/bitcoin.ts b/packages/utils/src/bitcoin.ts index 68035ab0eb..033900d082 100644 --- a/packages/utils/src/bitcoin.ts +++ b/packages/utils/src/bitcoin.ts @@ -46,5 +46,9 @@ export const getnBTCMinimalDenom = ({ export function getNomicRelayerUrl({ env }: { env: "mainnet" | "testnet" }) { return env === "testnet" ? ["https://testnet-relayer.nomic.io:8443"] - : ["https://relayer.nomic.mappum.io:8443"]; + : [ + "https://btc-relayer.nomic.io", + "https://btc-relay.nomic-main.ccvalidators.com", + "https://nomic-relayer.forbole.com", + ]; } diff --git a/packages/utils/src/coin.ts b/packages/utils/src/coin.ts index ccea55fb3d..33d58bc53d 100644 --- a/packages/utils/src/coin.ts +++ b/packages/utils/src/coin.ts @@ -1,4 +1,4 @@ -import { CoinPretty } from "@keplr-wallet/unit"; +import { CoinPretty } from "@osmosis-labs/unit"; import { sum } from "./math"; diff --git a/packages/utils/src/compare.ts b/packages/utils/src/compare.ts index d1dc02d1ca..27b90b938e 100644 --- a/packages/utils/src/compare.ts +++ b/packages/utils/src/compare.ts @@ -1,4 +1,4 @@ -import { Dec, Int } from "@keplr-wallet/unit"; +import { Dec, Int } from "@osmosis-labs/unit"; import { isNil } from "./common-utils"; diff --git a/packages/utils/src/math.ts b/packages/utils/src/math.ts index cabb58695c..60363a05f1 100644 --- a/packages/utils/src/math.ts +++ b/packages/utils/src/math.ts @@ -1,4 +1,4 @@ -import { Dec } from "@keplr-wallet/unit"; +import { Dec } from "@osmosis-labs/unit"; export function normalize( val: number, diff --git a/packages/web/.env b/packages/web/.env index cf30c16291..595afd1a9b 100644 --- a/packages/web/.env +++ b/packages/web/.env @@ -23,8 +23,8 @@ NEXT_PUBLIC_SIDECAR_BASE_URL=https://sqs.osmosis.zone # NEXT_PUBLIC_OSMOSIS_CHAIN_NAME_OVERWRITE=Osmosis (Testnet v13.X latest) # NEXT_PUBLIC_WALLETCONNECT_PROJECT_KEY=YOUR_WALLETCONNECT_PROJECT_KEY # NEXT_PUBLIC_WALLETCONNECT_RELAY_URL=wss://relay.walletconnect.com -# NEXT_PUBLIC_TIMESERIES_DATA_URL=https://stage-proxy-data-api.osmosis-labs.workers.dev -# NEXT_PUBLIC_INDEXER_DATA_URL=https://stage-proxy-data-indexer.osmosis-labs.workers.dev +# NEXT_PUBLIC_TIMESERIES_DATA_URL=https://data.stage.osmosis.zone +# NEXT_PUBLIC_INDEXER_DATA_URL=https://data.stage.osmosis.zone # Twitter api config, it's only used on server TWITTER_API_URL=https://api.twitter.com/ diff --git a/packages/web/.prettierignore b/packages/web/.prettierignore index f682f5a7ab..e299b0a860 100644 --- a/packages/web/.prettierignore +++ b/packages/web/.prettierignore @@ -29,3 +29,5 @@ public/tradingview/**/* public/datafeeds/**/* *.zip + +tsconfig.script.tsbuildinfo \ No newline at end of file diff --git a/packages/web/components/alert/__tests__/prettify.spec.ts b/packages/web/components/alert/__tests__/prettify.spec.ts index 90e0bb343c..b5a5c04773 100644 --- a/packages/web/components/alert/__tests__/prettify.spec.ts +++ b/packages/web/components/alert/__tests__/prettify.spec.ts @@ -1,4 +1,4 @@ -import { Dec } from "@keplr-wallet/unit"; +import { Dec } from "@osmosis-labs/unit"; import cases from "jest-in-case"; import { diff --git a/packages/web/components/alert/prettify.ts b/packages/web/components/alert/prettify.ts index 7f4038cdfd..e73cb6394c 100644 --- a/packages/web/components/alert/prettify.ts +++ b/packages/web/components/alert/prettify.ts @@ -1,9 +1,9 @@ import { AppCurrency } from "@keplr-wallet/types"; -import { CoinPretty, Dec, Int } from "@keplr-wallet/unit"; import { isInsufficientFeeError, isSlippageErrorMessage, } from "@osmosis-labs/tx"; +import { CoinPretty, Dec, Int } from "@osmosis-labs/unit"; import { MultiLanguageT } from "~/hooks"; diff --git a/packages/web/components/assets/price.tsx b/packages/web/components/assets/price.tsx index 4158141ceb..29549c1fdd 100644 --- a/packages/web/components/assets/price.tsx +++ b/packages/web/components/assets/price.tsx @@ -1,6 +1,6 @@ -import { PricePretty, RatePretty } from "@keplr-wallet/unit"; -import { Dec } from "@keplr-wallet/unit"; import { CommonPriceChartTimeFrame } from "@osmosis-labs/server"; +import { PricePretty, RatePretty } from "@osmosis-labs/unit"; +import { Dec } from "@osmosis-labs/unit"; import classNames from "classnames"; import { FunctionComponent, useMemo } from "react"; diff --git a/packages/web/components/assets/rate-ring.tsx b/packages/web/components/assets/rate-ring.tsx index de78400dfa..99329fc383 100644 --- a/packages/web/components/assets/rate-ring.tsx +++ b/packages/web/components/assets/rate-ring.tsx @@ -1,4 +1,4 @@ -import { RatePretty } from "@keplr-wallet/unit"; +import { RatePretty } from "@osmosis-labs/unit"; import classNames from "classnames"; import { FunctionComponent } from "react"; diff --git a/packages/web/components/assets/types.ts b/packages/web/components/assets/types.ts index 0595d67f45..e06d23f0c2 100644 --- a/packages/web/components/assets/types.ts +++ b/packages/web/components/assets/types.ts @@ -1,4 +1,4 @@ -import { RatePretty } from "@keplr-wallet/unit"; +import { RatePretty } from "@osmosis-labs/unit"; export type PoolAssetInfo = { coinDenom: string; diff --git a/packages/web/components/bridge/amount-and-review-screen.tsx b/packages/web/components/bridge/amount-and-review-screen.tsx index 77982cd28b..2f4e565286 100644 --- a/packages/web/components/bridge/amount-and-review-screen.tsx +++ b/packages/web/components/bridge/amount-and-review-screen.tsx @@ -1,5 +1,5 @@ -import { CoinPretty } from "@keplr-wallet/unit"; import type { Bridge, BridgeSupportedAsset } from "@osmosis-labs/bridge"; +import { CoinPretty } from "@osmosis-labs/unit"; import { isNil, noop } from "@osmosis-labs/utils"; import { observer } from "mobx-react-lite"; import { useMemo, useState } from "react"; diff --git a/packages/web/components/bridge/amount-screen.tsx b/packages/web/components/bridge/amount-screen.tsx index a620ad2e5c..03b07f4581 100644 --- a/packages/web/components/bridge/amount-screen.tsx +++ b/packages/web/components/bridge/amount-screen.tsx @@ -3,8 +3,8 @@ import { DisclosureButton, DisclosurePanel, } from "@headlessui/react"; -import { IntPretty } from "@keplr-wallet/unit"; import { MinimalAsset } from "@osmosis-labs/types"; +import { IntPretty } from "@osmosis-labs/unit"; import { isNil, noop, shorten } from "@osmosis-labs/utils"; import classNames from "classnames"; import { observer } from "mobx-react-lite"; @@ -19,7 +19,7 @@ import { useMemo, useState, } from "react"; -import { useMeasure } from "react-use"; +import { useMeasure, useUnmount } from "react-use"; import { Icon } from "~/components/assets"; import { BridgeReceiveAssetDropdown } from "~/components/bridge/bridge-receive-asset-dropdown"; @@ -41,7 +41,7 @@ import { useFeatureFlags, useTranslation, } from "~/hooks"; -import { BridgeScreen } from "~/hooks/bridge"; +import { BridgeScreen, useBridgeStore } from "~/hooks/bridge"; import { useEvmWalletAccount, useSwitchEvmChain } from "~/hooks/evm-wallet"; import { usePrice } from "~/hooks/queries/assets/use-price"; import { BridgeChainWithDisplayInfo } from "~/server/api/routers/bridge-transfer"; @@ -609,6 +609,10 @@ export const AmountScreen = observer( toChain, ]); + useUnmount(() => { + useBridgeStore.getState().setType("quote"); + }); + /** If an asset is disabled */ const areAssetTransfersDisabled = useMemo(() => { return direction === "withdraw" @@ -802,6 +806,7 @@ export const AmountScreen = observer( toChain && toAsset ) { + useBridgeStore.getState().setType("deposit-address"); return ( { return ( - {humanizedRemainingTime?.value}{" "} - {t(humanizedRemainingTime?.unitTranslationKey)} + {displayHumanizedTime({ humanizedTime: humanizedRemainingTime, t })} ); }; diff --git a/packages/web/components/bridge/quote-detail.tsx b/packages/web/components/bridge/quote-detail.tsx index 0c6c32a1f7..2704782e2c 100644 --- a/packages/web/components/bridge/quote-detail.tsx +++ b/packages/web/components/bridge/quote-detail.tsx @@ -1,4 +1,4 @@ -import { DecUtils } from "@keplr-wallet/unit"; +import { DecUtils } from "@osmosis-labs/unit"; import { isNil, shorten } from "@osmosis-labs/utils"; import classNames from "classnames"; import { FunctionComponent, PropsWithChildren } from "react"; diff --git a/packages/web/components/bridge/review-screen.tsx b/packages/web/components/bridge/review-screen.tsx index e8b7d4e3f5..60f161a9a3 100644 --- a/packages/web/components/bridge/review-screen.tsx +++ b/packages/web/components/bridge/review-screen.tsx @@ -3,7 +3,7 @@ import { DisclosureButton, DisclosurePanel, } from "@headlessui/react"; -import { CoinPretty, PricePretty } from "@keplr-wallet/unit"; +import { CoinPretty, PricePretty } from "@osmosis-labs/unit"; import { isNil, shorten } from "@osmosis-labs/utils"; import Image from "next/image"; import Link from "next/link"; diff --git a/packages/web/components/bridge/use-bridge-quotes.ts b/packages/web/components/bridge/use-bridge-quotes.ts index 1d2663f400..79156615eb 100644 --- a/packages/web/components/bridge/use-bridge-quotes.ts +++ b/packages/web/components/bridge/use-bridge-quotes.ts @@ -1,4 +1,3 @@ -import { CoinPretty, Dec, DecUtils, RatePretty } from "@keplr-wallet/unit"; import { Bridge, BridgeAsset, @@ -8,6 +7,7 @@ import { EvmBridgeTransactionRequest, } from "@osmosis-labs/bridge"; import { DeliverTxResponse } from "@osmosis-labs/stores"; +import { CoinPretty, Dec, DecUtils, RatePretty } from "@osmosis-labs/unit"; import { getNomicRelayerUrl, isNil } from "@osmosis-labs/utils"; import dayjs from "dayjs"; import { useCallback, useEffect, useMemo, useState } from "react"; diff --git a/packages/web/components/cards/apr-breakdown.tsx b/packages/web/components/cards/apr-breakdown.tsx index 83dfcc7d00..e1ec16a316 100644 --- a/packages/web/components/cards/apr-breakdown.tsx +++ b/packages/web/components/cards/apr-breakdown.tsx @@ -1,5 +1,5 @@ -import { RatePretty } from "@keplr-wallet/unit"; import type { PoolDataRange, PoolIncentives } from "@osmosis-labs/server"; +import { RatePretty } from "@osmosis-labs/unit"; import classNames from "classnames"; import { FunctionComponent } from "react"; diff --git a/packages/web/components/cards/bond-card.tsx b/packages/web/components/cards/bond-card.tsx index 78285140b3..c3e7659bbd 100644 --- a/packages/web/components/cards/bond-card.tsx +++ b/packages/web/components/cards/bond-card.tsx @@ -1,5 +1,5 @@ -import { CoinPretty, RatePretty } from "@keplr-wallet/unit"; import type { BondDuration } from "@osmosis-labs/server"; +import { CoinPretty, RatePretty } from "@osmosis-labs/unit"; import classNames from "classnames"; import moment from "dayjs"; import { Duration } from "dayjs/plugin/duration"; diff --git a/packages/web/components/cards/estimated-earnings-card.tsx b/packages/web/components/cards/estimated-earnings-card.tsx index 037d22ac40..b2ebfba230 100644 --- a/packages/web/components/cards/estimated-earnings-card.tsx +++ b/packages/web/components/cards/estimated-earnings-card.tsx @@ -1,4 +1,4 @@ -import { CoinPretty, Dec } from "@keplr-wallet/unit"; +import { CoinPretty, Dec } from "@osmosis-labs/unit"; import { observer } from "mobx-react-lite"; import React, { FunctionComponent } from "react"; diff --git a/packages/web/components/cards/my-position/__tests__/expanded.spec.tsx b/packages/web/components/cards/my-position/__tests__/expanded.spec.tsx index fb612ed5a7..baff9b5174 100644 --- a/packages/web/components/cards/my-position/__tests__/expanded.spec.tsx +++ b/packages/web/components/cards/my-position/__tests__/expanded.spec.tsx @@ -1,5 +1,5 @@ -import { CoinPretty, Dec, DecUtils, PricePretty } from "@keplr-wallet/unit"; import { DEFAULT_VS_CURRENCY } from "@osmosis-labs/server"; +import { CoinPretty, Dec, DecUtils, PricePretty } from "@osmosis-labs/unit"; import { render, screen } from "@testing-library/react"; import React from "react"; diff --git a/packages/web/components/cards/my-position/expanded.tsx b/packages/web/components/cards/my-position/expanded.tsx index 0f4aad7e0c..15b4873d8d 100644 --- a/packages/web/components/cards/my-position/expanded.tsx +++ b/packages/web/components/cards/my-position/expanded.tsx @@ -1,9 +1,9 @@ -import { CoinPretty, Dec, PricePretty } from "@keplr-wallet/unit"; import type { PositionHistoricalPerformance, UserPosition, UserPositionDetails, } from "@osmosis-labs/server"; +import { CoinPretty, Dec, PricePretty } from "@osmosis-labs/unit"; import classNames from "classnames"; import moment from "dayjs"; import { observer } from "mobx-react-lite"; diff --git a/packages/web/components/cards/my-position/index.tsx b/packages/web/components/cards/my-position/index.tsx index c7410e456e..6863da35bb 100644 --- a/packages/web/components/cards/my-position/index.tsx +++ b/packages/web/components/cards/my-position/index.tsx @@ -1,5 +1,5 @@ -import { Dec } from "@keplr-wallet/unit"; import type { UserPosition } from "@osmosis-labs/server"; +import { Dec } from "@osmosis-labs/unit"; import classNames from "classnames"; import { observer } from "mobx-react-lite"; import { FunctionComponent, ReactNode, useState } from "react"; diff --git a/packages/web/components/cards/stake-dashboard.tsx b/packages/web/components/cards/stake-dashboard.tsx index 1a0b0d15de..9a3b79af8c 100644 --- a/packages/web/components/cards/stake-dashboard.tsx +++ b/packages/web/components/cards/stake-dashboard.tsx @@ -1,7 +1,7 @@ import { Currency } from "@keplr-wallet/types"; -import { CoinPretty, Dec, DecUtils, PricePretty } from "@keplr-wallet/unit"; import { Staking } from "@osmosis-labs/keplr-stores"; import { DeliverTxResponse } from "@osmosis-labs/stores"; +import { CoinPretty, Dec, DecUtils, PricePretty } from "@osmosis-labs/unit"; import classNames from "classnames"; import { observer } from "mobx-react-lite"; import React, { useCallback, useEffect, useState } from "react"; diff --git a/packages/web/components/cards/stake-info-card.tsx b/packages/web/components/cards/stake-info-card.tsx index 024bf72d91..f69982d4a0 100644 --- a/packages/web/components/cards/stake-info-card.tsx +++ b/packages/web/components/cards/stake-info-card.tsx @@ -1,4 +1,4 @@ -import { CoinPretty, Dec, DecUtils } from "@keplr-wallet/unit"; +import { CoinPretty, Dec, DecUtils } from "@osmosis-labs/unit"; import classNames from "classnames"; import { observer } from "mobx-react-lite"; import Image from "next/image"; diff --git a/packages/web/components/cards/stake-tool.tsx b/packages/web/components/cards/stake-tool.tsx index f6e0c80dd2..ac9221d32f 100644 --- a/packages/web/components/cards/stake-tool.tsx +++ b/packages/web/components/cards/stake-tool.tsx @@ -1,4 +1,4 @@ -import { CoinPretty, Dec } from "@keplr-wallet/unit"; +import { CoinPretty, Dec } from "@osmosis-labs/unit"; import React from "react"; import { useMemo } from "react"; diff --git a/packages/web/components/cards/validator-squad-card.tsx b/packages/web/components/cards/validator-squad-card.tsx index 0c9c16fa3a..0df49ffd36 100644 --- a/packages/web/components/cards/validator-squad-card.tsx +++ b/packages/web/components/cards/validator-squad-card.tsx @@ -1,6 +1,6 @@ -import { CoinPretty, Dec } from "@keplr-wallet/unit"; import { Staking } from "@osmosis-labs/keplr-stores"; import { BondStatus } from "@osmosis-labs/types"; +import { CoinPretty, Dec } from "@osmosis-labs/unit"; import { observer } from "mobx-react-lite"; import React from "react"; import { useCallback, useMemo } from "react"; diff --git a/packages/web/components/chart/asset-breakdown.tsx b/packages/web/components/chart/asset-breakdown.tsx index 4bb0c0172e..ce700b72f1 100644 --- a/packages/web/components/chart/asset-breakdown.tsx +++ b/packages/web/components/chart/asset-breakdown.tsx @@ -1,4 +1,4 @@ -import { CoinPretty, Dec, Int, IntPretty } from "@keplr-wallet/unit"; +import { CoinPretty, Dec, Int, IntPretty } from "@osmosis-labs/unit"; import { truncate } from "@osmosis-labs/utils"; import classNames from "classnames"; import { FunctionComponent } from "react"; diff --git a/packages/web/components/chart/historical-chart.tsx b/packages/web/components/chart/historical-chart.tsx index e6fff6fac2..97848fed37 100644 --- a/packages/web/components/chart/historical-chart.tsx +++ b/packages/web/components/chart/historical-chart.tsx @@ -1,4 +1,4 @@ -import { Dec } from "@keplr-wallet/unit"; +import { Dec } from "@osmosis-labs/unit"; import { AreaData, AreaSeriesOptions, diff --git a/packages/web/components/chart/light-weight-charts/linear-chart.ts b/packages/web/components/chart/light-weight-charts/linear-chart.ts index c140365ae6..7d26d5ccae 100644 --- a/packages/web/components/chart/light-weight-charts/linear-chart.ts +++ b/packages/web/components/chart/light-weight-charts/linear-chart.ts @@ -1,4 +1,4 @@ -import { Dec } from "@keplr-wallet/unit"; +import { Dec } from "@osmosis-labs/unit"; import { AreaData, MouseEventParams, diff --git a/packages/web/components/chart/light-weight-charts/utils.ts b/packages/web/components/chart/light-weight-charts/utils.ts index 379db1d69e..47911e3cef 100644 --- a/packages/web/components/chart/light-weight-charts/utils.ts +++ b/packages/web/components/chart/light-weight-charts/utils.ts @@ -1,4 +1,4 @@ -import { Dec } from "@keplr-wallet/unit"; +import { Dec } from "@osmosis-labs/unit"; import { isBusinessDay, Time } from "lightweight-charts"; import { FormatOptions, formatPretty } from "~/utils/formatter"; diff --git a/packages/web/components/chart/pool-composition.tsx b/packages/web/components/chart/pool-composition.tsx index 148fba6b7c..016b6f9c0f 100644 --- a/packages/web/components/chart/pool-composition.tsx +++ b/packages/web/components/chart/pool-composition.tsx @@ -1,4 +1,4 @@ -import { CoinPretty } from "@keplr-wallet/unit"; +import { CoinPretty } from "@osmosis-labs/unit"; import Image from "next/image"; import { FunctionComponent } from "react"; diff --git a/packages/web/components/chart/price-breakdown.tsx b/packages/web/components/chart/price-breakdown.tsx index f6ac3cd42f..a3bb0b44ee 100644 --- a/packages/web/components/chart/price-breakdown.tsx +++ b/packages/web/components/chart/price-breakdown.tsx @@ -1,4 +1,4 @@ -import { Dec, IntPretty, PricePretty } from "@keplr-wallet/unit"; +import { Dec, IntPretty, PricePretty } from "@osmosis-labs/unit"; import classNames from "classnames"; import { FunctionComponent } from "react"; diff --git a/packages/web/components/chart/price-historical.tsx b/packages/web/components/chart/price-historical.tsx index 6930cfd639..fd581774ac 100644 --- a/packages/web/components/chart/price-historical.tsx +++ b/packages/web/components/chart/price-historical.tsx @@ -1,4 +1,4 @@ -import { Dec } from "@keplr-wallet/unit"; +import { Dec } from "@osmosis-labs/unit"; import { curveNatural } from "@visx/curve"; import { LinearGradient } from "@visx/gradient"; import { ParentSize } from "@visx/responsive"; diff --git a/packages/web/components/cl-deposit-input-group/index.tsx b/packages/web/components/cl-deposit-input-group/index.tsx index 7539a8acc7..56f9065d91 100644 --- a/packages/web/components/cl-deposit-input-group/index.tsx +++ b/packages/web/components/cl-deposit-input-group/index.tsx @@ -1,5 +1,5 @@ import { Currency } from "@keplr-wallet/types"; -import { CoinPretty, Dec, DecUtils, RatePretty } from "@keplr-wallet/unit"; +import { CoinPretty, Dec, DecUtils, RatePretty } from "@osmosis-labs/unit"; import classNames from "classnames"; import { observer } from "mobx-react-lite"; import Image from "next/image"; diff --git a/packages/web/components/complex/add-conc-liquidity.tsx b/packages/web/components/complex/add-conc-liquidity.tsx index 03741587ec..ce4c82e344 100644 --- a/packages/web/components/complex/add-conc-liquidity.tsx +++ b/packages/web/components/complex/add-conc-liquidity.tsx @@ -1,6 +1,6 @@ -import { Dec, DecUtils, PricePretty } from "@keplr-wallet/unit"; import type { Pool } from "@osmosis-labs/server"; import { QuasarVault } from "@osmosis-labs/stores"; +import { Dec, DecUtils, PricePretty } from "@osmosis-labs/unit"; import classNames from "classnames"; import debounce from "debounce"; import { observer } from "mobx-react-lite"; diff --git a/packages/web/components/complex/add-liquidity.tsx b/packages/web/components/complex/add-liquidity.tsx index 69bfe8cee0..6b45f19d92 100644 --- a/packages/web/components/complex/add-liquidity.tsx +++ b/packages/web/components/complex/add-liquidity.tsx @@ -1,6 +1,6 @@ -import { CoinPretty, RatePretty } from "@keplr-wallet/unit"; import { ObservableAddLiquidityConfig } from "@osmosis-labs/stores"; import { Currency } from "@osmosis-labs/types"; +import { CoinPretty, RatePretty } from "@osmosis-labs/unit"; import classNames from "classnames"; import { observer } from "mobx-react-lite"; import { FunctionComponent, ReactNode, useMemo } from "react"; diff --git a/packages/web/components/complex/my-pools-card-grid.tsx b/packages/web/components/complex/my-pools-card-grid.tsx index 3ae21c4d56..c3da91594d 100644 --- a/packages/web/components/complex/my-pools-card-grid.tsx +++ b/packages/web/components/complex/my-pools-card-grid.tsx @@ -1,4 +1,4 @@ -import { RatePretty } from "@keplr-wallet/unit"; +import { RatePretty } from "@osmosis-labs/unit"; import { observer } from "mobx-react-lite"; import { useCallback, useMemo, useRef, useState } from "react"; diff --git a/packages/web/components/complex/orders-history/cells/filled-progress.tsx b/packages/web/components/complex/orders-history/cells/filled-progress.tsx index 31e684a25c..4e9f45b402 100644 --- a/packages/web/components/complex/orders-history/cells/filled-progress.tsx +++ b/packages/web/components/complex/orders-history/cells/filled-progress.tsx @@ -1,5 +1,5 @@ -import { Dec, Int } from "@keplr-wallet/unit"; import type { MappedLimitOrder } from "@osmosis-labs/server"; +import { Dec, Int } from "@osmosis-labs/unit"; import classNames from "classnames"; import React, { useMemo } from "react"; diff --git a/packages/web/components/complex/orders-history/index.tsx b/packages/web/components/complex/orders-history/index.tsx index 5774d4281d..ee1a36176b 100644 --- a/packages/web/components/complex/orders-history/index.tsx +++ b/packages/web/components/complex/orders-history/index.tsx @@ -1,5 +1,5 @@ -import { CoinPretty, Dec, Int, PricePretty } from "@keplr-wallet/unit"; import { DEFAULT_VS_CURRENCY, MappedLimitOrder } from "@osmosis-labs/server"; +import { CoinPretty, Dec, Int, PricePretty } from "@osmosis-labs/unit"; import { useWindowVirtualizer } from "@tanstack/react-virtual"; import classNames from "classnames"; import dayjs from "dayjs"; diff --git a/packages/web/components/complex/orders-history/order-modal.tsx b/packages/web/components/complex/orders-history/order-modal.tsx index d6a19e9bc7..b24f3b6888 100644 --- a/packages/web/components/complex/orders-history/order-modal.tsx +++ b/packages/web/components/complex/orders-history/order-modal.tsx @@ -1,5 +1,5 @@ -import { CoinPretty, Dec, Int, PricePretty } from "@keplr-wallet/unit"; import { DEFAULT_VS_CURRENCY, MappedLimitOrder } from "@osmosis-labs/server"; +import { CoinPretty, Dec, Int, PricePretty } from "@osmosis-labs/unit"; import classNames from "classnames"; import dayjs from "dayjs"; import { observer } from "mobx-react-lite"; diff --git a/packages/web/components/complex/pool/create/cl/add-initial-liquidity.tsx b/packages/web/components/complex/pool/create/cl/add-initial-liquidity.tsx index a983c399e0..ac84f71a81 100644 --- a/packages/web/components/complex/pool/create/cl/add-initial-liquidity.tsx +++ b/packages/web/components/complex/pool/create/cl/add-initial-liquidity.tsx @@ -1,6 +1,6 @@ -import { CoinPretty, Dec, PricePretty } from "@keplr-wallet/unit"; import { DEFAULT_VS_CURRENCY } from "@osmosis-labs/server"; import { MinimalAsset } from "@osmosis-labs/types"; +import { CoinPretty, Dec, PricePretty } from "@osmosis-labs/unit"; import classNames from "classnames"; import { observer } from "mobx-react-lite"; import Image from "next/image"; diff --git a/packages/web/components/complex/pool/create/cl/set-base-info.tsx b/packages/web/components/complex/pool/create/cl/set-base-info.tsx index 2153c9a6d8..e2bbda4502 100644 --- a/packages/web/components/complex/pool/create/cl/set-base-info.tsx +++ b/packages/web/components/complex/pool/create/cl/set-base-info.tsx @@ -8,7 +8,7 @@ import { ListboxOptions, Transition, } from "@headlessui/react"; -import { RatePretty } from "@keplr-wallet/unit"; +import { RatePretty } from "@osmosis-labs/unit"; import { observer } from "mobx-react-lite"; import Image from "next/image"; import React, { Fragment, useState } from "react"; diff --git a/packages/web/components/complex/pool/create/step3-confirm.tsx b/packages/web/components/complex/pool/create/step3-confirm.tsx index 5548fb016d..9a8aadbf60 100644 --- a/packages/web/components/complex/pool/create/step3-confirm.tsx +++ b/packages/web/components/complex/pool/create/step3-confirm.tsx @@ -1,5 +1,5 @@ import { IBCCurrency } from "@keplr-wallet/types"; -import { Dec } from "@keplr-wallet/unit"; +import { Dec } from "@osmosis-labs/unit"; import { observer } from "mobx-react-lite"; import { FunctionComponent, useMemo } from "react"; diff --git a/packages/web/components/complex/portfolio/allocation.tsx b/packages/web/components/complex/portfolio/allocation.tsx index a787e2d068..19d2a910a5 100644 --- a/packages/web/components/complex/portfolio/allocation.tsx +++ b/packages/web/components/complex/portfolio/allocation.tsx @@ -1,5 +1,5 @@ -import { Dec } from "@keplr-wallet/unit"; import type { PortfolioAssets } from "@osmosis-labs/server"; +import { Dec } from "@osmosis-labs/unit"; import classNames from "classnames"; import { FunctionComponent, useEffect, useMemo, useState } from "react"; diff --git a/packages/web/components/complex/portfolio/assets-overview.tsx b/packages/web/components/complex/portfolio/assets-overview.tsx index 0902734513..558eab11c1 100644 --- a/packages/web/components/complex/portfolio/assets-overview.tsx +++ b/packages/web/components/complex/portfolio/assets-overview.tsx @@ -1,11 +1,11 @@ import { Transition } from "@headlessui/react"; -import { PricePretty } from "@keplr-wallet/unit"; -import { Dec, RatePretty } from "@keplr-wallet/unit"; import type { ChartPortfolioOverTimeResponse, Range, } from "@osmosis-labs/server"; import { DEFAULT_VS_CURRENCY } from "@osmosis-labs/server"; +import { PricePretty } from "@osmosis-labs/unit"; +import { Dec, RatePretty } from "@osmosis-labs/unit"; import classNames from "classnames"; import dayjs from "dayjs"; import { AreaData, Time } from "lightweight-charts"; @@ -157,7 +157,7 @@ export const AssetsOverview: FunctionComponent< value: undefined, }); - const [range, setRange] = useState("1d"); + const [range, setRange] = useState("7d"); const { data: portfolioOverTimeData, diff --git a/packages/web/components/complex/portfolio/open-orders.tsx b/packages/web/components/complex/portfolio/open-orders.tsx index 518a099b7b..ee62ed1682 100644 --- a/packages/web/components/complex/portfolio/open-orders.tsx +++ b/packages/web/components/complex/portfolio/open-orders.tsx @@ -1,5 +1,5 @@ -import { CoinPretty, Dec, Int, PricePretty } from "@keplr-wallet/unit"; import { DEFAULT_VS_CURRENCY } from "@osmosis-labs/server"; +import { CoinPretty, Dec, Int, PricePretty } from "@osmosis-labs/unit"; import React, { FunctionComponent } from "react"; import { FallbackImg } from "~/components/assets"; diff --git a/packages/web/components/complex/portfolio/performance.tsx b/packages/web/components/complex/portfolio/performance.tsx index 8c31f95287..2d204b5786 100644 --- a/packages/web/components/complex/portfolio/performance.tsx +++ b/packages/web/components/complex/portfolio/performance.tsx @@ -1,5 +1,5 @@ -import { PricePretty } from "@keplr-wallet/unit"; -import { RatePretty } from "@keplr-wallet/unit"; +import { PricePretty } from "@osmosis-labs/unit"; +import { RatePretty } from "@osmosis-labs/unit"; import { FunctionComponent } from "react"; import { PriceChange } from "~/components/assets/price"; diff --git a/packages/web/components/complex/remove-liquidity.tsx b/packages/web/components/complex/remove-liquidity.tsx index 9c5c53d6a7..acfede04d3 100644 --- a/packages/web/components/complex/remove-liquidity.tsx +++ b/packages/web/components/complex/remove-liquidity.tsx @@ -1,4 +1,4 @@ -import { CoinPretty, Dec, PricePretty } from "@keplr-wallet/unit"; +import { CoinPretty, Dec, PricePretty } from "@osmosis-labs/unit"; import classNames from "classnames"; import { observer } from "mobx-react-lite"; import Image from "next/image"; diff --git a/packages/web/components/control/crypto-fiat-input.tsx b/packages/web/components/control/crypto-fiat-input.tsx index 2c8a4c4ff6..e914ebc84e 100644 --- a/packages/web/components/control/crypto-fiat-input.tsx +++ b/packages/web/components/control/crypto-fiat-input.tsx @@ -1,5 +1,5 @@ -import { CoinPretty, Dec, DecUtils, PricePretty } from "@keplr-wallet/unit"; import { DEFAULT_VS_CURRENCY } from "@osmosis-labs/server"; +import { CoinPretty, Dec, DecUtils, PricePretty } from "@osmosis-labs/unit"; import { isValidNumericalRawInput } from "@osmosis-labs/utils"; import classNames from "classnames"; import { diff --git a/packages/web/components/control/token-select.tsx b/packages/web/components/control/token-select.tsx index d9983f0450..3b6b2a4412 100644 --- a/packages/web/components/control/token-select.tsx +++ b/packages/web/components/control/token-select.tsx @@ -1,5 +1,5 @@ import { AppCurrency } from "@keplr-wallet/types"; -import { CoinPretty } from "@keplr-wallet/unit"; +import { CoinPretty } from "@osmosis-labs/unit"; import classNames from "classnames"; import { observer } from "mobx-react-lite"; import Image from "next/image"; diff --git a/packages/web/components/earn/rewards/index.tsx b/packages/web/components/earn/rewards/index.tsx index ebc541f898..4f8e67c4e1 100644 --- a/packages/web/components/earn/rewards/index.tsx +++ b/packages/web/components/earn/rewards/index.tsx @@ -1,11 +1,11 @@ import { sleep } from "@axelar-network/axelarjs-sdk"; import type { EncodeObject } from "@cosmjs/proto-signing"; -import { PricePretty } from "@keplr-wallet/unit"; import { EarnStrategy } from "@osmosis-labs/server"; import { makeExecuteCosmwasmContractMsg, makeWithdrawDelegationRewardsMsg, } from "@osmosis-labs/tx"; +import { PricePretty } from "@osmosis-labs/unit"; import { useCallback } from "react"; import { Button } from "~/components/ui/button"; diff --git a/packages/web/components/earn/table/cells.tsx b/packages/web/components/earn/table/cells.tsx index 68ddd502bc..90e6f7e477 100644 --- a/packages/web/components/earn/table/cells.tsx +++ b/packages/web/components/earn/table/cells.tsx @@ -1,5 +1,5 @@ -import { Dec, PricePretty, RatePretty } from "@keplr-wallet/unit"; import { type EarnStrategy } from "@osmosis-labs/server"; +import { Dec, PricePretty, RatePretty } from "@osmosis-labs/unit"; import { CellContext } from "@tanstack/react-table"; import classNames from "classnames"; import dayjs from "dayjs"; diff --git a/packages/web/components/earn/table/utils.ts b/packages/web/components/earn/table/utils.ts index b67aef3eac..e1909baaa1 100644 --- a/packages/web/components/earn/table/utils.ts +++ b/packages/web/components/earn/table/utils.ts @@ -1,5 +1,5 @@ -import { RatePretty } from "@keplr-wallet/unit"; import { EarnStrategy, StrategyCMSData } from "@osmosis-labs/server"; +import { RatePretty } from "@osmosis-labs/unit"; import { FilterFn, SortingFn } from "@tanstack/react-table"; import dayjs from "dayjs"; diff --git a/packages/web/components/nomic/nomic-pending-transfers.tsx b/packages/web/components/nomic/nomic-pending-transfers.tsx index af0089cf67..1e183143da 100644 --- a/packages/web/components/nomic/nomic-pending-transfers.tsx +++ b/packages/web/components/nomic/nomic-pending-transfers.tsx @@ -1,9 +1,9 @@ -import { Dec } from "@keplr-wallet/unit"; import { superjson } from "@osmosis-labs/server"; +import { Dec } from "@osmosis-labs/unit"; import { getBitcoinExplorerUrl, shorten } from "@osmosis-labs/utils"; import classnames from "classnames"; import dayjs from "dayjs"; -import { useEffect, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { create } from "zustand"; import { createJSONStorage, persist } from "zustand/middleware"; import { useShallow } from "zustand/react/shallow"; @@ -20,7 +20,7 @@ import { useClipboard } from "~/hooks/use-clipboard"; import { ModalBase } from "~/modals"; import { BridgeChainWithDisplayInfo } from "~/server/api/routers/bridge-transfer"; import { useStore } from "~/stores"; -import { humanizeTime } from "~/utils/date"; +import { displayHumanizedTime, humanizeTime } from "~/utils/date"; import { api, RouterOutputs } from "~/utils/trpc"; interface NomicPendingTransfersProps { @@ -34,7 +34,7 @@ interface TransactionStore { RouterOutputs["bridgeTransfer"]["getNomicPendingDeposits"]["pendingDeposits"][number] >; upsertTransaction: ( - transactions: RouterOutputs["bridgeTransfer"]["getNomicPendingDeposits"]["pendingDeposits"] + transactions: RouterOutputs["bridgeTransfer"]["getNomicPendingDeposits"]["pendingDeposits"][number][] ) => void; } @@ -101,14 +101,15 @@ export const NomicPendingTransfers = ({ }: NomicPendingTransfersProps) => { const { t } = useTranslation(); const { accountStore } = useStore(); - const { upsertTransaction, transactions } = useNomicTransactionsStore( - useShallow((state) => ({ - upsertTransaction: state.upsertTransaction, - transactions: state.transactions, - })) - ); + const { upsertTransaction, transactions: rawTransactions } = + useNomicTransactionsStore( + useShallow((state) => ({ + upsertTransaction: state.upsertTransaction, + transactions: state.transactions, + })) + ); - const osmosisAddress = accountStore.getWallet( + const userOsmoAddress = accountStore.getWallet( accountStore.osmosisChainId )?.address; @@ -118,10 +119,10 @@ export const NomicPendingTransfers = ({ dataUpdatedAt: nomicDepositsDataUpdatedAt, } = api.bridgeTransfer.getNomicPendingDeposits.useQuery( { - userOsmoAddress: osmosisAddress!, + userOsmoAddress: userOsmoAddress!, }, { - enabled: !!osmosisAddress, + enabled: !!userOsmoAddress, refetchInterval, trpc: { context: { @@ -135,7 +136,13 @@ export const NomicPendingTransfers = ({ if (pendingDepositsData) { upsertTransaction(pendingDepositsData.pendingDeposits); } - }, [pendingDepositsData, upsertTransaction]); + }, [userOsmoAddress, pendingDepositsData, upsertTransaction]); + + const transactions = useMemo(() => { + return Array.from(rawTransactions.values()).filter( + (transaction) => transaction.userOsmoAddress === userOsmoAddress + ); + }, [rawTransactions, userOsmoAddress]); return ( <> @@ -158,9 +165,11 @@ export const NomicPendingTransfers = ({ refetchInterval={refetchInterval} dataUpdatedAt={nomicDepositsDataUpdatedAt} /> -

- {t("transfer.nomic.awaitingBtc")} -

+ {transactions.length === 0 && ( +

+ {t("transfer.nomic.awaitingBtc")} +

+ )} )} @@ -168,62 +177,60 @@ export const NomicPendingTransfers = ({
- {Array.from(transactions.values()) - .reverse() - .map((deposit) => { - const confirmationPercentage = - (deposit.confirmations / successThreshold) * 100; - const isSuccess = deposit.confirmations === successThreshold; + {transactions.reverse().map((deposit) => { + const confirmationPercentage = + (deposit.confirmations / successThreshold) * 100; + const isSuccess = deposit.confirmations === successThreshold; - return ( -
-
-

- {deposit.fiatValue - ?.sub(deposit.networkFee.fiatValue ?? new Dec(0)) - .sub(deposit.providerFee.fiatValue ?? new Dec(0)) - .toString()}{" "} - - ( - {deposit.amount - .sub(deposit.networkFee.amount) - .sub(deposit.providerFee.amount) - .toString()} - ) - -

- -
- {isSuccess ? ( -

- {t("transfer.nomic.depositSuccess")} -

- ) : ( - - )} + return ( +
+
+

+ {deposit.fiatValue + ?.sub(deposit.networkFee.fiatValue ?? new Dec(0)) + .sub(deposit.providerFee.fiatValue ?? new Dec(0)) + .toString()}{" "} + + ( + {deposit.amount + .sub(deposit.networkFee.amount) + .sub(deposit.providerFee.amount) + .toString()} + ) + +

+
- ); - })} + {isSuccess ? ( +

+ {t("transfer.nomic.depositSuccess")} +

+ ) : ( + + )} +
+ ); + })}
); @@ -287,9 +294,10 @@ const TransactionDetailsModal = ({

{t("transfer.nomic.estimatedAboutTime", { - time: `${humanizedEstimatedTime.value} ${t( - humanizedEstimatedTime.unitTranslationKey - )}`, + time: displayHumanizedTime({ + humanizedTime: humanizedEstimatedTime, + t, + }), })}

- {humanizedTime.value} {t(humanizedTime.unitTranslationKey)}{" "} + {displayHumanizedTime({ + humanizedTime, + t, + delimitedBy: useShortTimeUnits ? " " : undefined, + })}{" "} {t("remaining")}

); diff --git a/packages/web/components/one-click-trading/one-click-trading-settings.tsx b/packages/web/components/one-click-trading/one-click-trading-settings.tsx index 81bf3508f4..a6c666328e 100644 --- a/packages/web/components/one-click-trading/one-click-trading-settings.tsx +++ b/packages/web/components/one-click-trading/one-click-trading-settings.tsx @@ -1,6 +1,6 @@ -import { Dec } from "@keplr-wallet/unit"; import { makeRemoveAuthenticatorMsg } from "@osmosis-labs/tx"; import { OneClickTradingTransactionParams } from "@osmosis-labs/types"; +import { Dec } from "@osmosis-labs/unit"; import { noop, runIfFn } from "@osmosis-labs/utils"; import classNames from "classnames"; import Image from "next/image"; diff --git a/packages/web/components/one-click-trading/screens/spend-limit-screen.tsx b/packages/web/components/one-click-trading/screens/spend-limit-screen.tsx index 7167494745..22d9703989 100644 --- a/packages/web/components/one-click-trading/screens/spend-limit-screen.tsx +++ b/packages/web/components/one-click-trading/screens/spend-limit-screen.tsx @@ -1,5 +1,5 @@ -import { Dec, PricePretty } from "@keplr-wallet/unit"; import { DEFAULT_VS_CURRENCY } from "@osmosis-labs/server"; +import { Dec, PricePretty } from "@osmosis-labs/unit"; import { isNil, isNumeric } from "@osmosis-labs/utils"; import classNames from "classnames"; import { useState } from "react"; diff --git a/packages/web/components/pages/asset-info-page/balance.tsx b/packages/web/components/pages/asset-info-page/balance.tsx index 3ec9349bce..ef2fa94c1c 100644 --- a/packages/web/components/pages/asset-info-page/balance.tsx +++ b/packages/web/components/pages/asset-info-page/balance.tsx @@ -1,5 +1,5 @@ -import { Dec, PricePretty } from "@keplr-wallet/unit"; import { DEFAULT_VS_CURRENCY } from "@osmosis-labs/server"; +import { Dec, PricePretty } from "@osmosis-labs/unit"; import classNames from "classnames"; import { observer } from "mobx-react-lite"; diff --git a/packages/web/components/pages/asset-info-page/chart.tsx b/packages/web/components/pages/asset-info-page/chart.tsx index ea4d5ad744..f876505a56 100644 --- a/packages/web/components/pages/asset-info-page/chart.tsx +++ b/packages/web/components/pages/asset-info-page/chart.tsx @@ -1,4 +1,4 @@ -import { Dec } from "@keplr-wallet/unit"; +import { Dec } from "@osmosis-labs/unit"; import { UTCTimestamp } from "lightweight-charts"; import { observer } from "mobx-react-lite"; import { FunctionComponent, useMemo } from "react"; diff --git a/packages/web/components/pages/asset-info-page/details.tsx b/packages/web/components/pages/asset-info-page/details.tsx index dc92e3a600..1361854f1a 100644 --- a/packages/web/components/pages/asset-info-page/details.tsx +++ b/packages/web/components/pages/asset-info-page/details.tsx @@ -1,4 +1,4 @@ -import { Dec, PricePretty } from "@keplr-wallet/unit"; +import { Dec, PricePretty } from "@osmosis-labs/unit"; import { shorten } from "@osmosis-labs/utils"; import classNames from "classnames"; import { observer } from "mobx-react-lite"; diff --git a/packages/web/components/place-limit-tool/index.tsx b/packages/web/components/place-limit-tool/index.tsx index f70eb366bb..a474e615b2 100644 --- a/packages/web/components/place-limit-tool/index.tsx +++ b/packages/web/components/place-limit-tool/index.tsx @@ -1,6 +1,6 @@ -import { Dec, DecUtils, PricePretty } from "@keplr-wallet/unit"; import { DEFAULT_VS_CURRENCY } from "@osmosis-labs/server"; import { QuoteDirection } from "@osmosis-labs/tx"; +import { Dec, DecUtils, PricePretty } from "@osmosis-labs/unit"; import { isValidNumericalRawInput } from "@osmosis-labs/utils"; import classNames from "classnames"; import { observer } from "mobx-react-lite"; @@ -525,6 +525,13 @@ export const PlaceLimitTool: FunctionComponent = observer( }, [swapState.isBalancesFetched]); const errorDisplay = useMemo(() => { + if ( + swapState.error === "limitOrders.insufficientFunds" && + !account?.isWalletConnected + ) { + return; + } + if (swapState.error && !NON_DISPLAY_ERRORS.includes(swapState.error)) { if (swapState.error === "errors.generic") { return t("errors.uhOhSomethingWentWrong"); diff --git a/packages/web/components/place-limit-tool/limit-price-selector.tsx b/packages/web/components/place-limit-tool/limit-price-selector.tsx index 454831b1d7..be20e1041c 100644 --- a/packages/web/components/place-limit-tool/limit-price-selector.tsx +++ b/packages/web/components/place-limit-tool/limit-price-selector.tsx @@ -1,4 +1,4 @@ -import { Dec } from "@keplr-wallet/unit"; +import { Dec } from "@osmosis-labs/unit"; import classNames from "classnames"; import { parseAsString, useQueryState } from "nuqs"; import React, { FC, useCallback, useEffect, useMemo, useState } from "react"; diff --git a/packages/web/components/pool-detail/base-pool.tsx b/packages/web/components/pool-detail/base-pool.tsx index 272ace8414..8f54025e80 100644 --- a/packages/web/components/pool-detail/base-pool.tsx +++ b/packages/web/components/pool-detail/base-pool.tsx @@ -1,5 +1,5 @@ -import { IntPretty } from "@keplr-wallet/unit"; import type { Pool } from "@osmosis-labs/server"; +import { IntPretty } from "@osmosis-labs/unit"; import classNames from "classnames"; import { observer } from "mobx-react-lite"; import Link from "next/link"; diff --git a/packages/web/components/pool-detail/concentrated.tsx b/packages/web/components/pool-detail/concentrated.tsx index 9994abaa51..361eafb771 100644 --- a/packages/web/components/pool-detail/concentrated.tsx +++ b/packages/web/components/pool-detail/concentrated.tsx @@ -1,4 +1,4 @@ -import { Dec } from "@keplr-wallet/unit"; +import { Dec } from "@osmosis-labs/unit"; import classNames from "classnames"; import { observer } from "mobx-react-lite"; import dynamic from "next/dynamic"; diff --git a/packages/web/components/pool-detail/share.tsx b/packages/web/components/pool-detail/share.tsx index 2c1ba67584..3602890a1f 100644 --- a/packages/web/components/pool-detail/share.tsx +++ b/packages/web/components/pool-detail/share.tsx @@ -1,11 +1,11 @@ +import type { BondDuration, Pool } from "@osmosis-labs/server"; import { CoinPretty, Dec, IntPretty, PricePretty, RatePretty, -} from "@keplr-wallet/unit"; -import type { BondDuration, Pool } from "@osmosis-labs/server"; +} from "@osmosis-labs/unit"; import classNames from "classnames"; import { Duration } from "dayjs/plugin/duration"; import { observer } from "mobx-react-lite"; diff --git a/packages/web/components/stake/unbonding-in-progress.tsx b/packages/web/components/stake/unbonding-in-progress.tsx index 523dbab8df..8f6dd5668b 100644 --- a/packages/web/components/stake/unbonding-in-progress.tsx +++ b/packages/web/components/stake/unbonding-in-progress.tsx @@ -1,4 +1,4 @@ -import { CoinPretty } from "@keplr-wallet/unit"; +import { CoinPretty } from "@osmosis-labs/unit"; import dayjs from "dayjs"; import React from "react"; diff --git a/packages/web/components/swap-tool/index.tsx b/packages/web/components/swap-tool/index.tsx index 7cf86eb419..4065850280 100644 --- a/packages/web/components/swap-tool/index.tsx +++ b/packages/web/components/swap-tool/index.tsx @@ -1,7 +1,7 @@ import { WalletStatus } from "@cosmos-kit/core"; -import { Dec, DecUtils, PricePretty, RatePretty } from "@keplr-wallet/unit"; import { DEFAULT_VS_CURRENCY } from "@osmosis-labs/server"; import { QuoteDirection } from "@osmosis-labs/tx"; +import { Dec, DecUtils, PricePretty, RatePretty } from "@osmosis-labs/unit"; import { isNil } from "@osmosis-labs/utils"; import classNames from "classnames"; import { observer } from "mobx-react-lite"; diff --git a/packages/web/components/swap-tool/price-selector.tsx b/packages/web/components/swap-tool/price-selector.tsx index 5f8e670320..80b325e048 100644 --- a/packages/web/components/swap-tool/price-selector.tsx +++ b/packages/web/components/swap-tool/price-selector.tsx @@ -1,7 +1,7 @@ import { Menu, Transition } from "@headlessui/react"; -import { Dec, PricePretty } from "@keplr-wallet/unit"; import { DEFAULT_VS_CURRENCY, MaybeUserAssetCoin } from "@osmosis-labs/server"; import { Asset } from "@osmosis-labs/types"; +import { Dec, PricePretty } from "@osmosis-labs/unit"; import { getAssetFromAssetList } from "@osmosis-labs/utils"; import classNames from "classnames"; import { observer } from "mobx-react-lite"; diff --git a/packages/web/components/swap-tool/split-route.tsx b/packages/web/components/swap-tool/split-route.tsx index f18c20a0c2..0429a9b060 100644 --- a/packages/web/components/swap-tool/split-route.tsx +++ b/packages/web/components/swap-tool/split-route.tsx @@ -1,5 +1,5 @@ import { AppCurrency, Currency } from "@keplr-wallet/types"; -import { RatePretty } from "@keplr-wallet/unit"; +import { RatePretty } from "@osmosis-labs/unit"; import { useSingleton } from "@tippyjs/react"; import classNames from "classnames"; import { observer } from "mobx-react-lite"; diff --git a/packages/web/components/swap-tool/trade-details.tsx b/packages/web/components/swap-tool/trade-details.tsx index 8068c8e9ee..f2b3d37e03 100644 --- a/packages/web/components/swap-tool/trade-details.tsx +++ b/packages/web/components/swap-tool/trade-details.tsx @@ -1,7 +1,7 @@ import { Disclosure } from "@headlessui/react"; -import { Dec, PricePretty, RatePretty } from "@keplr-wallet/unit"; import { EmptyAmountError } from "@osmosis-labs/keplr-hooks"; import { DEFAULT_VS_CURRENCY } from "@osmosis-labs/server"; +import { Dec, PricePretty, RatePretty } from "@osmosis-labs/unit"; import classNames from "classnames"; import { observer } from "mobx-react-lite"; import { useEffect, useMemo, useState } from "react"; diff --git a/packages/web/components/transactions/transaction-details/transaction-transfer-details.tsx b/packages/web/components/transactions/transaction-details/transaction-transfer-details.tsx index 0291c36a94..3efc2d774b 100644 --- a/packages/web/components/transactions/transaction-details/transaction-transfer-details.tsx +++ b/packages/web/components/transactions/transaction-details/transaction-transfer-details.tsx @@ -1,4 +1,4 @@ -import { CoinPretty, Dec } from "@keplr-wallet/unit"; +import { CoinPretty, Dec } from "@osmosis-labs/unit"; import { getBitcoinExplorerUrl, getEvmExplorerUrl, diff --git a/packages/web/components/transactions/transaction-types/transaction-swap-row.tsx b/packages/web/components/transactions/transaction-types/transaction-swap-row.tsx index 6898a09e3f..6dafc2445d 100644 --- a/packages/web/components/transactions/transaction-types/transaction-swap-row.tsx +++ b/packages/web/components/transactions/transaction-types/transaction-swap-row.tsx @@ -1,4 +1,4 @@ -import { CoinPretty, PricePretty } from "@keplr-wallet/unit"; +import { CoinPretty, PricePretty } from "@osmosis-labs/unit"; import classNames from "classnames"; import React from "react"; diff --git a/packages/web/components/transactions/transaction-types/transaction-transfer-row.tsx b/packages/web/components/transactions/transaction-types/transaction-transfer-row.tsx index 4229310948..c2df8b68aa 100644 --- a/packages/web/components/transactions/transaction-types/transaction-transfer-row.tsx +++ b/packages/web/components/transactions/transaction-types/transaction-transfer-row.tsx @@ -1,5 +1,5 @@ -import { CoinPretty, Dec } from "@keplr-wallet/unit"; import { TxSnapshot } from "@osmosis-labs/bridge"; +import { CoinPretty, Dec } from "@osmosis-labs/unit"; import { shorten } from "@osmosis-labs/utils"; import classNames from "classnames"; import React from "react"; diff --git a/packages/web/e2e/pages/base-page.ts b/packages/web/e2e/pages/base-page.ts deleted file mode 100644 index 848b217aaa..0000000000 --- a/packages/web/e2e/pages/base-page.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { expect, Locator, Page } from "@playwright/test"; - -export class BasePage { - readonly page: Page; - readonly connectWalletBtn: Locator; - readonly kepltWalletBtn: Locator; - readonly portfolioLink: Locator; - readonly poolsLink: Locator; - - constructor(page: Page) { - this.page = page; - this.connectWalletBtn = page - .getByRole("button", { name: "Connect wallet", exact: true }) - .first(); - this.kepltWalletBtn = page.locator("button").filter({ hasText: /^Keplr$/ }); - this.portfolioLink = page.getByText("Portfolio"); - this.poolsLink = page.getByText("Pools"); - } - - async connectWallet() { - await this.connectWalletBtn.click(); - // This is needed to handle a wallet popup - const pagePromise = this.page.context().waitForEvent("page"); - await this.kepltWalletBtn.click(); - await this.page.waitForTimeout(1000); - // Handle Pop-up page -> - const newPage = await pagePromise; - await newPage.waitForLoadState("load", { timeout: 10000 }); - const pageTitle = await newPage.title(); - console.log("Title of the new page: " + pageTitle); - await newPage.getByRole("button", { name: "Approve" }).click(); - // PopUp page is auto-closed - // Handle Pop-up page <- - const wallet = this.page.locator("//button/div/span[@title]"); - await this.page.waitForTimeout(4000); - // Verify that wallet modal loaded correctly - const isWalletVisible = await wallet.isVisible({ timeout: 5000 }); - expect(isWalletVisible).toBeTruthy(); - console.log("Wallet is connected."); - } - - async gotoPortfolio() { - await this.portfolioLink.click(); - // we expect that after 2 seconds tokens are loaded and any failure after this point should be considered a bug. - await this.page.waitForTimeout(2000); - await this.printUrl(); - } - - async gotoPools() { - await this.poolsLink.click(); - } - - async printUrl() { - const currentUrl = this.page.url(); - console.log("FE opened at: " + currentUrl); - } -} diff --git a/packages/web/e2e/pages/pool-page.ts b/packages/web/e2e/pages/pool-page.ts deleted file mode 100644 index 6bc158e6d4..0000000000 --- a/packages/web/e2e/pages/pool-page.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { Locator, Page } from "@playwright/test"; - -import { BasePage } from "~/e2e/pages/base-page"; - -import { SwapPage } from "./swap-page"; - -export class PoolPage extends BasePage { - readonly page: Page; - readonly viewMore: Locator; - readonly poolsLink: Locator; - readonly balance: Locator; - readonly tradeBtn: Locator; - - constructor(page: Page) { - super(page); - this.page = page; - this.viewMore = page.getByText("View more"); - this.poolsLink = page.locator('//a//div[contains(text(), "Pools")]'); - this.balance = page.locator( - '//span[.="Total balance"]/..//h4[contains(@class, "text-osmoverse-100")]' - ); - this.tradeBtn = page.locator('//button/span[.="Trade Pair"]'); - } - - async getBalance() { - let totalBalance: string = await this.balance.innerText(); - console.log(`Total Balance for a Pool [${totalBalance}]`); - return totalBalance; - } - - async getTradeModal() { - await this.tradeBtn.click(); - return new SwapPage(this.page); - } -} diff --git a/packages/web/e2e/pages/pools-page.ts b/packages/web/e2e/pages/pools-page.ts deleted file mode 100644 index e84c27cbd0..0000000000 --- a/packages/web/e2e/pages/pools-page.ts +++ /dev/null @@ -1,99 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { Locator, Page } from "@playwright/test"; - -import { BasePage } from "~/e2e/pages/base-page"; - -import { PoolPage } from "./pool-page"; - -export class PoolsPage extends BasePage { - readonly page: Page; - readonly viewMore: Locator; - readonly poolsLink: Locator; - readonly balance: Locator; - readonly searchInput: Locator; - - constructor(page: Page) { - super(page); - this.page = page; - this.viewMore = page.getByText("View more"); - this.poolsLink = page.locator('//a//div[contains(text(), "Pools")]'); - this.balance = page.locator( - '//span[.="Total balance"]/..//h4[contains(@class, "text-osmoverse-100")]' - ); - this.searchInput = page.locator('//input[@id="search-input"]'); - } - - async goto() { - await this.page.goto("/"); - await this.page.waitForTimeout(2000); - await this.poolsLink.click(); - await this.page.waitForTimeout(2000); - // Sometimes pools take longer to load - // we expect that after 10 seconds tokens are loaded and any failure after this point should be considered a bug. - // 1464 is an OSMO/USDC pool - const locRows = '//tr/td/a[contains(@href, "pool/1464")]/../..'; - await this.page.locator(locRows).hover({ timeout: 10000 }); - await super.printUrl(); - } - - async viewPool(id: number, pair: string) { - await this.page - .locator(`//table//td/a[@href="/pool/${id}"]//span[.="${pair}"]`) - .click(); - // we expect that after 2 seconds tokens are loaded and any failure after this point should be considered a bug. - await this.page.waitForTimeout(2000); - await super.printUrl(); - return new PoolPage(this.page); - } - - async searchForPool(poolName: string) { - await this.searchInput.fill(poolName); - // we expect that after 2 seconds tokens are loaded and any failure after this point should be considered a bug. - await this.page.waitForTimeout(2000); - } - - async getPoolsNumber() { - const loc = '//tr/td//a[contains(@href, "/pool/")]/../..'; - const num = await this.page.locator(loc).count(); - console.log("Pools Count: " + num); - return num; - } - - async getTopTenPoolsByLiquidity() { - const loc = '//tr/td//a[contains(@href, "/pool/")]/../..'; - let liquidityList = []; - for (let i = 0; i < 10; i++) { - let tt = this.page.locator(loc).nth(i).locator("//td").nth(2); - let text: string = await tt.innerText(); - let n: number = Number(text.replace(/[^0-9.-]+/g, "")); - liquidityList.push(n); - } - console.log("Top 10 pools Liquidity: " + liquidityList); - return liquidityList; - } - - async getTopTenPoolsByVolume() { - const loc = '//tr/td//a[contains(@href, "/pool/")]/../..'; - let volumeList = []; - for (let i = 0; i < 10; i++) { - let tt = this.page.locator(loc).nth(i).locator("//td").nth(1); - let text: string = await tt.innerText(); - let n: number = Number(text.replace(/[^0-9.-]+/g, "")); - volumeList.push(n); - } - console.log("Top 10 pools Volume: " + volumeList); - return volumeList; - } - - async getTopTenPoolsByAPR() { - const loc = '//tr/td//a[contains(@href, "/pool/")]/../..'; - let aprList = []; - for (let i = 0; i < 10; i++) { - let tt = this.page.locator(loc).nth(i).locator("//td").nth(3); - let text: string = await tt.innerText(); - aprList.push(text); - } - console.log("Top 10 pools APRs: " + aprList); - return aprList; - } -} diff --git a/packages/web/e2e/pages/portfolio-page.ts b/packages/web/e2e/pages/portfolio-page.ts deleted file mode 100644 index a4981f138e..0000000000 --- a/packages/web/e2e/pages/portfolio-page.ts +++ /dev/null @@ -1,73 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { Locator, Page } from "@playwright/test"; - -import { BasePage } from "~/e2e/pages/base-page"; -import { TransactionsPage } from "~/e2e/pages/transactions-page"; - -export class PortfolioPage extends BasePage { - readonly hideZeros: Locator; - readonly viewMore: Locator; - readonly portfolioLink: Locator; - readonly viewTransactions: Locator; - readonly searchInput: Locator; - - constructor(page: Page) { - super(page); - this.hideZeros = page.locator( - '//label[.="Hide zero balances"]/following-sibling::button' - ); - this.viewMore = page.getByText("View more"); - this.portfolioLink = page.locator( - '//a//div[contains(text(), "Portfolio")]' - ); - this.viewTransactions = page.locator('//div/a[.="View all"]'); - this.searchInput = page.locator('//input[@id="search-input"]'); - } - - async goto() { - await this.page.goto("/"); - await this.portfolioLink.click(); - // we expect that after 2 seconds tokens are loaded and any failure after this point should be considered a bug. - await this.page.waitForTimeout(2000); - const currentUrl = this.page.url(); - console.log("FE opened at: " + currentUrl); - } - - async getBalanceFor(token: string) { - await this.page.evaluate(() => window.scrollBy(0, 250)); - const bal = this.page - .locator(`//tbody/tr//a[contains(@href, "/assets/${token}")]`) - .nth(1); - let tokenBalance: string = await bal.innerText(); - console.log(`Balance for ${token}: ${tokenBalance}`); - return tokenBalance; - } - - async viewTransactionsPage() { - await this.viewTransactions.click(); - await this.page.waitForTimeout(1000); - return new TransactionsPage(this.page); - } - - async hideZeroBalances() { - const isVisible = await this.hideZeros.isVisible({ timeout: 2000 }); - if (isVisible) { - await this.hideZeros.click(); - await this.page.waitForTimeout(1000); - } - } - - async viewMoreBalances() { - const isVisible = await this.viewMore.isVisible({ timeout: 2000 }); - if (isVisible) { - await this.viewMore.click(); - await this.page.waitForTimeout(1000); - } - } - - async searchForToken(tokenName: string) { - await this.searchInput.fill(tokenName); - // we expect that after 2 seconds tokens are loaded and any failure after this point should be considered a bug. - await this.page.waitForTimeout(2000); - } -} diff --git a/packages/web/e2e/pages/swap-page.ts b/packages/web/e2e/pages/swap-page.ts deleted file mode 100644 index 4e05a70d83..0000000000 --- a/packages/web/e2e/pages/swap-page.ts +++ /dev/null @@ -1,215 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { - type BrowserContext, - expect, - type Locator, - type Page, -} from "@playwright/test"; - -import { BasePage } from "~/e2e/pages/base-page"; - -export class SwapPage extends BasePage { - readonly page: Page; - readonly swapBtn: Locator; - readonly swapMaxBtn: Locator; - readonly swapInput: Locator; - readonly flipAssetsBtn: Locator; - readonly exchangeRate: Locator; - readonly trxSuccessful: Locator; - readonly trxBroadcasting: Locator; - readonly trxLink: Locator; - - constructor(page: Page) { - super(page); - this.page = page; - this.swapBtn = page.getByRole("button", { name: "Swap", exact: true }); - this.swapMaxBtn = page.getByRole("button", { name: "MAX", exact: true }); - this.swapInput = page.locator('//input[@data-testid="trade-input-swap"]'); - this.flipAssetsBtn = page.locator( - '//div/button[contains(@class, "ease-bounce")]' - ); - this.exchangeRate = page.locator('//span[@data-testid="token-price"]'); - this.trxSuccessful = page.locator('//h6[.="Transaction Succesful"]'); - this.trxLink = page.getByText("View explorer"); - this.trxBroadcasting = page.locator('//h6[.="Transaction Broadcasting"]'); - } - - async goto() { - const assetPromise = this.page.waitForRequest("**/assets.json"); - await this.page.goto("/"); - const request = await assetPromise; - expect(request).toBeTruthy(); - // we expect that after 2 seconds tokens are loaded and any failure after this point should be considered a bug. - await this.page.waitForTimeout(2000); - const currentUrl = this.page.url(); - console.log(`FE opened at: ${currentUrl}`); - } - - async flipTokenPair() { - await this.flipAssetsBtn.click(); - await this.page.waitForTimeout(2000); - console.log("Fliped token pair."); - } - - async enterAmount(amount: string) { - // Just enter an amount for the swap and wait for a quote - await this.swapInput.fill(amount, { timeout: 2000 }); - await this.page.waitForTimeout(2000); - await expect(this.swapInput).toHaveValue(amount, { timeout: 3000 }); - const exchangeRate = await this.getExchangeRate(); - console.log(`Swap ${amount} with rate: ${exchangeRate}`); - } - - async swapAndGetWalletMsg(context: BrowserContext) { - // Make sure to have sufficient balance and swap button is enabled - expect( - await this.isInsufficientBalance(), - "Insufficient balance for the swap!" - ).toBeFalsy(); - await expect(this.swapBtn).toBeEnabled({ timeout: 7000 }); - // Handle Pop-up page -> - const pageApprove = context.waitForEvent("page"); - await this.swapBtn.click(); - const approvePage = await pageApprove; - await approvePage.waitForLoadState(); - const approvePageTitle = approvePage.url(); - console.log(`Approve page is opened at: ${approvePageTitle}`); - const approveBtn = approvePage.getByRole("button", { - name: "Approve", - }); - await expect(approveBtn).toBeEnabled(); - const msgContentAmount = await approvePage - .getByText("type: osmosis/poolmanager/") - .textContent(); - console.log(`Wallet is approving this msg: \n${msgContentAmount}`); - // Approve trx - await approveBtn.click(); - // wait for trx confirmation - await this.page.waitForTimeout(4000); - //await approvePage.close(); - // Handle Pop-up page <- - return { msgContentAmount }; - } - - async selectPair(from: string, to: string) { - // Filter does not show already selected tokens - console.log(`Select pair ${from} to ${to}`); - const tokenLocator = - '//img[@alt="token icon"]/../..//h5 | //img[@alt="token icon"]/../..//span[@class="subtitle1"]'; - const fromToken = this.page.locator(tokenLocator).nth(0); - const toToken = this.page.locator(tokenLocator).nth(1); - - const fromTokenText = await fromToken.innerText(); - const toTokenText = await toToken.innerText(); - console.log(`Current pair: ${fromTokenText} / ${toTokenText}`); - - if (fromTokenText === from && toTokenText === to) { - console.log( - `Current pair: ${fromTokenText}${toTokenText} is already matching.` - ); - return; - } - - if (fromTokenText === to && toTokenText === from) { - await this.flipTokenPair(); - console.log(`Current pair: ${fromTokenText}${toTokenText} is fliped.`); - return; - } - - if (from === toTokenText || to === fromTokenText) { - await this.flipTokenPair(); - } - - if (fromTokenText !== from && toTokenText !== from) { - await fromToken.click(); - // we expect that after 1 second token filter is displayed. - await this.page.waitForTimeout(1000); - await this.page.getByPlaceholder("Search").fill(from); - const fromLocator = this.page.locator( - `//div/button[@data-testid]//h6[.='${from}']` - ); - await fromLocator.click(); - } - - if (toTokenText !== to && fromTokenText !== to) { - await toToken.click(); - // we expect that after 1 second token filter is displayed. - await this.page.waitForTimeout(1000); - await this.page.getByPlaceholder("Search").fill(to); - const toLocator = this.page.locator( - `//div/button[@data-testid]//h6[.='${to}']` - ); - await toLocator.click(); - } - // we expect that after 2 seconds exchange rate is populated. - await this.page.waitForTimeout(2000); - expect(await this.getExchangeRate()).toContain(from); - expect(await this.getExchangeRate()).toContain(to); - } - - async getExchangeRate() { - return await this.exchangeRate.innerText(); - } - - async isTransactionSuccesful(delay: number = 7) { - console.log("Wait for a transaction success for 7 seconds."); - return await this.trxSuccessful.isVisible({ - timeout: delay * 1000, - }); - } - - async getTransactionUrl() { - const trxUrl = await this.trxLink.getAttribute("href"); - console.log(`Trx url: ${trxUrl}`); - return trxUrl; - } - - async isTransactionBroadcasted(delay: number = 5) { - console.log("Wait for a transaction broadcasting for 5 seconds."); - return await this.trxBroadcasting.isVisible({ timeout: delay * 1000 }); - } - - async isInsufficientBalance() { - const issufBalanceBtn = this.page.locator( - '//button[.="Insufficient balance"]' - ); - return await issufBalanceBtn.isVisible({ timeout: 2000 }); - } - - async isError() { - const errorBtn = this.page.locator('//button[.="Error"]'); - return await errorBtn.isVisible({ timeout: 2000 }); - } - - async showSwapInfo() { - const swapInfo = this.page.locator("//button//span[.='Show details']"); - await swapInfo.click(); - console.log(`Price Impact: ${await this.getPriceInpact()}`); - } - - async getPriceInpact() { - const priceInpactSpan = this.page.locator( - '//span[.="Price Impact"]/..//span[@class="text-bullish-400"]' - ); - return await priceInpactSpan.textContent(); - } - - async takeScreenshot(name: string) { - await this.page.screenshot({ - path: `screenshot-swap-${name}.png`, - fullPage: true, - }); - } - - async getSelectedPair() { - const tokenLocator = - '//img[@alt="token icon"]/../..//h5 | //img[@alt="token icon"]/../..//span[@class="subtitle1"]'; - const fromToken = this.page.locator(tokenLocator).nth(0); - const toToken = this.page.locator(tokenLocator).nth(1); - - const fromTokenText = await fromToken.innerText(); - const toTokenText = await toToken.innerText(); - console.log(`Current pair: ${fromTokenText}/${toTokenText}`); - return `${fromTokenText}/${toTokenText}`; - } -} diff --git a/packages/web/e2e/pages/trade-page.ts b/packages/web/e2e/pages/trade-page.ts deleted file mode 100644 index 507400d4e1..0000000000 --- a/packages/web/e2e/pages/trade-page.ts +++ /dev/null @@ -1,353 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { - type BrowserContext, - expect, - type Locator, - type Page, -} from "@playwright/test"; - -import { BasePage } from "~/e2e/pages/base-page"; - -export class TradePage extends BasePage { - readonly page: Page; - readonly swapBtn: Locator; - readonly swapMaxBtn: Locator; - readonly flipAssetsBtn: Locator; - readonly exchangeRate: Locator; - readonly trxSuccessful: Locator; - readonly trxBroadcasting: Locator; - readonly trxLink: Locator; - readonly inputAmount: Locator; - readonly confirmSwapBtn: Locator; - readonly buyTabBtn: Locator; - readonly buyBtn: Locator; - readonly sellTabBtn: Locator; - readonly sellBtn: Locator; - readonly limitTabBtn: Locator; - readonly orderHistoryLink: Locator; - readonly limitPrice: Locator; - - constructor(page: Page) { - super(page); - this.page = page; - this.swapBtn = page.locator('//button[@data-testid="trade-button-swap"]'); - this.buyTabBtn = page.locator('//div[@class]/button[.="Buy"]/p[@class]/..'); - this.buyBtn = page.locator('//div[@class]/button[@class]/h6[.="Buy"]/..'); - this.sellBtn = page.locator('//div[@class]/button[@class]/h6[.="Sell"]/..'); - this.sellTabBtn = page.locator( - '//div[@class]/button[.="Sell"]/p[@class]/..' - ); - this.confirmSwapBtn = page.locator('//div[@class]/button[.="Confirm"]'); - this.swapMaxBtn = page.locator('//span[.="Max"]'); - this.flipAssetsBtn = page.locator( - '//div/button[contains(@class, "ease-bounce")]' - ); - this.exchangeRate = page.locator('//span[@data-testid="token-price"]'); - this.trxSuccessful = page.getByText("Transaction Successful"); - this.trxLink = page.getByText("View explorer"); - this.trxBroadcasting = page.locator('//h6[.="Transaction Broadcasting"]'); - this.inputAmount = page.locator( - "//input[contains(@data-testid, 'trade-input')]" - ); - this.limitTabBtn = page.locator('//div[@class="w-full"]/button[.="Limit"]'); - this.orderHistoryLink = page.getByText("Order history"); - this.limitPrice = page.locator("//div/input[@type='text']"); - } - - async goto() { - const assetPromise = this.page.waitForRequest("**/assets.json"); - await this.page.goto("/"); - const request = await assetPromise; - expect(request).toBeTruthy(); - // we expect that after 2 seconds tokens are loaded and any failure after this point should be considered a bug. - await this.page.waitForTimeout(2000); - const currentUrl = this.page.url(); - console.log(`FE opened at: ${currentUrl}`); - } - - async gotoOrdersHistory(timeout: number = 1) { - await this.page.waitForTimeout(1000); - await this.orderHistoryLink.click(); - await this.page.waitForTimeout(1000); - await new Promise((f) => setTimeout(f, timeout * 1000)); - const currentUrl = this.page.url(); - console.log(`FE opened at: ${currentUrl}`); - } - - async openBuyTab() { - await this.buyTabBtn.click(); - } - - async openSellTab() { - await this.sellTabBtn.click(); - } - - async openLimit() { - await this.limitTabBtn.click(); - await this.page.waitForTimeout(1000); - } - - async getLimitPrice() { - const lp = await this.limitPrice.inputValue(); - console.log(`Current limit price is: ${lp}`); - return lp; - } - - async setLimitPriceChange(change: string) { - const locator = `//button/span[contains(@class, "body2") and .="${change}"]`; - await this.page.locator(locator).click(); - await this.page.waitForTimeout(1000); - } - - async setLimitPrice(price: string) { - console.log(`Set Order Limit Price to: ${price}`); - await this.limitPrice.fill(price, { timeout: 2000 }); - } - - async flipTokenPair() { - await this.flipAssetsBtn.click(); - await this.page.waitForTimeout(2000); - console.log("Fliped token pair."); - } - - async clickMaxAmountButton() { - await this.swapMaxBtn.click({ timeout: 2000 }); - await this.page.waitForTimeout(1000); - console.log("Clicked Max token amount button."); - } - - async enterAmount(amount: string) { - // Just enter an amount for the swap and wait for a quote - await this.inputAmount.fill(amount, { timeout: 2000 }); - await this.page.waitForTimeout(1000); - await expect(this.inputAmount).toHaveValue(amount, { timeout: 1000 }); - const exchangeRate = await this.getExchangeRate(); - console.log(`Swap ${amount} with rate: ${exchangeRate}`); - } - - async swapAndGetWalletMsg(context: BrowserContext) { - // Make sure to have sufficient balance and swap button is enabled - expect( - await this.isInsufficientBalanceForSwap(), - "Insufficient balance for the swap!" - ).toBeFalsy(); - await expect(this.swapBtn).toBeEnabled({ timeout: 7000 }); - // Handle Pop-up page -> - await this.swapBtn.click(); - const pageApprove = context.waitForEvent("page"); - await this.confirmSwapBtn.click(); - const approvePage = await pageApprove; - await approvePage.waitForLoadState(); - const approvePageTitle = approvePage.url(); - console.log(`Approve page is opened at: ${approvePageTitle}`); - const approveBtn = approvePage.getByRole("button", { - name: "Approve", - }); - await expect(approveBtn).toBeEnabled(); - const msgContentAmount = await approvePage - .getByText("type: osmosis/poolmanager/") - .textContent(); - console.log(`Wallet is approving this msg: \n${msgContentAmount}`); - // Approve trx - await approveBtn.click(); - // wait for trx confirmation - await this.page.waitForTimeout(4000); - //await approvePage.close(); - // Handle Pop-up page <- - return { msgContentAmount }; - } - - async selectAsset(token: string) { - const tokenLocator = "//div//button[@type]//img[@alt]"; - const fromToken = this.page.locator(tokenLocator).nth(0); - await fromToken.click(); - // we expect that after 1 second token filter is displayed. - await this.page.waitForTimeout(1000); - await this.page.getByPlaceholder("Search").fill(token); - const fromLocator = this.page.locator( - `//div/button[@data-testid='token-select-asset']//span[.='${token}']` - ); - await fromLocator.click(); - } - - async selectPair(from: string, to: string) { - // Filter does not show already selected tokens - console.log(`Select pair ${from} to ${to}`); - const fromToken = this.page.locator( - "//div//button[@data-testid='token-in']//img[@alt]" - ); - const toToken = this.page.locator( - "//div//button[@data-testid='token-out']//img[@alt]" - ); - // Select From Token - await fromToken.click({ timeout: 4000 }); - // we expect that after 1 second token filter is displayed. - await this.page.waitForTimeout(1000); - await this.page.getByPlaceholder("Search").fill(from); - const fromLocator = this.page - .locator( - `//div/button[@data-testid='token-select-asset']//span[.='${from}']` - ) - .first(); - await fromLocator.click({ timeout: 4000 }); - // Select To Token - await toToken.click({ timeout: 4000 }); - // we expect that after 1 second token filter is displayed. - await this.page.waitForTimeout(1000); - await this.page.getByPlaceholder("Search").fill(to); - const toLocator = this.page - .locator( - `//div/button[@data-testid='token-select-asset']//span[.='${to}']` - ) - .first(); - await toLocator.click(); - // we expect that after 2 seconds exchange rate is populated. - await this.page.waitForTimeout(2000); - expect(await this.getExchangeRate()).toContain(from); - expect(await this.getExchangeRate()).toContain(to); - } - - async getExchangeRate() { - return await this.exchangeRate.innerText(); - } - - async isTransactionSuccesful(delay = 7) { - console.log(`Wait for a transaction success for ${delay} seconds.`); - await expect(this.trxSuccessful).toBeVisible({ - timeout: delay * 1000, - visible: true, - }); - } - - async getTransactionUrl() { - const trxUrl = await this.trxLink.getAttribute("href"); - console.log(`Trx url: ${trxUrl}`); - await this.page.reload(); - return trxUrl; - } - - async isTransactionBroadcasted(delay = 5) { - console.log(`Wait for a transaction broadcasting for ${delay} seconds.`); - return await this.trxBroadcasting.isVisible({ timeout: delay * 1000 }); - } - - async isInsufficientBalance() { - const issufBalanceBtn = this.page.locator( - '//span[.="Insufficient balance"]' - ); - return await issufBalanceBtn.isVisible({ timeout: 2000 }); - } - - async isInsufficientBalanceForSwap() { - const issufBalanceBtn = this.page.locator( - '//button[.="Insufficient balance"]' - ); - return await issufBalanceBtn.isVisible({ timeout: 2000 }); - } - - async isSufficientBalanceForTrade() { - // Make sure to have sufficient balance for a trade - expect( - await this.isInsufficientBalance(), - "Insufficient balance for the swap!" - ).toBeFalsy(); - } - - async isError() { - const errorBtn = this.page.locator('//button[.="Error"]'); - return await errorBtn.isVisible({ timeout: 2000 }); - } - - async showSwapInfo() { - const swapInfo = this.page.locator("//button//span[.='Show details']"); - await swapInfo.click({ timeout: 2000 }); - } - - async getPriceInpact() { - const priceInpactSpan = this.page.locator( - '//span[.="Price Impact"]/..//span[@class="text-bullish-400"]' - ); - return await priceInpactSpan.textContent(); - } - - async takeScreenshot(name: string) { - await this.page.screenshot({ - path: `screenshot-trade-${name}.png`, - fullPage: true, - }); - } - - async getSelectedSwapPair() { - const tokenLocator = "//div//button[@type]//img[@alt]/../h5"; - const fromToken = this.page.locator(tokenLocator).nth(0); - const toToken = this.page.locator(tokenLocator).nth(1); - await expect(fromToken).toBeVisible({ timeout: 2000 }); - const fromTokenText = await fromToken.innerText(); - const toTokenText = await toToken.innerText(); - console.log(`Current pair: ${fromTokenText}/${toTokenText}`); - return `${fromTokenText}/${toTokenText}`; - } - - async buyAndGetWalletMsg(context: BrowserContext, limit = false) { - await expect(this.buyBtn, "Buy button is disabled!").toBeEnabled({ - timeout: 7000, - }); - // Handle Pop-up page -> - await this.buyBtn.click(); - const pageApprove = context.waitForEvent("page"); - await this.confirmSwapBtn.click(); - await this.page.waitForTimeout(200); - const approvePage = await pageApprove; - await approvePage.waitForLoadState(); - const approveBtn = approvePage.getByRole("button", { - name: "Approve", - }); - await expect(approveBtn).toBeEnabled(); - let msgTextLocator = "type: osmosis/poolmanager/"; - if (limit) { - msgTextLocator = "Execute contract"; - } - const msgContentAmount = await approvePage - .getByText(msgTextLocator) - .textContent(); - console.log(`Wallet is approving this msg: \n${msgContentAmount}`); - // Approve trx - await approveBtn.click(); - // wait for trx confirmation - await this.page.waitForTimeout(2000); - // Handle Pop-up page <- - return { msgContentAmount }; - } - - async sellAndGetWalletMsg(context: BrowserContext, limit = false) { - // Make sure Sell button is enabled - await expect(this.sellBtn, "Sell button is disabled!").toBeEnabled({ - timeout: 7000, - }); - // Handle Pop-up page -> - await this.sellBtn.click(); - const pageApprove = context.waitForEvent("page"); - await this.confirmSwapBtn.click(); - await this.page.waitForTimeout(200); - const approvePage = await pageApprove; - await approvePage.waitForLoadState(); - const approveBtn = approvePage.getByRole("button", { - name: "Approve", - }); - await expect(approveBtn).toBeEnabled(); - let msgTextLocator = "type: osmosis/poolmanager/"; - if (limit) { - msgTextLocator = "Execute contract"; - } - const msgContentAmount = await approvePage - .getByText(msgTextLocator) - .textContent(); - console.log(`Wallet is approving this msg: \n${msgContentAmount}`); - // Approve trx - await approveBtn.click(); - // wait for trx confirmation - await this.page.waitForTimeout(2000); - // Handle Pop-up page <- - return { msgContentAmount }; - } -} diff --git a/packages/web/e2e/pages/transactions-page.ts b/packages/web/e2e/pages/transactions-page.ts deleted file mode 100644 index e17620ed28..0000000000 --- a/packages/web/e2e/pages/transactions-page.ts +++ /dev/null @@ -1,176 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { BrowserContext, expect, Locator, Page } from "@playwright/test"; - -import { BasePage } from "~/e2e/pages/base-page"; -const TRANSACTION_CONFIRMATION_TIMEOUT = 2000; - -export class TransactionsPage extends BasePage { - readonly transactionRow: Locator; - readonly viewExplorerLink: Locator; - readonly closeTransactionBtn: Locator; - readonly page: Page; - readonly claimAndClose: Locator; - readonly claimAllBtn: Locator; - - constructor(page: Page) { - super(page); - this.page = page; - this.transactionRow = page.locator('//div/p[.="Swapped"]'); - this.viewExplorerLink = page.locator('//a/span["View on explorer"]/..'); - this.closeTransactionBtn = page.locator('//button[@data-testid="close"]'); - this.claimAndClose = page.getByRole("button", { - name: "Claim and close", - exact: true, - }); - this.claimAllBtn = page.getByRole("button", { - name: "Claim all", - exact: true, - }); - } - - async open() { - await this.page.goto("/transactions"); - return this; - } - - async viewTransactionByNumber(number: number) { - await this.transactionRow.nth(number).click(); - await this.page.waitForTimeout(1000); - } - - async viewBySwapAmount(amount: any) { - // Transactions need some time to get loaded, wait for 30 seconds. - await this.page.waitForTimeout(30000); - await this.page.reload(); - const loc = `//div/div[@class="subtitle1 text-osmoverse-100" and contains(text(), "${amount}")]`; - let isTransactionVisible = await this.page - .locator(loc) - .isVisible({ timeout: 3000 }); - if (!isTransactionVisible) { - await this.page.waitForTimeout(30000); - await this.page.reload(); - } - await this.page.waitForTimeout(1000); - await this.page.locator(loc).click({ timeout: 3000 }); - } - - async closeTransaction() { - await this.closeTransactionBtn.click(); - } - - async viewOnExplorerIsVisible() { - expect(this.viewExplorerLink.isVisible).toBeTruthy(); - } - - async getOnExplorerLink() { - const trxUrl = await this.viewExplorerLink.getAttribute("href"); - console.log("Trx url: " + trxUrl); - return trxUrl; - } - - async takeScreenshot(name: string) { - await this.page.screenshot({ - path: `screenshot-transactions-${name}.png`, - fullPage: true, - }); - } - - async cancelLimitOrder( - amount: string, - price: string, - context: BrowserContext - ) { - const cancelBtn = `//td//span[.='${amount}']/../../../../..//td//p[.='$${price}']/../../..//button`; - console.log("Use locator for a cancel btn: " + cancelBtn); - await this.page.locator(cancelBtn).first().click(); - const pageApprove = context.waitForEvent("page"); - const approvePage = await pageApprove; - await approvePage.waitForLoadState(); - const approveBtn = approvePage.getByRole("button", { - name: "Approve", - }); - await expect(approveBtn).toBeEnabled(); - const msgContentAmount = await approvePage - .getByText("Execute contract") - .textContent(); - console.log("Wallet is approving this msg: \n" + msgContentAmount); - // Approve trx - await approveBtn.click(); - // Expect that this is a cancel limit call - expect(msgContentAmount).toContain("cancel_limit"); - // wait for trx confirmation - await this.page.waitForTimeout(TRANSACTION_CONFIRMATION_TIMEOUT); - } - - async isFilledByLimitPrice(price: any) { - const loc = `//td//span[.='Filled']/../../..//td//p[.='$${price}']`; - console.log("Use Limit Order locator: " + loc); - await expect(this.page.locator(loc).first()).toBeVisible({ - timeout: 120_000, - visible: true, - }); - } - - async claimAndCloseAny(context: BrowserContext) { - const isClaimable = await this.claimAndClose - .first() - .isVisible({ timeout: 3000 }); - if (!isClaimable) { - console.log("No partially filled orders to claim."); - return; - } - await this.claimAndClose.first().click(); - const pageApprove = context.waitForEvent("page"); - const approvePage = await pageApprove; - await approvePage.waitForLoadState(); - const approveBtn = approvePage.getByRole("button", { - name: "Approve", - }); - await expect(approveBtn).toBeEnabled(); - const msgContentAmount1 = await approvePage - .getByText("Execute contract") - .first() - .textContent(); - const msgContentAmount2 = await approvePage - .getByText("Execute contract") - .last() - .textContent(); - console.log( - "Wallet is approving this msg: \n" + - msgContentAmount1 + - "---- \n" + - msgContentAmount2 - ); - // Approve trx - await approveBtn.click(); - expect(msgContentAmount1).toContain("claim_limit"); - expect(msgContentAmount2).toContain("cancel_limit"); - // wait for trx confirmation - await this.page.waitForTimeout(TRANSACTION_CONFIRMATION_TIMEOUT); - } - - async claimAll(context: BrowserContext) { - await this.claimAllBtn.click(); - const pageApprove = context.waitForEvent("page"); - const approvePage = await pageApprove; - await approvePage.waitForLoadState(); - const approveBtn = approvePage.getByRole("button", { - name: "Approve", - }); - await expect(approveBtn).toBeEnabled(); - // Approve trx - await approveBtn.click(); - // wait for trx confirmation - await this.page.waitForTimeout(TRANSACTION_CONFIRMATION_TIMEOUT); - } - - async claimAllIfPresent(context: BrowserContext) { - const isClaimable = await this.claimAllBtn.isVisible({ timeout: 4000 }); - if (isClaimable) { - console.log("Claim All filled limit orders!"); - await this.claimAll(context); - } else { - console.log("No Claim All button."); - } - } -} diff --git a/packages/web/e2e/pages/wallet-page.ts b/packages/web/e2e/pages/wallet-page.ts deleted file mode 100644 index 0b6d4746fd..0000000000 --- a/packages/web/e2e/pages/wallet-page.ts +++ /dev/null @@ -1,79 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { expect, Locator, Page } from "@playwright/test"; - -export class WalletPage { - readonly page: Page; - readonly importWalletBtn: Locator; - readonly useRecoveryBtn: Locator; - readonly privateKeyBtn: Locator; - readonly privateKeyInput: Locator; - readonly importBtn: Locator; - readonly walletNameInput: Locator; - readonly walletPassInput: Locator; - readonly walletRePassInput: Locator; - readonly nextBtn: Locator; - readonly allCheckbox: Locator; - readonly saveBtn: Locator; - readonly finishBtn: Locator; - - constructor(page: Page) { - this.page = page; - this.importWalletBtn = page.getByText("Import an existing wallet"); - this.useRecoveryBtn = page.getByText("Use recovery phrase or private key"); - this.privateKeyBtn = page.getByRole("button", { - name: "Private key", - exact: true, - }); - this.privateKeyInput = page.locator('input[type="password"]'); - this.importBtn = page.getByRole("button", { name: "Import", exact: true }); - this.walletNameInput = page.locator('input[name="name"]'); - this.walletPassInput = page.locator('input[name="password"]'); - this.walletRePassInput = page.locator("input[name='confirmPassword']"); - this.nextBtn = page.getByRole("button", { name: "Next", exact: true }); - this.allCheckbox = page.locator('input[type="checkbox"]').first(); - this.saveBtn = page.getByRole("button", { name: "Save", exact: true }); - this.finishBtn = page.getByRole("button", { name: "Finish", exact: true }); - } - - async goto(extensionId: string) { - await this.page.goto(`chrome-extension://${extensionId}/register.html#`); - // IMO, it is better to assert navigation is successful - await expect(this.page.getByText("Your Interchain Gateway")).toBeVisible(); - } - - async importWalletWithPrivateKey(privateKey: string) { - await this.importWalletBtn.click(); - await this.useRecoveryBtn.click(); - await this.privateKeyBtn.click(); - await this.privateKeyInput.fill(privateKey); - await this.importBtn.click(); - } - - async setWalletNameAndPassword( - name: string, - password: string = "TestPassword2024." - ) { - await this.walletNameInput.fill(name); - await this.walletPassInput.fill(password); - await this.walletRePassInput.fill(password); - await this.nextBtn.click(); - } - - async selectChainsAndSave() { - await this.allCheckbox.check(); - await this.saveBtn.click(); - // IMO, it is better to assert default action is successful. Unless a failure is possible. - await expect(this.page.getByText("Account Created!")).toBeVisible(); - } - - async takeScreenshot() { - await this.page.screenshot({ - path: "screenshot-wallet-setup.png", - fullPage: true, - }); - } - - async finish() { - await this.finishBtn.click(); - } -} diff --git a/packages/web/e2e/tests/claim.spec.ts b/packages/web/e2e/tests/claim.spec.ts deleted file mode 100644 index 1786cc8724..0000000000 --- a/packages/web/e2e/tests/claim.spec.ts +++ /dev/null @@ -1,60 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { BrowserContext, chromium, test } from "@playwright/test"; -import process from "process"; - -import { TransactionsPage } from "~/e2e/pages/transactions-page"; -import { TestConfig } from "~/e2e/test-config"; -import { UnzipExtension } from "~/e2e/unzip-extension"; - -import { TradePage } from "../pages/trade-page"; -import { WalletPage } from "../pages/wallet-page"; - -test.describe("Test Claim All Orders feature", () => { - let context: BrowserContext; - const privateKey = process.env.PRIVATE_KEY ?? "private_key"; - let tradePage: TradePage; - - test.beforeAll(async () => { - const pathToExtension = new UnzipExtension().getPathToExtension(); - console.log("\nSetup Wallet Extension before tests."); - // Launch Chrome with a Keplr wallet extension - context = await chromium.launchPersistentContext( - "", - new TestConfig().getBrowserExtensionConfig(false, pathToExtension) - ); - // Get all new pages (including Extension) in the context and wait - const emptyPage = context.pages()[0]; - await emptyPage.waitForTimeout(2000); - const page = context.pages()[1]; - const walletPage = new WalletPage(page); - // Import existing Wallet (could be aggregated in one function). - await walletPage.importWalletWithPrivateKey(privateKey); - await walletPage.setWalletNameAndPassword("Claim All Orders"); - await walletPage.selectChainsAndSave(); - await walletPage.finish(); - // Switch to Application - tradePage = new TradePage(context.pages()[0]); - await tradePage.goto(); - await tradePage.connectWallet(); - }); - - test.afterAll(async () => { - await context.close(); - }); - - test("User should be able to Claim All filled limit orders", async () => { - await tradePage.goto(); - await tradePage.gotoOrdersHistory(10); - const p = context.pages()[0]; - const trxPage = new TransactionsPage(p); - await trxPage.claimAllIfPresent(context); - }); - - test("User should be able to Claim and Close partialy filled limit orders", async () => { - await tradePage.goto(); - await tradePage.gotoOrdersHistory(10); - const p = context.pages()[0]; - const trxPage = new TransactionsPage(p); - await trxPage.claimAndCloseAny(context); - }); -}); diff --git a/packages/web/e2e/tests/monitoring.limit.wallet.spec.ts b/packages/web/e2e/tests/monitoring.limit.wallet.spec.ts deleted file mode 100644 index 0a4ffab161..0000000000 --- a/packages/web/e2e/tests/monitoring.limit.wallet.spec.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { type BrowserContext, chromium, expect, test } from "@playwright/test"; - -import { TransactionsPage } from "~/e2e/pages/transactions-page"; -import { TestConfig } from "~/e2e/test-config"; -import { UnzipExtension } from "~/e2e/unzip-extension"; - -import { TradePage } from "../pages/trade-page"; -import { WalletPage } from "../pages/wallet-page"; - -test.describe("Test Filled Limit Order feature", () => { - let context: BrowserContext; - const privateKey = process.env.PRIVATE_KEY ?? "private_key"; - let tradePage: TradePage; - - test.beforeAll(async () => { - const pathToExtension = new UnzipExtension().getPathToExtension(); - console.log("\nSetup Wallet Extension before tests."); - // Launch Chrome with a Keplr wallet extension - context = await chromium.launchPersistentContext( - "", - new TestConfig().getBrowserExtensionConfig(false, pathToExtension) - ); - // Get all new pages (including Extension) in the context and wait - const emptyPage = context.pages()[0]; - await emptyPage.waitForTimeout(2000); - const page = context.pages()[1]; - const walletPage = new WalletPage(page); - // Import existing Wallet (could be aggregated in one function). - await walletPage.importWalletWithPrivateKey(privateKey); - await walletPage.setWalletNameAndPassword("Monitoring E2E Tests"); - await walletPage.selectChainsAndSave(); - await walletPage.finish(); - // Switch to Application - tradePage = new TradePage(context.pages()[0]); - await tradePage.goto(); - await tradePage.connectWallet(); - expect(await tradePage.isError(), "Swap is not available!").toBeFalsy(); - }); - - test.afterAll(async () => { - await context.close(); - }); - - test("User should be able to limit sell OSMO", async () => { - await tradePage.goto(); - await tradePage.openSellTab(); - await tradePage.openLimit(); - await tradePage.selectAsset("OSMO"); - await tradePage.enterAmount("1.08"); - await tradePage.setLimitPriceChange("Market"); - const { msgContentAmount } = await tradePage.sellAndGetWalletMsg( - context, - true - ); - expect(msgContentAmount, "No msg from the wallet!").toBeTruthy(); - // now this is converted from USDC - expect(msgContentAmount).toContain("place_limit"); - expect(msgContentAmount).toContain('"order_direction": "ask"'); - await tradePage.isTransactionSuccesful(); - await tradePage.getTransactionUrl(); - }); - - test("User should be able to limit buy OSMO", async () => { - const PRICE_INCREASE_FACTOR = 1.07; // 7% increase for limit price - const ORDER_HISTORY_TIMEOUT = 30; // Seconds to wait for order history - await tradePage.goto(); - await tradePage.openBuyTab(); - await tradePage.openLimit(); - await tradePage.selectAsset("OSMO"); - await tradePage.enterAmount("1.04"); - await tradePage.setLimitPriceChange("Market"); - const limitPrice = Number(await tradePage.getLimitPrice()); - const highLimitPrice = (limitPrice * PRICE_INCREASE_FACTOR).toFixed(4); - await tradePage.setLimitPrice(String(highLimitPrice)); - const { msgContentAmount } = await tradePage.buyAndGetWalletMsg( - context, - true - ); - expect(msgContentAmount, "No msg from the wallet!").toBeTruthy(); - expect(msgContentAmount).toContain('"quantity": "1040000"'); - expect(msgContentAmount).toContain("place_limit"); - expect(msgContentAmount).toContain('"order_direction": "bid"'); - await tradePage.isTransactionSuccesful(); - await tradePage.getTransactionUrl(); - await tradePage.gotoOrdersHistory(ORDER_HISTORY_TIMEOUT); - const p = context.pages()[0]; - const trxPage = new TransactionsPage(p); - await trxPage.isFilledByLimitPrice(highLimitPrice); - }); -}); diff --git a/packages/web/e2e/tests/monitoring.market.wallet.spec.ts b/packages/web/e2e/tests/monitoring.market.wallet.spec.ts deleted file mode 100644 index d67ad7268d..0000000000 --- a/packages/web/e2e/tests/monitoring.market.wallet.spec.ts +++ /dev/null @@ -1,90 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { type BrowserContext, chromium, expect, test } from "@playwright/test"; - -import { TestConfig } from "~/e2e/test-config"; -import { UnzipExtension } from "~/e2e/unzip-extension"; - -import { TradePage } from "../pages/trade-page"; -import { WalletPage } from "../pages/wallet-page"; - -test.describe("Test Market Buy/Sell Order feature", () => { - let context: BrowserContext; - const privateKey = process.env.PRIVATE_KEY ?? "private_key"; - let tradePage: TradePage; - const TRX_SUCCESS_TIMEOUT = 10000; - - test.beforeAll(async () => { - const pathToExtension = new UnzipExtension().getPathToExtension(); - console.log("\nSetup Wallet Extension before tests."); - // Launch Chrome with a Keplr wallet extension - context = await chromium.launchPersistentContext( - "", - new TestConfig().getBrowserExtensionConfig(false, pathToExtension) - ); - // Get all new pages (including Extension) in the context and wait - const emptyPage = context.pages()[0]; - await emptyPage.waitForTimeout(2000); - const page = context.pages()[1]; - const walletPage = new WalletPage(page); - // Import existing Wallet (could be aggregated in one function). - await walletPage.importWalletWithPrivateKey(privateKey); - await walletPage.setWalletNameAndPassword("Monitoring E2E Tests"); - await walletPage.selectChainsAndSave(); - await walletPage.finish(); - // Switch to Application - tradePage = new TradePage(context.pages()[0]); - await tradePage.goto(); - await tradePage.connectWallet(); - expect(await tradePage.isError(), "Swap is not available!").toBeFalsy(); - }); - - test.afterAll(async () => { - await context.close(); - }); - - // biome-ignore lint/complexity/noForEach: - [{ name: "WBTC" }, { name: "OSMO" }].forEach(({ name }) => { - test(`User should be able to Market Buy ${name}`, async () => { - await tradePage.goto(); - await tradePage.openBuyTab(); - await tradePage.selectAsset(name); - await tradePage.enterAmount("1.55"); - await tradePage.isSufficientBalanceForTrade(); - await tradePage.showSwapInfo(); - const { msgContentAmount } = await tradePage.buyAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain("type: osmosis/poolmanager/"); - await tradePage.isTransactionSuccesful(TRX_SUCCESS_TIMEOUT); - await tradePage.getTransactionUrl(); - }); - }); - - // unwrapped market sell tests just in case this affects anything. - test("User should be able to Market Sell WBTC", async () => { - await tradePage.goto(); - await tradePage.openSellTab(); - await tradePage.selectAsset("WBTC"); - await tradePage.enterAmount("1.54"); - await tradePage.isSufficientBalanceForTrade(); - await tradePage.showSwapInfo(); - const { msgContentAmount } = await tradePage.sellAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain("type: osmosis/poolmanager/"); - await tradePage.isTransactionSuccesful(TRX_SUCCESS_TIMEOUT); - await tradePage.getTransactionUrl(); - }); - - test("User should be able to Market Sell OSMO", async () => { - await tradePage.goto(); - await tradePage.openSellTab(); - await tradePage.selectAsset("OSMO"); - await tradePage.enterAmount("1.54"); - await tradePage.isSufficientBalanceForTrade(); - await tradePage.showSwapInfo(); - const { msgContentAmount } = await tradePage.sellAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain("type: osmosis/poolmanager/"); - await tradePage.isTransactionSuccesful(TRX_SUCCESS_TIMEOUT); - await tradePage.getTransactionUrl(); - }); -}); diff --git a/packages/web/e2e/tests/pools.spec.ts b/packages/web/e2e/tests/pools.spec.ts deleted file mode 100644 index 6c38cfd1cb..0000000000 --- a/packages/web/e2e/tests/pools.spec.ts +++ /dev/null @@ -1,72 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { BrowserContext, chromium, expect, Page, test } from "@playwright/test"; - -import { TestConfig } from "~/e2e/test-config"; - -import { PoolsPage } from "../pages/pools-page"; - -test.describe("Test Select Pool feature", () => { - let context: BrowserContext; - let poolsPage: PoolsPage; - let page: Page; - - test.beforeAll(async () => { - context = await chromium.launchPersistentContext( - "", - new TestConfig().getBrowserConfig(true) - ); - page = context.pages()[0]; - poolsPage = new PoolsPage(page); - }); - - test.afterAll(async () => { - await context.close(); - }); - - test("User should be able to see at least 10 pools", async () => { - await poolsPage.goto(); - expect(await poolsPage.getPoolsNumber()).toBeGreaterThan(10); - const topLiquidity = await poolsPage.getTopTenPoolsByLiquidity(); - topLiquidity.every(function (element) { - expect(element).toBeGreaterThan(10_000); - }); - const topVolume = await poolsPage.getTopTenPoolsByVolume(); - topVolume.every(function (element) { - expect(element).toBeGreaterThan(10_000); - }); - const topAPR = await poolsPage.getTopTenPoolsByAPR(); - topAPR.every(function (element) { - expect(element).toContain("%"); - }); - }); - - test("User should be able to select ATOM/USDC pool", async () => { - const poolName = "ATOM/USDC"; - await poolsPage.goto(); - await poolsPage.searchForPool(poolName); - const poolPage = await poolsPage.viewPool(1282, poolName); - const balance = await poolPage.getBalance(); - expect(balance).toEqual("$0"); - const tradeModal = await poolPage.getTradeModal(); - await tradeModal.enterAmount("1"); - const rate = await tradeModal.getExchangeRate(); - await tradeModal.showSwapInfo(); - expect(rate).toContain("ATOM"); - expect(rate).toContain("USDC"); - }); - - test("User should be able to select OSMO/USDC pool", async () => { - const poolName = "OSMO/USDC"; - await poolsPage.goto(); - await poolsPage.searchForPool(poolName); - const poolPage = await poolsPage.viewPool(1464, poolName); - const balance = await poolPage.getBalance(); - expect(balance).toEqual("$0"); - const tradeModal = await poolPage.getTradeModal(); - await tradeModal.enterAmount("1"); - const rate = await tradeModal.getExchangeRate(); - await tradeModal.showSwapInfo(); - expect(rate).toContain("OSMO"); - expect(rate).toContain("USDC"); - }); -}); diff --git a/packages/web/e2e/tests/portfolio.wallet.spec.ts b/packages/web/e2e/tests/portfolio.wallet.spec.ts deleted file mode 100644 index 4ce12f9997..0000000000 --- a/packages/web/e2e/tests/portfolio.wallet.spec.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { - type BrowserContext, - chromium, - expect, - type Page, - test, -} from "@playwright/test"; -import { addCoverageReport, attachCoverageReport } from "monocart-reporter"; - -import { TestConfig } from "~/e2e/test-config"; -import { UnzipExtension } from "~/e2e/unzip-extension"; - -import { PortfolioPage } from "../pages/portfolio-page"; -import { WalletPage } from "../pages/wallet-page"; - -test.describe("Test Portfolio feature", () => { - let context: BrowserContext; - const privateKey = process.env.PRIVATE_KEY ?? "pk"; - let portfolioPage: PortfolioPage; - const dollarBalanceRegEx = /\$\d+/; - let page: Page; - - test.beforeAll(async () => { - const pathToExtension = new UnzipExtension().getPathToExtension(); - console.log("\nSetup Wallet Extension before tests."); - // Launch Chrome with a Keplr wallet extension - context = await chromium.launchPersistentContext( - "", - new TestConfig().getBrowserExtensionConfig(true, pathToExtension) - ); - // Get all new pages (including Extension) in the context and wait - const emptyPage = context.pages()[0]; - await emptyPage.waitForTimeout(2000); - page = context.pages()[1]; - const walletPage = new WalletPage(page); - // Import existing Wallet (could be aggregated in one function). - await walletPage.importWalletWithPrivateKey(privateKey); - await walletPage.setWalletNameAndPassword("Test Portfolio"); - await walletPage.selectChainsAndSave(); - await walletPage.finish(); - // Switch to Application - page = context.pages()[0]; - await page.coverage.startJSCoverage({ - resetOnNavigation: false, - }); - portfolioPage = new PortfolioPage(page); - await portfolioPage.goto(); - await portfolioPage.connectWallet(); - await portfolioPage.hideZeroBalances(); - await portfolioPage.viewMoreBalances(); - }); - - test.afterAll(async () => { - const coverage = await page.coverage.stopJSCoverage(); - // coverage report - const report = await attachCoverageReport(coverage, test.info()); - console.log(report.summary); - - await addCoverageReport(coverage, test.info()); - await context.close(); - }); - - // biome-ignore lint/complexity/noForEach: - [ - { name: "OSMO" }, - { name: "ATOM" }, - { name: "USDT" }, - { name: "USDC" }, - { name: "TIA" }, - { name: "DAI" }, - ].forEach(({ name }) => { - test(`User should be able to see native balances for ${name}`, async () => { - await portfolioPage.searchForToken(name); - const osmoBalance = await portfolioPage.getBalanceFor(name); - expect(osmoBalance).toMatch(dollarBalanceRegEx); - }); - }); - - // biome-ignore lint/complexity/noForEach: - [ - { name: "INJ" }, - { name: "ETH.axl" }, - { name: "SOL" }, - { name: "milkTIA" }, - { name: "BTC" }, - { name: "WBTC" }, - { name: "ETH" }, - ].forEach(({ name }) => { - test(`User should be able to see bridged balances for ${name}`, async () => { - await portfolioPage.searchForToken(name); - const osmoBalance = await portfolioPage.getBalanceFor(name); - expect(osmoBalance).toMatch(dollarBalanceRegEx); - }); - }); -}); diff --git a/packages/web/e2e/tests/select.spec.ts b/packages/web/e2e/tests/select.spec.ts deleted file mode 100644 index 550fb1d86a..0000000000 --- a/packages/web/e2e/tests/select.spec.ts +++ /dev/null @@ -1,118 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { - type BrowserContext, - chromium, - type Page, - test, -} from "@playwright/test"; -import { addCoverageReport, attachCoverageReport } from "monocart-reporter"; - -import { TradePage } from "~/e2e/pages/trade-page"; -import { TestConfig } from "~/e2e/test-config"; - -// Pairs are selected from top 10 -test.describe("Test Select Swap Pair feature", () => { - let context: BrowserContext; - let swapPage: TradePage; - let page: Page; - - test.beforeAll(async () => { - context = await chromium.launchPersistentContext( - "", - new TestConfig().getBrowserConfig(true) - ); - page = context.pages()[0]; - await page.coverage.startJSCoverage({ - resetOnNavigation: false, - }); - swapPage = new TradePage(page); - await swapPage.goto(); - }); - - test.afterAll(async () => { - const coverage = await page.coverage.stopJSCoverage(); - // coverage report - const report = await attachCoverageReport(coverage, test.info()); - console.log(report.summary); - - await addCoverageReport(coverage, test.info()); - await context.close(); - }); - - // Price Impact-54.768% -> no liquidity - test("User should be able to select nBTC/USDC", async () => { - await swapPage.goto(); - await swapPage.selectPair("nBTC", "USDC"); - await swapPage.enterAmount("0.01"); - await swapPage.showSwapInfo(); - }); - - test("User should be able to select WBTC/USDC", async () => { - await swapPage.goto(); - await swapPage.selectPair("WBTC", "USDC"); - await swapPage.enterAmount("0.1"); - await swapPage.showSwapInfo(); - }); - - test("User should be able to select OSMO/USDC", async () => { - await swapPage.goto(); - await swapPage.selectPair("OSMO", "USDC"); - await swapPage.enterAmount("1"); - await swapPage.showSwapInfo(); - }); - - test("User should be able to select INJ/USDC", async () => { - await swapPage.goto(); - await swapPage.selectPair("INJ", "USDC"); - await swapPage.enterAmount("10"); - await swapPage.showSwapInfo(); - }); - - test("User should be able to select TIA/USDC", async () => { - await swapPage.goto(); - await swapPage.selectPair("TIA", "USDC"); - await swapPage.enterAmount("100"); - await swapPage.showSwapInfo(); - }); - - test("User should be able to select ATOM/USDC", async () => { - await swapPage.selectPair("ATOM", "USDC"); - await swapPage.enterAmount("100"); - }); - - test("User should be able to select USDT/USDC", async () => { - await swapPage.selectPair("USDT", "USDC"); - await swapPage.enterAmount("10000"); - }); - - test("User should be able to select TIA/OSMO", async () => { - await swapPage.selectPair("TIA", "OSMO"); - await swapPage.enterAmount("100"); - }); - - test("User should be able to select AKT/OSMO", async () => { - await swapPage.selectPair("AKT", "OSMO"); - await swapPage.enterAmount("100"); - }); - - test("User should be able to select PICA/OSMO", async () => { - await swapPage.selectPair("PICA", "OSMO"); - await swapPage.enterAmount("100"); - }); - - test("User should be able to select USDT/OSMO", async () => { - await swapPage.selectPair("USDT", "OSMO"); - await swapPage.enterAmount("100"); - }); - - test("User should be able to select TIA/BOOT", async () => { - // Just to verify some odd pair - await swapPage.selectPair("TIA", "BOOT"); - await swapPage.enterAmount("100"); - }); - - test("User should be able to select stATOM/USDC", async () => { - await swapPage.selectPair("stATOM", "USDC"); - await swapPage.enterAmount("100"); - }); -}); diff --git a/packages/web/e2e/tests/stables.wallet.spec.ts b/packages/web/e2e/tests/stables.wallet.spec.ts deleted file mode 100644 index 0cf3715892..0000000000 --- a/packages/web/e2e/tests/stables.wallet.spec.ts +++ /dev/null @@ -1,104 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { type BrowserContext, chromium, expect, test } from "@playwright/test"; -import process from "process"; - -import { TradePage } from "~/e2e/pages/trade-page"; -import { TestConfig } from "~/e2e/test-config"; -import { UnzipExtension } from "~/e2e/unzip-extension"; - -import { WalletPage } from "../pages/wallet-page"; - -test.describe("Test Swap Stables feature", () => { - let context: BrowserContext; - const privateKey = process.env.PRIVATE_KEY ?? "private_key"; - let tradePage: TradePage; - const USDC = - "ibc/498A0751C798A0D9A389AA3691123DADA57DAA4FE165D5C75894505B876BA6E4"; - const USDCa = - "ibc/D189335C6E4A68B513C10AB227BF1C1D38C746766278BA3EEB4FB14124F1D858"; - const allUSDT = - "factory/osmo1em6xs47hd82806f5cxgyufguxrrc7l0aqx7nzzptjuqgswczk8csavdxek/alloyed/allUSDT"; - const swapAmount = "0.55"; - - test.beforeAll(async () => { - const pathToExtension = new UnzipExtension().getPathToExtension(); - console.log("\nSetup Wallet Extension before tests."); - // Launch Chrome with a Keplr wallet extension - context = await chromium.launchPersistentContext( - "", - new TestConfig().getBrowserExtensionConfig(true, pathToExtension) - ); - // Get all new pages (including Extension) in the context and wait - const emptyPage = context.pages()[0]; - await emptyPage.waitForTimeout(2000); - let page = context.pages()[1]; - const walletPage = new WalletPage(page); - // Import existing Wallet (could be aggregated in one function). - await walletPage.importWalletWithPrivateKey(privateKey); - await walletPage.setWalletNameAndPassword("Test Stables"); - await walletPage.selectChainsAndSave(); - await walletPage.finish(); - page = context.pages()[0]; - tradePage = new TradePage(page); - - await tradePage.goto(); - await tradePage.connectWallet(); - expect(await tradePage.isError(), "Swap is not available!").toBeFalsy(); - }); - - test.afterAll(async () => { - await context.close(); - }); - - test("User should be able to swap USDC to USDC.eth.axl", async () => { - await tradePage.goto(); - await tradePage.selectPair("USDC", "USDC.eth.axl"); - await tradePage.enterAmount(swapAmount); - await tradePage.showSwapInfo(); - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain(`denom: ${USDC}`); - expect(msgContentAmount).toContain(`token_out_denom: ${USDCa}`); - await tradePage.isTransactionSuccesful(); - await tradePage.getTransactionUrl(); - }); - - test("User should be able to swap USDC.eth.axl to USDC", async () => { - await tradePage.goto(); - await tradePage.selectPair("USDC.eth.axl", "USDC"); - await tradePage.enterAmount(swapAmount); - await tradePage.showSwapInfo(); - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain(`denom: ${USDCa}`); - expect(msgContentAmount).toContain(`token_out_denom: ${USDC}`); - await tradePage.isTransactionSuccesful(); - await tradePage.getTransactionUrl(); - }); - - test("User should be able to swap USDT to USDC", async () => { - await tradePage.goto(); - await tradePage.selectPair("USDT", "USDC"); - await tradePage.enterAmount(swapAmount); - await tradePage.showSwapInfo(); - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain(USDC); - expect(msgContentAmount).toContain(allUSDT); - await tradePage.isTransactionSuccesful(); - await tradePage.getTransactionUrl(); - }); - - test("User should be able to swap USDC to USDT", async () => { - await tradePage.goto(); - await tradePage.selectPair("USDC", "USDT"); - await tradePage.enterAmount(swapAmount); - await tradePage.showSwapInfo(); - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain(`denom: ${USDC}`); - expect(msgContentAmount).toContain(allUSDT); - await tradePage.isTransactionSuccesful(); - await tradePage.getTransactionUrl(); - }); -}); diff --git a/packages/web/e2e/tests/swap.wallet.spec.ts b/packages/web/e2e/tests/swap.wallet.spec.ts deleted file mode 100644 index 4c3b82eb18..0000000000 --- a/packages/web/e2e/tests/swap.wallet.spec.ts +++ /dev/null @@ -1,236 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { type BrowserContext, chromium, expect, test } from "@playwright/test"; -import process from "process"; - -import { TradePage } from "~/e2e/pages/trade-page"; -import { TestConfig } from "~/e2e/test-config"; -import { UnzipExtension } from "~/e2e/unzip-extension"; - -import { WalletPage } from "../pages/wallet-page"; - -test.describe("Test Swap feature", () => { - let context: BrowserContext; - const walletId = - process.env.WALLET_ID ?? "osmo1qyc8u7cn0zjxcu9dvrjz5zwfnn0ck92v62ak9l"; - const privateKey = process.env.PRIVATE_KEY ?? "private_key"; - let tradePage: TradePage; - const USDC = - "ibc/498A0751C798A0D9A389AA3691123DADA57DAA4FE165D5C75894505B876BA6E4"; - const ATOM = - "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2"; - const TIA = - "ibc/D79E7D83AB399BFFF93433E54FAA480C191248FC556924A2A8351AE2638B3877"; - const INJ = - "ibc/64BA6E31FE887D66C6F8F31C7B1A80C7CA179239677B4088BB55F5EA07DBE273"; - const AKT = - "ibc/1480B8FD20AD5FCAE81EA87584D269547DD4D436843C1D20F15E00EB64743EF4"; - - test.beforeAll(async () => { - const pathToExtension = new UnzipExtension().getPathToExtension(); - console.log("\nSetup Wallet Extension before tests."); - // Launch Chrome with a Keplr wallet extension - context = await chromium.launchPersistentContext( - "", - new TestConfig().getBrowserExtensionConfig(true, pathToExtension) - ); - // Get all new pages (including Extension) in the context and wait - const emptyPage = context.pages()[0]; - await emptyPage.waitForTimeout(2000); - const page = context.pages()[1]; - const walletPage = new WalletPage(page); - // Import existing Wallet (could be aggregated in one function). - await walletPage.importWalletWithPrivateKey(privateKey); - await walletPage.setWalletNameAndPassword("Test Swaps"); - await walletPage.selectChainsAndSave(); - await walletPage.finish(); - // Switch to Application - tradePage = new TradePage(context.pages()[0]); - await tradePage.goto(); - await tradePage.connectWallet(); - expect(await tradePage.isError(), "Swap is not available!").toBeFalsy(); - }); - - test.afterAll(async () => { - await context.close(); - }); - - test("User should be able to swap OSMO to ATOM", async () => { - await tradePage.goto(); - await tradePage.selectPair("OSMO", "ATOM"); - await tradePage.enterAmount("0.2"); - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain(`token_out_denom: ${ATOM}`); - expect(msgContentAmount).toContain(`sender: ${walletId}`); - expect(msgContentAmount).toContain("denom: uosmo"); - await tradePage.isTransactionSuccesful(); - await tradePage.getTransactionUrl(); - }); - - test("User should be able to swap ATOM to OSMO", async () => { - await tradePage.goto(); - await tradePage.selectPair("ATOM", "OSMO"); - await tradePage.enterAmount("0.01"); - await tradePage.showSwapInfo(); - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain(`denom: ${ATOM}`); - expect(msgContentAmount).toContain(`sender: ${walletId}`); - expect(msgContentAmount).toContain("token_out_denom: uosmo"); - await tradePage.isTransactionSuccesful(); - await tradePage.getTransactionUrl(); - }); - - test("User should be able to swap OSMO to USDC", async () => { - await tradePage.goto(); - await tradePage.selectPair("OSMO", "USDC"); - await tradePage.enterAmount("0.2"); - await tradePage.showSwapInfo(); - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain(`token_out_denom: ${USDC}`); - expect(msgContentAmount).toContain(`sender: ${walletId}`); - expect(msgContentAmount).toContain("denom: uosmo"); - await tradePage.isTransactionSuccesful(); - await tradePage.getTransactionUrl(); - }); - - test("User should be able to swap OSMO to WBTC", async () => { - await tradePage.goto(); - await tradePage.selectPair("OSMO", "WBTC"); - await tradePage.enterAmount("0.9"); - await tradePage.showSwapInfo(); - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain(`sender: ${walletId}`); - expect(msgContentAmount).toContain("denom: uosmo"); - await tradePage.isTransactionSuccesful(); - await tradePage.getTransactionUrl(); - }); - - test("User should be able to swap USDC to OSMO", async () => { - await tradePage.goto(); - await tradePage.selectPair("USDC", "OSMO"); - await tradePage.enterAmount("0.1"); - await tradePage.showSwapInfo(); - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain("token_out_denom: uosmo"); - expect(msgContentAmount).toContain(`sender: ${walletId}`); - expect(msgContentAmount).toContain(`denom: ${USDC}`); - await tradePage.isTransactionSuccesful(); - await tradePage.getTransactionUrl(); - }); - - test("User should be able to swap ATOM to USDC", async () => { - await tradePage.goto(); - await tradePage.selectPair("ATOM", "USDC"); - await tradePage.enterAmount("0.015"); - await tradePage.showSwapInfo(); - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain(`denom: ${ATOM}`); - expect(msgContentAmount).toContain(`sender: ${walletId}`); - expect(msgContentAmount).toContain(`token_out_denom: ${USDC}`); - await tradePage.isTransactionSuccesful(); - await tradePage.getTransactionUrl(); - }); - - test("User should be able to swap USDC to ATOM", async () => { - await tradePage.goto(); - await tradePage.selectPair("USDC", "ATOM"); - await tradePage.enterAmount("0.1"); - await tradePage.showSwapInfo(); - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain(`denom: ${USDC}`); - expect(msgContentAmount).toContain(`sender: ${walletId}`); - expect(msgContentAmount).toContain(`token_out_denom: ${ATOM}`); - await tradePage.isTransactionSuccesful(); - await tradePage.getTransactionUrl(); - }); - - test("User should be able to swap USDC to TIA", async () => { - await tradePage.goto(); - await tradePage.selectPair("USDC", "TIA"); - await tradePage.enterAmount("0.1"); - await tradePage.showSwapInfo(); - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain(`denom: ${USDC}`); - expect(msgContentAmount).toContain(`sender: ${walletId}`); - expect(msgContentAmount).toContain(`token_out_denom: ${TIA}`); - await tradePage.isTransactionSuccesful(); - await tradePage.getTransactionUrl(); - }); - - test("User should be able to swap TIA to USDC", async () => { - await tradePage.goto(); - await tradePage.selectPair("TIA", "USDC"); - await tradePage.enterAmount("0.02"); - await tradePage.showSwapInfo(); - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain(`denom: ${TIA}`); - expect(msgContentAmount).toContain(`sender: ${walletId}`); - expect(msgContentAmount).toContain(`token_out_denom: ${USDC}`); - await tradePage.isTransactionSuccesful(); - await tradePage.getTransactionUrl(); - }); - - test("User should be able to swap USDC to INJ", async () => { - await tradePage.goto(); - await tradePage.selectPair("USDC", "INJ"); - await tradePage.enterAmount("0.2"); - await tradePage.showSwapInfo(); - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain(`denom: ${USDC}`); - expect(msgContentAmount).toContain(`sender: ${walletId}`); - expect(msgContentAmount).toContain(`token_out_denom: ${INJ}`); - await tradePage.isTransactionSuccesful(); - await tradePage.getTransactionUrl(); - }); - - test("User should be able to swap INJ to USDC", async () => { - await tradePage.goto(); - await tradePage.selectPair("INJ", "USDC"); - await tradePage.enterAmount("0.01"); - await tradePage.showSwapInfo(); - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain(`denom: ${INJ}`); - expect(msgContentAmount).toContain(`sender: ${walletId}`); - expect(msgContentAmount).toContain(`token_out_denom: ${USDC}`); - await tradePage.isTransactionSuccesful(); - await tradePage.getTransactionUrl(); - }); - - test("User should be able to swap USDC to AKT", async () => { - await tradePage.goto(); - await tradePage.selectPair("USDC", "AKT"); - await tradePage.enterAmount("0.1"); - await tradePage.showSwapInfo(); - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain(`denom: ${USDC}`); - expect(msgContentAmount).toContain(`sender: ${walletId}`); - expect(msgContentAmount).toContain(`token_out_denom: ${AKT}`); - await tradePage.isTransactionSuccesful(); - await tradePage.getTransactionUrl(); - }); - - test("User should be able to swap AKT to USDC", async () => { - await tradePage.goto(); - await tradePage.selectPair("AKT", "USDC"); - await tradePage.enterAmount("0.025"); - await tradePage.showSwapInfo(); - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain(`denom: ${AKT}`); - expect(msgContentAmount).toContain(`sender: ${walletId}`); - expect(msgContentAmount).toContain(`token_out_denom: ${USDC}`); - await tradePage.isTransactionSuccesful(); - await tradePage.getTransactionUrl(); - }); -}); diff --git a/packages/web/e2e/tests/trade.wallet.spec.ts b/packages/web/e2e/tests/trade.wallet.spec.ts deleted file mode 100644 index dc5fb8e54b..0000000000 --- a/packages/web/e2e/tests/trade.wallet.spec.ts +++ /dev/null @@ -1,128 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { type BrowserContext, chromium, expect, test } from "@playwright/test"; - -import { TransactionsPage } from "~/e2e/pages/transactions-page"; -import { TestConfig } from "~/e2e/test-config"; -import { UnzipExtension } from "~/e2e/unzip-extension"; - -import { TradePage } from "../pages/trade-page"; -import { WalletPage } from "../pages/wallet-page"; - -test.describe("Test Trade feature", () => { - let context: BrowserContext; - const privateKey = process.env.PRIVATE_KEY ?? "private_key"; - let tradePage: TradePage; - const USDC = - "ibc/498A0751C798A0D9A389AA3691123DADA57DAA4FE165D5C75894505B876BA6E4"; - const ATOM = - "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2"; - - test.beforeAll(async () => { - const pathToExtension = new UnzipExtension().getPathToExtension(); - console.log("\nSetup Keplr Wallet Extension before tests."); - // Launch Chrome with a Keplr wallet extension - context = await chromium.launchPersistentContext( - "", - new TestConfig().getBrowserExtensionConfig(false, pathToExtension) - ); - // Get all new pages (including Extension) in the context and wait - const emptyPage = context.pages()[0]; - await emptyPage.waitForTimeout(2000); - const page = context.pages()[1]; - const walletPage = new WalletPage(page); - // Import existing Wallet (could be aggregated in one function). - await walletPage.importWalletWithPrivateKey(privateKey); - await walletPage.setWalletNameAndPassword("Test Trades"); - await walletPage.selectChainsAndSave(); - await walletPage.finish(); - // Switch to Application - tradePage = new TradePage(context.pages()[0]); - await tradePage.goto(); - await tradePage.connectWallet(); - expect(await tradePage.isError(), "Swap is not available!").toBeFalsy(); - }); - - test.afterAll(async () => { - await context.close(); - }); - - test("User should be able to Buy ATOM", async () => { - await tradePage.goto(); - await tradePage.openBuyTab(); - await tradePage.selectAsset("ATOM"); - await tradePage.enterAmount("1.12"); - const { msgContentAmount } = await tradePage.buyAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain(`denom: ${ATOM}`); - expect(msgContentAmount).toContain("type: osmosis/poolmanager/"); - expect(msgContentAmount).toContain(`denom: ${USDC}`); - await tradePage.isTransactionSuccesful(); - await tradePage.getTransactionUrl(); - }); - - test("User should be able to Sell ATOM", async () => { - await tradePage.goto(); - await tradePage.openSellTab(); - await tradePage.selectAsset("ATOM"); - await tradePage.enterAmount("1.11"); - const { msgContentAmount } = await tradePage.sellAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain(`denom: ${USDC}`); - expect(msgContentAmount).toContain("type: osmosis/poolmanager/"); - expect(msgContentAmount).toContain(`denom: ${ATOM}`); - await tradePage.isTransactionSuccesful(); - await tradePage.getTransactionUrl(); - }); - - test("User should be able to limit sell ATOM", async () => { - await tradePage.goto(); - const amount = "1.01"; - await tradePage.openSellTab(); - await tradePage.openLimit(); - await tradePage.selectAsset("ATOM"); - await tradePage.enterAmount(amount); - await tradePage.setLimitPriceChange("5%"); - const limitPrice = await tradePage.getLimitPrice(); - const { msgContentAmount } = await tradePage.sellAndGetWalletMsg( - context, - true - ); - expect(msgContentAmount).toBeTruthy(); - //expect(msgContentAmount).toContain(amount + " ATOM (Cosmos Hub/channel-0)"); - expect(msgContentAmount).toContain("place_limit"); - expect(msgContentAmount).toContain('"order_direction": "ask"'); - await tradePage.isTransactionSuccesful(); - await tradePage.getTransactionUrl(); - await tradePage.gotoOrdersHistory(); - const trxPage = new TransactionsPage(context.pages()[0]); - await trxPage.cancelLimitOrder(`Sell $${amount} of`, limitPrice, context); - await tradePage.isTransactionSuccesful(); - await tradePage.getTransactionUrl(); - }); - - test("User should be able to cancel limit sell OSMO", async () => { - await tradePage.goto(); - const amount = "1.01"; - await tradePage.openSellTab(); - await tradePage.openLimit(); - await tradePage.selectAsset("OSMO"); - await tradePage.enterAmount(amount); - await tradePage.setLimitPriceChange("10%"); - const limitPrice = await tradePage.getLimitPrice(); - const { msgContentAmount } = await tradePage.sellAndGetWalletMsg( - context, - true - ); - expect(msgContentAmount).toBeTruthy(); - //expect(msgContentAmount).toContain(`${amount} OSMO`); - expect(msgContentAmount).toContain("place_limit"); - expect(msgContentAmount).toContain('"order_direction": "ask"'); - await tradePage.isTransactionSuccesful(); - await tradePage.getTransactionUrl(); - await tradePage.gotoOrdersHistory(); - const trxPage = new TransactionsPage(context.pages()[0]); - await trxPage.cancelLimitOrder(`Sell $${amount} of`, limitPrice, context); - await tradePage.isTransactionSuccesful(); - await tradePage.getTransactionUrl(); - }); -}); diff --git a/packages/web/e2e/tests/transactions.wallet.spec.ts b/packages/web/e2e/tests/transactions.wallet.spec.ts deleted file mode 100644 index 10dcf9a00e..0000000000 --- a/packages/web/e2e/tests/transactions.wallet.spec.ts +++ /dev/null @@ -1,95 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { - type BrowserContext, - chromium, - expect, - type Page, - test, -} from "@playwright/test"; -import process from "process"; - -import { SwapPage } from "~/e2e/pages/swap-page"; -import { TransactionsPage } from "~/e2e/pages/transactions-page"; -import { TestConfig } from "~/e2e/test-config"; -import { UnzipExtension } from "~/e2e/unzip-extension"; - -import { PortfolioPage } from "../pages/portfolio-page"; -import { WalletPage } from "../pages/wallet-page"; - -test.describe("Test Transactions feature", () => { - let context: BrowserContext; - let page: Page; - const walletId = - process.env.WALLET_ID ?? "osmo1qyc8u7cn0zjxcu9dvrjz5zwfnn0ck92v62ak9l"; - const privateKey = process.env.PRIVATE_KEY ?? "pk"; - let portfolioPage: PortfolioPage; - let transactionsPage: TransactionsPage; - let swapPage: SwapPage; - - test.beforeAll(async () => { - const pathToExtension = new UnzipExtension().getPathToExtension(); - console.log("\nSetup Wallet Extension before tests."); - // Launch Chrome with a Keplr wallet extension - context = await chromium.launchPersistentContext( - "", - new TestConfig().getBrowserExtensionConfig(true, pathToExtension) - ); - // Get all new pages (including Extension) in the context and wait - const emptyPage = context.pages()[0]; - await emptyPage.waitForTimeout(2000); - page = context.pages()[1]; - const walletPage = new WalletPage(page); - // Import existing Wallet (could be aggregated in one function). - await walletPage.importWalletWithPrivateKey(privateKey); - await walletPage.setWalletNameAndPassword("Test Transactions"); - await walletPage.selectChainsAndSave(); - await walletPage.finish(); - // Switch to Application - page = context.pages()[0]; - portfolioPage = new PortfolioPage(page); - await portfolioPage.goto(); - await portfolioPage.connectWallet(); - transactionsPage = await new TransactionsPage(page).open(); - }); - - test.afterAll(async () => { - await context.close(); - }); - - test("User should be able to see old transactions", async () => { - await transactionsPage.viewTransactionByNumber(10); - await transactionsPage.viewOnExplorerIsVisible(); - await transactionsPage.closeTransaction(); - await transactionsPage.viewTransactionByNumber(20); - await transactionsPage.viewOnExplorerIsVisible(); - await transactionsPage.closeTransaction(); - await transactionsPage.viewTransactionByNumber(35); - await transactionsPage.viewOnExplorerIsVisible(); - await transactionsPage.closeTransaction(); - }); - - test.skip("User should be able to see a new transaction", async () => { - swapPage = new SwapPage(context.pages()[0]); - await swapPage.goto(); - await swapPage.selectPair("USDC", "USDT"); - const rndInt = Math.floor(Math.random() * 99) + 1; - const swapAmount = `0.1${rndInt}`; - await swapPage.enterAmount(swapAmount); - const { msgContentAmount } = await swapPage.swapAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain(`sender: ${walletId}`); - expect(msgContentAmount).toContain( - "denom: ibc/498A0751C798A0D9A389AA3691123DADA57DAA4FE165D5C75894505B876BA6E4" - ); - expect(swapPage.isTransactionBroadcasted(10)); - expect(swapPage.isTransactionSuccesful(10)); - const swapTrxUrl = await swapPage.getTransactionUrl(); - await swapPage.gotoPortfolio(); - await portfolioPage.viewTransactionsPage(); - await transactionsPage.viewBySwapAmount(swapAmount); - await transactionsPage.viewOnExplorerIsVisible(); - const trxUrl = await transactionsPage.getOnExplorerLink(); - expect(trxUrl).toContain(swapTrxUrl); - await transactionsPage.closeTransaction(); - }); -}); diff --git a/packages/web/e2e/unzip-extension.ts b/packages/web/e2e/unzip-extension.ts deleted file mode 100644 index 701e848650..0000000000 --- a/packages/web/e2e/unzip-extension.ts +++ /dev/null @@ -1,28 +0,0 @@ -const decompress = require("decompress"); -import path from "path"; - -export class UnzipExtension { - getPathToExtension() { - console.log("Unzip Wallet Extension before tests."); - // Unzip keplr-extension-manifest - const pathToZip = path.join( - __dirname, - "./keplr-extension-manifest-v3-v0.12.125.zip" - ); - const pathToExtension = path.join(__dirname, "./keplr-extension-manifest"); - decompress(pathToZip, pathToExtension); - return pathToExtension; - } - - getPathToMetaMaskExtension() { - console.log("Unzip Wallet Extension before tests."); - // Unzip metamask-extension-manifest - const pathToZip = path.join(__dirname, "./metamask-chrome-12.1.1.zip"); - const pathToExtension = path.join( - __dirname, - "./metamask-extension-manifest" - ); - decompress(pathToZip, pathToExtension); - return pathToExtension; - } -} diff --git a/packages/web/hooks/__tests__/fiat-getters.spec.ts b/packages/web/hooks/__tests__/fiat-getters.spec.ts index 34bcb8c463..a453ea2db4 100644 --- a/packages/web/hooks/__tests__/fiat-getters.spec.ts +++ b/packages/web/hooks/__tests__/fiat-getters.spec.ts @@ -1,5 +1,5 @@ -import { Dec, Int, PricePretty } from "@keplr-wallet/unit"; import { Asset, DEFAULT_VS_CURRENCY } from "@osmosis-labs/server"; +import { Dec, Int, PricePretty } from "@osmosis-labs/unit"; import { getTokenInFeeAmountFiatValue, diff --git a/packages/web/hooks/__tests__/use-convert-variant.test.ts b/packages/web/hooks/__tests__/use-convert-variant.test.ts index c4b79abd3f..0425435213 100644 --- a/packages/web/hooks/__tests__/use-convert-variant.test.ts +++ b/packages/web/hooks/__tests__/use-convert-variant.test.ts @@ -1,4 +1,4 @@ -import { Dec } from "@keplr-wallet/unit"; +import { Dec } from "@osmosis-labs/unit"; import { checkLargeAmountDiff } from "../use-convert-variant"; diff --git a/packages/web/hooks/bridge.tsx b/packages/web/hooks/bridge.tsx index 30910f07af..bf2e536238 100644 --- a/packages/web/hooks/bridge.tsx +++ b/packages/web/hooks/bridge.tsx @@ -36,6 +36,7 @@ export const useBridgeStore = create( combine( { isVisible: false, + type: "quote" as "quote" | "deposit-address", step: BridgeScreen.Asset, direction: undefined as "deposit" | "withdraw" | undefined, selectedAssetDenom: undefined as string | undefined, @@ -112,6 +113,9 @@ export const useBridgeStore = create( fiatRampSelectionOpen: nextValue ?? !state.fiatRampSelectionOpen, })); }, + setType: (type: "quote" | "deposit-address") => { + set({ type }); + }, }) ) ); @@ -125,6 +129,7 @@ export const ImmersiveBridge = () => { const { isReady: isRouterReady } = useRouter(); const { + type, direction, isVisible, selectedAssetDenom, @@ -143,6 +148,7 @@ export const ImmersiveBridge = () => { isVisible: state.isVisible, step: state.step, direction: state.direction, + type: state.type, selectedAssetDenom: state.selectedAssetDenom, setIsVisible: state.setIsVisible, setStep: state.setStep, @@ -298,28 +304,56 @@ export const ImmersiveBridge = () => { )} { - setStep(BridgeScreen.Asset); - setSelectedAssetDenom(undefined); - } - : undefined, - }, - { - displayLabel: t("transfer.stepLabels.amount"), - onClick: - step === BridgeScreen.Review - ? () => setStep(BridgeScreen.Amount) - : undefined, - }, - { - displayLabel: t("transfer.stepLabels.review"), - }, - ]} + steps={ + type === "quote" + ? [ + { + displayLabel: t( + "transfer.stepLabels.asset" + ), + onClick: + step !== BridgeScreen.Asset + ? () => { + setStep(BridgeScreen.Asset); + setSelectedAssetDenom(undefined); + } + : undefined, + }, + { + displayLabel: t( + "transfer.stepLabels.amount" + ), + onClick: + step === BridgeScreen.Review + ? () => setStep(BridgeScreen.Amount) + : undefined, + }, + { + displayLabel: t( + "transfer.stepLabels.review" + ), + }, + ] + : [ + { + displayLabel: t( + "transfer.stepLabels.asset" + ), + onClick: + step !== BridgeScreen.Asset + ? () => { + setStep(BridgeScreen.Asset); + setSelectedAssetDenom(undefined); + } + : undefined, + }, + { + displayLabel: t( + "transfer.stepLabels.deposit" + ), + }, + ] + } currentStep={Number(step)} /> - {humanizedTime.value} {t(humanizedTime.unitTranslationKey)}{" "} - {t("remaining")} + {displayHumanizedTime({ humanizedTime, t })} {t("remaining")}

), }, diff --git a/packages/web/hooks/one-click-trading/__tests__/use-one-click-trading-params.spec.ts b/packages/web/hooks/one-click-trading/__tests__/use-one-click-trading-params.spec.ts index f3c9687f08..164f9693ae 100644 --- a/packages/web/hooks/one-click-trading/__tests__/use-one-click-trading-params.spec.ts +++ b/packages/web/hooks/one-click-trading/__tests__/use-one-click-trading-params.spec.ts @@ -1,10 +1,10 @@ -import { Dec, PricePretty } from "@keplr-wallet/unit"; import { DEFAULT_VS_CURRENCY } from "@osmosis-labs/server"; import { OneClickTradingInfo } from "@osmosis-labs/stores"; import { OneClickTradingHumanizedSessionPeriod, OneClickTradingTransactionParams, } from "@osmosis-labs/types"; +import { Dec, PricePretty } from "@osmosis-labs/unit"; import { OneClickTradingMaxGasLimit, unixSecondsToNanoSeconds, diff --git a/packages/web/hooks/one-click-trading/use-one-click-trading-params.ts b/packages/web/hooks/one-click-trading/use-one-click-trading-params.ts index 1db6f10bec..6c1dc15968 100644 --- a/packages/web/hooks/one-click-trading/use-one-click-trading-params.ts +++ b/packages/web/hooks/one-click-trading/use-one-click-trading-params.ts @@ -1,7 +1,7 @@ -import { Dec, DecUtils, PricePretty } from "@keplr-wallet/unit"; import { DEFAULT_VS_CURRENCY } from "@osmosis-labs/server"; import { OneClickTradingInfo } from "@osmosis-labs/stores"; import { OneClickTradingTransactionParams } from "@osmosis-labs/types"; +import { Dec, DecUtils, PricePretty } from "@osmosis-labs/unit"; import { OneClickTradingMaxGasLimit, runIfFn } from "@osmosis-labs/utils"; import { SetStateAction, diff --git a/packages/web/hooks/one-click-trading/use-one-click-trading-session.ts b/packages/web/hooks/one-click-trading/use-one-click-trading-session.ts index badca7c9d5..ee170f4f7e 100644 --- a/packages/web/hooks/one-click-trading/use-one-click-trading-session.ts +++ b/packages/web/hooks/one-click-trading/use-one-click-trading-session.ts @@ -103,7 +103,7 @@ export const useOneClickTradingSession = ({ return { oneClickTradingInfo: featureFlags.oneClickTrading ? value?.info : undefined, isOneClickTradingEnabled: featureFlags.oneClickTrading - ? value?.isEnabled + ? value?.isEnabled ?? false : false, isOneClickTradingExpired: featureFlags.oneClickTrading ? isExpired : false, getTimeRemaining, diff --git a/packages/web/hooks/one-click-trading/use-one-click-trading-swap-review.ts b/packages/web/hooks/one-click-trading/use-one-click-trading-swap-review.ts index e9650962e7..643bfaed91 100644 --- a/packages/web/hooks/one-click-trading/use-one-click-trading-swap-review.ts +++ b/packages/web/hooks/one-click-trading/use-one-click-trading-swap-review.ts @@ -1,7 +1,7 @@ -import { Dec, PricePretty } from "@keplr-wallet/unit"; import { OneClickTradingInfo } from "@osmosis-labs/stores"; import { makeRemoveAuthenticatorMsg } from "@osmosis-labs/tx"; import { OneClickTradingTransactionParams } from "@osmosis-labs/types"; +import { Dec, PricePretty } from "@osmosis-labs/unit"; import { useCallback, useEffect, useMemo } from "react"; import { useAsync } from "react-use"; import { create } from "zustand"; @@ -161,17 +161,20 @@ export function use1CTSwapReviewMessages() { const shouldFetchExistingSessionAuthenticator = !!account?.address && !!oneClickTradingInfo; + const enabledFetchingSessionAuthenticator = + isOneClickTradingEnabled && shouldFetchExistingSessionAuthenticator; + const { data: sessionAuthenticator, isLoading: isLoadingSessionAuthenticator, + error: sessionAuthenticatorError, } = api.local.oneClickTrading.getSessionAuthenticator.useQuery( { userOsmoAddress: account?.address ?? "", publicKey: oneClickTradingInfo?.publicKey ?? "", }, { - enabled: - isOneClickTradingEnabled && shouldFetchExistingSessionAuthenticator, + enabled: enabledFetchingSessionAuthenticator, cacheTime: 15_000, // 15 seconds staleTime: 15_000, // 15 seconds retry: false, @@ -244,17 +247,20 @@ export function use1CTSwapReviewMessages() { spendLimitTokenDecimals, transaction1CTParams, ]); + const isLoading = shouldSend1CTTx + ? isLoadingOneClickMessages || + (shouldFetchExistingSessionAuthenticator && + !sessionAuthenticatorError && + enabledFetchingSessionAuthenticator + ? isLoadingSessionAuthenticator + : false) || + isLoadingInfo + : false; return { oneClickMessages, shouldSend1CTTx, - isLoadingOneClickMessages: shouldSend1CTTx - ? isLoadingOneClickMessages || - (shouldFetchExistingSessionAuthenticator - ? isLoadingSessionAuthenticator - : false) || - isLoadingInfo - : false, + isLoadingOneClickMessages: isLoading, }; } diff --git a/packages/web/hooks/queries/assets/__tests__/use-coin-fiat-value.spec.ts b/packages/web/hooks/queries/assets/__tests__/use-coin-fiat-value.spec.ts index bae2f5365f..95b9394755 100644 --- a/packages/web/hooks/queries/assets/__tests__/use-coin-fiat-value.spec.ts +++ b/packages/web/hooks/queries/assets/__tests__/use-coin-fiat-value.spec.ts @@ -1,5 +1,5 @@ -import { CoinPretty, PricePretty } from "@keplr-wallet/unit"; import { DEFAULT_VS_CURRENCY } from "@osmosis-labs/server"; +import { CoinPretty, PricePretty } from "@osmosis-labs/unit"; import { mulPrice } from "../use-coin-fiat-value"; diff --git a/packages/web/hooks/queries/assets/use-coin-fiat-value.ts b/packages/web/hooks/queries/assets/use-coin-fiat-value.ts index 375e47855e..ee2acd23c2 100644 --- a/packages/web/hooks/queries/assets/use-coin-fiat-value.ts +++ b/packages/web/hooks/queries/assets/use-coin-fiat-value.ts @@ -1,6 +1,6 @@ import { FiatCurrency } from "@keplr-wallet/types"; -import { CoinPretty, PricePretty } from "@keplr-wallet/unit"; import { DEFAULT_VS_CURRENCY } from "@osmosis-labs/server"; +import { CoinPretty, PricePretty } from "@osmosis-labs/unit"; import { useMemo } from "react"; import { usePrice } from "~/hooks/queries/assets/use-price"; diff --git a/packages/web/hooks/staking/use-get-apr.ts b/packages/web/hooks/staking/use-get-apr.ts index 24c413fe0d..68ca3fb238 100644 --- a/packages/web/hooks/staking/use-get-apr.ts +++ b/packages/web/hooks/staking/use-get-apr.ts @@ -1,4 +1,4 @@ -import { Dec } from "@keplr-wallet/unit"; +import { Dec } from "@osmosis-labs/unit"; import { api } from "~/utils/trpc"; diff --git a/packages/web/hooks/ui-config/use-add-concentrated-liquidity-config.ts b/packages/web/hooks/ui-config/use-add-concentrated-liquidity-config.ts index 24f653964c..04d847f128 100644 --- a/packages/web/hooks/ui-config/use-add-concentrated-liquidity-config.ts +++ b/packages/web/hooks/ui-config/use-add-concentrated-liquidity-config.ts @@ -1,11 +1,3 @@ -import { - CoinPretty, - Dec, - DecUtils, - Int, - PricePretty, - RatePretty, -} from "@keplr-wallet/unit"; import { AmountConfig } from "@osmosis-labs/keplr-hooks"; import { ChainGetter, @@ -31,6 +23,14 @@ import { OsmosisQueries, PriceConfig, } from "@osmosis-labs/stores"; +import { + CoinPretty, + Dec, + DecUtils, + Int, + PricePretty, + RatePretty, +} from "@osmosis-labs/unit"; import { action, autorun, computed, makeObservable, observable } from "mobx"; import { useCallback, useEffect, useState } from "react"; diff --git a/packages/web/hooks/ui-config/use-asset-info-config.ts b/packages/web/hooks/ui-config/use-asset-info-config.ts index db144452db..aa3f9e149b 100644 --- a/packages/web/hooks/ui-config/use-asset-info-config.ts +++ b/packages/web/hooks/ui-config/use-asset-info-config.ts @@ -1,8 +1,8 @@ -import { PricePretty } from "@keplr-wallet/unit"; import { DEFAULT_VS_CURRENCY, type TokenHistoricalPrice, } from "@osmosis-labs/server"; +import { PricePretty } from "@osmosis-labs/unit"; import dayjs from "dayjs"; import { Time } from "lightweight-charts"; import { action, computed, makeObservable, observable } from "mobx"; diff --git a/packages/web/hooks/ui-config/use-historical-and-depth-data.ts b/packages/web/hooks/ui-config/use-historical-and-depth-data.ts index 4f86c69c02..07cb1a97c2 100644 --- a/packages/web/hooks/ui-config/use-historical-and-depth-data.ts +++ b/packages/web/hooks/ui-config/use-historical-and-depth-data.ts @@ -1,4 +1,3 @@ -import { Dec, DecUtils, Int } from "@keplr-wallet/unit"; import { BigDec, maxSpotPrice, @@ -13,6 +12,7 @@ import type { TokenPairHistoricalPrice, } from "@osmosis-labs/server"; import { Currency } from "@osmosis-labs/types"; +import { Dec, DecUtils, Int } from "@osmosis-labs/unit"; import { action, autorun, computed, makeObservable, observable } from "mobx"; import { useEffect, useState } from "react"; diff --git a/packages/web/hooks/use-convert-variant.ts b/packages/web/hooks/use-convert-variant.ts index b6c77bc3fc..e1a0cc66ed 100644 --- a/packages/web/hooks/use-convert-variant.ts +++ b/packages/web/hooks/use-convert-variant.ts @@ -1,6 +1,6 @@ -import { Dec } from "@keplr-wallet/unit"; import type { AssetVariant } from "@osmosis-labs/server"; import { getSwapMessages, type QuoteOutGivenIn } from "@osmosis-labs/tx"; +import { Dec } from "@osmosis-labs/unit"; import { useCallback, useMemo } from "react"; import { EventName } from "~/config"; diff --git a/packages/web/hooks/use-estimate-tx-fees.ts b/packages/web/hooks/use-estimate-tx-fees.ts index f1785bb330..2f80fe3aad 100644 --- a/packages/web/hooks/use-estimate-tx-fees.ts +++ b/packages/web/hooks/use-estimate-tx-fees.ts @@ -1,5 +1,4 @@ import { EncodeObject } from "@cosmjs/proto-signing"; -import { CoinPretty, Dec, DecUtils, PricePretty } from "@keplr-wallet/unit"; import { DEFAULT_VS_CURRENCY, superjson } from "@osmosis-labs/server"; import { AccountStore, @@ -12,6 +11,7 @@ import { SwapRequiresError, } from "@osmosis-labs/stores"; import { QuoteStdFee } from "@osmosis-labs/tx"; +import { CoinPretty, Dec, DecUtils, PricePretty } from "@osmosis-labs/unit"; import { isNil } from "@osmosis-labs/utils"; import { useQuery } from "@tanstack/react-query"; import cachified, { CacheEntry } from "cachified"; diff --git a/packages/web/hooks/use-get-earn-strategies.ts b/packages/web/hooks/use-get-earn-strategies.ts index 08e077aead..423f027a27 100644 --- a/packages/web/hooks/use-get-earn-strategies.ts +++ b/packages/web/hooks/use-get-earn-strategies.ts @@ -1,9 +1,9 @@ -import { Dec, PricePretty } from "@keplr-wallet/unit"; import { DEFAULT_VS_CURRENCY, type EarnStrategy, getDailyApr, } from "@osmosis-labs/server"; +import { Dec, PricePretty } from "@osmosis-labs/unit"; import { apiClient } from "@osmosis-labs/utils"; import { useQueries } from "@tanstack/react-query"; import { useMemo } from "react"; diff --git a/packages/web/hooks/use-swap.tsx b/packages/web/hooks/use-swap.tsx index fcf94c6a8f..cfc84a3c56 100644 --- a/packages/web/hooks/use-swap.tsx +++ b/packages/web/hooks/use-swap.tsx @@ -1,11 +1,4 @@ import type { StdFee } from "@cosmjs/amino"; -import { - CoinPretty, - Dec, - DecUtils, - IntPretty, - PricePretty, -} from "@keplr-wallet/unit"; import { NoRouteError, NotEnoughLiquidityError, @@ -20,6 +13,13 @@ import { SwapTxRouteOutGivenIn, } from "@osmosis-labs/tx"; import { Currency, MinimalAsset } from "@osmosis-labs/types"; +import { + CoinPretty, + Dec, + DecUtils, + IntPretty, + PricePretty, +} from "@osmosis-labs/unit"; import { getAssetFromAssetList, isNil, diff --git a/packages/web/hooks/user-settings/use-hide-dust-filter.ts b/packages/web/hooks/user-settings/use-hide-dust-filter.ts index 864459b902..26f0f50803 100644 --- a/packages/web/hooks/user-settings/use-hide-dust-filter.ts +++ b/packages/web/hooks/user-settings/use-hide-dust-filter.ts @@ -1,4 +1,4 @@ -import { PricePretty } from "@keplr-wallet/unit"; +import { PricePretty } from "@osmosis-labs/unit"; import { useMemo } from "react"; import { useStore } from "~/stores"; diff --git a/packages/web/localizations/de.json b/packages/web/localizations/de.json index 86e46407ff..1990711c97 100644 --- a/packages/web/localizations/de.json +++ b/packages/web/localizations/de.json @@ -2,7 +2,7 @@ "404": { "title": "Nicht gefunden" }, - "aboutSecondsRemaining": "Etwa {seconds} verbleibend", + "unknownTimeRemaining": "Unbekannte verbleibende Zeit", "addLiquidity": { "allAssets": "Alle Vermögenswerte", "autoswapCaption": "Verwenden Sie Autoswap, um Liquidität mit einem einzelnen Vermögenswert hinzuzufügen.", @@ -818,7 +818,8 @@ "stepLabels": { "asset": "Vermögenswert", "amount": "Menge", - "review": "Rezension" + "review": "Rezension", + "deposit": "Kaution" }, "moreBridgeOptions": { "titleDeposit": "Mehr Einzahlungsmöglichkeiten", diff --git a/packages/web/localizations/en.json b/packages/web/localizations/en.json index 4ffe1ceb80..4b261a8723 100644 --- a/packages/web/localizations/en.json +++ b/packages/web/localizations/en.json @@ -2,7 +2,7 @@ "404": { "title": "Not found" }, - "aboutSecondsRemaining": "About {seconds} remaining", + "unknownTimeRemaining": "Unknown time remaining", "addLiquidity": { "allAssets": "All assets", "autoswapCaption": "Use autoswap to add liquidity with a single asset.", @@ -818,7 +818,8 @@ "stepLabels": { "asset": "Asset", "amount": "Amount", - "review": "Review" + "review": "Review", + "deposit": "Deposit" }, "moreBridgeOptions": { "titleDeposit": "More deposit options", diff --git a/packages/web/localizations/es.json b/packages/web/localizations/es.json index bf849744fe..f51578fdc3 100644 --- a/packages/web/localizations/es.json +++ b/packages/web/localizations/es.json @@ -2,7 +2,7 @@ "404": { "title": "No encontrado" }, - "aboutSecondsRemaining": "Quedan aproximadamente {seconds}", + "unknownTimeRemaining": "Tiempo restante desconocido", "addLiquidity": { "allAssets": "Todos los activos", "autoswapCaption": "Use el intercambio automático para agregar liquidez con un solo activo.", @@ -818,7 +818,8 @@ "stepLabels": { "asset": "Activo", "amount": "Cantidad", - "review": "Revisar" + "review": "Revisar", + "deposit": "Depósito" }, "moreBridgeOptions": { "titleDeposit": "Más opciones de depósito", diff --git a/packages/web/localizations/fa.json b/packages/web/localizations/fa.json index f2d2512d6a..5f03d94a06 100644 --- a/packages/web/localizations/fa.json +++ b/packages/web/localizations/fa.json @@ -2,7 +2,7 @@ "404": { "title": "پیدا نشد" }, - "aboutSecondsRemaining": "درباره {seconds} باقی مانده است", + "unknownTimeRemaining": "زمان نامعلوم باقی مانده است", "addLiquidity": { "allAssets": "همه دارایی های شما", "autoswapCaption": "استفاده از تبدیل خودکار برای تبدیل یک دارایی به سایر دارایی ها", @@ -818,7 +818,8 @@ "stepLabels": { "asset": "دارایی", "amount": "میزان", - "review": "مرور" + "review": "مرور", + "deposit": "سپرده گذاری" }, "moreBridgeOptions": { "titleDeposit": "گزینه های سپرده بیشتر", diff --git a/packages/web/localizations/fr.json b/packages/web/localizations/fr.json index 561e14b286..2acc02b7ac 100644 --- a/packages/web/localizations/fr.json +++ b/packages/web/localizations/fr.json @@ -2,7 +2,7 @@ "404": { "title": "Page non trouvée" }, - "aboutSecondsRemaining": "Il reste environ {seconds}", + "unknownTimeRemaining": "Temps restant inconnu", "addLiquidity": { "allAssets": "Tous les actifs", "autoswapCaption": "Utilisez l'échange automatique pour ajouter de la liquidité avec un seul actif.", @@ -818,7 +818,8 @@ "stepLabels": { "asset": "Actif", "amount": "Montant", - "review": "Revoir" + "review": "Revoir", + "deposit": "Dépôt" }, "moreBridgeOptions": { "titleDeposit": "Plus d'options de dépôt", diff --git a/packages/web/localizations/gu.json b/packages/web/localizations/gu.json index d9a7fc3ceb..d5f79970e8 100644 --- a/packages/web/localizations/gu.json +++ b/packages/web/localizations/gu.json @@ -2,7 +2,7 @@ "404": { "title": "મળી નથી" }, - "aboutSecondsRemaining": "લગભગ {seconds} બાકી", + "unknownTimeRemaining": "અજ્ઞાત સમય બાકી", "addLiquidity": { "allAssets": "બધી સંપત્તિ", "autoswapCaption": "સિંગલ એસેટ સાથે લિક્વિડિટી ઉમેરવા માટે ઑટોસ્વેપનો ઉપયોગ કરો.", @@ -818,7 +818,8 @@ "stepLabels": { "asset": "એસેટ", "amount": "રકમ", - "review": "સમીક્ષા" + "review": "સમીક્ષા", + "deposit": "જમા" }, "moreBridgeOptions": { "titleDeposit": "વધુ થાપણ વિકલ્પો", diff --git a/packages/web/localizations/hi.json b/packages/web/localizations/hi.json index 408b62ee7b..238015367a 100644 --- a/packages/web/localizations/hi.json +++ b/packages/web/localizations/hi.json @@ -2,7 +2,7 @@ "404": { "title": "नहीं मिला" }, - "aboutSecondsRemaining": "लगभग {seconds} शेष हैं", + "unknownTimeRemaining": "शेष समय अज्ञात", "addLiquidity": { "allAssets": "सारी संपत्ति", "autoswapCaption": "एकल परिसंपत्ति में तरलता जोड़ने के लिए ऑटोस्वैप का उपयोग करें।", @@ -818,7 +818,8 @@ "stepLabels": { "asset": "संपत्ति", "amount": "मात्रा", - "review": "समीक्षा" + "review": "समीक्षा", + "deposit": "जमा" }, "moreBridgeOptions": { "titleDeposit": "अधिक जमा विकल्प", diff --git a/packages/web/localizations/ja.json b/packages/web/localizations/ja.json index 7991d1b1ab..46af580a25 100644 --- a/packages/web/localizations/ja.json +++ b/packages/web/localizations/ja.json @@ -2,7 +2,7 @@ "404": { "title": "見つかりません" }, - "aboutSecondsRemaining": "残り約{seconds}", + "unknownTimeRemaining": "残り時間不明", "addLiquidity": { "allAssets": "すべての資産", "autoswapCaption": "自動スワップを使用して、単一の資産に流動性を追加します。", @@ -818,7 +818,8 @@ "stepLabels": { "asset": "資産", "amount": "額", - "review": "レビュー" + "review": "レビュー", + "deposit": "デポジット" }, "moreBridgeOptions": { "titleDeposit": "その他の入金オプション", diff --git a/packages/web/localizations/ko.json b/packages/web/localizations/ko.json index 5ac0cb0dfb..dada7b9697 100644 --- a/packages/web/localizations/ko.json +++ b/packages/web/localizations/ko.json @@ -2,7 +2,7 @@ "404": { "title": "페이지를 찾을 수 없습니다" }, - "aboutSecondsRemaining": "{seconds} 남음", + "unknownTimeRemaining": "남은 시간을 알 수 없음", "addLiquidity": { "allAssets": "모든 자산", "autoswapCaption": "오토스왑을 통해 단일 자산의 유동성을 추가합니다", @@ -818,7 +818,8 @@ "stepLabels": { "asset": "유산", "amount": "양", - "review": "검토" + "review": "검토", + "deposit": "보증금" }, "moreBridgeOptions": { "titleDeposit": "더 많은 입금 옵션", diff --git a/packages/web/localizations/pl.json b/packages/web/localizations/pl.json index a69f34e528..5f9cc1dae1 100644 --- a/packages/web/localizations/pl.json +++ b/packages/web/localizations/pl.json @@ -2,7 +2,7 @@ "404": { "title": "Nie znaleziono" }, - "aboutSecondsRemaining": "Pozostało około {seconds}", + "unknownTimeRemaining": "Nieznany pozostały czas", "addLiquidity": { "allAssets": "Wszystkie tokeny", "autoswapCaption": "Użyj autowymiany, żeby dodać płynność jednym tokenem.", @@ -818,7 +818,8 @@ "stepLabels": { "asset": "Zaleta", "amount": "Kwota", - "review": "Recenzja" + "review": "Recenzja", + "deposit": "Depozyt" }, "moreBridgeOptions": { "titleDeposit": "Więcej opcji depozytu", diff --git a/packages/web/localizations/pt-br.json b/packages/web/localizations/pt-br.json index 9c30af4f84..6dfeb21360 100644 --- a/packages/web/localizations/pt-br.json +++ b/packages/web/localizations/pt-br.json @@ -2,7 +2,7 @@ "404": { "title": "Não encontrado" }, - "aboutSecondsRemaining": "Cerca de {seconds} restantes", + "unknownTimeRemaining": "Tempo restante desconhecido", "addLiquidity": { "allAssets": "Todos os ativos", "autoswapCaption": "Use autoswap para adicionar liquidez com um único ativo.", @@ -818,7 +818,8 @@ "stepLabels": { "asset": "Ativo", "amount": "Quantia", - "review": "Análise" + "review": "Análise", + "deposit": "Depósito" }, "moreBridgeOptions": { "titleDeposit": "Mais opções de depósito", diff --git a/packages/web/localizations/ro.json b/packages/web/localizations/ro.json index 76affba517..34601e55f3 100644 --- a/packages/web/localizations/ro.json +++ b/packages/web/localizations/ro.json @@ -2,7 +2,7 @@ "404": { "title": "Nu a fost gasit" }, - "aboutSecondsRemaining": "Aproximativ {seconds} rămase", + "unknownTimeRemaining": "Timp rămas necunoscut", "addLiquidity": { "allAssets": "Toate activele", "autoswapCaption": "Utilizeaza schimbul automat pentru a adauga lichiditate cu un singur activ.", @@ -818,7 +818,8 @@ "stepLabels": { "asset": "Atu", "amount": "Cantitate", - "review": "Revizuire" + "review": "Revizuire", + "deposit": "Depozit" }, "moreBridgeOptions": { "titleDeposit": "Mai multe opțiuni de depunere", diff --git a/packages/web/localizations/ru.json b/packages/web/localizations/ru.json index 57ec454cba..6674b7156a 100644 --- a/packages/web/localizations/ru.json +++ b/packages/web/localizations/ru.json @@ -2,7 +2,7 @@ "404": { "title": "Не найдено" }, - "aboutSecondsRemaining": "Около {seconds} осталось", + "unknownTimeRemaining": "Неизвестно оставшееся время", "addLiquidity": { "allAssets": "Все активы", "autoswapCaption": "Используйте автосвоп, чтобы добавить ликвидность с помощью одного актива.", @@ -818,7 +818,8 @@ "stepLabels": { "asset": "Объект", "amount": "Количество", - "review": "Обзор" + "review": "Обзор", + "deposit": "Депозит" }, "moreBridgeOptions": { "titleDeposit": "Больше вариантов депозита", diff --git a/packages/web/localizations/tr.json b/packages/web/localizations/tr.json index 57e6145fe7..39179a17db 100644 --- a/packages/web/localizations/tr.json +++ b/packages/web/localizations/tr.json @@ -2,7 +2,7 @@ "404": { "title": "Bulunamadı" }, - "aboutSecondsRemaining": "{seconds} kalan süre hakkında", + "unknownTimeRemaining": "Bilinmeyen kalan süre", "addLiquidity": { "allAssets": "Tüm varlıklar", "autoswapCaption": "Tek bir varlıkla likidite eklemek için otomatik takası kullanın.", @@ -818,7 +818,8 @@ "stepLabels": { "asset": "Varlık", "amount": "Miktar", - "review": "Gözden geçirmek" + "review": "Gözden geçirmek", + "deposit": "Depozito" }, "moreBridgeOptions": { "titleDeposit": "Daha fazla para yatırma seçeneği", diff --git a/packages/web/localizations/zh-cn.json b/packages/web/localizations/zh-cn.json index 094c361f06..b7a4a7483c 100644 --- a/packages/web/localizations/zh-cn.json +++ b/packages/web/localizations/zh-cn.json @@ -2,7 +2,7 @@ "404": { "title": "未找到" }, - "aboutSecondsRemaining": "大约剩余{seconds}", + "unknownTimeRemaining": "剩余时间未知", "addLiquidity": { "allAssets": "全部资产", "autoswapCaption": "使用自动兑换为单边资产添加流动性.", @@ -818,7 +818,8 @@ "stepLabels": { "asset": "资产", "amount": "数量", - "review": "审查" + "review": "审查", + "deposit": "订金" }, "moreBridgeOptions": { "titleDeposit": "更多存款选择", diff --git a/packages/web/localizations/zh-hk.json b/packages/web/localizations/zh-hk.json index 242334e93e..e32ab0acd4 100644 --- a/packages/web/localizations/zh-hk.json +++ b/packages/web/localizations/zh-hk.json @@ -2,7 +2,7 @@ "404": { "title": "搵唔到呢一頁喎" }, - "aboutSecondsRemaining": "大約剩餘{seconds}", + "unknownTimeRemaining": "剩餘時間未知", "addLiquidity": { "allAssets": "所有資產", "autoswapCaption": "使用自動兌換以使用單一資產加入流動性", @@ -818,7 +818,8 @@ "stepLabels": { "asset": "資產", "amount": "數量", - "review": "審查" + "review": "審查", + "deposit": "訂金" }, "moreBridgeOptions": { "titleDeposit": "更多存款選擇", diff --git a/packages/web/localizations/zh-tw.json b/packages/web/localizations/zh-tw.json index f14dba6e3b..09532f6902 100644 --- a/packages/web/localizations/zh-tw.json +++ b/packages/web/localizations/zh-tw.json @@ -2,7 +2,7 @@ "404": { "title": "找不到這頁面" }, - "aboutSecondsRemaining": "大約剩餘{seconds}", + "unknownTimeRemaining": "剩餘時間未知", "addLiquidity": { "allAssets": "所有資產", "autoswapCaption": "使用自動兌換以使用單一資產加入流動性", @@ -818,7 +818,8 @@ "stepLabels": { "asset": "資產", "amount": "數量", - "review": "審查" + "review": "審查", + "deposit": "訂金" }, "moreBridgeOptions": { "titleDeposit": "更多存款選擇", diff --git a/packages/web/modals/add-funds.tsx b/packages/web/modals/add-funds.tsx index 534990e025..24b3899563 100644 --- a/packages/web/modals/add-funds.tsx +++ b/packages/web/modals/add-funds.tsx @@ -1,5 +1,5 @@ -import { CoinPretty, PricePretty } from "@keplr-wallet/unit"; import { MinimalAsset } from "@osmosis-labs/types"; +import { CoinPretty, PricePretty } from "@osmosis-labs/unit"; import classNames from "classnames"; import Image from "next/image"; import { parseAsString, useQueryStates } from "nuqs"; diff --git a/packages/web/modals/increase-concentrated-liquidity.tsx b/packages/web/modals/increase-concentrated-liquidity.tsx index f57b4b4fe6..4adf5c55fc 100644 --- a/packages/web/modals/increase-concentrated-liquidity.tsx +++ b/packages/web/modals/increase-concentrated-liquidity.tsx @@ -1,5 +1,5 @@ -import { Dec } from "@keplr-wallet/unit"; import type { UserPosition, UserPositionDetails } from "@osmosis-labs/server"; +import { Dec } from "@osmosis-labs/unit"; import { observer } from "mobx-react-lite"; import dynamic from "next/dynamic"; import Image from "next/image"; diff --git a/packages/web/modals/profile.tsx b/packages/web/modals/profile.tsx index a2c2655e21..df4f3ab94f 100644 --- a/packages/web/modals/profile.tsx +++ b/packages/web/modals/profile.tsx @@ -1,5 +1,5 @@ -import { Dec, PricePretty } from "@keplr-wallet/unit"; import { DEFAULT_VS_CURRENCY } from "@osmosis-labs/server"; +import { Dec, PricePretty } from "@osmosis-labs/unit"; import { formatICNSName, shorten } from "@osmosis-labs/utils"; import classNames from "classnames"; import { observer } from "mobx-react-lite"; @@ -138,7 +138,7 @@ export const ProfileModal: FunctionComponent< onAfterClose={() => { setShow1CTSettings(false); }} - className="relative max-h-screen overflow-hidden" + className="relative max-h-screen overflow-hidden sm:mx-0" >
{show1CT && show1CTSettings ? ( diff --git a/packages/web/modals/remove-concentrated-liquidity.tsx b/packages/web/modals/remove-concentrated-liquidity.tsx index fb37700d1d..b641375835 100644 --- a/packages/web/modals/remove-concentrated-liquidity.tsx +++ b/packages/web/modals/remove-concentrated-liquidity.tsx @@ -1,10 +1,10 @@ -import { CoinPretty, PricePretty } from "@keplr-wallet/unit"; import type { PositionHistoricalPerformance, UserPosition, UserPositionDetails, } from "@osmosis-labs/server"; import { DEFAULT_VS_CURRENCY } from "@osmosis-labs/server"; +import { CoinPretty, PricePretty } from "@osmosis-labs/unit"; import classNames from "classnames"; import { observer } from "mobx-react-lite"; import Image from "next/image"; diff --git a/packages/web/modals/remove-liquidity.tsx b/packages/web/modals/remove-liquidity.tsx index 15905aa536..26c43e10af 100644 --- a/packages/web/modals/remove-liquidity.tsx +++ b/packages/web/modals/remove-liquidity.tsx @@ -1,6 +1,6 @@ -import { Dec, Int } from "@keplr-wallet/unit"; import { WeightedPoolRawResponse } from "@osmosis-labs/server"; import { NoAvailableSharesError } from "@osmosis-labs/stores"; +import { Dec, Int } from "@osmosis-labs/unit"; import { observer } from "mobx-react-lite"; import { FunctionComponent, useCallback, useState } from "react"; diff --git a/packages/web/modals/review-order.tsx b/packages/web/modals/review-order.tsx index 4b97b6d78b..e37bdc5f9b 100644 --- a/packages/web/modals/review-order.tsx +++ b/packages/web/modals/review-order.tsx @@ -1,14 +1,14 @@ +import { DEFAULT_VS_CURRENCY } from "@osmosis-labs/server"; +import { ObservableSlippageConfig } from "@osmosis-labs/stores"; +import { QuoteDirection } from "@osmosis-labs/tx"; +import { OneClickTradingTransactionParams } from "@osmosis-labs/types"; import { CoinPretty, Dec, IntPretty, PricePretty, RatePretty, -} from "@keplr-wallet/unit"; -import { DEFAULT_VS_CURRENCY } from "@osmosis-labs/server"; -import { ObservableSlippageConfig } from "@osmosis-labs/stores"; -import { QuoteDirection } from "@osmosis-labs/tx"; -import { OneClickTradingTransactionParams } from "@osmosis-labs/types"; +} from "@osmosis-labs/unit"; import classNames from "classnames"; import Image from "next/image"; import { parseAsString, useQueryState } from "nuqs"; diff --git a/packages/web/modals/superfluid-validator.tsx b/packages/web/modals/superfluid-validator.tsx index 58c936ac25..8c2ba13780 100644 --- a/packages/web/modals/superfluid-validator.tsx +++ b/packages/web/modals/superfluid-validator.tsx @@ -1,5 +1,5 @@ -import { CoinPretty, RatePretty } from "@keplr-wallet/unit"; import { BondStatus } from "@osmosis-labs/types"; +import { CoinPretty, RatePretty } from "@osmosis-labs/unit"; import { createColumnHelper, flexRender, diff --git a/packages/web/modals/token-select-modal-limit.tsx b/packages/web/modals/token-select-modal-limit.tsx index d75f52b0e4..9ed343aa1d 100644 --- a/packages/web/modals/token-select-modal-limit.tsx +++ b/packages/web/modals/token-select-modal-limit.tsx @@ -1,5 +1,5 @@ -import { PricePretty } from "@keplr-wallet/unit"; import { DEFAULT_VS_CURRENCY } from "@osmosis-labs/server"; +import { PricePretty } from "@osmosis-labs/unit"; import classNames from "classnames"; import { observer } from "mobx-react-lite"; import Image from "next/image"; diff --git a/packages/web/modals/token-select.tsx b/packages/web/modals/token-select.tsx index 15dc0bba59..699474687d 100644 --- a/packages/web/modals/token-select.tsx +++ b/packages/web/modals/token-select.tsx @@ -1,5 +1,5 @@ import { AppCurrency, IBCCurrency } from "@keplr-wallet/types"; -import { CoinPretty } from "@keplr-wallet/unit"; +import { CoinPretty } from "@osmosis-labs/unit"; import classNames from "classnames"; import { observer } from "mobx-react-lite"; import Image from "next/image"; diff --git a/packages/web/modals/validator-squad-modal.tsx b/packages/web/modals/validator-squad-modal.tsx index 6b8ee0b91f..aad0c29398 100644 --- a/packages/web/modals/validator-squad-modal.tsx +++ b/packages/web/modals/validator-squad-modal.tsx @@ -1,10 +1,10 @@ import { Currency } from "@keplr-wallet/types"; -import { CoinPretty, Dec, RatePretty } from "@keplr-wallet/unit"; import { ObservableQueryValidatorsInner, Staking, } from "@osmosis-labs/keplr-stores"; import { Staking as StakingType } from "@osmosis-labs/keplr-stores"; +import { CoinPretty, Dec, RatePretty } from "@osmosis-labs/unit"; import { normalizeUrl, truncate } from "@osmosis-labs/utils"; import { RankingInfo, rankItem } from "@tanstack/match-sorter-utils"; import { diff --git a/packages/web/modals/variants-conversion.tsx b/packages/web/modals/variants-conversion.tsx index 0abd298409..94472bbe0f 100644 --- a/packages/web/modals/variants-conversion.tsx +++ b/packages/web/modals/variants-conversion.tsx @@ -1,5 +1,5 @@ -import { Dec, PricePretty, RatePretty } from "@keplr-wallet/unit"; import type { AssetVariant } from "@osmosis-labs/server"; +import { Dec, PricePretty, RatePretty } from "@osmosis-labs/unit"; import classNames from "classnames"; import { observer } from "mobx-react-lite"; import React, { useEffect } from "react"; diff --git a/packages/web/package.json b/packages/web/package.json index 57cc219d90..5db6b87bf3 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -42,7 +42,6 @@ "@keplr-wallet/common": "0.10.24-ibc.go.v7.hot.fix", "@keplr-wallet/crypto": "0.12.48", "@keplr-wallet/types": "0.10.24-ibc.go.v7.hot.fix", - "@keplr-wallet/unit": "0.10.24-ibc.go.v7.hot.fix", "@next/bundle-analyzer": "^12.1.6", "@opentelemetry/api": "^1.9.0", "@opentelemetry/api-logs": "^0.52.1", @@ -56,6 +55,7 @@ "@osmosis-labs/trpc": "^1.0.0", "@osmosis-labs/tx": "^1.0.0", "@osmosis-labs/types": "^1.0.0", + "@osmosis-labs/unit": "0.10.24-ibc.go.v7.hot.fix", "@osmosis-labs/utils": "^1.0.0", "@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-icons": "^1.3.0", @@ -95,7 +95,6 @@ "classnames": "^2.3.2", "dayjs": "^1.10.7", "debounce": "^1.2.1", - "decompress": "^4.2.1", "eventemitter3": "^4.0.7", "fancy-canvas": "^2.1.0", "fast-deep-equal": "^3.1.3", @@ -135,7 +134,6 @@ }, "devDependencies": { "@keplr-wallet/provider-mock": "0.12.12", - "@playwright/test": "^1.48.0", "@testing-library/jest-dom": "^6.1.4", "@testing-library/react": "^14.1.2", "@testing-library/user-event": "^14.5.1", @@ -162,7 +160,6 @@ "jest-in-case": "^1.0.2", "jest-launchdarkly-mock": "^2.1.0", "knip": "^5.17.4", - "monocart-reporter": "^2.6.0", "msw-trpc": "1.3.3", "postcss": "^8.4.5", "prettier": "^2.8.8", diff --git a/packages/web/pages/api/pools.ts b/packages/web/pages/api/pools.ts index a6bb5e6b28..6be0578813 100644 --- a/packages/web/pages/api/pools.ts +++ b/packages/web/pages/api/pools.ts @@ -1,4 +1,3 @@ -import { Dec } from "@keplr-wallet/unit"; import { CONCENTRATED_LIQ_POOL_TYPE, COSMWASM_POOL_TYPE, @@ -7,6 +6,7 @@ import { WEIGHTED_POOL_TYPE, } from "@osmosis-labs/pools/build/types"; import { getPools, queryNumPools } from "@osmosis-labs/server"; +import { Dec } from "@osmosis-labs/unit"; import { isNumeric } from "@osmosis-labs/utils"; import { AssetLists } from "~/config/generated/asset-lists"; diff --git a/packages/web/pages/components.tsx b/packages/web/pages/components.tsx index 625490741c..0d36db247d 100644 --- a/packages/web/pages/components.tsx +++ b/packages/web/pages/components.tsx @@ -1,5 +1,5 @@ -import { RatePretty } from "@keplr-wallet/unit"; import type { CommonPriceChartTimeFrame } from "@osmosis-labs/server"; +import { RatePretty } from "@osmosis-labs/unit"; import { NextPage } from "next"; import { GetServerSideProps, GetServerSidePropsContext } from "next"; import Image from "next/image"; diff --git a/packages/web/pages/pools.tsx b/packages/web/pages/pools.tsx index d7bba26b7a..12927a99a5 100644 --- a/packages/web/pages/pools.tsx +++ b/packages/web/pages/pools.tsx @@ -1,4 +1,4 @@ -import { Dec, DecUtils } from "@keplr-wallet/unit"; +import { Dec, DecUtils } from "@osmosis-labs/unit"; import { observer } from "mobx-react-lite"; import type { NextPage } from "next"; import { NextSeo } from "next-seo"; diff --git a/packages/web/pages/stake.tsx b/packages/web/pages/stake.tsx index 68c5792d66..6ddcfe99b2 100644 --- a/packages/web/pages/stake.tsx +++ b/packages/web/pages/stake.tsx @@ -1,8 +1,8 @@ -import { CoinPretty, Dec } from "@keplr-wallet/unit"; import { Staking as StakingType } from "@osmosis-labs/keplr-stores"; import { DeliverTxResponse } from "@osmosis-labs/stores"; import { makeDelegateToValidatorSetMsg } from "@osmosis-labs/tx"; import { BondStatus } from "@osmosis-labs/types"; +import { CoinPretty, Dec } from "@osmosis-labs/unit"; import { observer } from "mobx-react-lite"; import React, { useCallback, useEffect, useMemo, useState } from "react"; diff --git a/packages/web/server/api/routers/bridge-transfer.ts b/packages/web/server/api/routers/bridge-transfer.ts index 4760009224..c74dfe7cde 100644 --- a/packages/web/server/api/routers/bridge-transfer.ts +++ b/packages/web/server/api/routers/bridge-transfer.ts @@ -1,4 +1,3 @@ -import { CoinPretty, Dec, DecUtils, PricePretty } from "@keplr-wallet/unit"; import { Bridge, BridgeChain, @@ -21,6 +20,7 @@ import { UserOsmoAddressSchema, } from "@osmosis-labs/trpc"; import { ExternalInterfaceBridgeTransferMethod } from "@osmosis-labs/types"; +import { CoinPretty, Dec, DecUtils, PricePretty } from "@osmosis-labs/unit"; import { BitcoinChainInfo, EthereumChainInfo, @@ -735,6 +735,7 @@ export const bridgeTransferRouter = createTRPCRouter({ return { ...deposit, + userOsmoAddress: input.userOsmoAddress, amount: new CoinPretty( { coinDecimals: deposit.networkFee.decimals, diff --git a/packages/web/server/api/routers/local-bridge-transfer.ts b/packages/web/server/api/routers/local-bridge-transfer.ts index f87a5b91d9..05f598d118 100644 --- a/packages/web/server/api/routers/local-bridge-transfer.ts +++ b/packages/web/server/api/routers/local-bridge-transfer.ts @@ -1,4 +1,3 @@ -import { CoinPretty, Dec, PricePretty } from "@keplr-wallet/unit"; import type { Bridge } from "@osmosis-labs/bridge"; import { bridgeChainSchema, @@ -20,6 +19,7 @@ import { UserCosmosAddressSchema, UserEvmAddressSchema, } from "@osmosis-labs/trpc"; +import { CoinPretty, Dec, PricePretty } from "@osmosis-labs/unit"; import { getAddress } from "viem"; import { z } from "zod"; diff --git a/packages/web/stores/__tests__/transfer-history.spec.tsx b/packages/web/stores/__tests__/transfer-history.spec.tsx index 8e85f14186..5ae6e4a0b8 100644 --- a/packages/web/stores/__tests__/transfer-history.spec.tsx +++ b/packages/web/stores/__tests__/transfer-history.spec.tsx @@ -15,15 +15,21 @@ describe("PendingTransferCaption", () => { if (key === "timeUnits.seconds") { return "seconds"; } + if (key === "timeUnits.minutes") { + return "minutes"; + } + if (key === "timeUnits.hours") { + return "hours"; + } + if (key === "unknownTimeRemaining") { + return "Unknown time remaining"; + } if (key === "transfer.amountToChain") { return `Transfer ${options.amount} to ${options.chain}`; } if (key === "transfer.amountFromChain") { return `Transfer ${options.amount} from ${options.chain}`; } - if (key === "aboutSecondsRemaining") { - return `About ${options.seconds} remaining`; - } if (key === "estimated") { return "Estimated"; } @@ -82,8 +88,28 @@ describe("PendingTransferCaption", () => { /> ); - jest.advanceTimersByTime(296000); // Advance time by 4 minutes and 56 seconds + jest.advanceTimersByTime(300000); // Advance time by 5 minutes + + expect(screen.getByText(/Unknown time remaining/)).toBeInTheDocument(); + }); + + it("displays the hours and minutes", () => { + const estimatedArrivalUnix = dayjs() + .add(3, "hours") + .add(59, "minutes") + .unix(); + + render( + + ); - expect(screen.getByText(/About 5 seconds remaining/)).toBeInTheDocument(); + expect( + screen.getByText(/Estimated 3 hours and 58 minutes remaining/) + ).toBeInTheDocument(); }); }); diff --git a/packages/web/stores/transfer-history.tsx b/packages/web/stores/transfer-history.tsx index ef4d9225bb..c7cb3f8735 100644 --- a/packages/web/stores/transfer-history.tsx +++ b/packages/web/stores/transfer-history.tsx @@ -1,5 +1,4 @@ import { KVStore } from "@keplr-wallet/common"; -import { CoinPretty, Dec } from "@keplr-wallet/unit"; import { TransferFailureReason, TransferStatus, @@ -7,6 +6,7 @@ import { TransferStatusReceiver, TxSnapshot, } from "@osmosis-labs/bridge"; +import { CoinPretty, Dec } from "@osmosis-labs/unit"; import dayjs from "dayjs"; import { action, @@ -23,7 +23,7 @@ import { FunctionComponent, useEffect, useRef } from "react"; import { displayToast, ToastType } from "~/components/alert"; import { RadialProgress } from "~/components/radial-progress"; import { useTranslation } from "~/hooks"; -import { humanizeTime } from "~/utils/date"; +import { displayHumanizedTime, humanizeTime } from "~/utils/date"; import { formatPretty } from "~/utils/formatter"; export const TRANSFER_HISTORY_STORE_KEY = "transfer_history"; @@ -331,9 +331,6 @@ export class TransferHistoryStore implements TransferStatusReceiver { (await this.kvStore.get(TRANSFER_HISTORY_STORE_KEY)) ?? []; storedSnapshots.forEach(async (snapshot) => { - if (this.isSnapshotExpired(snapshot)) { - return; - } const statusSource = this.transferStatusProviders.find((source) => snapshot.provider.startsWith(source.providerId) ); @@ -358,11 +355,6 @@ export class TransferHistoryStore implements TransferStatusReceiver { this.isRestoredFromIndexedDB = true; }); } - - protected isSnapshotExpired(snapshot: TxSnapshot): boolean { - const expiryMs = this.historyExpireDays * 86_400_00; - return Date.now() - snapshot.createdAtUnix * 1000 > expiryMs; - } } const PendingTransferLoadingIcon: FunctionComponent<{ @@ -436,13 +428,12 @@ export const PendingTransferCaption: FunctionComponent<{ if (progressRef.current) { // DANGER: We update the HTML directly because react-toastify is having issues while handling react state changes progressRef.current.textContent = - date.diff(dayjs(), "seconds") < 5 - ? t("aboutSecondsRemaining", { - seconds: "5 " + t("timeUnits.seconds"), - }) - : `${t("estimated")} ${humanizedTime.value} ${t( - humanizedTime.unitTranslationKey - )} ${t("remaining")}`; + date.diff(dayjs(), "seconds") < 1 + ? t("unknownTimeRemaining") + : `${t("estimated")} ${displayHumanizedTime({ + humanizedTime, + t, + })} ${t("remaining")}`; } }; diff --git a/packages/web/stores/user-settings/hide-dust.tsx b/packages/web/stores/user-settings/hide-dust.tsx index 79f49b53ac..2443f15650 100644 --- a/packages/web/stores/user-settings/hide-dust.tsx +++ b/packages/web/stores/user-settings/hide-dust.tsx @@ -1,4 +1,4 @@ -import { Dec } from "@keplr-wallet/unit"; +import { Dec } from "@osmosis-labs/unit"; import { action, computed, makeObservable, observable } from "mobx"; import { FunctionComponent } from "react"; diff --git a/packages/web/utils/__tests__/date.spec.ts b/packages/web/utils/__tests__/date.spec.ts index 4ea72e5a95..e58596c5f5 100644 --- a/packages/web/utils/__tests__/date.spec.ts +++ b/packages/web/utils/__tests__/date.spec.ts @@ -15,56 +15,62 @@ cases( (opts) => { const inputDate = dayjs().add(opts.input, "second"); const result = humanizeTime(inputDate); - expect(result.value).toEqual(opts.expected.value); - if (opts.expected.unit !== "") { - expect(result.unitTranslationKey).toEqual( - `timeUnits.${opts.expected.unit}` - ); + + // Check the first time unit + for (const [index, expectedUnit] of opts.expected.entries()) { + expect(result[index].value).toEqual(expectedUnit.value); + if (expectedUnit.unit !== "") { + expect(result[index].unitTranslationKey).toEqual( + `timeUnits.${expectedUnit.unit}` + ); + } } }, [ { name: "should return seconds for less than a minute", input: 30, // 30 seconds from now - expected: { value: 30, unit: "seconds" }, + expected: [{ value: 30, unit: "seconds" }], }, { name: "should return a single second", input: 1, // 1 second from now - expected: { value: 1, unit: "second" }, + expected: [{ value: 1, unit: "second" }], }, { name: "should return minutes for less than an hour", input: 120, // 2 minutes from now - expected: { value: 2, unit: "minutes" }, + expected: [{ value: 2, unit: "minutes" }], }, { name: "should return a single minute", input: 60, // 1 minute from now - expected: { value: 1, unit: "minute" }, + expected: [{ value: 1, unit: "minute" }], }, { name: "should return 59 minutes", input: 59 * 60, // 59 minutes from now - expected: { value: 59, unit: "minutes" }, + expected: [{ value: 59, unit: "minutes" }], }, { - name: "should return hours for less than a day", - input: 2 * 60 * 60, // 2 hours from now - expected: { value: 2, unit: "hours" }, + name: "should return hours and minutes for less than a day", + input: 2 * 60 * 60 + 30 * 60, // 2 hours and 30 minutes from now + expected: [ + { value: 2, unit: "hours" }, + { value: 30, unit: "minutes" }, + ], }, { name: "should return a single hour", input: 60 * 60, // 1 hour from now - expected: { value: 1, unit: "hour" }, + expected: [{ value: 1, unit: "hour" }], }, { name: "should return formatted date for more than a day", - input: 25 * 60 * 60, // 25 hours from now - expected: { - value: 1, - unit: "day", // No unit expected for dates - }, + input: 32 * 24 * 60 * 60, // 32 days from now + expected: [ + { value: dayjs().add(32, "days").format("MMM D, YYYY"), unit: "" }, + ], }, ] ); diff --git a/packages/web/utils/__tests__/formatter.spec.ts b/packages/web/utils/__tests__/formatter.spec.ts index 0d128fdd76..d8a3f44125 100644 --- a/packages/web/utils/__tests__/formatter.spec.ts +++ b/packages/web/utils/__tests__/formatter.spec.ts @@ -1,5 +1,5 @@ -import { Dec, PricePretty } from "@keplr-wallet/unit"; import { DEFAULT_VS_CURRENCY } from "@osmosis-labs/server"; +import { Dec, PricePretty } from "@osmosis-labs/unit"; import cases from "jest-in-case"; import { compressZeros, formatFiatPrice } from "../formatter"; diff --git a/packages/web/utils/date.ts b/packages/web/utils/date.ts index c0885f39ac..af4f375a5b 100644 --- a/packages/web/utils/date.ts +++ b/packages/web/utils/date.ts @@ -6,68 +6,102 @@ export function humanizeTime( ): { value: number | string; unitTranslationKey: string; -} { +}[] { // If less than a minute, show seconds const secondsDiff = date.diff(dayjs(), "seconds"); if (secondsDiff < 60) { - return { - value: Math.max(secondsDiff, 0), - unitTranslationKey: - secondsDiff === 1 - ? useShortTimeUnits - ? "timeUnitsShort.second" - : "timeUnits.second" - : useShortTimeUnits - ? "timeUnitsShort.seconds" - : "timeUnits.seconds", - }; + return [ + { + value: Math.max(secondsDiff, 0), + unitTranslationKey: + secondsDiff === 1 + ? useShortTimeUnits + ? "timeUnitsShort.second" + : "timeUnits.second" + : useShortTimeUnits + ? "timeUnitsShort.seconds" + : "timeUnits.seconds", + }, + ]; } const minutesDiff = date.diff(dayjs(), "minutes"); if (minutesDiff < 60) { - return { - value: minutesDiff, - unitTranslationKey: - minutesDiff === 1 - ? useShortTimeUnits - ? "timeUnitsShort.minute" - : "timeUnits.minute" - : useShortTimeUnits - ? "timeUnitsShort.minutes" - : "timeUnits.minutes", - }; + return [ + { + value: minutesDiff, + unitTranslationKey: + minutesDiff === 1 + ? useShortTimeUnits + ? "timeUnitsShort.minute" + : "timeUnits.minute" + : useShortTimeUnits + ? "timeUnitsShort.minutes" + : "timeUnits.minutes", + }, + ]; } const hoursDiff = date.diff(dayjs(), "hours"); if (hoursDiff < 24) { - return { - value: hoursDiff, - unitTranslationKey: - hoursDiff === 1 - ? useShortTimeUnits - ? "timeUnitsShort.hour" - : "timeUnits.hour" - : useShortTimeUnits - ? "timeUnitsShort.hours" - : "timeUnits.hours", - }; + const minutes = date.diff(dayjs(), "minutes") % 60; + return [ + { + value: hoursDiff, + unitTranslationKey: + hoursDiff === 1 + ? useShortTimeUnits + ? "timeUnitsShort.hour" + : "timeUnits.hour" + : useShortTimeUnits + ? "timeUnitsShort.hours" + : "timeUnits.hours", + }, + { + value: minutes, + unitTranslationKey: + minutes === 1 + ? useShortTimeUnits + ? "timeUnitsShort.minute" + : "timeUnits.minute" + : useShortTimeUnits + ? "timeUnitsShort.minutes" + : "timeUnits.minutes", + }, + ]; } const daysDiff = date.diff(dayjs(), "days"); if (daysDiff < 30) { - return { - value: daysDiff, - unitTranslationKey: - daysDiff === 1 - ? useShortTimeUnits - ? "timeUnitsShort.day" - : "timeUnits.day" - : useShortTimeUnits - ? "timeUnitsShort.days" - : "timeUnits.days", - }; + return [ + { + value: daysDiff, + unitTranslationKey: + daysDiff === 1 + ? useShortTimeUnits + ? "timeUnitsShort.day" + : "timeUnits.day" + : useShortTimeUnits + ? "timeUnitsShort.days" + : "timeUnits.days", + }, + ]; } // For months and years, since it's formatted differently, you might need to handle it separately in your translation logic - return { value: date.format("MMM D, YYYY"), unitTranslationKey: "" }; + return [{ value: date.format("MMM D, YYYY"), unitTranslationKey: "" }]; +} + +export function displayHumanizedTime({ + humanizedTime, + t, + delimitedBy = " and ", +}: { + humanizedTime: ReturnType; + t: (key: string) => string; + delimitedBy?: string; +}) { + return humanizedTime + .map((time) => `${time.value} ${t(time.unitTranslationKey)}`) + .join(delimitedBy); } diff --git a/packages/web/utils/formatter.ts b/packages/web/utils/formatter.ts index 3dc89c67ea..4252cf8d04 100644 --- a/packages/web/utils/formatter.ts +++ b/packages/web/utils/formatter.ts @@ -1,3 +1,4 @@ +import { trimZerosFromEnd } from "@osmosis-labs/stores"; import { CoinPretty, Dec, @@ -5,8 +6,7 @@ import { IntPretty, PricePretty, RatePretty, -} from "@keplr-wallet/unit"; -import { trimZerosFromEnd } from "@osmosis-labs/stores"; +} from "@osmosis-labs/unit"; import { getDecimalCount, diff --git a/yarn.lock b/yarn.lock index 9b991c599f..68ff9b29e9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2139,6 +2139,60 @@ resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@biomejs/biome@1.9.4": + version "1.9.4" + resolved "https://registry.yarnpkg.com/@biomejs/biome/-/biome-1.9.4.tgz#89766281cbc3a0aae865a7ff13d6aaffea2842bf" + integrity sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog== + optionalDependencies: + "@biomejs/cli-darwin-arm64" "1.9.4" + "@biomejs/cli-darwin-x64" "1.9.4" + "@biomejs/cli-linux-arm64" "1.9.4" + "@biomejs/cli-linux-arm64-musl" "1.9.4" + "@biomejs/cli-linux-x64" "1.9.4" + "@biomejs/cli-linux-x64-musl" "1.9.4" + "@biomejs/cli-win32-arm64" "1.9.4" + "@biomejs/cli-win32-x64" "1.9.4" + +"@biomejs/cli-darwin-arm64@1.9.4": + version "1.9.4" + resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.9.4.tgz#dfa376d23a54a2d8f17133c92f23c1bf2e62509f" + integrity sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw== + +"@biomejs/cli-darwin-x64@1.9.4": + version "1.9.4" + resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.9.4.tgz#eafc2ce3849d385fc02238aad1ca4a73395a64d9" + integrity sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg== + +"@biomejs/cli-linux-arm64-musl@1.9.4": + version "1.9.4" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.9.4.tgz#d780c3e01758fc90f3268357e3f19163d1f84fca" + integrity sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA== + +"@biomejs/cli-linux-arm64@1.9.4": + version "1.9.4" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.9.4.tgz#8ed1dd0e89419a4b66a47f95aefb8c46ae6041c9" + integrity sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g== + +"@biomejs/cli-linux-x64-musl@1.9.4": + version "1.9.4" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.9.4.tgz#f36982b966bd671a36671e1de4417963d7db15fb" + integrity sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg== + +"@biomejs/cli-linux-x64@1.9.4": + version "1.9.4" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64/-/cli-linux-x64-1.9.4.tgz#a0a7f56680c76b8034ddc149dbf398bdd3a462e8" + integrity sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg== + +"@biomejs/cli-win32-arm64@1.9.4": + version "1.9.4" + resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.9.4.tgz#e2ef4e0084e76b7e26f0fc887c5ef1265ea56200" + integrity sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg== + +"@biomejs/cli-win32-x64@1.9.4": + version "1.9.4" + resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-x64/-/cli-win32-x64-1.9.4.tgz#4c7afa90e3970213599b4095e62f87e5972b2340" + integrity sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA== + "@chain-registry/client@^1.48.1": version "1.48.12" resolved "https://registry.yarnpkg.com/@chain-registry/client/-/client-1.48.12.tgz#8ade67c85698b5865398760e82d1185e765bb0db" @@ -4334,11 +4388,6 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== -"@jridgewell/sourcemap-codec@^1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" - integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== - "@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.13", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.18": version "0.3.18" resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz" @@ -5860,12 +5909,12 @@ resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== -"@playwright/test@^1.48.0": - version "1.48.0" - resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.48.0.tgz#4b81434a3ca75e2a6f82a645287784223a45434c" - integrity sha512-W5lhqPUVPqhtc/ySvZI5Q8X2ztBOUgZ8LbAFy0JQgrXZs2xaILrUcNO3rQjwbLPfGK13+rZsDa1FpG+tqYkT5w== +"@playwright/test@1.49.0": + version "1.49.0" + resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.49.0.tgz#74227385b58317ee076b86b56d0e1e1b25cff01e" + integrity sha512-DMulbwQURa8rNIQrf94+jPJQ4FmOVdpE5ZppRNvWVjvhC+6sOeo28r8MgIpQRYouXRtt/FCCXU7zn20jnHR4Qw== dependencies: - playwright "1.48.0" + playwright "1.49.0" "@polka/url@^1.0.0-next.20": version "1.0.0-next.21" @@ -7270,6 +7319,13 @@ resolved "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz" integrity sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ== +"@types/node@22.7.5": + version "22.7.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b" + integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ== + dependencies: + undici-types "~6.19.2" + "@types/node@^13.7.0": version "13.13.52" resolved "https://registry.npmjs.org/@types/node/-/node-13.13.52.tgz" @@ -8384,14 +8440,6 @@ abort-controller@^3.0.0: dependencies: event-target-shim "^5.0.0" -accepts@^1.3.5: - version "1.3.8" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" - integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== - dependencies: - mime-types "~2.1.34" - negotiator "0.6.3" - acorn-globals@^7.0.0: version "7.0.1" resolved "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz" @@ -8405,13 +8453,6 @@ acorn-jsx@^5.3.2: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn-loose@^8.4.0: - version "8.4.0" - resolved "https://registry.yarnpkg.com/acorn-loose/-/acorn-loose-8.4.0.tgz#26d3e219756d1e180d006f5bcc8d261a28530f55" - integrity sha512-M0EUka6rb+QC4l9Z3T0nJEzNOO7JcoJlYMrBlyBCiFSXRyxjLKayd4TbQs2FDRWQU1h9FR7QVNHt+PEaoNL5rQ== - dependencies: - acorn "^8.11.0" - acorn-node@^1.8.2: version "1.8.2" resolved "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz" @@ -8431,13 +8472,6 @@ acorn-walk@^8.0.0, acorn-walk@^8.0.2: resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz" integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== -acorn-walk@^8.3.3: - version "8.3.3" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.3.tgz#9caeac29eefaa0c41e3d4c65137de4d6f34df43e" - integrity sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw== - dependencies: - acorn "^8.11.0" - acorn@^7.0.0: version "7.4.1" resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" @@ -8453,11 +8487,6 @@ acorn@^8.1.0, acorn@^8.8.1: resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz" integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== -acorn@^8.11.0, acorn@^8.12.1: - version "8.12.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" - integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== - acorn@^8.11.3: version "8.11.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" @@ -9628,14 +9657,6 @@ cacache@^18.0.0: tar "^6.1.11" unique-filename "^3.0.0" -cache-content-type@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-content-type/-/cache-content-type-1.0.1.tgz#035cde2b08ee2129f4a8315ea8f00a00dba1453c" - integrity sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA== - dependencies: - mime-types "^2.1.18" - ylru "^1.2.0" - cachified@^3.5.4: version "3.5.4" resolved "https://registry.npmjs.org/cachified/-/cachified-3.5.4.tgz" @@ -10174,11 +10195,6 @@ comma-separated-tokens@^2.0.0: resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz#4e89c9458acb61bc8fef19f4529973b2392839ee" integrity sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg== -commander@^12.1.0: - version "12.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3" - integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== - commander@^2.8.1: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -10264,23 +10280,6 @@ console-control-strings@^1.1.0: resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== -console-grid@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/console-grid/-/console-grid-2.2.2.tgz#7b786f6c977b1ae5dcaab21c167f97329ca3fad4" - integrity sha512-ohlgXexdDTKLNsZz7DSJuCAwmRc8omSS61txOk39W3NOthgKGr1a1jJpZ5BCQe4PlrwMw01OvPQ1Bl3G7Y/uFg== - -content-disposition@~0.5.2: - version "0.5.4" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" - integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== - dependencies: - safe-buffer "5.2.1" - -content-type@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" - integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== - conventional-changelog-angular@7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz#5eec8edbff15aa9b1680a8dcfbd53e2d7eb2ba7a" @@ -10376,14 +10375,6 @@ cookie@^0.4.2: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== -cookies@~0.9.0: - version "0.9.1" - resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.9.1.tgz#3ffed6f60bb4fb5f146feeedba50acc418af67e3" - integrity sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw== - dependencies: - depd "~2.0.0" - keygrip "~1.1.0" - copy-anything@^3.0.2: version "3.0.5" resolved "https://registry.yarnpkg.com/copy-anything/-/copy-anything-3.0.5.tgz#2d92dce8c498f790fa7ad16b01a1ae5a45b020a0" @@ -10927,7 +10918,7 @@ decompress-unzip@^4.0.1: pify "^2.3.0" yauzl "^2.4.2" -decompress@^4.2.1: +decompress@4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/decompress/-/decompress-4.2.1.tgz#007f55cc6a62c055afa37c07eb6a4ee1b773f118" integrity sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ== @@ -10975,11 +10966,6 @@ deep-equal@^2.0.5: which-collection "^1.0.1" which-typed-array "^1.1.9" -deep-equal@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" - integrity sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw== - deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz" @@ -11098,16 +11084,6 @@ delegates@^1.0.0: resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz" integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== -depd@^2.0.0, depd@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" - integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== - -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= - deprecation@^2.0.0, deprecation@^2.3.1: version "2.3.1" resolved "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz" @@ -11131,11 +11107,6 @@ destr@^2.0.3: resolved "https://registry.yarnpkg.com/destr/-/destr-2.0.3.tgz#7f9e97cb3d16dbdca7be52aca1644ce402cfe449" integrity sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ== -destroy@^1.0.4: - version "1.2.0" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" - integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== - detect-browser@5.3.0, detect-browser@^5.2.0: version "5.3.0" resolved "https://registry.npmjs.org/detect-browser/-/detect-browser-5.3.0.tgz" @@ -11274,6 +11245,11 @@ dotenv-expand@^10.0.0, dotenv-expand@~10.0.0: resolved "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz" integrity sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A== +dotenv@16.4.5: + version "16.4.5" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" + integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== + dotenv@^16.0.0: version "16.0.3" resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz" @@ -11342,16 +11318,6 @@ eciesjs@^0.3.15: futoin-hkdf "^1.5.3" secp256k1 "^5.0.0" -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== - -eight-colors@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eight-colors/-/eight-colors-1.3.0.tgz#e66ac937ecd1fd7ca89be3e81f917a6ff9cb255f" - integrity sha512-hVoK898cR71ADj7L1LZWaECLaSkzzPtqGXIaKv4K6Pzb72QgjLVsQaNI+ELDQQshzFvgp5xTPkaYkPGqw3YR+g== - ejs@^3.1.7: version "3.1.10" resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b" @@ -11425,11 +11391,6 @@ encode-utf8@^1.0.3: resolved "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz" integrity sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw== -encodeurl@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== - encoding@^0.1.13: version "0.1.13" resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz" @@ -11780,11 +11741,6 @@ escalade@^3.1.1, escalade@^3.1.2: resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== -escape-html@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== - escape-string-regexp@2.0.0, escape-string-regexp@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz" @@ -12634,14 +12590,6 @@ foreground-child@^3.1.0: cross-spawn "^7.0.0" signal-exit "^4.0.1" -foreground-child@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.2.1.tgz#767004ccf3a5b30df39bed90718bab43fe0a59f7" - integrity sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA== - dependencies: - cross-spawn "^7.0.0" - signal-exit "^4.0.1" - forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz" @@ -12670,11 +12618,6 @@ fraction.js@^4.1.2: resolved "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.2.tgz" integrity sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA== -fresh@~0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== - fs-constants@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz" @@ -13428,30 +13371,11 @@ html-escaper@^2.0.0: resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== -http-assert@^1.3.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.5.0.tgz#c389ccd87ac16ed2dfa6246fd73b926aa00e6b8f" - integrity sha512-uPpH7OKX4H25hBmU6G1jWNaqJGpTXxey+YOUizJUAgu0AjLUeC8D73hTrhvDS5D+GJN1DN1+hhc/eF/wpxtp0w== - dependencies: - deep-equal "~1.0.1" - http-errors "~1.8.0" - http-cache-semantics@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== -http-errors@^1.6.3, http-errors@~1.8.0: - version "1.8.1" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" - integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== - dependencies: - depd "~1.1.2" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.1" - http-proxy-agent@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz" @@ -13630,7 +13554,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -14369,11 +14293,6 @@ istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz" integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== -istanbul-lib-coverage@^3.2.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" - integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== - istanbul-lib-instrument@^5.0.4: version "5.1.0" resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz" @@ -14405,15 +14324,6 @@ istanbul-lib-report@^3.0.0: make-dir "^3.0.0" supports-color "^7.1.0" -istanbul-lib-report@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" - integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== - dependencies: - istanbul-lib-coverage "^3.0.0" - make-dir "^4.0.0" - supports-color "^7.1.0" - istanbul-lib-source-maps@^4.0.0: version "4.0.1" resolved "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz" @@ -14431,14 +14341,6 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -istanbul-reports@^3.1.7: - version "3.1.7" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" - integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== - dependencies: - html-escaper "^2.0.0" - istanbul-lib-report "^3.0.0" - iterable-lookahead@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/iterable-lookahead/-/iterable-lookahead-1.0.0.tgz#896dfcb78680bdb50036e97edb034c8b68a9737f" @@ -15333,13 +15235,6 @@ keccak@^3.0.3: node-gyp-build "^4.2.0" readable-stream "^3.6.0" -keygrip@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.1.0.tgz#871b1681d5e159c62a445b0c74b615e0917e7226" - integrity sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ== - dependencies: - tsscmp "1.0.6" - keyv@^4.5.4: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" @@ -15391,53 +15286,6 @@ knip@^5.17.4: zod "^3.22.4" zod-validation-error "^3.0.3" -koa-compose@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-4.1.0.tgz#507306b9371901db41121c812e923d0d67d3e877" - integrity sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw== - -koa-convert@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/koa-convert/-/koa-convert-2.0.0.tgz#86a0c44d81d40551bae22fee6709904573eea4f5" - integrity sha512-asOvN6bFlSnxewce2e/DK3p4tltyfC4VM7ZwuTuepI7dEQVcvpyFuBcEARu1+Hxg8DIwytce2n7jrZtRlPrARA== - dependencies: - co "^4.6.0" - koa-compose "^4.1.0" - -koa-static-resolver@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/koa-static-resolver/-/koa-static-resolver-1.0.6.tgz#c2f33ac3e2ac21e77feb96a01e175080dfa4a686" - integrity sha512-ZX5RshSzH8nFn05/vUNQzqw32nEigsPa67AVUr6ZuQxuGdnCcTLcdgr4C81+YbJjpgqKHfacMBd7NmJIbj7fXw== - -koa@^2.15.3: - version "2.15.3" - resolved "https://registry.yarnpkg.com/koa/-/koa-2.15.3.tgz#062809266ee75ce0c75f6510a005b0e38f8c519a" - integrity sha512-j/8tY9j5t+GVMLeioLaxweJiKUayFhlGqNTzf2ZGwL0ZCQijd2RLHK0SLW5Tsko8YyyqCZC2cojIb0/s62qTAg== - dependencies: - accepts "^1.3.5" - cache-content-type "^1.0.0" - content-disposition "~0.5.2" - content-type "^1.0.4" - cookies "~0.9.0" - debug "^4.3.2" - delegates "^1.0.0" - depd "^2.0.0" - destroy "^1.0.4" - encodeurl "^1.0.2" - escape-html "^1.0.3" - fresh "~0.5.2" - http-assert "^1.3.0" - http-errors "^1.6.3" - is-generator-function "^1.0.7" - koa-compose "^4.1.0" - koa-convert "^2.0.0" - on-finished "^2.3.0" - only "~0.0.2" - parseurl "^1.3.2" - statuses "^1.5.0" - type-is "^1.6.16" - vary "^1.1.2" - language-subtag-registry@^0.3.20: version "0.3.23" resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz#23529e04d9e3b74679d70142df3fd2eb6ec572e7" @@ -16006,11 +15854,6 @@ lz-string@^1.5.0: resolved "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz" integrity sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ== -lz-utils@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/lz-utils/-/lz-utils-2.0.2.tgz#9ccf1f76400617da5b3f5a05192f5227cffd6881" - integrity sha512-i1PJN4hNEevkrvLMqNWCCac1BcB5SRaghywG7HVzWOyVkFOasLCG19ND1sY1F/ZEsM6SnGtoXyBWnmfqOM5r6g== - magic-string@^0.16.0: version "0.16.0" resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.16.0.tgz#970ebb0da7193301285fb1aa650f39bdd81eb45a" @@ -16018,7 +15861,7 @@ magic-string@^0.16.0: dependencies: vlq "^0.2.1" -make-dir@4.0.0, make-dir@^4.0.0: +make-dir@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== @@ -16188,11 +16031,6 @@ mdn-data@2.0.14: resolved "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz" integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== - memoizee@^0.4.15: version "0.4.15" resolved "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz" @@ -16462,11 +16300,6 @@ mime-db@1.51.0: resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz" integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - mime-types@^2.1.12, mime-types@~2.1.19: version "2.1.34" resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz" @@ -16474,13 +16307,6 @@ mime-types@^2.1.12, mime-types@~2.1.19: dependencies: mime-db "1.51.0" -mime-types@^2.1.18, mime-types@~2.1.24, mime-types@~2.1.34: - version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - mime@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" @@ -16550,13 +16376,6 @@ minimatch@9.0.3: dependencies: brace-expansion "^2.0.1" -minimatch@^10.0.1: - version "10.0.1" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.0.1.tgz#ce0521856b453c86e25f2c4c0d03e6ff7ddc440b" - integrity sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ== - dependencies: - brace-expansion "^2.0.1" - minimatch@^3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz" @@ -16779,62 +16598,6 @@ modify-values@^1.0.1: resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== -monocart-code-viewer@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/monocart-code-viewer/-/monocart-code-viewer-1.1.4.tgz#c0cde53285d62510378ba98cfc46c63bdd43efd8" - integrity sha512-ehSe1lBG7D1VDVLjTkHV63J3zAgzyhlC9OaxOri7D0X4L5/EcZUOG5TEoMmYErL+YGSOQXghU9kSSAelwNnp1Q== - -monocart-coverage-reports@^2.9.2: - version "2.9.2" - resolved "https://registry.yarnpkg.com/monocart-coverage-reports/-/monocart-coverage-reports-2.9.2.tgz#04af099401df414fb686a59b09a4dbdab324c8ea" - integrity sha512-kczj6csD/OYJN4/qsRq5E8bMytHHw+Mi8InOnGH/zwszwsI92X4rbH9SJgmKm10wqzbOPwfxcHezLelK3CFWrA== - dependencies: - "@bcoe/v8-coverage" "^0.2.3" - "@jridgewell/sourcemap-codec" "^1.5.0" - acorn "^8.12.1" - acorn-loose "^8.4.0" - acorn-walk "^8.3.3" - commander "^12.1.0" - console-grid "^2.2.2" - diff-sequences "^29.6.3" - eight-colors "^1.3.0" - foreground-child "^3.2.1" - istanbul-lib-coverage "^3.2.2" - istanbul-lib-report "^3.0.1" - istanbul-reports "^3.1.7" - lz-utils "^2.0.2" - minimatch "^10.0.1" - monocart-code-viewer "^1.1.4" - monocart-formatter "^3.0.0" - monocart-locator "^1.0.2" - turbogrid "^3.2.0" - -monocart-formatter@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/monocart-formatter/-/monocart-formatter-3.0.0.tgz#da587413223ea62f6f52d3b1cbfb4a0aa5d96d63" - integrity sha512-91OQpUb/9iDqvrblUv6ki11Jxi1d3Fp5u2jfVAPl3UdNp9TM+iBleLzXntUS51W0o+zoya3CJjZZ01z2XWn25g== - -monocart-locator@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/monocart-locator/-/monocart-locator-1.0.2.tgz#0149c0eec9c2b724b77853d4bf0feedd7517fc61" - integrity sha512-v8W5hJLcWMIxLCcSi/MHh+VeefI+ycFmGz23Froer9QzWjrbg4J3gFJBuI/T1VLNoYxF47bVPPxq8ZlNX4gVCw== - -monocart-reporter@^2.6.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/monocart-reporter/-/monocart-reporter-2.6.1.tgz#8c274d8a20abfb868e9cdeafd3623a10fb90a6ae" - integrity sha512-E/RIT/2j/+/YbTPaAOIoJk19TsDIQ7KQIZ4E2QSqPebDZYVXD28JmdQIbhaDV9Jl+nZVq4Kns2izvD5WVlfGZA== - dependencies: - console-grid "^2.2.2" - eight-colors "^1.3.0" - koa "^2.15.3" - koa-static-resolver "^1.0.6" - lz-utils "^2.0.2" - monocart-coverage-reports "^2.9.2" - monocart-formatter "^3.0.0" - monocart-locator "^1.0.2" - nodemailer "^6.9.14" - turbogrid "^3.2.0" - motion@10.16.2: version "10.16.2" resolved "https://registry.yarnpkg.com/motion/-/motion-10.16.2.tgz#7dc173c6ad62210a7e9916caeeaf22c51e598d21" @@ -16986,7 +16749,7 @@ natural-compare@^1.4.0: resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= -negotiator@0.6.3, negotiator@^0.6.3: +negotiator@^0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== @@ -17159,11 +16922,6 @@ node-releases@^2.0.8: resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz" integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w== -nodemailer@^6.9.14: - version "6.9.14" - resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.9.14.tgz#845fda981f9fd5ac264f4446af908a7c78027f75" - integrity sha512-Dobp/ebDKBvz91sbtRKhcznLThrKxKt97GI2FAlAyy+fk19j73Uz3sBXolVtmcXjaorivqsbbbjDY+Jkt4/bQA== - nomic-bitcoin@^5.0.0-pre.0: version "5.0.0-pre.0" resolved "https://registry.yarnpkg.com/nomic-bitcoin/-/nomic-bitcoin-5.0.0-pre.0.tgz#e99f798d0ab0fcef83bfefd57bd26f77572f25ac" @@ -17606,13 +17364,6 @@ on-exit-leak-free@^0.2.0: resolved "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-0.2.0.tgz" integrity sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg== -on-finished@^2.3.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" - integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== - dependencies: - ee-first "1.1.1" - once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" @@ -17641,11 +17392,6 @@ onetime@^6.0.0: dependencies: mimic-fn "^4.0.0" -only@~0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" - integrity sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ== - open@^8.4.0: version "8.4.2" resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" @@ -17937,11 +17683,6 @@ parse5@^7.0.0, parse5@^7.1.1: dependencies: entities "^4.4.0" -parseurl@^1.3.2: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - path-exists@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz" @@ -18144,17 +17885,17 @@ pkg-types@^1.0.3: mlly "^1.2.0" pathe "^1.1.0" -playwright-core@1.48.0: - version "1.48.0" - resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.48.0.tgz#34d209dd4aba8fccd4a96116f1c4f7630f868722" - integrity sha512-RBvzjM9rdpP7UUFrQzRwR8L/xR4HyC1QXMzGYTbf1vjw25/ya9NRAVnXi/0fvFopjebvyPzsmoK58xxeEOaVvA== +playwright-core@1.49.0: + version "1.49.0" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.49.0.tgz#8e69ffed3f41855b854982f3632f2922c890afcb" + integrity sha512-R+3KKTQF3npy5GTiKH/T+kdhoJfJojjHESR1YEWhYuEKRVfVaxH3+4+GvXE5xyCngCxhxnykk0Vlah9v8fs3jA== -playwright@1.48.0: - version "1.48.0" - resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.48.0.tgz#00855d9a25f1991d422867f1c32af5d90f457b48" - integrity sha512-qPqFaMEHuY/ug8o0uteYJSRfMGFikhUysk8ZvAtfKmUK3kc/6oNl/y3EczF8OFGYIi/Ex2HspMfzYArk6+XQSA== +playwright@1.49.0: + version "1.49.0" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.49.0.tgz#df6b9e05423377a99658202844a294a8afb95d0a" + integrity sha512-eKpmys0UFDnfNb3vfsf8Vx2LEOtflgRebl0Im2eQQnYMA4Aqd+Zw8bEOB+7ZKvN76901mRnqdsiOGKxzVTbi7A== dependencies: - playwright-core "1.48.0" + playwright-core "1.49.0" optionalDependencies: fsevents "2.3.2" @@ -19446,7 +19187,7 @@ safe-array-concat@^1.1.2: has-symbols "^1.0.3" isarray "^2.0.5" -safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -19669,11 +19410,6 @@ set-harmonic-interval@^1.0.1: resolved "https://registry.npmjs.org/set-harmonic-interval/-/set-harmonic-interval-1.0.1.tgz" integrity sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g== -setprototypeof@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" - integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== - sha.js@^2.4.0, sha.js@^2.4.11, sha.js@^2.4.8, sha.js@^2.4.9: version "2.4.11" resolved "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz" @@ -20170,11 +19906,6 @@ standard-http-error@^2.0.1: dependencies: standard-error ">= 1.1.0 < 2" -"statuses@>= 1.5.0 < 2", statuses@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== - std-env@^3.7.0: version "3.7.0" resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.7.0.tgz#c9f7386ced6ecf13360b6c6c55b8aaa4ef7481d2" @@ -20860,11 +20591,6 @@ toggle-selection@^1.0.6: resolved "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz" integrity sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ== -toidentifier@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" - integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== - totalist@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz" @@ -20988,11 +20714,6 @@ tslib@^2.4.0: resolved "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz" integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== -tsscmp@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb" - integrity sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA== - tsx@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/tsx/-/tsx-4.6.2.tgz#8e9c1456ad4f1102c5c42c5be7fd428259b7d39b" @@ -21070,11 +20791,6 @@ turbo@^2.0.14: turbo-windows-64 "2.0.14" turbo-windows-arm64 "2.0.14" -turbogrid@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/turbogrid/-/turbogrid-3.2.0.tgz#469098b8a4d39b5835c4eb70ff9658e56b8531a6" - integrity sha512-c+2qrCGWzoYpLlxtHgRJ4V5dDRE9fUT7D9maxtdBCqJ0NzCdY+x7xF3/F6cG/+n3VIzKfIS+p9Z/0YMQPf6k/Q== - tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz" @@ -21139,14 +20855,6 @@ type-fest@^3.0.0: resolved "https://registry.npmjs.org/type-fest/-/type-fest-3.8.0.tgz" integrity sha512-FVNSzGQz9Th+/9R6Lvv7WIAkstylfHN2/JYxkyhhmKFYh9At2DST8t6L6Lref9eYO8PXFTfG9Sg1Agg0K3vq3Q== -type-is@^1.6.16: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - type-tagger@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/type-tagger/-/type-tagger-1.0.0.tgz" @@ -21260,6 +20968,11 @@ typescript@5.4.5, "typescript@>=3 < 6": resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611" integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ== +typescript@5.6.3: + version "5.6.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.3.tgz#5f3449e31c9d94febb17de03cc081dd56d81db5b" + integrity sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw== + ufo@^1.3.2, ufo@^1.4.0, ufo@^1.5.3: version "1.5.3" resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.5.3.tgz#3325bd3c977b6c6cd3160bf4ff52989adc9d3344" @@ -21322,6 +21035,11 @@ undici-types@~5.26.4: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + unenv@^1.9.0: version "1.9.0" resolved "https://registry.yarnpkg.com/unenv/-/unenv-1.9.0.tgz#469502ae85be1bd3a6aa60f810972b1a904ca312" @@ -21685,11 +21403,6 @@ varuint-bitcoin@^2.0.0: dependencies: uint8array-tools "^0.0.8" -vary@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== - verror@1.10.0: version "1.10.0" resolved "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz" @@ -22316,11 +22029,6 @@ yauzl@^2.4.2: buffer-crc32 "~0.2.3" fd-slicer "~1.1.0" -ylru@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ylru/-/ylru-1.4.0.tgz#0cf0aa57e9c24f8a2cbde0cc1ca2c9592ac4e0f6" - integrity sha512-2OQsPNEmBCvXuFlIni/a+Rn+R2pHW9INm0BxXJ4hVDA8TirqMj+J/Rp9ItLatT/5pZqWwefVrTQcHpixsxnVlA== - yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz"