diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000000..d5d401c5189 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,31 @@ +# Use the latest 2.1 version of CircleCI pipeline process engine. +# See: https://circleci.com/docs/configuration-reference +version: 2.1 + +# Define a job to be invoked later in a workflow. +# See: https://circleci.com/docs/jobs-steps/#jobs-overview & https://circleci.com/docs/configuration-reference/#jobs +jobs: + say-hello: + # Specify the execution environment. You can specify an image from Docker Hub or use one of our convenience images from CircleCI's Developer Hub. + # See: https://circleci.com/docs/executor-intro/ & https://circleci.com/docs/configuration-reference/#executor-job + docker: + # Specify the version you desire here + # See: https://circleci.com/developer/images/image/cimg/base + - image: cimg/base:current + + # Add steps to the job + # See: https://circleci.com/docs/jobs-steps/#steps-overview & https://circleci.com/docs/configuration-reference/#steps + steps: + # Checkout the code as the first step. + - checkout + - run: + name: "Say hello" + command: "echo Hello, World!" + +# Orchestrate jobs using workflows +# See: https://circleci.com/docs/workflows/ & https://circleci.com/docs/configuration-reference/#workflows +workflows: + say-hello-workflow: # This is the name of the workflow, feel free to change it to better match your workflow. + # Inside the workflow, you define the jobs you want to run. + jobs: + - say-hello diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index b01ad10c152..feac4b614be 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -3,6 +3,8 @@ name: Bug Report about: Report a bug or unexpected behavior in the Uniswap interfaces. title: "[Bug] " labels: bug +assignees: '' + --- ## 📱 Interface Affected diff --git a/.github/ISSUE_TEMPLATE/custom.md b/.github/ISSUE_TEMPLATE/custom.md new file mode 100644 index 00000000000..48d5f81fa42 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/custom.md @@ -0,0 +1,10 @@ +--- +name: Custom issue template +about: Describe this issue template's purpose here. +title: '' +labels: '' +assignees: '' + +--- + + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000000..36014cde565 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: 'enhancement' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/jekyll-gh-pages.yml b/.github/workflows/jekyll-gh-pages.yml new file mode 100644 index 00000000000..e31d81c5864 --- /dev/null +++ b/.github/workflows/jekyll-gh-pages.yml @@ -0,0 +1,51 @@ +# Sample workflow for building and deploying a Jekyll site to GitHub Pages +name: Deploy Jekyll with GitHub Pages dependencies preinstalled + +on: + # Runs on pushes targeting the default branch + push: + branches: ["main"] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + # Build job + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Pages + uses: actions/configure-pages@v5 + - name: Build with Jekyll + uses: actions/jekyll-build-pages@v1 + with: + source: ./ + destination: ./_site + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + + # Deployment job + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml new file mode 100644 index 00000000000..f2c9e97c91d --- /dev/null +++ b/.github/workflows/static.yml @@ -0,0 +1,43 @@ +# Simple workflow for deploying static content to GitHub Pages +name: Deploy static content to Pages + +on: + # Runs on pushes targeting the default branch + push: + branches: ["main"] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + # Single deploy job since we're just deploying + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Pages + uses: actions/configure-pages@v5 + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + # Upload entire repository + path: '.' + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/tag_and_release.yml b/.github/workflows/tag_and_release.yml index d96e0d46fef..ec6b8721bc6 100644 --- a/.github/workflows/tag_and_release.yml +++ b/.github/workflows/tag_and_release.yml @@ -3,7 +3,10 @@ on: push: branches: - 'main' - +permissions: + contents: write + issues: write + pull-requests: write jobs: deploy-to-prod: runs-on: ubuntu-latest @@ -31,9 +34,9 @@ jobs: tag_prefix: "" - name: 🪽 Release - uses: actions/create-release@c9ba6969f07ed90fae07e2e66100dd03f9b1a50e + uses: actions/create-release@8e3b4a5e184b498423d5b25ca5ceb5a9258c92c2 env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Or use your PAT with: tag_name: ${{ steps.github-tag-action.outputs.new_tag }} release_name: Release ${{ steps.github-tag-action.outputs.new_tag }} diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..034e8480320 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,21 @@ +# Security Policy + +## Supported Versions + +Use this section to tell people about which versions of your project are +currently being supported with security updates. + +| Version | Supported | +| ------- | ------------------ | +| 5.1.x | :white_check_mark: | +| 5.0.x | :x: | +| 4.0.x | :white_check_mark: | +| < 4.0 | :x: | + +## Reporting a Vulnerability + +Use this section to tell people how to report a vulnerability. + +Tell them where to go, how often they can expect to get an update on a +reported vulnerability, what to expect if the vulnerability is accepted or +declined, etc. diff --git a/apps/extension/package.json b/apps/extension/package.json index ad4bff5873a..9dcc7292896 100644 --- a/apps/extension/package.json +++ b/apps/extension/package.json @@ -93,9 +93,9 @@ "swc-loader": "0.2.6", "tamagui-loader": "1.125.17", "typescript": "5.3.3", - "webpack": "5.90.0", + "webpack": "5.94.0", "webpack-cli": "5.1.4", - "webpack-dev-server": "4.15.1" + "webpack-dev-server": "5.2.1" }, "private": true, "scripts": { diff --git a/apps/mobile/Gemfile b/apps/mobile/Gemfile index a07e6ca69f3..a9e494ea9a1 100644 --- a/apps/mobile/Gemfile +++ b/apps/mobile/Gemfile @@ -1,8 +1,8 @@ source "https://rubygems.org" -gem 'fastlane', '2.214.0' +gem 'fastlane', '2.215.0' # Exclude problematic versions of cocoapods and activesupport that causes build failures. -gem 'cocoapods', '1.14.3' +gem 'cocoapods', '1.15.0' gem 'activesupport', '7.1.2' gem 'xcodeproj', '1.27.0' gem 'concurrent-ruby', '1.3.4' diff --git a/apps/mobile/Gemfile.lock b/apps/mobile/Gemfile.lock index b5891798a1a..c99f3366066 100644 --- a/apps/mobile/Gemfile.lock +++ b/apps/mobile/Gemfile.lock @@ -1,7 +1,9 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (3.0.6) + CFPropertyList (3.0.7) + base64 + nkf rexml activesupport (7.1.2) base64 @@ -13,37 +15,40 @@ GEM minitest (>= 5.1) mutex_m tzinfo (~> 2.0) - addressable (2.8.6) - public_suffix (>= 2.0.2, < 6.0) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) algoliasearch (1.27.5) httpclient (~> 2.8, >= 2.8.3) json (>= 1.5.1) - artifactory (3.0.15) + artifactory (3.0.17) atomos (0.1.3) - aws-eventstream (1.3.0) - aws-partitions (1.877.0) - aws-sdk-core (3.190.1) + aws-eventstream (1.4.0) + aws-partitions (1.1166.0) + aws-sdk-core (3.233.0) aws-eventstream (~> 1, >= 1.3.0) - aws-partitions (~> 1, >= 1.651.0) - aws-sigv4 (~> 1.8) + aws-partitions (~> 1, >= 1.992.0) + aws-sigv4 (~> 1.9) + base64 + bigdecimal jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.75.0) - aws-sdk-core (~> 3, >= 3.188.0) - aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.142.0) - aws-sdk-core (~> 3, >= 3.189.0) + logger + aws-sdk-kms (1.113.0) + aws-sdk-core (~> 3, >= 3.231.0) + aws-sigv4 (~> 1.5) + aws-sdk-s3 (1.199.1) + aws-sdk-core (~> 3, >= 3.231.0) aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.8) - aws-sigv4 (1.8.0) + aws-sigv4 (~> 1.5) + aws-sigv4 (1.12.1) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) - base64 (0.2.0) - bigdecimal (3.1.9) + base64 (0.3.0) + bigdecimal (3.2.3) claide (1.1.0) - cocoapods (1.14.3) + cocoapods (1.15.0) addressable (~> 2.8) claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.14.3) + cocoapods-core (= 1.15.0) cocoapods-deintegrate (>= 1.0.3, < 2.0) cocoapods-downloader (>= 2.1, < 3.0) cocoapods-plugins (>= 1.0.0, < 2.0) @@ -58,7 +63,7 @@ GEM nap (~> 1.0) ruby-macho (>= 2.3.0, < 3.0) xcodeproj (>= 1.23.0, < 2.0) - cocoapods-core (1.14.3) + cocoapods-core (1.15.0) activesupport (>= 5.0, < 8) addressable (~> 2.8) algoliasearch (~> 1.0) @@ -82,19 +87,19 @@ GEM commander (4.6.0) highline (~> 2.0.0) concurrent-ruby (1.3.4) - connection_pool (2.5.0) + connection_pool (2.5.4) declarative (0.0.20) - digest-crc (0.6.5) + digest-crc (0.7.0) rake (>= 12.0.0, < 14.0.0) - domain_name (0.6.20231109) + domain_name (0.6.20240107) dotenv (2.8.1) - drb (2.2.1) + drb (2.2.3) emoji_regex (3.2.3) escape (0.0.4) - ethon (0.16.0) + ethon (0.15.0) ffi (>= 1.15.0) - excon (0.109.0) - faraday (1.10.3) + excon (0.112.0) + faraday (1.10.4) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) faraday-excon (~> 1.1) @@ -110,20 +115,20 @@ GEM faraday (>= 0.8.0) http-cookie (~> 1.0.0) faraday-em_http (1.0.0) - faraday-em_synchrony (1.0.0) + faraday-em_synchrony (1.0.1) faraday-excon (1.1.0) faraday-httpclient (1.0.1) - faraday-multipart (1.0.4) - multipart-post (~> 2) - faraday-net_http (1.0.1) + faraday-multipart (1.1.1) + multipart-post (~> 2.0) + faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) faraday-rack (1.0.0) faraday-retry (1.0.3) - faraday_middleware (1.2.0) + faraday_middleware (1.2.1) faraday (~> 1.0) - fastimage (2.3.0) - fastlane (2.214.0) + fastimage (2.4.0) + fastlane (2.215.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -144,6 +149,7 @@ GEM google-apis-playcustomapp_v1 (~> 0.1) google-cloud-storage (~> 1.31) highline (~> 2.0) + http-cookie (~> 1.0.5) json (< 3.0.0) jwt (>= 2.1.0, < 3) mini_magick (>= 4.9.4, < 5.0.0) @@ -155,116 +161,120 @@ GEM security (= 0.1.3) simctl (~> 1.6.3) terminal-notifier (>= 2.0.0, < 3.0.0) - terminal-table (>= 1.4.5, < 2.0.0) + terminal-table (~> 3) tty-screen (>= 0.6.3, < 1.0.0) tty-spinner (>= 0.8.0, < 1.0.0) word_wrap (~> 1.0.0) xcodeproj (>= 1.13.0, < 2.0.0) xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3) - fastlane-plugin-get_version_name (0.2.2) - fastlane-plugin-versioning_android (0.1.1) - ffi (1.17.1) + ffi (1.17.2) fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.54.0) - google-apis-core (>= 0.11.0, < 2.a) - google-apis-core (0.11.2) + google-apis-androidpublisher_v3 (0.87.0) + google-apis-core (>= 0.15.0, < 2.a) + google-apis-core (0.18.0) addressable (~> 2.5, >= 2.5.1) - googleauth (>= 0.16.2, < 2.a) - httpclient (>= 2.8.1, < 3.a) + googleauth (~> 1.9) + httpclient (>= 2.8.3, < 3.a) mini_mime (~> 1.0) + mutex_m representable (~> 3.0) retriable (>= 2.0, < 4.a) - rexml - webrick - google-apis-iamcredentials_v1 (0.17.0) - google-apis-core (>= 0.11.0, < 2.a) - google-apis-playcustomapp_v1 (0.13.0) - google-apis-core (>= 0.11.0, < 2.a) - google-apis-storage_v1 (0.29.0) - google-apis-core (>= 0.11.0, < 2.a) - google-cloud-core (1.6.1) + google-apis-iamcredentials_v1 (0.24.0) + google-apis-core (>= 0.15.0, < 2.a) + google-apis-playcustomapp_v1 (0.17.0) + google-apis-core (>= 0.15.0, < 2.a) + google-apis-storage_v1 (0.56.0) + google-apis-core (>= 0.15.0, < 2.a) + google-cloud-core (1.8.0) google-cloud-env (>= 1.0, < 3.a) google-cloud-errors (~> 1.0) - google-cloud-env (2.1.0) + google-cloud-env (2.3.1) + base64 (~> 0.2) faraday (>= 1.0, < 3.a) - google-cloud-errors (1.3.1) - google-cloud-storage (1.45.0) + google-cloud-errors (1.5.0) + google-cloud-storage (1.57.0) addressable (~> 2.8) digest-crc (~> 0.4) - google-apis-iamcredentials_v1 (~> 0.1) - google-apis-storage_v1 (~> 0.29.0) + google-apis-core (>= 0.18, < 2) + google-apis-iamcredentials_v1 (~> 0.18) + google-apis-storage_v1 (>= 0.42) google-cloud-core (~> 1.6) - googleauth (>= 0.16.2, < 2.a) + googleauth (~> 1.9) mini_mime (~> 1.0) - googleauth (1.9.1) + google-logging-utils (0.2.0) + googleauth (1.15.0) faraday (>= 1.0, < 3.a) - google-cloud-env (~> 2.1) - jwt (>= 1.4, < 3.0) + google-cloud-env (~> 2.2) + google-logging-utils (~> 0.1) + jwt (>= 1.4, < 4.0) multi_json (~> 1.11) os (>= 0.9, < 2.0) signet (>= 0.16, < 2.a) highline (2.0.3) - http-cookie (1.0.5) + http-cookie (1.0.8) domain_name (~> 0.5) - httpclient (2.8.3) + httpclient (2.9.0) + mutex_m i18n (1.14.7) concurrent-ruby (~> 1.0) jmespath (1.6.2) - json (2.7.1) - jwt (2.7.1) - mini_magick (4.12.0) + json (2.15.0) + jwt (2.10.2) + base64 + logger (1.7.0) + mini_magick (4.13.2) mini_mime (1.1.5) - minitest (5.25.4) + minitest (5.25.5) molinillo (0.8.0) - multi_json (1.15.0) - multipart-post (2.3.0) + multi_json (1.17.0) + multipart-post (2.4.1) mutex_m (0.3.0) nanaimo (0.4.0) nap (1.1.0) - naturally (2.2.1) + naturally (2.3.0) netrc (0.11.0) + nkf (0.2.0) optparse (0.1.1) os (1.1.4) - plist (3.7.1) + plist (3.7.2) public_suffix (4.0.7) - rake (13.1.0) + rake (13.3.0) representable (3.2.0) declarative (< 0.1.0) trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) - rexml (3.4.1) + rexml (3.4.4) rouge (2.0.7) ruby-macho (2.5.1) ruby2_keywords (0.0.5) - rubyzip (2.3.2) + rubyzip (2.4.1) security (0.1.3) - signet (0.18.0) + signet (0.21.0) addressable (~> 2.8) faraday (>= 0.17.5, < 3.a) - jwt (>= 1.5, < 3.0) + jwt (>= 1.5, < 4.0) multi_json (~> 1.10) simctl (1.6.10) CFPropertyList naturally terminal-notifier (2.0.0) - terminal-table (1.8.0) - unicode-display_width (~> 1.1, >= 1.1.1) + terminal-table (3.0.2) + unicode-display_width (>= 1.1.1, < 3) trailblazer-option (0.1.2) tty-cursor (0.7.1) tty-screen (0.8.2) tty-spinner (0.9.3) tty-cursor (~> 0.7) - typhoeus (1.4.1) - ethon (>= 0.9.0) + typhoeus (1.5.0) + ethon (>= 0.9.0, < 0.16.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) uber (0.1.0) - unicode-display_width (1.8.0) - webrick (1.8.1) + unicode-display_width (2.6.0) word_wrap (1.0.0) xcodeproj (1.27.0) CFPropertyList (>= 2.3.3, < 4.0) @@ -283,12 +293,10 @@ PLATFORMS DEPENDENCIES activesupport (= 7.1.2) - cocoapods (= 1.14.3) + cocoapods (= 1.15.0) concurrent-ruby (= 1.3.4) - fastlane (= 2.214.0) - fastlane-plugin-get_version_name - fastlane-plugin-versioning_android + fastlane (= 2.215.0) xcodeproj (= 1.27.0) BUNDLED WITH - 2.4.10 + 2.3.26 diff --git a/apps/mobile/package.json b/apps/mobile/package.json index 70aa1633b50..8d69f608761 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -152,7 +152,7 @@ "react-native-keyboard-controller": "1.17.5", "react-native-localize": "2.2.6", "react-native-markdown-display": "7.0.0-alpha.2", - "react-native-mmkv": "2.10.1", + "react-native-mmkv": "2.11.0", "react-native-onesignal": "5.2.9", "react-native-pager-view": "6.5.1", "react-native-passkey": "3.1.0", diff --git a/apps/web/cypress/support/commands.ts b/apps/web/cypress/support/commands.ts new file mode 100644 index 00000000000..476905a0daa --- /dev/null +++ b/apps/web/cypress/support/commands.ts @@ -0,0 +1,168 @@ +import 'cypress-hardhat/lib/browser' + +import { Eip1193 } from 'cypress-hardhat/lib/browser/eip1193' +import { FeatureFlagClient, FeatureFlags, getFeatureFlagName } from 'uniswap/src/features/gating/flags' +import { ALLOW_ANALYTICS_ATOM_KEY } from 'utilities/src/telemetry/analytics/constants' +import { UserState, initialState } from '../../src/state/user/reducer' +import { setInitialUserState } from '../utils/user-state' + +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace Cypress { + interface ApplicationWindow { + ethereum: Eip1193 + } + interface Chainable { + /** + * Wait for a specific event to be sent to amplitude. If the event is found, the subject will be the event. + * + * @param {string} eventName - The type of the event to search for e.g. SwapEventName.SWAP_TRANSACTION_COMPLETED + * @param {number} timeout - The maximum amount of time (in ms) to wait for the event. + * @returns {Chainable} + */ + waitForAmplitudeEvent(eventName: string, requiredProperties?: string[]): Chainable + /** + * Intercepts a specific graphql operation and responds with the given fixture. + * @param {string} operationName - The name of the graphql operation to intercept. + * @param {string} fixturePath - The path to the fixture to respond with. + */ + interceptGraphqlOperation(operationName: string, fixturePath: string): Chainable + /** + * Intercepts a quote request and responds with the given fixture. + * @param {string} fixturePath - The path to the fixture to respond with. + */ + interceptQuoteRequest(fixturePath: string): Chainable + } + interface Cypress { + eagerlyConnect?: boolean + } + interface VisitOptions { + featureFlags?: Array<{ flag: FeatureFlags; value: boolean }> + /** + * Initial user state. + * @default {@type import('../utils/user-state').CONNECTED_WALLET_USER_STATE} + */ + userState?: Partial + /** + * If false, prevents the app from eagerly connecting to the injected provider. + * @default true + */ + eagerlyConnect?: false + } + } +} + +export function registerCommands() { + // sets up the injected provider to be a mock ethereum provider with the given mnemonic/index + // eslint-disable-next-line no-undef + Cypress.Commands.overwrite( + 'visit', + (original, url: string | Partial, options?: Partial) => { + if (typeof url !== 'string') { + throw new Error('Invalid arguments. The first argument to cy.visit must be the path.') + } + + // Parse overrides + const flagsOn: FeatureFlags[] = [] + const flagsOff: FeatureFlags[] = [] + options?.featureFlags?.forEach((f) => { + if (f.value) { + flagsOn.push(f.flag) + } else { + flagsOff.push(f.flag) + } + }) + + // Format into URL parameters + const overrideParams = new URLSearchParams() + if (flagsOn.length > 0) { + overrideParams.append( + 'featureFlagOverride', + flagsOn.map((flag) => getFeatureFlagName(flag, FeatureFlagClient.Web)).join(','), + ) + } + if (flagsOff.length > 0) { + overrideParams.append( + 'featureFlagOverrideOff', + flagsOn.map((flag) => getFeatureFlagName(flag, FeatureFlagClient.Web)).join(','), + ) + } + + return cy.provider().then((provider) => + original({ + ...options, + url: + [...overrideParams.entries()].length === 0 + ? url + : url.includes('?') + ? `${url}&${overrideParams.toString()}` + : `${url}?${overrideParams.toString()}`, + onBeforeLoad(win) { + options?.onBeforeLoad?.(win) + + setInitialUserState(win, { + ...initialState, + ...(options?.userState ?? {}), + }) + + win.ethereum = provider + win.Cypress.eagerlyConnect = options?.eagerlyConnect ?? true + win.localStorage.setItem(ALLOW_ANALYTICS_ATOM_KEY, 'true') + win.localStorage.setItem('showUniswapExtensionLaunchAtom', 'false') + }, + }), + ) + }, + ) + + Cypress.Commands.add('waitForAmplitudeEvent', (eventName, requiredProperties) => { + function findAndDiscardEventsUpToTarget() { + const events = Cypress.env('amplitudeEventCache') + const targetEventIndex = events.findIndex((event) => { + if (event.event_type !== eventName) { + return false + } + if (requiredProperties) { + return requiredProperties.every((prop) => event.event_properties[prop]) + } + return true + }) + + if (targetEventIndex !== -1) { + const event = events[targetEventIndex] + Cypress.env('amplitudeEventCache', events.slice(targetEventIndex + 1)) + return cy.wrap(event) + } else { + // If not found, retry after waiting for more events to be sent. + return cy.wait('@amplitude').then(findAndDiscardEventsUpToTarget) + } + } + return findAndDiscardEventsUpToTarget() + }) + + Cypress.env('graphqlInterceptions', new Map()) + + Cypress.Commands.add('interceptGraphqlOperation', (operationName, fixturePath) => { + const graphqlInterceptions = Cypress.env('graphqlInterceptions') + cy.intercept(/(?:interface|beta).gateway.uniswap.org\/v1\/graphql/, (req) => { + req.headers['origin'] = 'https://app.uniswap.org' + const currentOperationName = req.body.operationName + + if (graphqlInterceptions.has(currentOperationName)) { + const fixturePath = graphqlInterceptions.get(currentOperationName) + req.reply({ fixture: fixturePath }) + } else { + req.continue() + } + }).as(operationName) + + graphqlInterceptions.set(operationName, fixturePath) + }) + + Cypress.Commands.add('interceptQuoteRequest', (fixturePath) => { + return cy.intercept(/(?:interface|beta)\.gateway\.uniswap\.org\/v2\/quote/, (req) => { + req.headers['origin'] = 'https://app.uniswap.org' + req.reply({ fixture: fixturePath }) + }) + }) +} diff --git a/apps/web/package.json b/apps/web/package.json index 95063c98f64..9761dcb163d 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -150,7 +150,7 @@ "vitest": "3.2.1", "vitest-fetch-mock": "0.4.5", "wait-on": "8.0.2", - "webpack": "5.90.0", + "webpack": "5.94.0", "wrangler": "4.28.0" }, "dependencies": { @@ -222,8 +222,8 @@ "expo-crypto": "12.8.1", "fancy-canvas": "2.1.0", "framer-motion": "10.17.6", - "graphql": "16.6.0", - "hono": "4.8.4", + "graphql": "16.8.1", + "hono": "4.9.7", "html-entities": "2.6.0", "i18next": "23.10.0", "jotai": "1.3.7", diff --git a/apps/web/src/components/Logo/DoubleLogo.tsx b/apps/web/src/components/Logo/DoubleLogo.tsx index 610c4e8205c..9d3dfc98b7e 100644 --- a/apps/web/src/components/Logo/DoubleLogo.tsx +++ b/apps/web/src/components/Logo/DoubleLogo.tsx @@ -47,7 +47,7 @@ function LogolessPlaceholder({ return ( - {currency?.symbol?.toUpperCase().replace('$', '').replace(/\s+/g, '').slice(0, 3)} + {currency?.symbol?.toUpperCase().replace(/\$/g, '').replace(/\s+/g, '').slice(0, 3)} {showNetworkLogo && ( diff --git a/apps/web/src/pages/Landing/Landing.e2e.test.ts b/apps/web/src/pages/Landing/Landing.e2e.test.ts index aec2b7a703b..e213ceaa6c1 100644 --- a/apps/web/src/pages/Landing/Landing.e2e.test.ts +++ b/apps/web/src/pages/Landing/Landing.e2e.test.ts @@ -53,7 +53,7 @@ test.describe('Landing Page', () => { await page.unrouteAll({ behavior: 'ignoreErrors' }) }) test('renders UK compliance banner in UK', async ({ page }) => { - await page.route(/(?:interface|beta).gateway.uniswap.org\/v1\/amplitude-proxy/, async (route) => { + await page.route(/(?:interface|beta)\.gateway\.uniswap\.org\/v1\/amplitude-proxy/, async (route) => { const requestBody = JSON.stringify(await route.request().postDataJSON()) const originalResponse = await route.fetch() const byteSize = new Blob([requestBody]).size diff --git a/apps/web/src/playwright/fixtures/graphql.ts b/apps/web/src/playwright/fixtures/graphql.ts index 5f2ed08e1e0..59823342aac 100644 --- a/apps/web/src/playwright/fixtures/graphql.ts +++ b/apps/web/src/playwright/fixtures/graphql.ts @@ -58,7 +58,7 @@ export const test = base.extend({ } } - await page.route(/(?:interface|beta).(gateway|api).uniswap.org\/v1\/graphql/, async (route) => { + await page.route(/(?:interface|beta)\.(gateway|api)\.uniswap\.org\/v1\/graphql/, async (route) => { const request = route.request() const postData = request.postData() if (!postData) { diff --git a/packages/ui/package.json b/packages/ui/package.json index d7f21662fd3..b2be1a7682d 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -2,47 +2,41 @@ "name": "ui", "version": "0.0.0", "dependencies": { - "@gorhom/bottom-sheet": "4.6.4", - "@react-native-masked-view/masked-view": "0.3.2", - "@shopify/flash-list": "1.7.3", - "@shopify/react-native-skia": "1.12.4", - "@storybook/react": "8.5.2", - "@tamagui/animations-react-native": "1.125.17", - "@tamagui/font-inter": "1.125.17", - "@tamagui/helpers-icon": "1.125.17", - "@tamagui/portal": "1.125.17", - "@tamagui/react-native-media-driver": "1.125.17", - "@tamagui/remove-scroll": "1.125.17", - "@tamagui/theme-base": "1.125.17", - "@tanstack/react-query": "5.77.2", - "@testing-library/react-hooks": "8.0.1", - "ethers": "5.7.2", - "expo-blur": "14.0.3", - "expo-linear-gradient": "14.0.2", + "@gorhom/bottom-sheet": "4.5.1", + "@react-native-masked-view/masked-view": "0.2.9", + "@shopify/flash-list": "1.6.3", + "@shopify/react-native-skia": "1.4.2", + "@storybook/react": "8.4.2", + "@tamagui/animations-react-native": "1.114.4", + "@tamagui/font-inter": "1.114.4", + "@tamagui/helpers-icon": "1.114.4", + "@tamagui/react-native-media-driver": "1.114.4", + "@tamagui/remove-scroll": "1.114.4", + "@tamagui/theme-base": "1.114.4", + "@testing-library/react-hooks": "7.0.2", + "ethers": "6.0.0", + "expo-linear-gradient": "12.7.2", "i18next": "23.10.0", "qrcode": "1.5.1", - "react": "18.3.1", - "react-i18next": "14.1.0", - "react-native": "0.77.2", + "react": "18.2.0", + "react-native": "0.73.6", "react-native-fast-image": "8.6.3", - "react-native-gesture-handler": "2.22.1", + "react-native-gesture-handler": "2.19.0", "react-native-image-colors": "1.5.2", - "react-native-keyboard-controller": "1.17.5", - "react-native-reanimated": "3.16.7", - "react-native-safe-area-context": "5.1.0", - "react-native-svg": "15.11.2", - "react-native-webview": "13.13.5", - "tamagui": "1.125.17", + "react-native-reanimated": "3.15.0", + "react-native-safe-area-context": "4.9.0", + "react-native-svg": "15.1.0", + "react-native-webview": "11.23.1", + "tamagui": "1.114.4", "utilities": "workspace:^", "uuid": "9.0.0", "wcag-contrast": "3.0.0" }, "devDependencies": { - "@storybook/test": "8.5.2", - "@tamagui/animations-moti": "1.125.17", - "@tamagui/core": "1.125.17", - "@testing-library/react-native": "13.0.0", - "@types/chrome": "0.0.304", + "@tamagui/animations-moti": "1.114.4", + "@tamagui/build": "1.114.4", + "@tamagui/core": "1.114.4", + "@testing-library/react-native": "11.5.0", "@types/qrcode": "1.5.5", "@uniswap/eslint-config": "workspace:^", "camelcase": "6.3.0", @@ -63,15 +57,17 @@ "module:jsx": "src", "private": true, "scripts": { - "build:icons": "bunx tsx ./src/scripts/componentize-icons.ts && biome check --write --unsafe", - "build:icons:missing": "bun run build:icons --skip-existing", + "build": "tamagui-build --ignore-base-url && node -r esbuild-register ./src/scripts/remove-declaration-files-from-utilities.ts", + "clean": "tamagui-build clean", + "build:icons": "node -r esbuild-register ./src/scripts/componentize-icons.ts", + "build:icons:missing": "yarn build:icons --skip-existing", "check:deps:usage": "depcheck", "lint": "eslint src --max-warnings=0", - "format": "biome check . --linter-enabled=false", + "format": "../../scripts/prettier.sh", "lint:fix": "eslint src --fix", "test": "jest && echo 'ignoring'", "typecheck": "tsc -b", - "watch": "bun run build --watch" + "watch": "yarn build --watch" }, "sideEffects": [ "*.css" diff --git a/packages/uniswap/package.json b/packages/uniswap/package.json index 134290c7a7c..b0ef401bf29 100644 --- a/packages/uniswap/package.json +++ b/packages/uniswap/package.json @@ -76,7 +76,7 @@ "expo-haptics": "14.0.1", "expo-web-browser": "14.0.2", "fuse.js": "6.5.3", - "graphql": "16.6.0", + "graphql": "16.8.1", "i18next": "23.10.0", "i18next-resources-to-backend": "1.2.1", "idb-keyval": "6.2.1", @@ -96,7 +96,7 @@ "react-native-fast-image": "8.6.3", "react-native-gesture-handler": "2.22.1", "react-native-localize": "2.2.6", - "react-native-mmkv": "2.10.1", + "react-native-mmkv": "2.11.0", "react-native-reanimated": "3.16.7", "react-native-svg": "15.11.2", "react-native-webview": "13.13.5", diff --git a/packages/utilities/package.json b/packages/utilities/package.json index 5d6ff4e591c..59fcda15023 100644 --- a/packages/utilities/package.json +++ b/packages/utilities/package.json @@ -24,7 +24,7 @@ "@uniswap/sdk-core": "7.7.2", "dayjs": "1.11.7", "expo-localization": "16.0.1", - "graphql": "16.6.0", + "graphql": "16.8.1", "jsbi": "3.2.5", "promise": "8.3.0", "react": "18.3.1", diff --git a/packages/wallet/package.json b/packages/wallet/package.json index da490de9e11..7a619b7c796 100644 --- a/packages/wallet/package.json +++ b/packages/wallet/package.json @@ -35,7 +35,7 @@ "dayjs": "1.11.7", "ethers": "5.7.2", "fuse.js": "6.5.3", - "graphql": "16.6.0", + "graphql": "16.8.1", "i18next": "23.10.0", "jsbi": "3.2.5", "lodash": "4.17.21",