ci(release): publish latest release
17
.editorconfig
Normal file
@ -0,0 +1,17 @@
|
||||
# Editor configuration, see http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
# Windows files
|
||||
[*.bat]
|
||||
end_of_line = crlf
|
8
.eslintignore
Normal file
@ -0,0 +1,8 @@
|
||||
**/dist/**
|
||||
**/build/**
|
||||
**/node_modules/**
|
||||
**/types/**
|
||||
**/*.test.{js,jsx,ts,tsx}
|
||||
**/*.spec.{js,jsx,ts,tsx}
|
||||
**/config-overrides.js
|
||||
**/.eslintrc.js
|
5
.firebaserc
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"projects": {
|
||||
"default": "uniswap-mobile"
|
||||
}
|
||||
}
|
3
.gitattributes
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# Windows files should use crlf line endings
|
||||
# https://help.github.com/articles/dealing-with-line-endings/
|
||||
*.bat text eol=crlf
|
1
.github/CODEOWNERS
vendored
@ -1 +0,0 @@
|
||||
* @uniswap/web-reviewers
|
22
.github/ISSUE_TEMPLATE/bug-report.md
vendored
@ -1,22 +0,0 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: Describe an issue in the Uniswap Interface
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
**Bug Description**
|
||||
A clear and concise description of the bug.
|
||||
|
||||
**Steps to Reproduce**
|
||||
|
||||
1. Go to ...
|
||||
2. Click on ...
|
||||
...
|
||||
|
||||
**Expected Behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Additional Context**
|
||||
Add any other context about the problem here (screenshots, whether the bug only occurs only in certain mobile/desktop/browser environments, etc.)
|
8
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,8 +0,0 @@
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: Support
|
||||
url: https://discord.gg/FCfyBSbCU5
|
||||
about: Please ask and answer questions here
|
||||
- name: List a token
|
||||
url: https://github.com/Uniswap/default-token-list#adding-a-token
|
||||
about: Any requests to add a token to Uniswap should go here
|
19
.github/ISSUE_TEMPLATE/feature-request.md
vendored
@ -1,19 +0,0 @@
|
||||
---
|
||||
name: Feature Request
|
||||
about: Suggest an idea for improving the UX of the Uniswap Interface
|
||||
title: ''
|
||||
labels: 'improvement'
|
||||
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.
|
48
.github/actions/report/action.yml
vendored
@ -1,48 +0,0 @@
|
||||
name: Report
|
||||
description: Report test failures via Slack
|
||||
inputs:
|
||||
name:
|
||||
description: The name of the failing test
|
||||
required: true
|
||||
SLACK_WEBHOOK_URL:
|
||||
description: The webhook URL to send the report to
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- uses: slackapi/slack-github-action@007b2c3c751a190b6f0f040e47ed024deaa72844
|
||||
with:
|
||||
payload: |
|
||||
{
|
||||
"text": "${{ inputs.name }} failing on `${{ github.ref_name }}`",
|
||||
"blocks": [
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": "*${{ inputs.name }} failing on `${{ github.ref_name }}`:* <https://github.com/${{ github.repository}}/actions/runs/${{ github.run_id }}|view failing action>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": "_This is blocking pull requests and branch promotions._\n_Please prioritize fixing the build._"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ inputs.SLACK_WEBHOOK_URL }}
|
||||
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
|
||||
# The !oncall bot requires its own message:
|
||||
- uses: slackapi/slack-github-action@007b2c3c751a190b6f0f040e47ed024deaa72844
|
||||
with:
|
||||
payload: |
|
||||
{
|
||||
"text": "!oncall web"
|
||||
}
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ inputs.SLACK_WEBHOOK_URL }}
|
||||
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
|
49
.github/actions/setup/action.yml
vendored
@ -1,49 +0,0 @@
|
||||
name: Setup
|
||||
description: checkout repo, setup node, and install node_modules
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
registry-url: https://registry.npmjs.org
|
||||
# cache is intentionally omitted, as it is faster with yarn v1 to cache node_modules.
|
||||
|
||||
- uses: actions/cache@v3
|
||||
id: install-cache
|
||||
with:
|
||||
# node_modules/.cache is intentionally omitted, as this is used for build tool caches.
|
||||
path: |
|
||||
node_modules
|
||||
!node_modules/.cache
|
||||
key: ${{ runner.os }}-install-${{ hashFiles('yarn.lock') }}
|
||||
- if: steps.install-cache.outputs.cache-hit != 'true'
|
||||
run: yarn install --frozen-lockfile --ignore-scripts
|
||||
shell: bash
|
||||
|
||||
# Run patch-package to apply patches to dependencies.
|
||||
- run: yarn patch-package
|
||||
shell: bash
|
||||
|
||||
# Contracts are compiled from source. If source hasn't changed, the contracts do not need to be re-compiled.
|
||||
- uses: actions/cache@v3
|
||||
id: contracts-cache
|
||||
with:
|
||||
path: |
|
||||
src/abis/types
|
||||
src/types/v3
|
||||
key: ${{ runner.os }}-contracts-${{ hashFiles('src/abis/**/*.json', 'node_modules/@uniswap/**/artifacts/contracts/**/*.json') }}
|
||||
- if: steps.contracts-cache.outputs.cache-hit != 'true'
|
||||
run: yarn contracts
|
||||
shell: bash
|
||||
|
||||
# These operations cannot be cached, so they are run concurrently
|
||||
# - ajv: Validators compile quickly, so caching can be omitted.
|
||||
# - graphql: GraphQL is generated from schema and client-side graphql queries. The schema is always fetched and
|
||||
# changes to client-side queries are hard to detect, so it is always re-generated.
|
||||
# - i18n: Messages are extracted from source and compiled. No caching extractor is available (out-of-the-box).
|
||||
- run: yarn concurrently --max-processes=100% npm:ajv npm:graphql npm:i18n
|
||||
shell: bash
|
12
.github/dependabot.yml
vendored
@ -1,12 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: npm
|
||||
# Files stored in repository root
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: 'daily'
|
||||
allow:
|
||||
- dependency-name: '@uniswap/default-token-list'
|
||||
- dependency-name: '@uniswap/token-lists'
|
||||
reviewers:
|
||||
- 'Uniswap/dependabot-reviewers'
|
52
.github/pull_request_template.md
vendored
@ -1,52 +0,0 @@
|
||||
<!-- Your PR title must follow conventional commits: https://github.com/Uniswap/interface#pr-title -->
|
||||
|
||||
## Description
|
||||
<!-- Summary of change, including motivation and context. -->
|
||||
<!-- Use verb-driven language: "Fixes XYZ" instead of "This change fixes XYZ" -->
|
||||
|
||||
|
||||
<!-- Delete inapplicable lines: -->
|
||||
_Linear ticket:_
|
||||
_Slack thread:_
|
||||
_Relevant docs:_
|
||||
|
||||
|
||||
<!-- Delete this section if your change does not affect UI. -->
|
||||
## Screen capture
|
||||
|
||||
### Before
|
||||
| Mobile | Desktop |
|
||||
| ------------ | ------------ |
|
||||
| paste_before | paste_before |
|
||||
|
||||
|
||||
### After
|
||||
| Mobile | Desktop |
|
||||
| ------------ | ----------- |
|
||||
| paste_after | paste_after |
|
||||
|
||||
|
||||
## Test plan
|
||||
|
||||
<!-- Delete this section if your change is not a bug fix. -->
|
||||
### Reproducing the error
|
||||
|
||||
<!-- Include steps to reproduce the bug. -->
|
||||
1.
|
||||
|
||||
### QA (ie manual testing)
|
||||
|
||||
<!-- Include steps to test the change, ensuring no regression. -->
|
||||
- [ ] N/A
|
||||
|
||||
|
||||
#### Devices
|
||||
<!-- If applicable, include different devices and screen sizes that may be affected, and how you've tested them. -->
|
||||
|
||||
|
||||
### Automated testing
|
||||
|
||||
<!-- If N/A, check and note so it is obvious to your reviewers and does not show up as an incomplete task. -->
|
||||
<!-- eg - [x] Unit test N/A -->
|
||||
- [ ] Unit test
|
||||
- [ ] Integration/E2E test
|
73
.github/workflows/1-main-to-staging.yml
vendored
@ -1,73 +0,0 @@
|
||||
name: 1 | Push main -> staging
|
||||
|
||||
# This CI job is responsible for pushing the current contents of the `main` branch to the
|
||||
# `releases/staging` branch, which will in turn kick off a deploy to the staging environment.
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
# https://stackoverflow.com/questions/57921401/push-to-origin-from-github-action
|
||||
jobs:
|
||||
push-staging:
|
||||
name: 'Push to staging branch'
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: push/staging
|
||||
steps:
|
||||
- name: Check test status
|
||||
uses: actions/github-script@v6.4.1
|
||||
with:
|
||||
script: |
|
||||
const statuses = await github.rest.repos.listCommitStatusesForRef({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
ref: context.sha
|
||||
})
|
||||
const status = statuses.data.find(status => status.context === 'Test / promotion')?.state || 'missing'
|
||||
core.info('Status: ' + status)
|
||||
if (status !== 'success') {
|
||||
core.setFailed('"Test / promotion" must be successful before pushing')
|
||||
}
|
||||
|
||||
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
with:
|
||||
token: ${{ secrets.RELEASE_SERVICE_ACCESS_TOKEN }}
|
||||
ref: main
|
||||
|
||||
# The source file must exist for the corresponding translation messages to be downloaded.
|
||||
- run: touch src/locales/en-US.po
|
||||
- name: Download translations
|
||||
uses: crowdin/github-action@3133cc916c35590475cf6705f482fb653d8e36e9
|
||||
with:
|
||||
upload_sources: false
|
||||
download_translations: true
|
||||
project_id: 458284
|
||||
token: ${{ secrets.CROWDIN_PERSONAL_TOKEN_SECRET }}
|
||||
source: 'src/locales/en-US.po'
|
||||
translation: 'src/locales/%locale%.po'
|
||||
localization_branch_name: main
|
||||
create_pull_request: false
|
||||
push_translations: false
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Git config
|
||||
run: |
|
||||
git config user.name 'UL Service Account'
|
||||
git config user.email 'hello-happy-puppy@users.noreply.github.com'
|
||||
|
||||
- name: Add translations
|
||||
run: |
|
||||
rm src/locales/en-US.po
|
||||
git add -f src/locales/*.po
|
||||
git commit -m 'ci(t9n): download translations from crowdin'
|
||||
|
||||
- name: Add CODEOWNERS
|
||||
run: |
|
||||
echo '* @uniswap/web-admins' > CODEOWNERS
|
||||
git add CODEOWNERS
|
||||
git commit -m 'ci: add global CODEOWNERS'
|
||||
|
||||
- name: Git push
|
||||
run: |
|
||||
git push origin main:releases/staging --force
|
64
.github/workflows/2-deploy-to-staging.yml
vendored
@ -1,64 +0,0 @@
|
||||
name: 2 | Deploy staging
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'releases/staging'
|
||||
|
||||
jobs:
|
||||
deploy-to-staging:
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: deploy/staging
|
||||
steps:
|
||||
- uses: slackapi/slack-github-action@007b2c3c751a190b6f0f040e47ed024deaa72844
|
||||
continue-on-error: true
|
||||
with:
|
||||
payload: |
|
||||
{
|
||||
"text": "Deploy _started_ for ${{ github.ref_name }}"
|
||||
}
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup
|
||||
- run: yarn build
|
||||
env:
|
||||
REACT_APP_STAGING: 1
|
||||
|
||||
- name: Update Cloudflare Pages deployment
|
||||
id: pages-deployment
|
||||
uses: cloudflare/pages-action@364c7ca09a4b57837c5967871d64a2c31adb8c0d
|
||||
with:
|
||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
projectName: interface-staging
|
||||
directory: build
|
||||
githubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Cloudflare uses `main` as the default production branch, so we push using the `main` branch so that it can be aliased by a custom domain.
|
||||
branch: main
|
||||
|
||||
- uses: slackapi/slack-github-action@007b2c3c751a190b6f0f040e47ed024deaa72844
|
||||
continue-on-error: true
|
||||
if: always()
|
||||
with:
|
||||
payload: |
|
||||
{
|
||||
"text": "Deploy *${{ steps.pages-deployment.outcome }}* for ${{ github.ref_name }}"
|
||||
}
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
|
||||
|
||||
- name: Upload source maps to Sentry
|
||||
uses: getsentry/action-release@bd5f874fcda966ba48139b0140fb3ec0cb3aabdd
|
||||
continue-on-error: true
|
||||
env:
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
|
||||
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
|
||||
with:
|
||||
environment: staging
|
||||
sourcemaps: './build/static/js'
|
||||
url_prefix: '~/static/js'
|
42
.github/workflows/3-staging-to-prod.yml
vendored
@ -1,42 +0,0 @@
|
||||
name: 3 | Push staging -> prod
|
||||
|
||||
# This CI job is responsible for force pushing the content of releases/staging to releases/prod. It
|
||||
# is restricted to web-reviewers through virtue of the GitHub environment protection rules for the
|
||||
# prod environment.
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
push-prod:
|
||||
name: 'Push to prod branch'
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: push/prod
|
||||
steps:
|
||||
- name: Check test status
|
||||
uses: actions/github-script@v6.4.1
|
||||
with:
|
||||
script: |
|
||||
const statuses = await github.rest.repos.listCommitStatusesForRef({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
ref: context.sha
|
||||
})
|
||||
const status = statuses.data.find(status => status.context === 'Test / promotion')?.state || 'missing'
|
||||
core.info('Status: ' + status)
|
||||
if (status !== 'success') {
|
||||
core.setFailed('"Test / promotion" must be successful before pushing')
|
||||
}
|
||||
|
||||
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
|
||||
with:
|
||||
token: ${{ secrets.RELEASE_SERVICE_ACCESS_TOKEN }}
|
||||
ref: releases/staging
|
||||
- name: Git config
|
||||
run: |
|
||||
git config user.name "UL Service Account"
|
||||
git config user.email "hello-happy-puppy@users.noreply.github.com"
|
||||
- name: Git push
|
||||
run: |
|
||||
git push origin releases/staging:releases/prod --force
|
111
.github/workflows/4-deploy-to-prod.yml
vendored
@ -1,111 +0,0 @@
|
||||
name: 4 | Deploy prod
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'releases/prod'
|
||||
|
||||
jobs:
|
||||
deploy-to-prod:
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: deploy/prod
|
||||
steps:
|
||||
- uses: slackapi/slack-github-action@007b2c3c751a190b6f0f040e47ed024deaa72844
|
||||
continue-on-error: true
|
||||
with:
|
||||
payload: |
|
||||
{
|
||||
"text": "Deploy _started_ for ${{ github.ref_name }}"
|
||||
}
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup
|
||||
- run: yarn build
|
||||
|
||||
- name: Bump and tag
|
||||
id: github-tag-action
|
||||
uses: mathieudutour/github-tag-action@d745f2e74aaf1ee82e747b181f7a0967978abee0
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
release_branches: releases/prod
|
||||
default_bump: patch
|
||||
|
||||
- name: Pin to IPFS
|
||||
id: pinata
|
||||
uses: anantaramdas/ipfs-pinata-deploy-action@39bbda1ce1fe24c69c6f57861b8038278d53688d
|
||||
with:
|
||||
pin-name: Uniswap ${{ steps.github-tag-action.outputs.new_tag }}
|
||||
path: './build'
|
||||
pinata-api-key: ${{ secrets.PINATA_API_KEY }}
|
||||
pinata-secret-api-key: ${{ secrets.PINATA_API_SECRET_KEY }}
|
||||
|
||||
- name: Convert CIDv0 to CIDv1
|
||||
id: convert-cidv0
|
||||
uses: uniswap/convert-cidv0-cidv1@v1.0.0
|
||||
with:
|
||||
cidv0: ${{ steps.pinata.outputs.hash }}
|
||||
|
||||
- name: Publish release
|
||||
uses: actions/create-release@v1.1.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ steps.github-tag-action.outputs.new_tag }}
|
||||
release_name: Release ${{ steps.github-tag-action.outputs.new_tag }}
|
||||
body: |
|
||||
IPFS hash of the deployment:
|
||||
- CIDv0: `${{ steps.pinata.outputs.hash }}`
|
||||
- CIDv1: `${{ steps.convert-cidv0.outputs.cidv1 }}`
|
||||
|
||||
The latest release is always mirrored at [app.uniswap.org](https://app.uniswap.org).
|
||||
|
||||
You can also access the Uniswap Interface from an IPFS gateway.
|
||||
**BEWARE**: The Uniswap interface uses [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) to remember your settings, such as which tokens you have imported.
|
||||
**You should always use an IPFS gateway that enforces origin separation**, or our hosted deployment of the latest release at [app.uniswap.org](https://app.uniswap.org).
|
||||
Your Uniswap settings are never remembered across different URLs.
|
||||
|
||||
IPFS gateways:
|
||||
- https://${{ steps.convert-cidv0.outputs.cidv1 }}.ipfs.dweb.link/
|
||||
- https://${{ steps.convert-cidv0.outputs.cidv1 }}.ipfs.cf-ipfs.com/
|
||||
- [ipfs://${{ steps.pinata.outputs.hash }}/](ipfs://${{ steps.pinata.outputs.hash }}/)
|
||||
|
||||
${{ steps.github-tag-action.outputs.changelog }}
|
||||
|
||||
- name: Update Cloudflare Pages deployment
|
||||
uses: cloudflare/pages-action@364c7ca09a4b57837c5967871d64a2c31adb8c0d
|
||||
id: pages-deployment
|
||||
with:
|
||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
projectName: ${{ secrets.CLOUDFLARE_PROJECT_NAME }}
|
||||
directory: build
|
||||
githubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Cloudflare uses `main` as the default production branch, so we push using the `main` branch so that it can be aliased by a custom domain.
|
||||
branch: main
|
||||
|
||||
- uses: slackapi/slack-github-action@007b2c3c751a190b6f0f040e47ed024deaa72844
|
||||
continue-on-error: true
|
||||
if: always()
|
||||
with:
|
||||
payload: |
|
||||
{
|
||||
"text": "Deploy *${{ steps.pages-deployment.outcome }}* for ${{ github.ref_name }}"
|
||||
}
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
|
||||
|
||||
- name: Upload source maps to Sentry
|
||||
uses: getsentry/action-release@4744f6a65149f441c5f396d5b0877307c0db52c7
|
||||
continue-on-error: true
|
||||
env:
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
|
||||
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
|
||||
with:
|
||||
environment: production
|
||||
sourcemaps: './build/static/js'
|
||||
url_prefix: '~/static/js'
|
17
.github/workflows/check-pr-title.yaml
vendored
@ -1,17 +0,0 @@
|
||||
name: Check PR Title
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- edited
|
||||
- synchronize
|
||||
|
||||
jobs:
|
||||
# Ensures that the PR title adheres to [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/).
|
||||
conventional-commit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: amannn/action-semantic-pull-request@v3.4.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
26
.github/workflows/crowdin.yaml
vendored
@ -1,26 +0,0 @@
|
||||
name: Crowdin Upload
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
upload-sources:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup
|
||||
- run: yarn i18n:extract
|
||||
|
||||
- name: Upload Crowdin sources
|
||||
uses: crowdin/github-action@3133cc916c35590475cf6705f482fb653d8e36e9
|
||||
with:
|
||||
upload_sources: true
|
||||
download_translations: false
|
||||
project_id: 458284
|
||||
token: ${{ secrets.CROWDIN_PERSONAL_TOKEN_SECRET }}
|
||||
source: 'src/locales/en-US.po'
|
||||
translation: 'src/locales/%locale%.po'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
@ -1,91 +0,0 @@
|
||||
name: Slack notification on pushes to releases/*
|
||||
|
||||
# This CI job will push notifications to Slack whenever code is merged into any releases/* branch
|
||||
#
|
||||
# The steps of the command line kung-fu shown below are as follows:
|
||||
# First we take the JSON-formatted Github context
|
||||
# echo $GITHUB_CONTEXT \
|
||||
# Then we parse out the specific fields we want for our messages using jq and format it into tab-separated values
|
||||
# | jq '.event.commits[] | [.url, .id[0:7], .author.username, .timestamp, .message] | @tsv' \
|
||||
# We need to do some cleaning on this output - specifically removing quotes and replacing newlines with something easier to split
|
||||
# | sed 's/"//g' | sed 's/\\t/;/g' | sed 's/\\n/;/g' | sed 's/\\//g' \
|
||||
# We then use awk to format the TSV into a Slack message
|
||||
# | awk -F';' '{print "• <"$1"|"$2"> (<https://github.com/"$3"|"$3">, "$4") - "$5}' \
|
||||
# We need to deal with some escaping issues with newlines so that we don't break the Slack message format
|
||||
# | sed 's/$/\\n/g' | tr -d '\n' \
|
||||
# Finally we have to truncate the message to 3,000 characters max, otherwise Slack will reject it
|
||||
# | awk '{print substr($0,0,3000);}' \
|
||||
# Then shove the bytes into a file to store them in their exact format
|
||||
# > /tmp/parsed_github_context
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'releases/*'
|
||||
|
||||
jobs:
|
||||
notify-slack:
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: notify/releases
|
||||
steps:
|
||||
- name: Parse event to slug
|
||||
id: parse-slug
|
||||
env:
|
||||
GITHUB_CONTEXT: ${{ toJson(github) }}
|
||||
# Formats the contents of the GitHub event into slugs: one line per commit, formatted for Slack.
|
||||
# Explanation for each line is in the comments above.
|
||||
run: |
|
||||
echo $GITHUB_CONTEXT \
|
||||
| jq '.event.commits[] | [.url, .id[0:7], .author.username, .timestamp, .message] | @tsv' \
|
||||
| sed 's/"//g' | sed 's/\\t/;/g' | sed 's/\\n/;/g' | sed 's/\\//g' \
|
||||
| awk -F';' '{print "• <"$1"|"$2"> (<https://github.com/"$3"|"$3">, "$4") - "$5}' \
|
||||
| sed 's/$/\\n/g' | tr -d '\n' \
|
||||
| awk '{print substr($0,0,3000);}' \
|
||||
> /tmp/parsed_github_context
|
||||
echo "SLACK_COMMITS=$(cat /tmp/parsed_github_context)" >> "$GITHUB_OUTPUT"
|
||||
- uses: slackapi/slack-github-action@007b2c3c751a190b6f0f040e47ed024deaa72844
|
||||
with:
|
||||
payload: |
|
||||
{
|
||||
"text": "GitHub Action build result: ${{ job.status }}\n${{ github.event.pull_request.html_url || github.event.head_commit.url }}",
|
||||
"blocks": [
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": "*Code merged to <https://github.com/Uniswap/interface/tree/${{ github.ref }}|${{ github.ref_name }}> branch:*\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": "*Actor*: <https://github.com/${{ github.triggering_actor }}/|${{ github.triggering_actor }}>\n*Force pushed*: ${{ github.event.forced || false }}\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": "${{ steps.parse-slug.outputs.SLACK_COMMITS || 'New branch created' }}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": "<${{ github.event.compare}}|View Diff>"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
|
24
.github/workflows/semgrep.yml
vendored
@ -1,24 +0,0 @@
|
||||
name: Semgrep
|
||||
on:
|
||||
workflow_dispatch: {}
|
||||
pull_request: {}
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- .github/workflows/semgrep.yml
|
||||
schedule:
|
||||
# random HH:MM to avoid a load spike on GitHub Actions at 00:00
|
||||
- cron: '2 11 * * *'
|
||||
jobs:
|
||||
semgrep:
|
||||
name: semgrep/ci
|
||||
runs-on: ubuntu-20.04
|
||||
env:
|
||||
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
|
||||
container:
|
||||
image: returntocorp/semgrep
|
||||
if: (github.actor != 'dependabot[bot]')
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- run: semgrep ci
|
40
.github/workflows/tag_and_release.yml
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
name: "Tag and release"
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
|
||||
jobs:
|
||||
deploy-to-prod:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: 🧷️ Get version
|
||||
uses: juliangruber/read-file-action@02bbba9876a8f870efd4ad64e3b9088d3fb94d4b
|
||||
id: version
|
||||
with:
|
||||
path: VERSION
|
||||
|
||||
- name: 🧾️ Get release notes
|
||||
uses: juliangruber/read-file-action@02bbba9876a8f870efd4ad64e3b9088d3fb94d4b
|
||||
id: release-notes
|
||||
with:
|
||||
path: RELEASE
|
||||
|
||||
- name: 🏷️ Tag
|
||||
id: github-tag-action
|
||||
uses: uniswap/github-tag-action@7bddacd4864a0f5671e836721db60174d8a9c399
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
custom_tag: ${{ steps.version.outputs.content }}
|
||||
tag_prefix: ""
|
||||
|
||||
- name: 🪽 Release
|
||||
uses: actions/create-release@v1.1.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ steps.github-tag-action.outputs.new_tag }}
|
||||
release_name: Release ${{ steps.github-tag-action.outputs.new_tag }}
|
||||
body: ${{ steps.release-notes.outputs.content }}
|
278
.github/workflows/test.yml
vendored
@ -1,278 +0,0 @@
|
||||
name: Test
|
||||
|
||||
# Many build steps have their own caches, so each job has its own cache to improve subsequent build times.
|
||||
# Build tools are configured to cache to node_modules/.cache, so they are cached independently of node_modules.
|
||||
# Caches are saved every run (by keying on github.run_id), and the most recent available cache is loaded.
|
||||
# See https://jongleberry.medium.com/speed-up-your-ci-and-dx-with-node-modules-cache-ac8df82b7bb0.
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- releases/staging
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: node_modules/.cache
|
||||
key: ${{ runner.os }}-eslint-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-eslint-
|
||||
- run: yarn lint
|
||||
- if: failure() && github.ref_name == 'main'
|
||||
uses: ./.github/actions/report
|
||||
with:
|
||||
name: Lint
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TEST_REPORTER_WEBHOOK }}
|
||||
|
||||
typecheck:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: node_modules/.cache
|
||||
key: ${{ runner.os }}-tsc-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-tsc-
|
||||
- run: yarn typecheck
|
||||
- if: failure() && github.ref_name == 'main'
|
||||
uses: ./.github/actions/report
|
||||
with:
|
||||
name: Typecheck
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TEST_REPORTER_WEBHOOK }}
|
||||
|
||||
deps-tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup
|
||||
- run: yarn yarn-deduplicate --strategy=highest --list --fail
|
||||
- if: failure() && github.ref_name == 'main'
|
||||
uses: ./.github/actions/report
|
||||
with:
|
||||
name: Dependency checks
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TEST_REPORTER_WEBHOOK }}
|
||||
|
||||
unit-tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: node_modules/.cache
|
||||
key: ${{ runner.os }}-jest-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-jest-
|
||||
- run: yarn test --coverage --maxWorkers=100%
|
||||
- uses: codecov/codecov-action@v3
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
fail_ci_if_error: false
|
||||
flags: unit-tests
|
||||
- if: failure() && github.ref_name == 'main'
|
||||
uses: ./.github/actions/report
|
||||
with:
|
||||
name: Unit tests
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TEST_REPORTER_WEBHOOK }}
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: node_modules/.swc
|
||||
key: ${{ runner.os }}-swc-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-swc-
|
||||
- run: yarn build
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: build
|
||||
path: build
|
||||
if-no-files-found: error
|
||||
|
||||
cypress-typecheck:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: node_modules/.cache
|
||||
key: ${{ runner.os }}-cypress-tsc-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-cypress-tsc-
|
||||
- run: yarn typecheck:cypress
|
||||
- if: failure() && github.ref_name == 'main'
|
||||
uses: ./.github/actions/report
|
||||
with:
|
||||
name: Cypress typecheck
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TEST_REPORTER_WEBHOOK }}
|
||||
|
||||
# Allows for parallel re-runs of cypress tests without re-building.
|
||||
cypress-rerun:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: exit 0
|
||||
|
||||
cypress-test-matrix:
|
||||
needs: [build, cypress-rerun]
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
containers: [1, 2, 3, 4]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: /root/.cache/Cypress
|
||||
key: ${{ runner.os }}-cypress-${{ hashFiles('**/node_modules/cypress/package.json') }}
|
||||
- run: |
|
||||
yarn cypress install
|
||||
yarn cypress info
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: build
|
||||
path: build
|
||||
|
||||
- uses: actions/cache/restore@v3
|
||||
with:
|
||||
path: cache
|
||||
key: ${{ runner.os }}-hardhat-${{ hashFiles('hardhat.config.js') }}-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-hardhat-${{ hashFiles('hardhat.config.js') }}-
|
||||
|
||||
- uses: cypress-io/github-action@v4
|
||||
with:
|
||||
install: false
|
||||
record: true
|
||||
parallel: true
|
||||
start: yarn serve
|
||||
wait-on: 'http://localhost:3000'
|
||||
browser: electron
|
||||
group: e2e
|
||||
spec: ${{ github.ref_name == 'releases/staging' && 'cypress/{e2e,staging}/**/*.test.ts' || 'cypress/e2e/**/*.test.ts' }}
|
||||
env:
|
||||
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
COMMIT_INFO_BRANCH: ${{ github.event.pull_request.head.ref || github.ref_name }}
|
||||
COMMIT_INFO_MESSAGE: ${{ github.event.pull_request.title || github.event.head_commit.message }}
|
||||
COMMIT_INFO_AUTHOR: ${{ github.event.sender.login || github.event.head_commit.author.login }}
|
||||
# Cypress requires an email for filtering by author, but GitHub does not expose one.
|
||||
# GitHub's public profile email can be deterministically produced from user id/login.
|
||||
COMMIT_INFO_EMAIL: ${{ github.event.sender.id || github.event.head_commit.author.id }}+${{ github.event.sender.login || github.event.head_commit.author.login }}@users.noreply.github.com
|
||||
COMMIT_INFO_SHA: ${{ github.event.pull_request.head.sha || github.event.head_commit.sha }}
|
||||
COMMIT_INFO_TIMESTAMP: ${{ github.event.pull_request.updated_at || github.event.head_commit.timestamp }}
|
||||
CYPRESS_PULL_REQUEST_ID: ${{ github.event.pull_request.number }}
|
||||
CYPRESS_PULL_REQUEST_URL: ${{ github.event.pull_request.html_url }}
|
||||
- if: failure() && github.ref_name == 'main'
|
||||
uses: ./.github/actions/report
|
||||
with:
|
||||
name: Cypress tests
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TEST_REPORTER_WEBHOOK }}
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: hardhat-cache
|
||||
path: cache
|
||||
|
||||
hardhat-cache:
|
||||
needs: [cypress-test-matrix]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: hardhat-cache
|
||||
path: cache
|
||||
- uses: actions/cache/save@v3
|
||||
with:
|
||||
path: cache
|
||||
key: ${{ runner.os }}-hardhat-${{ hashFiles('hardhat.config.js') }}-${{ github.run_id }}
|
||||
|
||||
cloud-typecheck:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: node_modules/.cache
|
||||
key: ${{ runner.os }}-cloud-tsc-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-cloud-tsc-
|
||||
- run: yarn typecheck:cloud
|
||||
- if: failure() && github.ref_name == 'main'
|
||||
uses: ./.github/actions/report
|
||||
with:
|
||||
name: Cloud typecheck
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TEST_REPORTER_WEBHOOK }}
|
||||
|
||||
cloud-tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: node_modules/.cache
|
||||
key: ${{ runner.os }}-cloud-jest-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-cloud-jest-
|
||||
# Ignore start:cloud output so it doesn't flood the test output.
|
||||
# Only use 1 worker for testing, as the other is used to run start:cloud (the proxy server under test).
|
||||
- run: yarn start-server-and-test 'yarn start:cloud >/dev/null' 3000 'yarn test:cloud --coverage --maxWorkers=1'
|
||||
- uses: codecov/codecov-action@v3
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
fail_ci_if_error: false
|
||||
flags: cloud-tests
|
||||
|
||||
pre:
|
||||
if: ${{ github.ref_name == 'main' || github.ref_name == 'releases/staging' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/github-script@v6.4.1
|
||||
with:
|
||||
script: |
|
||||
github.rest.repos.createCommitStatus({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
sha: context.sha,
|
||||
state: 'pending',
|
||||
context: 'Test / promotion',
|
||||
description: 'Running tests...',
|
||||
target_url: 'https://github.com/Uniswap/interface/actions/runs/' + context.runId
|
||||
})
|
||||
|
||||
post:
|
||||
if: ${{ github.ref_name == 'main' || github.ref_name == 'releases/staging' }}
|
||||
needs: [pre, lint, typecheck, deps-tests, unit-tests, cypress-test-matrix, cloud-tests]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/github-script@v6.4.1
|
||||
with:
|
||||
script: |
|
||||
github.rest.repos.createCommitStatus({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
sha: context.sha,
|
||||
state: ${{ env.STATUS }} ? 'success' : 'failure',
|
||||
context: 'Test / promotion',
|
||||
description: ${{ env.STATUS }} ? 'All tests passed' : 'One or more tests failed and are blocking promotion',
|
||||
target_url: 'https://github.com/Uniswap/interface/actions/runs/' + context.runId
|
||||
})
|
||||
env:
|
||||
STATUS: |
|
||||
${{ needs.lint.result == 'success' }} &&
|
||||
${{ needs.typecheck.result == 'success' }} &&
|
||||
${{ needs.deps-tests.result == 'success' }} &&
|
||||
${{ needs.unit-tests.result == 'success' }} &&
|
||||
${{ needs.cypress-test-matrix.result == 'success' }} &&
|
||||
${{ needs.cloud-tests.result == 'success' }}
|
77
.gitignore
vendored
@ -1,57 +1,48 @@
|
||||
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
|
||||
# generated contract types
|
||||
/src/types/v3
|
||||
/src/abis/types
|
||||
/src/locales/**/*.js
|
||||
/src/locales/**/*.po
|
||||
|
||||
# generated files
|
||||
/src/**/__generated__
|
||||
|
||||
# schema
|
||||
schema.graphql
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
node_modules
|
||||
.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
/cache
|
||||
/functions/coverage
|
||||
/.swc
|
||||
coverage
|
||||
|
||||
# builds
|
||||
/build
|
||||
/dts
|
||||
# next.js
|
||||
.next/
|
||||
out/
|
||||
build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
instrumented
|
||||
.nyc_output
|
||||
.nyc_output/**/*
|
||||
|
||||
/.netlify
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
notes.txt
|
||||
# local env files
|
||||
.env
|
||||
.env.defaults.local
|
||||
|
||||
# turbo
|
||||
.turbo
|
||||
|
||||
# .yarn files
|
||||
.yarn/cache
|
||||
.yarn/versions
|
||||
.yarn/install-state.gz
|
||||
|
||||
dist/out-tsc/*
|
||||
|
||||
# Locale backup files
|
||||
packages/wallet/src/i18n/locales/*_old.json
|
||||
|
||||
# ci
|
||||
.ci-cache/
|
||||
|
||||
|
||||
# JetBrains
|
||||
.idea/
|
||||
|
||||
package-lock.json
|
||||
|
||||
cypress/downloads
|
||||
cypress/videos
|
||||
cypress/screenshots
|
||||
|
||||
.vercel
|
||||
|
||||
.wrangler
|
||||
|
2
.husky/pre-commit
Normal file → Executable file
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
npx lint-staged
|
||||
yarn g:run-fast-checks
|
3
.lintstagedrc
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"**/*+(.ts?|.tsx)": ["turbo staged:lint:fix staged:format --filter=// --"]
|
||||
}
|
3
.npmrc
@ -1 +1,2 @@
|
||||
engine-strict = true
|
||||
# used in tandem with package.json engines section to only use yarn
|
||||
engine-strict=true
|
||||
|
2
.nvmrc
@ -1 +1 @@
|
||||
v18.16.0
|
||||
v18
|
||||
|
6
.vscode/extensions.json
vendored
@ -1,6 +0,0 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"dbaeumer.vscode-eslint"
|
||||
],
|
||||
"unwantedRecommendations": []
|
||||
}
|
25
.vscode/settings.json
vendored
@ -1,25 +0,0 @@
|
||||
{
|
||||
"npm.packageManager": "yarn",
|
||||
"typescript.updateImportsOnFileMove.enabled": "always",
|
||||
"javascript.updateImportsOnFileMove.enabled": "always",
|
||||
"editor.formatOnSaveMode": "file",
|
||||
"editor.tabCompletion": "on",
|
||||
"editor.tabSize": 2,
|
||||
"editor.formatOnSave": false,
|
||||
"editor.inlineSuggest.enabled": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll": true
|
||||
},
|
||||
"files.eol": "\n",
|
||||
"eslint.enable": true,
|
||||
"eslint.debug": true,
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
|
||||
},
|
||||
"[typescriptreact]": {
|
||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
|
||||
},
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
diff --git a/src/components/bottomSheet/BottomSheet.tsx b/src/components/bottomSheet/BottomSheet.tsx
|
||||
index 3b1264fb69d8a32e06cba4e2a1d592cee921b2aa..29e4e6464dc38567a1c97ddffb1e1ae016afbc3f 100644
|
||||
--- a/src/components/bottomSheet/BottomSheet.tsx
|
||||
+++ b/src/components/bottomSheet/BottomSheet.tsx
|
||||
@@ -636,6 +636,7 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
|
||||
const animateToPositionCompleted = useWorkletCallback(
|
||||
function animateToPositionCompleted(isFinished?: boolean) {
|
||||
isForcedClosing.value = false;
|
||||
+ animatedCurrentIndex.value = animatedNextPositionIndex.value;
|
||||
|
||||
if (!isFinished) {
|
||||
return;
|
13
.yarn/patches/@shopify-flash-list-npm-1.4.3-dc03c28fdd.patch
Normal file
@ -0,0 +1,13 @@
|
||||
diff --git a/android/src/main/kotlin/com/shopify/reactnative/flash_list/AutoLayoutView.kt b/android/src/main/kotlin/com/shopify/reactnative/flash_list/AutoLayoutView.kt
|
||||
index 6b78bd93e244649ee5d80bf4436bd742994d91fb..457179850746db36f568737e36d31f18968a1e80 100644
|
||||
--- a/android/src/main/kotlin/com/shopify/reactnative/flash_list/AutoLayoutView.kt
|
||||
+++ b/android/src/main/kotlin/com/shopify/reactnative/flash_list/AutoLayoutView.kt
|
||||
@@ -26,7 +26,7 @@ class AutoLayoutView(context: Context) : ReactViewGroup(context) {
|
||||
|
||||
/** Overriding draw instead of onLayout. RecyclerListView uses absolute positions for each and every item which means that changes in child layouts may not trigger onLayout on this container. The same layout
|
||||
* can still cause views to overlap. Therefore, it makes sense to override draw to do correction. */
|
||||
- override fun dispatchDraw(canvas: Canvas?) {
|
||||
+ override fun dispatchDraw(canvas: Canvas) {
|
||||
fixLayout()
|
||||
fixFooter()
|
||||
super.dispatchDraw(canvas)
|
@ -0,0 +1,91 @@
|
||||
diff --git a/android/src/main/java/expo/modules/localauthentication/LocalAuthenticationModule.kt b/android/src/main/java/expo/modules/localauthentication/LocalAuthenticationModule.kt
|
||||
index 9980dfabbd5179753ba99f50c6ecfadd732cfdb9..c7b0bc2acd8ab516e9d14ef108a078a64afe8b97 100644
|
||||
--- a/android/src/main/java/expo/modules/localauthentication/LocalAuthenticationModule.kt
|
||||
+++ b/android/src/main/java/expo/modules/localauthentication/LocalAuthenticationModule.kt
|
||||
@@ -7,6 +7,7 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
+import android.provider.Settings
|
||||
import androidx.biometric.BiometricManager
|
||||
import androidx.biometric.BiometricPrompt
|
||||
import androidx.biometric.BiometricPrompt.PromptInfo
|
||||
@@ -89,7 +90,7 @@ class LocalAuthenticationModule(context: Context) : ExportedModule(context), Act
|
||||
|
||||
@ExpoMethod
|
||||
fun supportedAuthenticationTypesAsync(promise: Promise) {
|
||||
- val result = biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_WEAK)
|
||||
+ val result = biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG)
|
||||
val results: MutableList<Int> = ArrayList()
|
||||
if (result == BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE) {
|
||||
promise.resolve(results)
|
||||
@@ -122,13 +123,13 @@ class LocalAuthenticationModule(context: Context) : ExportedModule(context), Act
|
||||
|
||||
@ExpoMethod
|
||||
fun hasHardwareAsync(promise: Promise) {
|
||||
- val result = biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_WEAK)
|
||||
+ val result = biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG)
|
||||
promise.resolve(result != BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE)
|
||||
}
|
||||
|
||||
@ExpoMethod
|
||||
fun isEnrolledAsync(promise: Promise) {
|
||||
- val result = biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_WEAK)
|
||||
+ val result = biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG)
|
||||
promise.resolve(result == BiometricManager.BIOMETRIC_SUCCESS)
|
||||
}
|
||||
|
||||
@@ -138,13 +139,31 @@ class LocalAuthenticationModule(context: Context) : ExportedModule(context), Act
|
||||
if (isDeviceSecure) {
|
||||
level = SECURITY_LEVEL_SECRET
|
||||
}
|
||||
- val result = biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_WEAK)
|
||||
+ val result = biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG)
|
||||
if (result == BiometricManager.BIOMETRIC_SUCCESS) {
|
||||
level = SECURITY_LEVEL_BIOMETRIC
|
||||
}
|
||||
promise.resolve(level)
|
||||
}
|
||||
|
||||
+ @ExpoMethod
|
||||
+ fun enrollForAuthentication(promise: Promise) {
|
||||
+ if (Build.VERSION.SDK_INT >= 30) {
|
||||
+ val intent = Intent(Settings.ACTION_BIOMETRIC_ENROLL)
|
||||
+ intent.putExtra(
|
||||
+ Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED,
|
||||
+ BiometricManager.Authenticators.BIOMETRIC_STRONG
|
||||
+ )
|
||||
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
+ currentActivity!!.startActivity(intent)
|
||||
+ promise.resolve(true)
|
||||
+ } else {
|
||||
+ val intent = Intent(Settings.ACTION_FINGERPRINT_ENROLL)
|
||||
+ currentActivity!!.startActivity(intent)
|
||||
+ promise.resolve(true)
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
@ExpoMethod
|
||||
fun authenticateAsync(options: Map<String?, Any?>, promise: Promise) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||
@@ -220,10 +239,16 @@ class LocalAuthenticationModule(context: Context) : ExportedModule(context), Act
|
||||
promptInfoBuilder.setNegativeButtonText(it)
|
||||
}
|
||||
} else {
|
||||
- promptInfoBuilder.setAllowedAuthenticators(
|
||||
- BiometricManager.Authenticators.BIOMETRIC_WEAK
|
||||
- or BiometricManager.Authenticators.DEVICE_CREDENTIAL
|
||||
- )
|
||||
+ if (Build.VERSION.SDK_INT >= 30) {
|
||||
+ promptInfoBuilder.setAllowedAuthenticators(
|
||||
+ BiometricManager.Authenticators.BIOMETRIC_STRONG
|
||||
+ or BiometricManager.Authenticators.DEVICE_CREDENTIAL
|
||||
+ )
|
||||
+ } else {
|
||||
+ promptInfoBuilder.setAllowedAuthenticators(
|
||||
+ BiometricManager.Authenticators.BIOMETRIC_STRONG
|
||||
+ )
|
||||
+ }
|
||||
}
|
||||
promptInfoBuilder.setConfirmationRequired(requireConfirmation)
|
||||
val promptInfo = promptInfoBuilder.build()
|
14
.yarn/patches/multiformats-npm-9.4.2-44b8a13c1d.patch
Normal file
@ -0,0 +1,14 @@
|
||||
diff --git a/basics b/basics
|
||||
deleted file mode 100644
|
||||
index 1a79016a006c6efd5e4cee071f134128d0ffd100..0000000000000000000000000000000000000000
|
||||
--- a/basics
|
||||
+++ /dev/null
|
||||
@@ -1 +0,0 @@
|
||||
-module.exports = require('./cjs/src/basics.js')
|
||||
diff --git a/basics.js b/basics.js
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..1a79016a006c6efd5e4cee071f134128d0ffd100
|
||||
--- /dev/null
|
||||
+++ b/basics.js
|
||||
@@ -0,0 +1 @@
|
||||
+module.exports = require('./cjs/src/basics.js')
|
@ -0,0 +1,19 @@
|
||||
diff --git a/android/src/main/java/com/mpiannucci/reactnativecontextmenu/ContextMenuView.java b/android/src/main/java/com/mpiannucci/reactnativecontextmenu/ContextMenuView.java
|
||||
index 4b5b90b7b478668fdff3fd12d5e028d423ada057..af30dc6f700b3b3cfde5c149bf1f865786df3e27 100644
|
||||
--- a/android/src/main/java/com/mpiannucci/reactnativecontextmenu/ContextMenuView.java
|
||||
+++ b/android/src/main/java/com/mpiannucci/reactnativecontextmenu/ContextMenuView.java
|
||||
@@ -67,6 +67,14 @@ public class ContextMenuView extends ReactViewGroup implements PopupMenu.OnMenuI
|
||||
contextMenu.show();
|
||||
}
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean onDoubleTap(MotionEvent e) {
|
||||
+ if (dropdownMenuMode) {
|
||||
+ contextMenu.show();
|
||||
+ }
|
||||
+ return super.onSingleTapConfirmed(e);
|
||||
+ }
|
||||
});
|
||||
}
|
||||
|
@ -0,0 +1,12 @@
|
||||
diff --git a/RNFastImage.podspec b/RNFastImage.podspec
|
||||
index db0fada63fc06191f8620d336d244edde6c3dba3..286fa816e47996fdff9f25261644d612c682ae0b 100644
|
||||
--- a/RNFastImage.podspec
|
||||
+++ b/RNFastImage.podspec
|
||||
@@ -16,6 +16,6 @@ Pod::Spec.new do |s|
|
||||
s.source_files = "ios/**/*.{h,m}"
|
||||
|
||||
s.dependency 'React-Core'
|
||||
- s.dependency 'SDWebImage', '~> 5.11.1'
|
||||
+ s.dependency 'SDWebImage', '~> 5.15.5'
|
||||
s.dependency 'SDWebImageWebPCoder', '~> 0.8.4'
|
||||
end
|
19
.yarn/patches/react-native-npm-0.71.13-e260a84bbf.patch
Normal file
@ -0,0 +1,19 @@
|
||||
diff --git a/jest/setup.js b/jest/setup.js
|
||||
index 3738bd2c61e516fa431f61fda47f2474f72dba42..2b3266007b3c9412d99e7ceee205ee52e3008077 100644
|
||||
--- a/jest/setup.js
|
||||
+++ b/jest/setup.js
|
||||
@@ -17,12 +17,12 @@ jest.requireActual('@react-native/polyfills/error-guard');
|
||||
|
||||
global.__DEV__ = true;
|
||||
|
||||
-global.performance = {
|
||||
+if (!global.performance) global.performance = {
|
||||
now: jest.fn(Date.now),
|
||||
};
|
||||
|
||||
global.regeneratorRuntime = jest.requireActual('regenerator-runtime/runtime');
|
||||
-global.window = global;
|
||||
+if (!global.window) global.window = global;
|
||||
|
||||
global.requestAnimationFrame = function (callback) {
|
||||
return setTimeout(callback, 0);
|
@ -0,0 +1,38 @@
|
||||
diff --git a/src/charts/line/ChartPath.tsx b/src/charts/line/ChartPath.tsx
|
||||
index 3807c185c9456d2976c305df94574ff7d948b32a..5cf985422cf49120f943c98084b08c16faf452d9 100644
|
||||
--- a/src/charts/line/ChartPath.tsx
|
||||
+++ b/src/charts/line/ChartPath.tsx
|
||||
@@ -18,7 +18,6 @@ const BACKGROUND_COMPONENTS = [
|
||||
'LineChartHighlight',
|
||||
'LineChartHorizontalLine',
|
||||
'LineChartGradient',
|
||||
- 'LineChartDot',
|
||||
'LineChartTooltip',
|
||||
];
|
||||
const FOREGROUND_COMPONENTS = ['LineChartHighlight', 'LineChartDot'];
|
||||
@@ -166,10 +165,25 @@ export function LineChartPathWrapper({
|
||||
<View style={StyleSheet.absoluteFill}>
|
||||
<AnimatedSVG animatedProps={svgProps} height={height}>
|
||||
<LineChartPath color={color} width={strokeWidth} {...pathProps} />
|
||||
+ </AnimatedSVG>
|
||||
+ </View>
|
||||
+
|
||||
+ </LineChartPathContext.Provider>
|
||||
+ <LineChartPathContext.Provider
|
||||
+ value={{
|
||||
+ color,
|
||||
+ isInactive: false,
|
||||
+ isTransitionEnabled: pathProps.isTransitionEnabled ?? true,
|
||||
+ }}
|
||||
+ >
|
||||
+ <View style={StyleSheet.absoluteFill}>
|
||||
+ <AnimatedSVG animatedProps={svgProps} height={height}>
|
||||
{foregroundChildren}
|
||||
</AnimatedSVG>
|
||||
</View>
|
||||
+
|
||||
</LineChartPathContext.Provider>
|
||||
+
|
||||
</>
|
||||
);
|
||||
}
|
52
.yarn/plugins/@yarnpkg/plugin-constraints.cjs
vendored
Normal file
550
.yarn/plugins/@yarnpkg/plugin-version.cjs
vendored
Normal file
28
.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
vendored
Normal file
783
.yarn/releases/yarn-3.2.3.cjs
vendored
Executable file
39
.yarnrc.yml
Normal file
@ -0,0 +1,39 @@
|
||||
enableTelemetry: false
|
||||
|
||||
changesetBaseRefs:
|
||||
- main
|
||||
- origin/main
|
||||
- upstream/main
|
||||
|
||||
changesetIgnorePatterns:
|
||||
- '**/*.test.{js,jsx,ts,tsx}'
|
||||
|
||||
defaultSemverRangePrefix: ''
|
||||
|
||||
enableGlobalCache: false
|
||||
|
||||
nmMode: hardlinks-local
|
||||
|
||||
logFilters:
|
||||
- code: YN0002
|
||||
level: discard
|
||||
- code: YN0060
|
||||
level: discard
|
||||
- code: YN0006
|
||||
level: discard
|
||||
- code: YN0076
|
||||
level: discard
|
||||
- code: YN0013
|
||||
level: discard
|
||||
|
||||
nodeLinker: node-modules
|
||||
|
||||
plugins:
|
||||
- path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
|
||||
spec: '@yarnpkg/plugin-workspace-tools'
|
||||
- path: .yarn/plugins/@yarnpkg/plugin-version.cjs
|
||||
spec: '@yarnpkg/plugin-version'
|
||||
- path: .yarn/plugins/@yarnpkg/plugin-constraints.cjs
|
||||
spec: '@yarnpkg/plugin-constraints'
|
||||
|
||||
yarnPath: .yarn/releases/yarn-3.2.3.cjs
|
1
CODEOWNERS
Normal file
@ -0,0 +1 @@
|
||||
* @uniswap/web-admins
|
90
README.md
@ -1,80 +1,54 @@
|
||||
# Uniswap Labs Interface
|
||||
# Uniswap Labs: Front End Interfaces
|
||||
|
||||
[![codecov](https://codecov.io/gh/Uniswap/interface/branch/main/graph/badge.svg?token=YVT2Y86O82)](https://codecov.io/gh/Uniswap/interface)
|
||||
An open source repository for all Uniswap front end interfaces maintained by Uniswap Labs. Uniswap is a protocol for decentralized exchange of Ethereum tokens.
|
||||
|
||||
[![Unit Tests](https://github.com/Uniswap/interface/actions/workflows/unit-tests.yaml/badge.svg)](https://github.com/Uniswap/interface/actions/workflows/unit-tests.yaml)
|
||||
[![Integration Tests](https://github.com/Uniswap/interface/actions/workflows/integration-tests.yaml/badge.svg)](https://github.com/Uniswap/interface/actions/workflows/integration-tests.yaml)
|
||||
[![Lint](https://github.com/Uniswap/interface/actions/workflows/lint.yml/badge.svg)](https://github.com/Uniswap/interface/actions/workflows/lint.yml)
|
||||
[![Release](https://github.com/Uniswap/interface/actions/workflows/release.yaml/badge.svg)](https://github.com/Uniswap/interface/actions/workflows/release.yaml)
|
||||
[![Crowdin](https://badges.crowdin.net/uniswap-interface/localized.svg)](https://crowdin.com/project/uniswap-interface)
|
||||
## Interfaces
|
||||
|
||||
An open source interface for Uniswap -- a protocol for decentralized exchange of Ethereum tokens.
|
||||
- Web: [app.uniswap.org](https://app.uniswap.org)
|
||||
- Wallet: [wallet.uniswap.org](https://wallet.uniswap.org)
|
||||
|
||||
## Socials / Contact
|
||||
|
||||
- Website: [uniswap.org](https://uniswap.org/)
|
||||
- Interface: [app.uniswap.org](https://app.uniswap.org)
|
||||
- Docs: [uniswap.org/docs/](https://docs.uniswap.org/)
|
||||
- Twitter: [@Uniswap](https://twitter.com/Uniswap)
|
||||
- Reddit: [/r/Uniswap](https://www.reddit.com/r/Uniswap/)
|
||||
- Email: [contact@uniswap.org](mailto:contact@uniswap.org)
|
||||
- Discord: [Uniswap](https://discord.gg/FCfyBSbCU5)
|
||||
- Whitepapers:
|
||||
- [V1](https://hackmd.io/C-DvwDSfSxuh-Gd4WKE_ig)
|
||||
- [V2](https://uniswap.org/whitepaper.pdf)
|
||||
- [V3](https://uniswap.org/whitepaper-v3.pdf)
|
||||
|
||||
## Accessing the Uniswap Interface
|
||||
## Uniswap Links
|
||||
|
||||
To access the Uniswap Interface, use an IPFS gateway link from the
|
||||
[latest release](https://github.com/Uniswap/uniswap-interface/releases/latest),
|
||||
or visit [app.uniswap.org](https://app.uniswap.org).
|
||||
- Website: [uniswap.org](https://uniswap.org/)
|
||||
- Docs: [uniswap.org/docs/](https://docs.uniswap.org/)
|
||||
|
||||
## Unsupported tokens
|
||||
## Whitepapers
|
||||
|
||||
Check out `useUnsupportedTokenList()` in [src/state/lists/hooks.ts](./src/state/lists/hooks.ts) for blocking tokens in your instance of the interface.
|
||||
- [V3](https://uniswap.org/whitepaper-v3.pdf)
|
||||
- [V2](https://uniswap.org/whitepaper.pdf)
|
||||
- [V1](https://hackmd.io/C-DvwDSfSxuh-Gd4WKE_ig)
|
||||
|
||||
You can block an entire list of tokens by passing in a tokenlist like [here](./src/constants/lists.ts)
|
||||
## Apps
|
||||
|
||||
## Contributions
|
||||
For instructions per application or package, see the README published for each application:
|
||||
|
||||
For steps on local deployment, development, and code contribution, please see [CONTRIBUTING](./CONTRIBUTING.md).
|
||||
- [Web](apps/web/README.md)
|
||||
- [Mobile](apps/mobile/README.md)
|
||||
|
||||
#### PR Title
|
||||
Your PR title must follow [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/#summary), and should start with one of the following [types](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#type):
|
||||
## Releases
|
||||
|
||||
- build: Changes that affect the build system or external dependencies (example scopes: yarn, eslint, typescript)
|
||||
- ci: Changes to our CI configuration files and scripts (example scopes: vercel, github, cypress)
|
||||
- docs: Documentation only changes
|
||||
- feat: A new feature
|
||||
- fix: A bug fix
|
||||
- perf: A code change that improves performance
|
||||
- refactor: A code change that neither fixes a bug nor adds a feature
|
||||
- style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
|
||||
- test: Adding missing tests or correcting existing tests
|
||||
All interface releases are tagged and published to this repository. To browse them easily, see the [Github releases tab](https://github.com/Uniswap/interface/releases).
|
||||
|
||||
Example commit messages:
|
||||
## Translations
|
||||
|
||||
- feat: adds support for gnosis safe wallet
|
||||
- fix: removes a polling memory leak
|
||||
- chore: bumps redux version
|
||||
Translations for our applications are done through [crowdin](https://crowdin.com).
|
||||
|
||||
Other things to note:
|
||||
| App | Coverage |
|
||||
| ------- | -------- |
|
||||
| web | [![Crowdin](https://badges.crowdin.net/uniswap-interface/localized.svg)](https://crowdin.com/project/uniswap-interface) |
|
||||
| mobile | [![Crowdin](https://badges.crowdin.net/uniswap-wallet/localized.svg)](https://crowdin.com/project/uniswap-wallet) |
|
||||
|
||||
- Please describe the change using verb statements (ex: Removes X from Y)
|
||||
- PRs with multiple changes should use a list of verb statements
|
||||
- Add any relevant unit / integration tests
|
||||
- Changes will be previewable via vercel. Non-obvious changes should include instructions for how to reproduce them
|
||||
## 🗂 Directory Structure
|
||||
|
||||
|
||||
## Accessing Uniswap V2
|
||||
|
||||
The Uniswap Interface supports swapping, adding liquidity, removing liquidity and migrating liquidity for Uniswap protocol V2.
|
||||
|
||||
- Swap on Uniswap V2: <https://app.uniswap.org/swap?use=v2>
|
||||
- View V2 liquidity: <https://app.uniswap.org/pools/v2>
|
||||
- Add V2 liquidity: <https://app.uniswap.org/add/v2>
|
||||
- Migrate V2 liquidity to V3: <https://app.uniswap.org/migrate/v2>
|
||||
|
||||
## Accessing Uniswap V1
|
||||
|
||||
The Uniswap V1 interface for mainnet and testnets is accessible via IPFS gateways
|
||||
linked from the [v1.0.0 release](https://github.com/Uniswap/uniswap-interface/releases/tag/v1.0.0).
|
||||
| Folder | Contents |
|
||||
| ----------- | ------------------------------------------------------------------------------ |
|
||||
| `apps/` | The home for each standalone application. |
|
||||
| `config/` | Shared infrastructure packages and configurations. |
|
||||
| `packages/` | Shared code packages covering UI, shared functionality, and shared utilities. |
|
||||
|
43
RELEASE
Normal file
@ -0,0 +1,43 @@
|
||||
IPFS hash of the deployment:
|
||||
- CIDv0: `Qmbx2qmXcLfaqtEm71XnBrTZRJSepmMiCYqQa833MUehQR`
|
||||
- CIDv1: `bafybeigkhbeiart6cgq77am7th53hpxehbvlevnzxuqn3z7qvk2nagv2my`
|
||||
|
||||
The latest release is always mirrored at [app.uniswap.org](https://app.uniswap.org).
|
||||
|
||||
You can also access the Uniswap Interface from an IPFS gateway.
|
||||
**BEWARE**: The Uniswap interface uses [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) to remember your settings, such as which tokens you have imported.
|
||||
**You should always use an IPFS gateway that enforces origin separation**, or our hosted deployment of the latest release at [app.uniswap.org](https://app.uniswap.org).
|
||||
Your Uniswap settings are never remembered across different URLs.
|
||||
|
||||
IPFS gateways:
|
||||
- https://bafybeigkhbeiart6cgq77am7th53hpxehbvlevnzxuqn3z7qvk2nagv2my.ipfs.dweb.link/
|
||||
- https://bafybeigkhbeiart6cgq77am7th53hpxehbvlevnzxuqn3z7qvk2nagv2my.ipfs.cf-ipfs.com/
|
||||
- [ipfs://Qmbx2qmXcLfaqtEm71XnBrTZRJSepmMiCYqQa833MUehQR/](ipfs://Qmbx2qmXcLfaqtEm71XnBrTZRJSepmMiCYqQa833MUehQR/)
|
||||
|
||||
## 5.1.0 (2023-12-05)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **web:** [info] add TDP chart toggle controls (#5223) c9ffc36
|
||||
* **web:** add H1 to token detail page (#5272) b75724c
|
||||
* **web:** page titles for all pages (#5327) b45bcab
|
||||
* **web:** refresh swap flow (#5315) 83f70d4
|
||||
* **web:** use Context for swap state (#5266) 37a649e
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **web:** network downtime warning is not positioned correctly (#5281) 8b3ebb3
|
||||
* **web:** page titles not updating properly (#5346) 6a29762
|
||||
* **web:** put tdp text content in p tags (#5308) e5ca253
|
||||
* **web:** remove trailing slash from canonicals (#5305) 00844b1
|
||||
* **web:** tab title bug (#5258) e4b92be
|
||||
* **web:** use nondenominational festive uni logo (#5361) 6f47a78
|
||||
|
||||
|
||||
### Tests
|
||||
|
||||
* **web:** add tests for token page title (#5307) 714c0fa
|
||||
|
||||
|
1
VERSION
Normal file
@ -0,0 +1 @@
|
||||
web/5.1.0
|
49
apps/mobile/.detoxrc.json
Normal file
@ -0,0 +1,49 @@
|
||||
{
|
||||
"testRunner": "jest",
|
||||
"runnerConfig": "e2e/config.json",
|
||||
"skipLegacyWorkersInjection": true,
|
||||
"apps": {
|
||||
"ios.debug": {
|
||||
"type": "ios.app",
|
||||
"binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/Uniswap.app",
|
||||
"build": "RN_SRC_EXT=e2e.js,e2e.ts xcodebuild -workspace ios/Uniswap.xcworkspace -scheme Uniswap -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build -UseModernBuildSystem=YES -arch x86_64"
|
||||
},
|
||||
"ios.release": {
|
||||
"type": "ios.app",
|
||||
"binaryPath": "ios/build/Build/Products/Release-iphonesimulator/Uniswap.app",
|
||||
"build": "RN_SRC_EXT=e2e.js,e2e.ts xcodebuild -workspace ios/Uniswap.xcworkspace -scheme Uniswap -configuration Release -sdk iphonesimulator -derivedDataPath ios/build -UseModernBuildSystem=YES -arch x86_64"
|
||||
},
|
||||
"android": {
|
||||
"type": "android.apk",
|
||||
"binaryPath": "SPECIFY_PATH_TO_YOUR_APP_BINARY"
|
||||
}
|
||||
},
|
||||
"devices": {
|
||||
"simulator": {
|
||||
"type": "ios.simulator",
|
||||
"device": {
|
||||
"type": "iPhone 12 Pro Max"
|
||||
}
|
||||
},
|
||||
"emulator": {
|
||||
"type": "android.emulator",
|
||||
"device": {
|
||||
"avdName": "Pixel_3a_API_30_x86"
|
||||
}
|
||||
}
|
||||
},
|
||||
"configurations": {
|
||||
"ios.sim.debug": {
|
||||
"device": "simulator",
|
||||
"app": "ios.debug"
|
||||
},
|
||||
"ios.sim.release": {
|
||||
"device": "simulator",
|
||||
"app": "ios.release"
|
||||
},
|
||||
"android": {
|
||||
"device": "emulator",
|
||||
"app": "android"
|
||||
}
|
||||
}
|
||||
}
|
12
apps/mobile/.eslintignore
Normal file
@ -0,0 +1,12 @@
|
||||
.eslintrc.js
|
||||
babel.config.js
|
||||
jest.config.js
|
||||
metro.config.js
|
||||
node_modules
|
||||
|
||||
generated*.ts
|
||||
__generated__/
|
||||
|
||||
storybook-static
|
||||
|
||||
coverage
|
28
apps/mobile/.eslintrc.js
Normal file
@ -0,0 +1,28 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ['custom'],
|
||||
parserOptions: {
|
||||
project: 'tsconfig.json',
|
||||
tsconfigRootDir: __dirname,
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
ecmaVersion: 2018,
|
||||
sourceType: 'module',
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.ts', '*.tsx', '*.js', '*.jsx'],
|
||||
rules: {},
|
||||
},
|
||||
{
|
||||
files: ['*.ts', '*.tsx'],
|
||||
rules: {},
|
||||
},
|
||||
{
|
||||
files: ['*.js', '*.jsx'],
|
||||
rules: {},
|
||||
},
|
||||
],
|
||||
rules: {},
|
||||
}
|
116
apps/mobile/.gitignore
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
# OSX
|
||||
#
|
||||
.DS_Store
|
||||
|
||||
# Xcode
|
||||
#
|
||||
build/
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
!default.mode1v3
|
||||
*.mode2v3
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
xcuserdata
|
||||
*.xccheckout
|
||||
*.moved-aside
|
||||
DerivedData
|
||||
*.hmap
|
||||
*.ipa
|
||||
*.xcuserstate
|
||||
ios/.xcode.env.local
|
||||
ios/GoogleService-Info.plist
|
||||
|
||||
# Android/IntelliJ
|
||||
#
|
||||
build/
|
||||
.idea
|
||||
.gradle
|
||||
local.properties
|
||||
*.iml
|
||||
*.hprof
|
||||
*.jks
|
||||
keystore.properties
|
||||
*.aab
|
||||
|
||||
# node.js
|
||||
#
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
# BUCK
|
||||
buck-out/
|
||||
\.buckd/
|
||||
*.keystore
|
||||
!debug.keystore
|
||||
|
||||
# Yarn
|
||||
.yarn/cache
|
||||
.yarn/versions
|
||||
.yarn/install-state.gz
|
||||
|
||||
# fastlane
|
||||
#
|
||||
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
|
||||
# screenshots whenever they are needed.
|
||||
# For more information about the recommended setup visit:
|
||||
# https://docs.fastlane.tools/best-practices/source-control/
|
||||
|
||||
fastlane/report.xml
|
||||
fastlane/Preview.html
|
||||
fastlane/screenshots
|
||||
fastlane/.env
|
||||
fastlane/.env.*
|
||||
fastlane/builds
|
||||
|
||||
# firebase
|
||||
firebase-debug.log
|
||||
firestore-debug.log
|
||||
ui-debug.log
|
||||
|
||||
# Bundle artifact
|
||||
*.jsbundle
|
||||
*.jsbundle.map
|
||||
|
||||
# Detox artifacts
|
||||
artifacts/
|
||||
|
||||
# CocoaPods
|
||||
/ios/Pods/
|
||||
|
||||
# ccache
|
||||
.ccache
|
||||
|
||||
# hardhat network fork
|
||||
/cache/
|
||||
|
||||
# Storybook
|
||||
build-storybook.log
|
||||
storybook-static/*
|
||||
|
||||
# Private keys
|
||||
.env.local
|
||||
|
||||
# Snyk
|
||||
.dccache
|
||||
|
||||
./lib/
|
||||
|
||||
# Jest
|
||||
coverage/
|
||||
|
||||
# Swift GraphQL codegen
|
||||
# Ignores everything inside the schema folder except the README.md
|
||||
!ios/WidgetsCore/MobileSchema/
|
||||
ios/WidgetsCore/MobileSchema/*
|
||||
!ios/WidgetsCore/MobileSchema/README.md
|
||||
|
||||
# Swift env
|
||||
ios/WidgetsCore/Env.swift
|
||||
|
||||
# Sentry
|
||||
ios/sentry.properties
|
||||
android/sentry.properties
|
6
apps/mobile/.prettierignore
Normal file
@ -0,0 +1,6 @@
|
||||
ios
|
||||
android
|
||||
src/abis/types
|
||||
generated*.ts
|
||||
__generated__/
|
||||
.eslintrc.js
|
1
apps/mobile/.watchmanconfig
Normal file
@ -0,0 +1 @@
|
||||
{}
|
@ -0,0 +1,12 @@
|
||||
diff --git a/RNFastImage.podspec b/RNFastImage.podspec
|
||||
index db0fada63fc06191f8620d336d244edde6c3dba3..286fa816e47996fdff9f25261644d612c682ae0b 100644
|
||||
--- a/RNFastImage.podspec
|
||||
+++ b/RNFastImage.podspec
|
||||
@@ -16,6 +16,6 @@ Pod::Spec.new do |s|
|
||||
s.source_files = "ios/**/*.{h,m}"
|
||||
|
||||
s.dependency 'React-Core'
|
||||
- s.dependency 'SDWebImage', '~> 5.11.1'
|
||||
+ s.dependency 'SDWebImage', '~> 5.15.5'
|
||||
s.dependency 'SDWebImageWebPCoder', '~> 0.8.4'
|
||||
end
|
1
apps/mobile/CODEOWNERS
Normal file
@ -0,0 +1 @@
|
||||
* @Uniswap/mobile-release-admins
|
10
apps/mobile/Gemfile
Normal file
@ -0,0 +1,10 @@
|
||||
# Autogenerated by fastlane
|
||||
#
|
||||
# Ensure this file is checked in to source control!
|
||||
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem 'fastlane'
|
||||
|
||||
plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
|
||||
eval_gemfile(plugins_path) if File.exist?(plugins_path)
|
222
apps/mobile/Gemfile.lock
Normal file
@ -0,0 +1,222 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
CFPropertyList (3.0.6)
|
||||
rexml
|
||||
addressable (2.8.5)
|
||||
public_suffix (>= 2.0.2, < 6.0)
|
||||
artifactory (3.0.15)
|
||||
atomos (0.1.3)
|
||||
aws-eventstream (1.2.0)
|
||||
aws-partitions (1.805.0)
|
||||
aws-sdk-core (3.180.3)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
aws-partitions (~> 1, >= 1.651.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
jmespath (~> 1, >= 1.6.1)
|
||||
aws-sdk-kms (1.71.0)
|
||||
aws-sdk-core (~> 3, >= 3.177.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-s3 (1.132.1)
|
||||
aws-sdk-core (~> 3, >= 3.179.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.6)
|
||||
aws-sigv4 (1.6.0)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
babosa (1.0.4)
|
||||
claide (1.1.0)
|
||||
colored (1.2)
|
||||
colored2 (3.1.2)
|
||||
commander (4.6.0)
|
||||
highline (~> 2.0.0)
|
||||
declarative (0.0.20)
|
||||
digest-crc (0.6.5)
|
||||
rake (>= 12.0.0, < 14.0.0)
|
||||
domain_name (0.5.20190701)
|
||||
unf (>= 0.0.5, < 1.0.0)
|
||||
dotenv (2.8.1)
|
||||
emoji_regex (3.2.3)
|
||||
excon (0.100.0)
|
||||
faraday (1.10.3)
|
||||
faraday-em_http (~> 1.0)
|
||||
faraday-em_synchrony (~> 1.0)
|
||||
faraday-excon (~> 1.1)
|
||||
faraday-httpclient (~> 1.0)
|
||||
faraday-multipart (~> 1.0)
|
||||
faraday-net_http (~> 1.0)
|
||||
faraday-net_http_persistent (~> 1.0)
|
||||
faraday-patron (~> 1.0)
|
||||
faraday-rack (~> 1.0)
|
||||
faraday-retry (~> 1.0)
|
||||
ruby2_keywords (>= 0.0.4)
|
||||
faraday-cookie_jar (0.0.7)
|
||||
faraday (>= 0.8.0)
|
||||
http-cookie (~> 1.0.0)
|
||||
faraday-em_http (1.0.0)
|
||||
faraday-em_synchrony (1.0.0)
|
||||
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-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 (~> 1.0)
|
||||
fastimage (2.2.7)
|
||||
fastlane (2.214.0)
|
||||
CFPropertyList (>= 2.3, < 4.0.0)
|
||||
addressable (>= 2.8, < 3.0.0)
|
||||
artifactory (~> 3.0)
|
||||
aws-sdk-s3 (~> 1.0)
|
||||
babosa (>= 1.0.3, < 2.0.0)
|
||||
bundler (>= 1.12.0, < 3.0.0)
|
||||
colored
|
||||
commander (~> 4.6)
|
||||
dotenv (>= 2.1.1, < 3.0.0)
|
||||
emoji_regex (>= 0.1, < 4.0)
|
||||
excon (>= 0.71.0, < 1.0.0)
|
||||
faraday (~> 1.0)
|
||||
faraday-cookie_jar (~> 0.0.6)
|
||||
faraday_middleware (~> 1.0)
|
||||
fastimage (>= 2.1.0, < 3.0.0)
|
||||
gh_inspector (>= 1.1.2, < 2.0.0)
|
||||
google-apis-androidpublisher_v3 (~> 0.3)
|
||||
google-apis-playcustomapp_v1 (~> 0.1)
|
||||
google-cloud-storage (~> 1.31)
|
||||
highline (~> 2.0)
|
||||
json (< 3.0.0)
|
||||
jwt (>= 2.1.0, < 3)
|
||||
mini_magick (>= 4.9.4, < 5.0.0)
|
||||
multipart-post (>= 2.0.0, < 3.0.0)
|
||||
naturally (~> 2.2)
|
||||
optparse (~> 0.1.1)
|
||||
plist (>= 3.1.0, < 4.0.0)
|
||||
rubyzip (>= 2.0.0, < 3.0.0)
|
||||
security (= 0.1.3)
|
||||
simctl (~> 1.6.3)
|
||||
terminal-notifier (>= 2.0.0, < 3.0.0)
|
||||
terminal-table (>= 1.4.5, < 2.0.0)
|
||||
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)
|
||||
gh_inspector (1.1.3)
|
||||
google-apis-androidpublisher_v3 (0.48.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-apis-core (0.11.1)
|
||||
addressable (~> 2.5, >= 2.5.1)
|
||||
googleauth (>= 0.16.2, < 2.a)
|
||||
httpclient (>= 2.8.1, < 3.a)
|
||||
mini_mime (~> 1.0)
|
||||
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.19.0)
|
||||
google-apis-core (>= 0.9.0, < 2.a)
|
||||
google-cloud-core (1.6.0)
|
||||
google-cloud-env (~> 1.0)
|
||||
google-cloud-errors (~> 1.0)
|
||||
google-cloud-env (1.6.0)
|
||||
faraday (>= 0.17.3, < 3.0)
|
||||
google-cloud-errors (1.3.1)
|
||||
google-cloud-storage (1.44.0)
|
||||
addressable (~> 2.8)
|
||||
digest-crc (~> 0.4)
|
||||
google-apis-iamcredentials_v1 (~> 0.1)
|
||||
google-apis-storage_v1 (~> 0.19.0)
|
||||
google-cloud-core (~> 1.6)
|
||||
googleauth (>= 0.16.2, < 2.a)
|
||||
mini_mime (~> 1.0)
|
||||
googleauth (1.7.0)
|
||||
faraday (>= 0.17.3, < 3.a)
|
||||
jwt (>= 1.4, < 3.0)
|
||||
memoist (~> 0.16)
|
||||
multi_json (~> 1.11)
|
||||
os (>= 0.9, < 2.0)
|
||||
signet (>= 0.16, < 2.a)
|
||||
highline (2.0.3)
|
||||
http-cookie (1.0.5)
|
||||
domain_name (~> 0.5)
|
||||
httpclient (2.8.3)
|
||||
jmespath (1.6.2)
|
||||
json (2.6.3)
|
||||
jwt (2.7.1)
|
||||
memoist (0.16.2)
|
||||
mini_magick (4.12.0)
|
||||
mini_mime (1.1.5)
|
||||
multi_json (1.15.0)
|
||||
multipart-post (2.3.0)
|
||||
nanaimo (0.3.0)
|
||||
naturally (2.2.1)
|
||||
optparse (0.1.1)
|
||||
os (1.1.4)
|
||||
plist (3.7.0)
|
||||
public_suffix (5.0.3)
|
||||
rake (13.0.6)
|
||||
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.2.6)
|
||||
rouge (2.0.7)
|
||||
ruby2_keywords (0.0.5)
|
||||
rubyzip (2.3.2)
|
||||
security (0.1.3)
|
||||
signet (0.17.0)
|
||||
addressable (~> 2.8)
|
||||
faraday (>= 0.17.5, < 3.a)
|
||||
jwt (>= 1.5, < 3.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)
|
||||
trailblazer-option (0.1.2)
|
||||
tty-cursor (0.7.1)
|
||||
tty-screen (0.8.1)
|
||||
tty-spinner (0.9.3)
|
||||
tty-cursor (~> 0.7)
|
||||
uber (0.1.0)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.8.2)
|
||||
unicode-display_width (1.8.0)
|
||||
webrick (1.8.1)
|
||||
word_wrap (1.0.0)
|
||||
xcodeproj (1.22.0)
|
||||
CFPropertyList (>= 2.3.3, < 4.0)
|
||||
atomos (~> 0.1.3)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
nanaimo (~> 0.3.0)
|
||||
rexml (~> 3.2.4)
|
||||
xcpretty (0.3.0)
|
||||
rouge (~> 2.0.7)
|
||||
xcpretty-travis-formatter (1.0.1)
|
||||
xcpretty (~> 0.2, >= 0.0.7)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
fastlane
|
||||
fastlane-plugin-get_version_name
|
||||
fastlane-plugin-versioning_android
|
||||
|
||||
BUNDLED WITH
|
||||
1.17.2
|
204
apps/mobile/README.md
Normal file
@ -0,0 +1,204 @@
|
||||
# Uniswap Wallet
|
||||
|
||||
[Uniswap Wallet](https://wallet.uniswap.org/) is the simplest, safest, and most powerful self-custodial crypto wallet. It is developed by the Uniswap Labs team, inventors of the Uniswap Protocol.
|
||||
|
||||
If you have suggestions on how we can improve the app, or would like to report a bug or a problem, check out the [Uniswap Help Center](https://support.uniswap.org/).
|
||||
|
||||
## Setup
|
||||
|
||||
### Requirements
|
||||
|
||||
This guide assumes that:
|
||||
|
||||
- You are using a Mac (you will need a Mac computer in order to run the Xcode iOS Simulator)
|
||||
- You are using an Apple Silicon Mac (if you’re not sure, go to → About this Mac and check if the chip name starts with "Apple")
|
||||
|
||||
Note: if you are indeed using an Apple Silicon Mac, we recommend setting up your environment _without_ using Rosetta. Some instructions on how to do that can be found [here](https://medium.com/@davidjasonharding/developing-a-react-native-app-on-an-m1-mac-without-rosetta-29fcc7314d70).
|
||||
|
||||
### Packages and Software
|
||||
|
||||
#### Xcode
|
||||
|
||||
You should start with downloading Xcode if you don't already have it installed, since the file is so large. You can find it here: [developer.apple.com/xcode](https://developer.apple.com/xcode/)
|
||||
|
||||
You must use **XCode 15** to compile the app.
|
||||
|
||||
#### Homebrew
|
||||
|
||||
We’ll be using Homebrew to install many of the other required tools through the command line.
|
||||
|
||||
1. Open a terminal
|
||||
2. Copy and paste the command from [brew.sh](https://brew.sh/) into your terminal and run it
|
||||
|
||||
#### nvm
|
||||
|
||||
`nvm` is the Node Version Manager. While not required, it makes it easy to install Node and switch between different versions. A minimum Node version of 18 is required to use this repository.
|
||||
|
||||
Copy the curl command listed under _Install & Update Script_ on [this page](https://github.com/nvm-sh/nvm#install--update-script) and run it in your terminal.
|
||||
|
||||
To make sure nvm installed correctly, try running `nvm -v` (you may need to quit and re-open the terminal window). It should return a version number. If it returns something like `zsh: command not found: nvm`, it hasn’t been installed correctly.
|
||||
|
||||
#### node
|
||||
|
||||
Now we want to use nvm to install a specific version of node.
|
||||
|
||||
Run the following command in your terminal:
|
||||
`nvm install 18`
|
||||
|
||||
and then when it’s finished, run:
|
||||
`nvm use 18`
|
||||
|
||||
Quit and re-open the terminal, and then run:
|
||||
`node -v`
|
||||
|
||||
to make sure you get a version number that starts with `v18.`.
|
||||
|
||||
#### yarn
|
||||
|
||||
We use yarn as our package manager and to run scripts.
|
||||
|
||||
Run the following command to install it:
|
||||
`npm install --global yarn`
|
||||
(npm comes with node, so it should work if the above step has been completed correctly)
|
||||
|
||||
Then run:
|
||||
`yarn -v`
|
||||
to see if it installed correctly.
|
||||
|
||||
#### Ruby
|
||||
|
||||
Use `rbenv` to install a specific version of `ruby`:
|
||||
`brew install rbenv ruby-build`
|
||||
|
||||
Run `rbenv init` and follow the instructions to complete the installation.
|
||||
|
||||
After following the instructions, make sure you `source` your `.zshrc` or `.bash_profile`, or start a new terminal session.
|
||||
|
||||
Install a version of `ruby`:
|
||||
`rbenv install 3.2.2`
|
||||
|
||||
Set this as your default version:
|
||||
`rbenv global 3.2.2`
|
||||
|
||||
#### CocoaPods
|
||||
|
||||
Install cocoapods:
|
||||
`gem install cocoapods -v 1.13.0`
|
||||
|
||||
### Add Xcode Command Line Tools
|
||||
|
||||
Open Xcode and go to:
|
||||
|
||||
`Preferences → Locations → Command Line Tools`
|
||||
|
||||
And select the version that pops up.
|
||||
|
||||
## Development
|
||||
|
||||
Once all the setup steps above are completed, you're ready to try running the app locally!
|
||||
|
||||
### Environment variables
|
||||
|
||||
Note: The app will likely have limited functionality when running it locally with the default environment variables.
|
||||
|
||||
Use the environment variables defined in the `.env.defaults.local` file to run the app locally.
|
||||
|
||||
### Compile contract ABI types
|
||||
|
||||
This is done in bootstrap but good to know about. Before the code will compile you need to generate types for the smart contracts the wallet interacts with. Run `yarn g:prepare` at the top level. Re-run this if the ABIs are ever changed.
|
||||
|
||||
### Run the app
|
||||
|
||||
In the root directory, run `yarn` to install all the necessary npm packages.
|
||||
|
||||
Then run `yarn mobile pod` to install all the necessary pods. (You may need to updated source repos with `pod repo update` if this fails.)
|
||||
|
||||
Finally, run `yarn mobile ios` to boot up the iOS Simulator and run the app inside it. The JS bundler (metro) should automatically open in a new terminal window. If it does not, start it manually with `yarn start`.
|
||||
|
||||
Or you can use one command to run them all one after the other: `yarn && yarn pod && yarn ios`
|
||||
|
||||
You can also run the app from Xcode, which is necessary for any Swift related changes. Xcode will automatically start the metro bundler.
|
||||
|
||||
Hopefully you now (after a few minutes) see the Uniswap Wallet running in the iOS Simulator!
|
||||
|
||||
### Enabling Flipper
|
||||
|
||||
We do not check Flipper into source. To prevent `pod install` from adding Flipper, set an environment variable in your `.bash_profile` or `.zshrc` or `.zprofile`:
|
||||
|
||||
```bash
|
||||
# To enable flipper inclusion (optional)
|
||||
export USE_FLIPPER=1
|
||||
```
|
||||
|
||||
Note: To disable Flipper, the whole line should be commented out, as setting this value to 0 will not disable Flipper.
|
||||
|
||||
## Important Libraries and Tools
|
||||
|
||||
These are some tools you might want to familiarize yourself with to understand the codebase better and how different aspects of it work.
|
||||
|
||||
- [Redux](https://redux.js.org/) and [Redux Toolkit](https://redux-toolkit.js.org/): state management
|
||||
- [redux-saga](https://redux-saga.js.org/) & [typed-redux-saga](https://github.com/agiledigital/typed-redux-saga): Redux side effect manager -- used for complex/stateful network calls
|
||||
- [ethers](https://docs.ethers.io/v5/)
|
||||
- [Tamagui](https://tamagui.dev): UI framework
|
||||
- [React navigation](https://reactnavigation.org/): routing and navigation with animations and gestures
|
||||
- [react-i18next](https://react.i18next.com/): i18n
|
||||
|
||||
## Migrations
|
||||
|
||||
We use `redux-persist` to persist Redux state between user sessions. When the Redux state schema is altered, a migration may be needed to transfer the existing persisted state to the new Redux schema. Failing to define a migration results in the app defaulting to the persisted schema, which will very likely cause `undefined` errors because the code has references to Redux state properties that were dropped in favor the the persisted schema.
|
||||
|
||||
### When to define a migration
|
||||
|
||||
Anytime a required property is added or any property is renamed or deleted to/from Redux state. Migrations are not necessary when optional properties are added to an existing slice. Make sure to always add new required properties to the `schema.ts` file as well.
|
||||
|
||||
### How to migrate
|
||||
|
||||
1. Increment the `version` of `persistConfig` defined within `store.ts`
|
||||
2. Create a migration function within `migrations.ts`. The migration key should be the same as the `version` defined in the previous step
|
||||
3. Write a test for your migration within `migrations.test.ts`
|
||||
4. Create a new schema within `schema.ts` and ensure it is being exported by the `getSchema` function at the bottom of the file
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common issues
|
||||
|
||||
- `zsh: command not found: [package name]`
|
||||
This means whichever package you're trying to run (`[package name]`) wasn’t correctly installed, or your Terminal can’t figure out how to run it. If you just installed it, try quitting terminal and re-opening it. Otherwise try reinstalling the package.
|
||||
|
||||
- `unable to open file (in target "OneSignalNotificationServiceExtension" in project "Uniswap")`.
|
||||
Resolve this issue by navigating to the `ios/` directory and running `pod update`.
|
||||
|
||||
### Common fixes
|
||||
|
||||
If something isn’t working the way it should or you’re getting a weird error when trying to run the app, try the following:
|
||||
|
||||
1. Quit the terminal
|
||||
2. Quit Metro terminal
|
||||
3. Open Finder and navigate to the `mobile` directory
|
||||
4. Delete the `node_modules` folder
|
||||
5. Navigate into the `ios` folder
|
||||
6. Delete the `Pods` folder
|
||||
7. Open XCode
|
||||
8. Go to Product → Clean Build Folder
|
||||
9. Open your terminal again
|
||||
10. Navigate to the `mobile` directory in the terminal
|
||||
11. Run `yarn && yarn pod` again
|
||||
12. Run `yarn ios`
|
||||
|
||||
### Shell profile setup
|
||||
|
||||
Your shell profile file is most likely one of: `.bash_profile`, `.zshrc`, or `.zprofile`, and will be located in `/Users/[username]/`. You can reveal hidden files in Finder by pressing `⌘` + `Shift` + `.`.
|
||||
|
||||
If issues with your terminal or shell seem to be the cause of some of your problems, here is an example of what that file may look like in order for your terminal to be able to run the app locally:
|
||||
|
||||
```zsh
|
||||
eval "$(/opt/homebrew/bin/brew shellenv)"
|
||||
|
||||
export NVM_DIR="$HOME/.nvm"
|
||||
[ -s "/opt/homebrew/opt/nvm/nvm.sh" ] && \. "/opt/homebrew/opt/nvm/nvm.sh" # This loads nvm
|
||||
[ -s "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" ] && \. "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" # This loads nvm bash_completion
|
||||
|
||||
# To enable flipper inclusion (optional)
|
||||
export USE_FLIPPER=1
|
||||
export PATH="/opt/homebrew/opt/ruby/bin:$PATH"
|
||||
```
|
8
apps/mobile/__mocks__/@react-native-firebase/app.ts
Normal file
@ -0,0 +1,8 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||
export default {
|
||||
app: () => ({
|
||||
auth: () => ({
|
||||
signInAnonymously: () => undefined,
|
||||
}),
|
||||
}),
|
||||
}
|
@ -0,0 +1 @@
|
||||
export default {}
|
@ -0,0 +1 @@
|
||||
export default {}
|
@ -0,0 +1,13 @@
|
||||
import React, { PropsWithChildren, ReactNode } from 'react'
|
||||
import { View, ViewProps } from 'react-native'
|
||||
|
||||
// react-native-masked-view for Storybook web
|
||||
// https://github.com/react-native-masked-view/masked-view/issues/70#issuecomment-1171801526
|
||||
function MaskedViewWeb({
|
||||
maskElement,
|
||||
...props
|
||||
}: PropsWithChildren<{ maskElement: ReactNode }>): React.CElement<ViewProps, View> {
|
||||
return React.createElement(View, props, maskElement)
|
||||
}
|
||||
|
||||
export default MaskedViewWeb
|
22
apps/mobile/__mocks__/@shopify/react-native-skia.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import React, { PropsWithChildren } from 'react'
|
||||
import { View, ViewProps } from 'react-native'
|
||||
|
||||
// Source: https://github.com/Shopify/react-native-skia/issues/548#issuecomment-1157609472
|
||||
|
||||
const PlainView = ({
|
||||
children,
|
||||
...props
|
||||
}: PropsWithChildren<unknown>): React.CElement<ViewProps, View> => {
|
||||
return React.createElement(View, props, children)
|
||||
}
|
||||
const noop = (): null => null
|
||||
|
||||
export const BlurMask = PlainView
|
||||
export const Canvas = PlainView
|
||||
export const Circle = PlainView
|
||||
export const Group = PlainView
|
||||
export const LinearGradient = PlainView
|
||||
export const Mask = PlainView
|
||||
export const Path = PlainView
|
||||
export const Rect = PlainView
|
||||
export const vec = noop
|
11
apps/mobile/__mocks__/react-native-context-menu-view.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import React, { PropsWithChildren } from 'react'
|
||||
import { View, ViewProps } from 'react-native'
|
||||
|
||||
const PlainView = ({
|
||||
children,
|
||||
...props
|
||||
}: PropsWithChildren<unknown>): React.CElement<ViewProps, View> => {
|
||||
return React.createElement(View, props, children)
|
||||
}
|
||||
|
||||
export default PlainView
|
13
apps/mobile/__mocks__/react-native-fast-image.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import React, { PropsWithChildren } from 'react'
|
||||
import { Image, ImageProps } from 'react-native'
|
||||
|
||||
const PlainImage = ({
|
||||
children,
|
||||
...props
|
||||
}: PropsWithChildren<ImageProps>): React.CElement<ImageProps, Image> => {
|
||||
return React.createElement(Image, props, children)
|
||||
}
|
||||
|
||||
PlainImage.resizeMode = {}
|
||||
|
||||
export default PlainImage
|
1
apps/mobile/__mocks__/react-native-permissions.ts
Normal file
@ -0,0 +1 @@
|
||||
export default {}
|
4
apps/mobile/android/.env.template
Normal file
@ -0,0 +1,4 @@
|
||||
KEYSTORE_FILE=op://Android/keystore-properties-$APP_ENV/storeFile
|
||||
STORE_PASSWORD=op://Android/keystore-properties-$APP_ENV/storePassword
|
||||
KEYSTORE_ALIAS=op://Android/keystore-properties-$APP_ENV/keyAlias
|
||||
KEY_PASSWORD=op://Android/keystore-properties-$APP_ENV/keyPassword
|
4
apps/mobile/android/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# Known Issues
|
||||
|
||||
Android 14 (API level 34) features cannot be used until we upgrade to React Native 0.71.13. That means that the sdk versions cannot be upgraded to 34 until React Native is also upgraded.
|
||||
https://github.com/facebook/react-native/issues/37769
|
251
apps/mobile/android/app/build.gradle
Normal file
@ -0,0 +1,251 @@
|
||||
import com.android.build.OutputFile
|
||||
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'com.facebook.react'
|
||||
id 'com.google.gms.google-services'
|
||||
id 'maven-publish'
|
||||
id 'kotlin-android'
|
||||
}
|
||||
|
||||
def nodeModulesPath = "../../../../node_modules"
|
||||
def rnRoot = "../.."
|
||||
|
||||
|
||||
def keystorePropertiesFile = rootProject.file("keystore.properties");
|
||||
def keystoreProperties = new Properties()
|
||||
if (keystorePropertiesFile.exists()) {
|
||||
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
|
||||
}
|
||||
|
||||
react {
|
||||
root = file("$rnRoot/")
|
||||
reactNativeDir = file("$nodeModulesPath/react-native")
|
||||
codegenDir = file("$nodeModulesPath/react-native-codegen")
|
||||
cliFile = file("$nodeModulesPath/react-native/cli.js")
|
||||
debuggableVariants = ["devDebug", "betaDebug", "prodDebug"]
|
||||
hermesCommand = "../../node_modules/react-native/sdks/hermesc/%OS-BIN%/hermesc" // This is relative to the project root.
|
||||
}
|
||||
/**
|
||||
* Set this to true to create four separate APKs instead of one,
|
||||
* one for each native architecture. This is useful if you don't
|
||||
* use App Bundles (https://developer.android.com/guide/app-bundle/)
|
||||
* and want to have separate APKs to upload to the Play Store.
|
||||
*/
|
||||
def enableSeparateBuildPerCPUArchitecture = false
|
||||
|
||||
/**
|
||||
* Set this to true to Run Proguard on Release builds to minify the Java bytecode.
|
||||
*/
|
||||
def enableProguardInReleaseBuilds = false
|
||||
|
||||
/**
|
||||
* The preferred build flavor of JavaScriptCore (JSC)
|
||||
*
|
||||
* For example, to use the international variant, you can use:
|
||||
* `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
|
||||
*
|
||||
* The international variant includes ICU i18n library and necessary data
|
||||
* allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
|
||||
* give correct results when using with locales other than en-US. Note that
|
||||
* this variant is about 6MiB larger per architecture than default.
|
||||
*/
|
||||
def jscFlavor = 'org.webkit:android-jsc-intl:+'
|
||||
|
||||
/**
|
||||
* Private function to get the list of Native Architectures you want to build.
|
||||
* This reads the value from reactNativeArchitectures in your gradle.properties
|
||||
* file and works together with the --active-arch-only flag of react-native run-android.
|
||||
*/
|
||||
def reactNativeArchitectures() {
|
||||
def value = project.getProperties().get("reactNativeArchitectures")
|
||||
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
|
||||
}
|
||||
|
||||
boolean isCI = System.getenv('CI') != null
|
||||
boolean sentryPropertiesAvailable = System.getenv('SENTRY_AUTH_TOKEN') != null && System.getenv('SENTRY_PROJECT') != null && System.getenv('SENTRY_ORG') != null
|
||||
|
||||
if (isCI && sentryPropertiesAvailable) {
|
||||
project.ext.sentryCli = [
|
||||
logLevel: "info",
|
||||
]
|
||||
|
||||
apply from: "../../../../node_modules/@sentry/react-native/sentry.gradle"
|
||||
apply plugin: "io.sentry.android.gradle"
|
||||
|
||||
sentry {
|
||||
uploadNativeSymbols = true
|
||||
includeNativeSources = true
|
||||
|
||||
autoInstallation {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
ndkVersion rootProject.ext.ndkVersion
|
||||
|
||||
namespace "com.uniswap"
|
||||
defaultConfig {
|
||||
applicationId "com.uniswap.mobile"
|
||||
compileSdk rootProject.ext.compileSdkVersion
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
multiDexEnabled true
|
||||
}
|
||||
splits {
|
||||
abi {
|
||||
reset()
|
||||
enable enableSeparateBuildPerCPUArchitecture
|
||||
universalApk false // If true, also generate a universal APK
|
||||
include (*reactNativeArchitectures())
|
||||
}
|
||||
}
|
||||
signingConfigs {
|
||||
debug {
|
||||
storeFile file('debug.keystore')
|
||||
storePassword 'android'
|
||||
keyAlias 'androiddebugkey'
|
||||
keyPassword 'android'
|
||||
}
|
||||
release {
|
||||
storeFile file(System.getenv("ANDROID_KEYSTORE_FILE") ?: 'keystore.jks')
|
||||
storePassword System.getenv("ANDROID_STORE_PASSWORD") ?: keystoreProperties.getProperty("STORE_PASSWORD")
|
||||
keyAlias System.getenv("ANDROID_KEYSTORE_ALIAS") ?: keystoreProperties.getProperty("KEYSTORE_ALIAS")
|
||||
keyPassword System.getenv("ANDROID_KEY_PASSWORD") ?: keystoreProperties.getProperty("KEY_PASSWORD")
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions += "variant"
|
||||
|
||||
productFlavors {
|
||||
dev {
|
||||
isDefault(true)
|
||||
applicationIdSuffix ".dev"
|
||||
versionName "1.18"
|
||||
dimension "variant"
|
||||
}
|
||||
beta {
|
||||
applicationIdSuffix ".beta"
|
||||
versionName "1.18"
|
||||
dimension "variant"
|
||||
}
|
||||
prod {
|
||||
dimension "variant"
|
||||
versionName "1.18"
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
signingConfig signingConfigs.debug
|
||||
}
|
||||
release {
|
||||
signingConfig signingConfigs.release
|
||||
minifyEnabled enableProguardInReleaseBuilds
|
||||
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
||||
}
|
||||
}
|
||||
|
||||
// applicationVariants are e.g. debug, release
|
||||
applicationVariants.all { variant ->
|
||||
variant.outputs.each { output ->
|
||||
// For each separate APK per architecture, set a unique version code as described here:
|
||||
// https://developer.android.com/studio/build/configure-apk-splits.html
|
||||
// Example: versionCode 1 will generate 1001 for armeabi-v7a, 1002 for x86, etc.
|
||||
def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
|
||||
def abi = output.getFilter(OutputFile.ABI)
|
||||
if (abi != null) { // null for the universal-debug, universal-release variants
|
||||
output.versionCodeOverride =
|
||||
defaultConfig.versionCode * 1000 + versionCodes.get(abi)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
resources.excludes.add("META-INF/*")
|
||||
}
|
||||
buildFeatures {
|
||||
compose true
|
||||
}
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion = "1.4.6"
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
jniLibs {
|
||||
srcDir '../../../../node_modules/@uniswap/ethers-rs-mobile/android/jniLibs'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// The version of react-native is set by the React Native Gradle Plugin
|
||||
implementation "com.facebook.react:react-android"
|
||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
|
||||
|
||||
// Used to deal with Flipper/OkHttp issues with DevSupportManager
|
||||
implementation "androidx.multidex:multidex:$multidexVersion"
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinSerialization"
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle"
|
||||
|
||||
implementation 'com.google.android.play:integrity:1.2.0'
|
||||
|
||||
// Guava
|
||||
implementation "com.google.guava:guava:24.1-jre"
|
||||
// Guava fix
|
||||
implementation "com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava"
|
||||
|
||||
//TODO: Revisit dependencies during security audit
|
||||
//Drive
|
||||
implementation('com.google.api-client:google-api-client-android:2.1.0') {
|
||||
exclude group: 'org.apache.httpcomponents'
|
||||
exclude module: 'guava-jdk5'
|
||||
}
|
||||
implementation('com.google.apis:google-api-services-drive:v3-rev20221023-2.0.0') {
|
||||
exclude group: 'org.apache.httpcomponents'
|
||||
exclude module: 'guava-jdk5'
|
||||
}
|
||||
implementation 'com.google.android.gms:play-services-auth:20.4.0'
|
||||
|
||||
implementation 'com.google.api-client:google-api-client-jackson2:1.31.1'
|
||||
implementation 'com.google.auth:google-auth-library-oauth2-http:1.11.0'
|
||||
|
||||
implementation "androidx.compose.foundation:foundation:$compose"
|
||||
implementation "androidx.compose.material:material:$compose"
|
||||
implementation "androidx.compose.ui:ui:$compose"
|
||||
|
||||
implementation "androidx.security:security-crypto:1.0.0"
|
||||
implementation 'com.lambdapioneer.argon2kt:argon2kt:1.3.0'
|
||||
|
||||
implementation "com.google.accompanist:accompanist-flowlayout:$flowlayout"
|
||||
|
||||
implementation project(':@sentry_react-native')
|
||||
// Used for device-reported performance class.
|
||||
implementation("androidx.core:core-performance:$corePerf")
|
||||
implementation("androidx.core:core-performance-play-services:$corePerf")
|
||||
|
||||
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
|
||||
exclude group:'com.facebook.fbjni'
|
||||
}
|
||||
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
|
||||
exclude group:'com.squareup.okhttp3', module:'okhttp'
|
||||
}
|
||||
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}")
|
||||
|
||||
if (hermesEnabled.toBoolean()) {
|
||||
implementation("com.facebook.react:hermes-android")
|
||||
} else {
|
||||
implementation jscFlavor
|
||||
}
|
||||
}
|
||||
|
||||
apply from: file("${nodeModulesPath}/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
|
BIN
apps/mobile/android/app/debug.keystore
Normal file
10
apps/mobile/android/app/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
29
apps/mobile/android/app/src/beta/AndroidManifest.xml
Normal file
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
|
||||
<application
|
||||
android:usesCleartextTraffic="true"
|
||||
tools:ignore="GoogleAppIndexingWarning"
|
||||
tools:targetApi="28">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true">
|
||||
<intent-filter android:autoVerify="true" android:priority="1">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data android:scheme="https" />
|
||||
<data android:host="uniswap.org" />
|
||||
<data android:host="app.uniswap.org" />
|
||||
<data android:host="uniswap.com" />
|
||||
<data android:host="app.uniswap.com" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
</manifest>
|
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@mipmap/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
BIN
apps/mobile/android/app/src/beta/res/mipmap-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 852 B |
After Width: | Height: | Size: 16 KiB |
BIN
apps/mobile/android/app/src/beta/res/mipmap-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 8.0 KiB |
After Width: | Height: | Size: 459 B |
After Width: | Height: | Size: 8.0 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 84 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 84 KiB |
4
apps/mobile/android/app/src/beta/res/values/strings.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<resources>
|
||||
<string name="app_name">Uniswap Beta</string>
|
||||
</resources>
|
13
apps/mobile/android/app/src/debug/AndroidManifest.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||
|
||||
<application
|
||||
android:usesCleartextTraffic="true"
|
||||
tools:targetApi="28"
|
||||
tools:ignore="GoogleAppIndexingWarning">
|
||||
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
|
||||
</application>
|
||||
</manifest>
|
@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
|
||||
* directory of this source tree.
|
||||
*/
|
||||
package com.uniswap;
|
||||
|
||||
import android.content.Context;
|
||||
import com.facebook.flipper.android.AndroidFlipperClient;
|
||||
import com.facebook.flipper.android.utils.FlipperUtils;
|
||||
import com.facebook.flipper.core.FlipperClient;
|
||||
import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;
|
||||
import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
|
||||
import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;
|
||||
import com.facebook.flipper.plugins.inspector.DescriptorMapping;
|
||||
import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
|
||||
import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
|
||||
import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
|
||||
import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
|
||||
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
|
||||
import com.facebook.react.ReactInstanceManager;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.modules.network.NetworkingModule;
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
public class ReactNativeFlipper {
|
||||
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
|
||||
if (FlipperUtils.shouldEnableFlipper(context)) {
|
||||
final FlipperClient client = AndroidFlipperClient.getInstance(context);
|
||||
|
||||
client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
|
||||
client.addPlugin(new DatabasesFlipperPlugin(context));
|
||||
client.addPlugin(new SharedPreferencesFlipperPlugin(context));
|
||||
client.addPlugin(CrashReporterPlugin.getInstance());
|
||||
|
||||
NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
|
||||
NetworkingModule.setCustomClientBuilder(
|
||||
new NetworkingModule.CustomClientBuilder() {
|
||||
@Override
|
||||
public void apply(OkHttpClient.Builder builder) {
|
||||
builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
|
||||
}
|
||||
});
|
||||
client.addPlugin(networkFlipperPlugin);
|
||||
client.start();
|
||||
|
||||
// Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
|
||||
// Hence we run if after all native modules have been initialized
|
||||
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
|
||||
if (reactContext == null) {
|
||||
reactInstanceManager.addReactInstanceEventListener(
|
||||
new ReactInstanceManager.ReactInstanceEventListener() {
|
||||
@Override
|
||||
public void onReactContextInitialized(ReactContext reactContext) {
|
||||
reactInstanceManager.removeReactInstanceEventListener(this);
|
||||
reactContext.runOnNativeModulesQueueThread(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
client.addPlugin(new FrescoFlipperPlugin());
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
client.addPlugin(new FrescoFlipperPlugin());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
27
apps/mobile/android/app/src/dev/AndroidManifest.xml
Normal file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<application
|
||||
android:usesCleartextTraffic="true"
|
||||
tools:ignore="GoogleAppIndexingWarning"
|
||||
tools:targetApi="28">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true">
|
||||
<intent-filter android:autoVerify="true" android:priority="2">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data android:scheme="https" />
|
||||
<data android:host="uniswap.org" />
|
||||
<data android:host="app.uniswap.org" />
|
||||
<data android:host="uniswap.com" />
|
||||
<data android:host="app.uniswap.com" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
</manifest>
|
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@mipmap/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
BIN
apps/mobile/android/app/src/dev/res/mipmap-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 858 B |
After Width: | Height: | Size: 18 KiB |
BIN
apps/mobile/android/app/src/dev/res/mipmap-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 9.3 KiB |
After Width: | Height: | Size: 464 B |
After Width: | Height: | Size: 9.3 KiB |
BIN
apps/mobile/android/app/src/dev/res/mipmap-xhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 28 KiB |