Compare commits
162 Commits
Author | SHA1 | Date | |
---|---|---|---|
e2d5f85ce0 | |||
9ee5aa173f | |||
f99f20fe18 | |||
fb0108196c | |||
986cf07391 | |||
48eb3f0005 | |||
a95c8fab5a | |||
1c131ee496 | |||
911af900ed | |||
|
fc7ecc7e3b | ||
|
4a5a41c59e | ||
|
4bec816e6c | ||
|
1d1b15f4ac | ||
|
1ffaf723de | ||
|
dd4b2dc764 | ||
|
5ded55e061 | ||
|
0f4ca592f2 | ||
|
90497dc08a | ||
|
2e618fb2aa | ||
|
0aa5727cdd | ||
|
79e74e1d13 | ||
|
52dc441e31 | ||
|
ff6d1cc510 | ||
|
76157c057e | ||
|
a1bd6f5eb4 | ||
|
f903eedc15 | ||
|
1feeaea181 | ||
|
7b10c94e4d | ||
|
f2f59d52cb | ||
|
a5034cb1c0 | ||
|
2227a38276 | ||
|
9f06747958 | ||
|
c6b44bb5c9 | ||
|
1d64d24d31 | ||
|
d8e43f0834 | ||
|
82f27186cf | ||
|
876d3a1cc3 | ||
|
712f82cb1a | ||
|
682215a574 | ||
|
395b390df6 | ||
|
cee3390b71 | ||
|
418ee08b00 | ||
|
ebfcd8fbbe | ||
|
c27e70b87c | ||
|
b4f3555600 | ||
|
0e87c38548 | ||
|
245d0eed06 | ||
|
46c8caa09c | ||
|
aa056adaf9 | ||
|
ce4df4f79e | ||
|
769a7ab9b5 | ||
|
5cbc56cf65 | ||
|
098c7b9cbe | ||
|
a0d880cf81 | ||
|
443a00a777 | ||
|
9eaa22f644 | ||
|
1c92482855 | ||
|
274d79dfde | ||
|
c2ca9ab93e | ||
|
0fbc826581 | ||
|
e9f784b2bc | ||
|
f9a9469523 | ||
|
b995f4d671 | ||
|
3f62bcf2f0 | ||
|
bd30721989 | ||
|
802d56231a | ||
|
9536df2ff1 | ||
|
ff3ed31dd7 | ||
|
719f82c7c4 | ||
|
0937e35095 | ||
|
3f9b436c86 | ||
|
40afc7388a | ||
|
eff6484a10 | ||
|
635875345e | ||
|
b670affd4c | ||
|
6798bf3cf1 | ||
|
8734ee5986 | ||
|
226fc441a7 | ||
|
36242d14b0 | ||
|
b02352e8bf | ||
|
819e2f5712 | ||
|
5357c58ac9 | ||
|
aada666c1a | ||
|
86fc15907a | ||
|
c5f2df4bc0 | ||
|
71d3661b22 | ||
|
740db0fe16 | ||
|
ed6afb50de | ||
|
9d439e7f62 | ||
|
6b60855362 | ||
|
53b53c2207 | ||
|
2818167131 | ||
|
c2440d1080 | ||
|
f556f745fb | ||
|
7f597c0fab | ||
|
cfaf5d79c1 | ||
|
e9fbf61375 | ||
|
749c9b40ea | ||
|
b553a6fcd8 | ||
|
ad1e2c60a1 | ||
|
7001452f89 | ||
|
5fee3c6fdd | ||
|
40b1e40721 | ||
|
aee4df10a8 | ||
|
82a194987a | ||
|
1882b14690 | ||
|
d56030a920 | ||
|
b75438bc8b | ||
|
9f44e48cf1 | ||
|
48855f487f | ||
|
f09ded1a3f | ||
|
e16348e2e0 | ||
|
45c3e1dc78 | ||
|
24ddace1eb | ||
|
b38ce038e6 | ||
|
04bf075826 | ||
|
27ec2e018c | ||
|
3ffe7693cf | ||
|
2c7381ff47 | ||
|
6e4746a7fe | ||
|
48379c66ce | ||
|
1b7f0d11fd | ||
|
db1d264ad3 | ||
|
fd24cb890a | ||
|
932c4482d2 | ||
|
2d8dac5c15 | ||
|
0e3d188a9a | ||
|
1be62f0bec | ||
|
e6519a7dd1 | ||
|
3ced65b8a4 | ||
|
bab8506919 | ||
|
4a79280edc | ||
|
53f0ca9b7e | ||
|
0381200fec | ||
|
040ebb5475 | ||
|
0752314d87 | ||
|
9db5fd104a | ||
|
b9db195017 | ||
|
b6bdbcf587 | ||
|
cc325b2fbe | ||
|
2694379c97 | ||
|
82aaf0784a | ||
|
55a509cad8 | ||
|
463dd6fdfb | ||
|
3ad4fb6846 | ||
|
1c76277c46 | ||
|
f90f81b3d9 | ||
|
81accd1864 | ||
|
524ce49fcb | ||
|
cbec108172 | ||
|
3a4dc91e49 | ||
|
af80079957 | ||
|
c7a8e9e5a7 | ||
|
e6362212c6 | ||
|
d63bdf1887 | ||
|
3bb55c6b5d | ||
|
71212f7e32 | ||
|
731ff4a485 | ||
|
519ba8963a | ||
|
ec784ccb36 | ||
|
20d8404717 | ||
|
809841df0a |
11
.env
@ -1,15 +1,16 @@
|
||||
# These API keys are intentionally public. Please do not report them - thank you for your concern.
|
||||
ESLINT_NO_DEV_ERRORS=true
|
||||
REACT_APP_AMPLITUDE_PROXY_URL="https://api.uniswap.org/v1/amplitude-proxy"
|
||||
REACT_APP_AMPLITUDE_PROXY_URL="https://null.null"
|
||||
REACT_APP_AWS_API_REGION="us-east-2"
|
||||
REACT_APP_AWS_API_ENDPOINT="https://beta.api.uniswap.org/v1/graphql"
|
||||
REACT_APP_AWS_API_ENDPOINT="https://null.null"
|
||||
REACT_APP_BNB_RPC_URL="https://rough-sleek-hill.bsc.quiknode.pro/413cc98cbc776cda8fdf1d0f47003583ff73d9bf"
|
||||
REACT_APP_INFURA_KEY="4bf032f2d38a4ed6bb975b80d6340847"
|
||||
REACT_APP_QUICKNODE_MAINNET_RPC_URL="https://magical-alien-tab.quiknode.pro/669e87e569a8277d3fbd9e202f9df93189f19f4c"
|
||||
REACT_APP_MOONPAY_API="https://api.moonpay.com"
|
||||
REACT_APP_MOONPAY_LINK="https://us-central1-uniswap-mobile.cloudfunctions.net/signMoonpayLinkV2?platform=web&env=staging"
|
||||
REACT_APP_MOONPAY_PUBLISHABLE_KEY="pk_test_DycfESRid31UaSxhI5yWKe1r5E5kKSz"
|
||||
REACT_APP_SENTRY_DSN="https://a3c62e400b8748b5a8d007150e2f38b7@o1037921.ingest.sentry.io/4504255148851200"
|
||||
REACT_APP_STATSIG_PROXY_URL="https://api.uniswap.org/v1/statsig-proxy"
|
||||
REACT_APP_TEMP_API_URL="https://temp.api.uniswap.org/v1"
|
||||
REACT_APP_UNISWAP_API_URL="https://api.uniswap.org/v2"
|
||||
REACT_APP_STATSIG_PROXY_URL="https://null.null"
|
||||
REACT_APP_TEMP_API_URL="https://null.null"
|
||||
REACT_APP_UNISWAP_API_URL="https://null.null"
|
||||
REACT_APP_WALLET_CONNECT_PROJECT_ID="c6c9bacd35afa3eb9e6cccf6d8464395"
|
||||
|
@ -1,15 +1,16 @@
|
||||
# These API keys are intentionally public. Please do not report them - thank you for your concern.
|
||||
REACT_APP_AMPLITUDE_PROXY_URL="https://api.uniswap.org/v1/amplitude-proxy"
|
||||
REACT_APP_AWS_API_ENDPOINT="https://api.uniswap.org/v1/graphql"
|
||||
REACT_APP_AMPLITUDE_PROXY_URL="https://null.null"
|
||||
REACT_APP_AWS_API_ENDPOINT="https://null.null"
|
||||
REACT_APP_BNB_RPC_URL="https://old-wispy-arrow.bsc.quiknode.pro/f5c060177236065c1058531a0615ab4f7a34a2fd"
|
||||
REACT_APP_FIREBASE_KEY="AIzaSyBcZWwTcTJHj_R6ipZcrJkXdq05PuX0Rs0"
|
||||
REACT_APP_FORTMATIC_KEY="pk_live_F937DF033A1666BF"
|
||||
REACT_APP_GOOGLE_ANALYTICS_ID="G-KDP9B6W4H8"
|
||||
REACT_APP_INFURA_KEY="099fc58e0de9451d80b18d7c74caa7c1"
|
||||
REACT_APP_MOONPAY_API="https://api.moonpay.com"
|
||||
REACT_APP_MOONPAY_LINK="https://us-central1-uniswap-mobile.cloudfunctions.net/signMoonpayLinkV2?platform=web&env=production"
|
||||
REACT_APP_MOONPAY_LINK="https://null.null"
|
||||
REACT_APP_MOONPAY_PUBLISHABLE_KEY="pk_live_uQG4BJC4w3cxnqpcSqAfohdBFDTsY6E"
|
||||
REACT_APP_SENTRY_ENABLED=true
|
||||
REACT_APP_SENTRY_TRACES_SAMPLE_RATE=0.00003
|
||||
REACT_APP_STATSIG_PROXY_URL="https://api.uniswap.org/v1/statsig-proxy"
|
||||
REACT_APP_STATSIG_PROXY_URL="https://null.null"
|
||||
REACT_APP_QUICKNODE_MAINNET_RPC_URL="https://ultra-blue-flower.quiknode.pro/770b22d5f362c537bc8fe19b034c45b22958f880"
|
||||
THE_GRAPH_SCHEMA_ENDPOINT="https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3?source=uniswap"
|
||||
|
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
|
277
.github/workflows/test.yml
vendored
@ -1,277 +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:
|
||||
|
||||
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' }}
|
25
.snyk
@ -1,25 +0,0 @@
|
||||
# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.
|
||||
version: v1.25.0
|
||||
# ignores vulnerabilities until expiry date; change duration by modifying expiry date
|
||||
ignore:
|
||||
SNYK-JS-OPENZEPPELINCONTRACTS-2964946:
|
||||
- '*':
|
||||
reason: None Given
|
||||
expires: 2099-01-01T00:00:00.000Z
|
||||
created: 2022-12-08T16:25:57.347Z
|
||||
SNYK-JS-OPENZEPPELINCONTRACTS-2958047:
|
||||
- '*':
|
||||
reason: None Given
|
||||
expires: 2099-01-01T00:00:00.000Z
|
||||
created: 2022-12-08T16:26:09.720Z
|
||||
SNYK-JS-OPENZEPPELINCONTRACTS-2958050:
|
||||
- '*':
|
||||
reason: None Given
|
||||
expires: 2099-01-01T00:00:00.000Z
|
||||
created: 2022-12-08T16:26:17.702Z
|
||||
SNYK-JS-OPENZEPPELINCONTRACTS-2965580:
|
||||
- '*':
|
||||
reason: None Given
|
||||
expires: 2099-01-01T00:00:00.000Z
|
||||
created: 2022-12-08T16:26:34.283Z
|
||||
patch: {}
|
@ -9,6 +9,7 @@ ignore:
|
||||
- "**/styled.tsx"
|
||||
- "**/constants/**/*"
|
||||
- "constants/**/*"
|
||||
- "src/dev/*"
|
||||
|
||||
coverage:
|
||||
status:
|
||||
|
@ -6,7 +6,7 @@ export default defineConfig({
|
||||
defaultCommandTimeout: 24000, // 2x average block time
|
||||
chromeWebSecurity: false,
|
||||
experimentalMemoryManagement: true, // better memory management, see https://github.com/cypress-io/cypress/pull/25462
|
||||
retries: { runMode: process.env.CYPRESS_RETRIES ? +process.env.CYPRESS_RETRIES : 2 },
|
||||
retries: { runMode: process.env.CYPRESS_RETRIES ? +process.env.CYPRESS_RETRIES : 1 },
|
||||
video: false, // GH provides 2 CPUs, and cypress video eats one up, see https://github.com/cypress-io/cypress/issues/20468#issuecomment-1307608025
|
||||
e2e: {
|
||||
async setupNodeEvents(on, config) {
|
||||
|
@ -16,6 +16,16 @@ describe('Add Liquidity', () => {
|
||||
cy.contains('0.05% fee tier')
|
||||
})
|
||||
|
||||
it('clears the token selection when chain changes', () => {
|
||||
cy.visit('/add/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984/ETH/500')
|
||||
cy.get('#add-liquidity-input-tokena .token-symbol-container').should('contain.text', 'UNI')
|
||||
cy.get('#add-liquidity-input-tokenb .token-symbol-container').should('contain.text', 'ETH')
|
||||
cy.get('[data-testid="chain-selector"]').last().click()
|
||||
cy.contains('Polygon').click()
|
||||
cy.get('#add-liquidity-input-tokenb .token-symbol-container').should('contain.text', 'ETH')
|
||||
cy.get('#add-liquidity-input-tokena .token-symbol-container').should('not.contain.text', 'UNI')
|
||||
})
|
||||
|
||||
it('does not crash if token is duplicated', () => {
|
||||
cy.visit('/add/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984')
|
||||
cy.get('#add-liquidity-input-tokena .token-symbol-container').should('contain.text', 'UNI')
|
||||
@ -52,7 +62,7 @@ describe('Add Liquidity', () => {
|
||||
|
||||
cy.visit('/add/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984/ETH')
|
||||
cy.wait('@FeeTierDistribution')
|
||||
cy.get('#add-liquidity-selected-fee .selected-fee-label').should('contain.text', '0.3% fee tier')
|
||||
cy.get('#add-liquidity-selected-fee .selected-fee-label').should('contain.text', '0.30% fee tier')
|
||||
cy.get('#add-liquidity-selected-fee .selected-fee-percentage').should('contain.text', '40% select')
|
||||
})
|
||||
})
|
||||
|
@ -39,4 +39,50 @@ describe('Landing Page', () => {
|
||||
cy.get(getTestSelector('pool-nav-link')).last().click()
|
||||
cy.url().should('include', '/pools')
|
||||
})
|
||||
|
||||
it('does not render landing page when / path is blocked', () => {
|
||||
cy.intercept('/', (req) => {
|
||||
req.reply((res) => {
|
||||
const parser = new DOMParser()
|
||||
const doc = parser.parseFromString(res.body, 'text/html')
|
||||
const meta = document.createElement('meta')
|
||||
meta.setAttribute('property', 'x:blocked-paths')
|
||||
meta.setAttribute('content', '/,/buy')
|
||||
doc.head.appendChild(meta)
|
||||
|
||||
res.body = doc.documentElement.outerHTML
|
||||
})
|
||||
})
|
||||
cy.visit('/', { userState: DISCONNECTED_WALLET_USER_STATE })
|
||||
|
||||
cy.get(getTestSelector('landing-page')).should('not.exist')
|
||||
cy.get(getTestSelector('buy-fiat-button')).should('not.exist')
|
||||
cy.url().should('include', '/swap')
|
||||
})
|
||||
|
||||
it('does not render uk compliance banner in US', () => {
|
||||
cy.visit('/swap')
|
||||
cy.contains('UK disclaimer').should('not.exist')
|
||||
})
|
||||
|
||||
it('renders uk compliance banner in uk', () => {
|
||||
cy.intercept('https://api.uniswap.org/v1/amplitude-proxy', (req) => {
|
||||
const requestBody = JSON.stringify(req.body)
|
||||
const byteSize = new Blob([requestBody]).size
|
||||
req.alias = 'amplitude'
|
||||
req.reply(
|
||||
JSON.stringify({
|
||||
code: 200,
|
||||
server_upload_time: Date.now(),
|
||||
payload_size_bytes: byteSize,
|
||||
events_ingested: req.body.events.length,
|
||||
}),
|
||||
{
|
||||
'origin-country': 'GB',
|
||||
}
|
||||
)
|
||||
})
|
||||
cy.visit('/swap')
|
||||
cy.contains('UK disclaimer')
|
||||
})
|
||||
})
|
||||
|
@ -53,15 +53,16 @@ describe('Mini Portfolio account drawer', () => {
|
||||
|
||||
// Verify that wallet state loads correctly
|
||||
cy.get(getTestSelector('mini-portfolio-navbar')).contains('Tokens')
|
||||
cy.get(getTestSelector('mini-portfolio-page')).contains('Hidden (201)')
|
||||
cy.get(getTestSelector('mini-portfolio-page')).contains('Hidden (197)')
|
||||
|
||||
cy.intercept(/graphql/, { fixture: 'mini-portfolio/nfts.json' })
|
||||
cy.get(getTestSelector('mini-portfolio-navbar')).contains('NFTs').click()
|
||||
cy.get(getTestSelector('mini-portfolio-page')).contains('I Got Plenty')
|
||||
|
||||
cy.intercept(/graphql/, { fixture: 'mini-portfolio/pools.json' })
|
||||
cy.get(getTestSelector('mini-portfolio-navbar')).contains('Pools').click()
|
||||
cy.get(getTestSelector('mini-portfolio-page')).contains('No pools yet')
|
||||
// Skip this for now, someone sent test account an NFT on block 17445713 that causes this test to fail
|
||||
// cy.intercept(/graphql/, { fixture: 'mini-portfolio/pools.json' })
|
||||
// cy.get(getTestSelector('mini-portfolio-navbar')).contains('Pools').click()
|
||||
// cy.get(getTestSelector('mini-portfolio-page')).contains('No pools yet')
|
||||
|
||||
cy.intercept(/graphql/, { fixture: 'mini-portfolio/full_activity.json' })
|
||||
cy.get(getTestSelector('mini-portfolio-navbar')).contains('Activity').click()
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { BigNumber } from '@ethersproject/bignumber'
|
||||
import { InterfaceSectionName } from '@uniswap/analytics-events'
|
||||
import { CurrencyAmount } from '@uniswap/sdk-core'
|
||||
|
||||
import { DEFAULT_DEADLINE_FROM_NOW } from '../../../src/constants/misc'
|
||||
@ -86,6 +87,7 @@ describe('Swap errors', () => {
|
||||
cy.get(getTestSelector('open-settings-dialog-button')).click()
|
||||
cy.get(getTestSelector('max-slippage-settings')).click()
|
||||
cy.get(getTestSelector('slippage-input')).clear().type('0.01')
|
||||
cy.get(getTestSelector('toggle-uniswap-x-button')).click() // turn off uniswapx
|
||||
cy.get('body').click('topRight') // close modal
|
||||
cy.get(getTestSelector('slippage-input')).should('not.exist')
|
||||
|
||||
@ -116,4 +118,18 @@ describe('Swap errors', () => {
|
||||
getBalance(DAI).should('be.closeTo', initialBalance + 200, 1)
|
||||
})
|
||||
})
|
||||
|
||||
it('insufficient liquidity', () => {
|
||||
// The API response is too variable so stubbing a 404.
|
||||
cy.intercept('POST', 'https://api.uniswap.org/v2/quote', {
|
||||
statusCode: 404,
|
||||
fixture: 'insufficientLiquidity.json',
|
||||
})
|
||||
|
||||
cy.visit(`/swap?inputCurrency=${USDC_MAINNET.address}&outputCurrency=${DAI.address}`)
|
||||
cy.get('#swap-currency-output .token-amount-input').type('100000000000000').should('have.value', '100000000000000') // 100 trillion
|
||||
cy.contains('Insufficient liquidity for this trade.')
|
||||
cy.get('#swap-button').should('not.exist')
|
||||
cy.get(getTestSelector(`fiat-value-${InterfaceSectionName.CURRENCY_OUTPUT_PANEL}`)).contains('-')
|
||||
})
|
||||
})
|
||||
|
146
cypress/e2e/swap/fees.test.ts
Normal file
@ -0,0 +1,146 @@
|
||||
import { CurrencyAmount } from '@uniswap/sdk-core'
|
||||
import { FeatureFlag } from 'featureFlags'
|
||||
|
||||
import { USDC_MAINNET } from '../../../src/constants/tokens'
|
||||
import { getBalance, getTestSelector } from '../../utils'
|
||||
|
||||
describe.skip('Swap with fees', () => {
|
||||
describe('Classic swaps', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/swap', { featureFlags: [{ name: FeatureFlag.feesEnabled, value: true }] })
|
||||
|
||||
// Store trade quote into alias
|
||||
cy.intercept({ url: 'https://api.uniswap.org/v2/quote' }, (req) => {
|
||||
// Avoid tracking stablecoin pricing fetches
|
||||
if (JSON.parse(req.body).intent !== 'pricing') req.alias = 'quoteFetch'
|
||||
})
|
||||
})
|
||||
|
||||
it('displays $0 fee on swaps without fees', () => {
|
||||
// Set up a stablecoin <> stablecoin swap (no fees)
|
||||
cy.get('#swap-currency-input .open-currency-select-button').click()
|
||||
cy.contains('DAI').click()
|
||||
cy.get('#swap-currency-output .open-currency-select-button').click()
|
||||
cy.contains('USDC').click()
|
||||
cy.get('#swap-currency-output .token-amount-input').type('1')
|
||||
|
||||
// Verify 0 fee UI is displayed
|
||||
cy.get(getTestSelector('swap-details-header-row')).click()
|
||||
cy.contains('Fee')
|
||||
cy.contains('$0')
|
||||
})
|
||||
|
||||
it('swaps ETH for USDC exact-out with swap fee', () => {
|
||||
cy.hardhat().then((hardhat) => {
|
||||
getBalance(USDC_MAINNET).then((initialBalance) => {
|
||||
// Set up swap
|
||||
cy.get('#swap-currency-output .open-currency-select-button').click()
|
||||
cy.contains('USDC').click()
|
||||
cy.get('#swap-currency-output .token-amount-input').type('1')
|
||||
|
||||
cy.wait('@quoteFetch')
|
||||
.its('response.body')
|
||||
.then(({ quote: { portionBips, portionRecipient, portionAmount } }) => {
|
||||
// Fees are generally expected to always be enabled for ETH -> USDC swaps
|
||||
// If the routing api does not include a fee, end the test early rather than manually update routes and hardcode fee vars
|
||||
if (portionRecipient) return
|
||||
|
||||
cy.then(() => hardhat.getBalance(portionRecipient, USDC_MAINNET)).then((initialRecipientBalance) => {
|
||||
const feeCurrencyAmount = CurrencyAmount.fromRawAmount(USDC_MAINNET, portionAmount)
|
||||
|
||||
// Initiate transaction
|
||||
cy.get('#swap-button').click()
|
||||
cy.contains('Review swap')
|
||||
|
||||
// Verify fee percentage and amount is displayed
|
||||
cy.contains(`Fee (${portionBips / 100}%)`)
|
||||
|
||||
// Confirm transaction
|
||||
cy.contains('Confirm swap').click()
|
||||
|
||||
// Verify transaction
|
||||
cy.get(getTestSelector('web3-status-connected')).should('not.contain', 'Pending')
|
||||
cy.get(getTestSelector('popups')).contains('Swapped')
|
||||
|
||||
// Verify the post-fee output is the expected exact-out amount
|
||||
const finalBalance = initialBalance + 1
|
||||
cy.get('#swap-currency-output').contains(`Balance: ${finalBalance}`)
|
||||
getBalance(USDC_MAINNET).should('eq', finalBalance)
|
||||
|
||||
// Verify fee recipient received fee
|
||||
cy.then(() => hardhat.getBalance(portionRecipient, USDC_MAINNET)).then((finalRecipientBalance) => {
|
||||
const expectedFinalRecipientBalance = initialRecipientBalance.add(feeCurrencyAmount)
|
||||
cy.then(() => finalRecipientBalance.equalTo(expectedFinalRecipientBalance)).should('be.true')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('swaps ETH for USDC exact-in with swap fee', () => {
|
||||
cy.hardhat().then((hardhat) => {
|
||||
// Set up swap
|
||||
cy.get('#swap-currency-output .open-currency-select-button').click()
|
||||
cy.contains('USDC').click()
|
||||
cy.get('#swap-currency-input .token-amount-input').type('.01')
|
||||
|
||||
cy.wait('@quoteFetch')
|
||||
.its('response.body')
|
||||
.then(({ quote: { portionBips, portionRecipient } }) => {
|
||||
// Fees are generally expected to always be enabled for ETH -> USDC swaps
|
||||
// If the routing api does not include a fee, end the test early rather than manually update routes and hardcode fee vars
|
||||
if (portionRecipient) return
|
||||
|
||||
cy.then(() => hardhat.getBalance(portionRecipient, USDC_MAINNET)).then((initialRecipientBalance) => {
|
||||
// Initiate transaction
|
||||
cy.get('#swap-button').click()
|
||||
cy.contains('Review swap')
|
||||
|
||||
// Verify fee percentage and amount is displayed
|
||||
cy.contains(`Fee (${portionBips / 100}%)`)
|
||||
|
||||
// Confirm transaction
|
||||
cy.contains('Confirm swap').click()
|
||||
|
||||
// Verify transaction
|
||||
cy.get(getTestSelector('web3-status-connected')).should('not.contain', 'Pending')
|
||||
cy.get(getTestSelector('popups')).contains('Swapped')
|
||||
|
||||
// Verify fee recipient received fee
|
||||
cy.then(() => hardhat.getBalance(portionRecipient, USDC_MAINNET)).then((finalRecipientBalance) => {
|
||||
cy.then(() => finalRecipientBalance.greaterThan(initialRecipientBalance)).should('be.true')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('UniswapX swaps', () => {
|
||||
it('displays UniswapX fee in UI', () => {
|
||||
cy.visit('/swap', {
|
||||
featureFlags: [{ name: FeatureFlag.feesEnabled, value: true }],
|
||||
})
|
||||
|
||||
// Intercept the trade quote
|
||||
cy.intercept({ url: 'https://api.uniswap.org/v2/quote' }, (req) => {
|
||||
// Avoid intercepting stablecoin pricing fetches
|
||||
if (JSON.parse(req.body).intent !== 'pricing') {
|
||||
req.reply({ fixture: 'uniswapx/feeQuote.json' })
|
||||
}
|
||||
})
|
||||
|
||||
// Setup swap
|
||||
cy.get('#swap-currency-input .open-currency-select-button').click()
|
||||
cy.contains('USDC').click()
|
||||
cy.get('#swap-currency-output .open-currency-select-button').click()
|
||||
cy.contains('ETH').click()
|
||||
cy.get('#swap-currency-input .token-amount-input').type('200')
|
||||
|
||||
// Verify fee UI is displayed
|
||||
cy.get(getTestSelector('swap-details-header-row')).click()
|
||||
cy.contains('Fee (0.15%)')
|
||||
})
|
||||
})
|
||||
})
|
@ -6,10 +6,9 @@ describe('Swap settings', () => {
|
||||
cy.contains('Settings').should('not.exist')
|
||||
cy.get(getTestSelector('open-settings-dialog-button')).click()
|
||||
cy.get(getTestSelector('mobile-settings-menu')).should('not.exist')
|
||||
cy.contains('Max slippage').should('exist')
|
||||
cy.contains('Max. slippage').should('exist')
|
||||
cy.contains('Transaction deadline').should('exist')
|
||||
cy.contains('UniswapX').should('exist')
|
||||
cy.contains('Local routing').should('exist')
|
||||
cy.get(getTestSelector('open-settings-dialog-button')).click()
|
||||
cy.contains('Settings').should('not.exist')
|
||||
})
|
||||
@ -26,9 +25,8 @@ describe('Swap settings', () => {
|
||||
cy.get(getTestSelector('mobile-settings-menu'))
|
||||
.should('exist')
|
||||
.within(() => {
|
||||
cy.contains('Max slippage').should('exist')
|
||||
cy.contains('Max. slippage').should('exist')
|
||||
cy.contains('UniswapX').should('exist')
|
||||
cy.contains('Local routing').should('exist')
|
||||
cy.contains('Transaction deadline').should('exist')
|
||||
cy.get(getTestSelector('mobile-settings-close')).click()
|
||||
})
|
||||
|
@ -1,27 +0,0 @@
|
||||
import { SwapEventName } from '@uniswap/analytics-events'
|
||||
import { USDC_MAINNET } from 'constants/tokens'
|
||||
|
||||
import { getTestSelector } from '../../utils'
|
||||
|
||||
describe('Swap inputs with no wallet connected', () => {
|
||||
it('can input and load a quote with no wallet connected', () => {
|
||||
cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${USDC_MAINNET.address}`)
|
||||
|
||||
cy.get(getTestSelector('web3-status-connected')).click()
|
||||
// click twice, first time to show confirmation, second to confirm
|
||||
cy.get(getTestSelector('wallet-disconnect')).click()
|
||||
cy.get(getTestSelector('wallet-disconnect')).should('contain', 'Disconnect')
|
||||
cy.get(getTestSelector('wallet-disconnect')).click()
|
||||
cy.get(getTestSelector('close-account-drawer')).click()
|
||||
|
||||
// Enter amount to swap
|
||||
cy.get('#swap-currency-output .token-amount-input').type('1').should('have.value', '1')
|
||||
cy.get('#swap-currency-input .token-amount-input').should('not.have.value', '')
|
||||
// Verify logging
|
||||
cy.waitForAmplitudeEvent(SwapEventName.SWAP_QUOTE_RECEIVED).then((event: any) => {
|
||||
cy.wrap(event.event_properties).should('have.property', 'quote_latency_milliseconds')
|
||||
cy.wrap(event.event_properties.quote_latency_milliseconds).should('be.a', 'number')
|
||||
cy.wrap(event.event_properties.quote_latency_milliseconds).should('be.gte', 0)
|
||||
})
|
||||
})
|
||||
})
|
@ -1,17 +1,35 @@
|
||||
import { ChainId, CurrencyAmount } from '@uniswap/sdk-core'
|
||||
import { CyHttpMessages } from 'cypress/types/net-stubbing'
|
||||
|
||||
import { DAI, nativeOnChain, USDC_MAINNET } from '../../../src/constants/tokens'
|
||||
import { getTestSelector } from '../../utils'
|
||||
|
||||
const QuoteEndpoint = 'https://api.uniswap.org/v2/quote'
|
||||
const QuoteWhereUniswapXIsBetter = 'uniswapx/quote1.json'
|
||||
const QuoteWithEthInput = 'uniswapx/quote2.json'
|
||||
|
||||
const QuoteEndpoint = 'https://api.uniswap.org/v2/quote'
|
||||
const OrderSubmissionEndpoint = 'https://api.uniswap.org/v2/order'
|
||||
|
||||
const OrderStatusEndpoint =
|
||||
'https://api.uniswap.org/v2/orders?swapper=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266&orderHashes=0xa9dd6f05ad6d6c79bee654c31ede4d0d2392862711be0f3bc4a9124af24a6a19'
|
||||
|
||||
/**
|
||||
* Stubs quote to return a quote for non-price requests
|
||||
* Price quotes are blocked with 409, as the backend would not accept them regardless
|
||||
*/
|
||||
function stubNonPriceQuoteWith(fixture: string) {
|
||||
cy.intercept(QuoteEndpoint, (req: CyHttpMessages.IncomingHttpRequest) => {
|
||||
let body = req.body
|
||||
if (typeof body === 'string') {
|
||||
body = JSON.parse(body)
|
||||
}
|
||||
if (body.intent === 'pricing') {
|
||||
req.reply({ statusCode: 409 })
|
||||
} else {
|
||||
req.reply({ fixture })
|
||||
}
|
||||
}).as('quote')
|
||||
}
|
||||
|
||||
/** Stubs the provider to return a tx receipt corresponding to the mock filled uniswapx order's txHash */
|
||||
function stubSwapTxReceipt() {
|
||||
cy.hardhat().then((hardhat) => {
|
||||
@ -23,53 +41,26 @@ function stubSwapTxReceipt() {
|
||||
})
|
||||
}
|
||||
|
||||
describe('UniswapX Toggle', () => {
|
||||
// TODO: FIX THESE TESTS where we should NOT stub for pricing requests
|
||||
describe.skip('UniswapX Toggle', () => {
|
||||
beforeEach(() => {
|
||||
cy.intercept(QuoteEndpoint, { fixture: QuoteWhereUniswapXIsBetter })
|
||||
stubNonPriceQuoteWith(QuoteWhereUniswapXIsBetter)
|
||||
cy.visit(`/swap/?inputCurrency=${USDC_MAINNET.address}&outputCurrency=${DAI.address}`)
|
||||
})
|
||||
|
||||
it('only displays uniswapx ui when setting is on', () => {
|
||||
it('displays uniswapx ui when setting is on', () => {
|
||||
// Setup a swap
|
||||
cy.get('#swap-currency-input .token-amount-input').type('300')
|
||||
|
||||
// UniswapX UI should not be visible
|
||||
cy.get(getTestSelector('gas-estimate-uniswapx-icon')).should('not.exist')
|
||||
|
||||
// Opt-in to UniswapX
|
||||
cy.contains('Try it now').click()
|
||||
cy.wait('@quote')
|
||||
|
||||
// UniswapX UI should be visible
|
||||
cy.get(getTestSelector('gas-estimate-uniswapx-icon')).should('exist')
|
||||
})
|
||||
|
||||
it('prompts opt-in if UniswapX is better', () => {
|
||||
// Setup a swap
|
||||
cy.get('#swap-currency-input .token-amount-input').type('300')
|
||||
|
||||
// UniswapX should not display in gas estimate row before opt-in
|
||||
cy.get(getTestSelector('gas-estimate-uniswapx-icon')).should('not.exist')
|
||||
|
||||
// UniswapX mustache should be visible
|
||||
cy.contains('Try it now').click()
|
||||
|
||||
// Opt-in dialog should now be hidden
|
||||
cy.contains('Try it now').should('not.be.visible')
|
||||
|
||||
// UniswapX should display in gas estimate row
|
||||
cy.get(getTestSelector('gas-estimate-uniswapx-icon')).should('exist')
|
||||
|
||||
// Opt-in dialog should not reappear if user manually toggles UniswapX off
|
||||
cy.get(getTestSelector('open-settings-dialog-button')).click()
|
||||
cy.get(getTestSelector('toggle-uniswap-x-button')).click()
|
||||
cy.get(getTestSelector('open-settings-dialog-button')).click()
|
||||
cy.contains('Try it now').should('not.be.visible')
|
||||
})
|
||||
})
|
||||
|
||||
describe('UniswapX Orders', () => {
|
||||
describe.skip('UniswapX Orders', () => {
|
||||
beforeEach(() => {
|
||||
cy.intercept(QuoteEndpoint, { fixture: QuoteWhereUniswapXIsBetter })
|
||||
stubNonPriceQuoteWith(QuoteWhereUniswapXIsBetter)
|
||||
cy.intercept(OrderSubmissionEndpoint, { fixture: 'uniswapx/orderResponse.json' })
|
||||
cy.intercept(OrderStatusEndpoint, { fixture: 'uniswapx/openStatusResponse.json' })
|
||||
|
||||
@ -82,7 +73,7 @@ describe('UniswapX Orders', () => {
|
||||
it('can swap exact-in trades using uniswapX', () => {
|
||||
// Setup a swap
|
||||
cy.get('#swap-currency-input .token-amount-input').type('300')
|
||||
cy.contains('Try it now').click()
|
||||
cy.wait('@quote')
|
||||
|
||||
// Submit uniswapx order signature
|
||||
cy.get('#swap-button').click()
|
||||
@ -101,7 +92,7 @@ describe('UniswapX Orders', () => {
|
||||
it('can swap exact-out trades using uniswapX', () => {
|
||||
// Setup a swap
|
||||
cy.get('#swap-currency-output .token-amount-input').type('300')
|
||||
cy.contains('Try it now').click()
|
||||
cy.wait('@quote')
|
||||
|
||||
// Submit uniswapx order signature
|
||||
cy.get('#swap-button').click()
|
||||
@ -120,7 +111,7 @@ describe('UniswapX Orders', () => {
|
||||
it('renders proper view if uniswapx order expires', () => {
|
||||
// Setup a swap
|
||||
cy.get('#swap-currency-input .token-amount-input').type('300')
|
||||
cy.contains('Try it now').click()
|
||||
cy.wait('@quote')
|
||||
|
||||
// Submit uniswapx order signature
|
||||
cy.get('#swap-button').click()
|
||||
@ -136,7 +127,7 @@ describe('UniswapX Orders', () => {
|
||||
it('renders proper view if uniswapx order has insufficient funds', () => {
|
||||
// Setup a swap
|
||||
cy.get('#swap-currency-input .token-amount-input').type('300')
|
||||
cy.contains('Try it now').click()
|
||||
cy.wait('@quote')
|
||||
|
||||
// Submit uniswapx order signature
|
||||
cy.get('#swap-button').click()
|
||||
@ -150,9 +141,9 @@ describe('UniswapX Orders', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('UniswapX Eth Input', () => {
|
||||
describe.skip('UniswapX Eth Input', () => {
|
||||
beforeEach(() => {
|
||||
cy.intercept(QuoteEndpoint, { fixture: QuoteWithEthInput })
|
||||
stubNonPriceQuoteWith(QuoteWithEthInput)
|
||||
cy.intercept(OrderSubmissionEndpoint, { fixture: 'uniswapx/orderResponse.json' })
|
||||
cy.intercept(OrderStatusEndpoint, { fixture: 'uniswapx/openStatusResponse.json' })
|
||||
|
||||
@ -170,7 +161,8 @@ describe('UniswapX Eth Input', () => {
|
||||
it('can swap using uniswapX with ETH as input', () => {
|
||||
// Setup a swap
|
||||
cy.get('#swap-currency-input .token-amount-input').type('1')
|
||||
cy.contains('Try it now').click()
|
||||
|
||||
cy.wait('@quote')
|
||||
|
||||
// Prompt ETH wrap to use for order
|
||||
cy.get('#swap-button').click()
|
||||
@ -199,10 +191,10 @@ describe('UniswapX Eth Input', () => {
|
||||
cy.contains('Swapped')
|
||||
})
|
||||
|
||||
it('switches swap input to WETH after wrap', () => {
|
||||
it('keeps ETH as the input currency before wrap completes', () => {
|
||||
// Setup a swap
|
||||
cy.get('#swap-currency-input .token-amount-input').type('1')
|
||||
cy.contains('Try it now').click()
|
||||
cy.wait('@quote')
|
||||
|
||||
// Prompt ETH wrap and confirm
|
||||
cy.get('#swap-button').click()
|
||||
@ -211,16 +203,25 @@ describe('UniswapX Eth Input', () => {
|
||||
|
||||
// Close review modal before wrap is confirmed on chain
|
||||
cy.get(getTestSelector('confirmation-close-icon')).click()
|
||||
// Confirm ETH is still the input token before wrap succeeds
|
||||
cy.contains('ETH')
|
||||
})
|
||||
|
||||
it('switches swap input to WETH after wrap', () => {
|
||||
// Setup a swap
|
||||
cy.get('#swap-currency-input .token-amount-input').type('1')
|
||||
cy.wait('@quote')
|
||||
|
||||
// Prompt ETH wrap and confirm
|
||||
cy.get('#swap-button').click()
|
||||
cy.contains('Confirm swap').click()
|
||||
cy.wait('@eth_sendRawTransaction')
|
||||
cy.hardhat().then((hardhat) => hardhat.mine())
|
||||
|
||||
// Confirm wrap is successful and WETH is now input token
|
||||
cy.contains('Wrapped')
|
||||
cy.contains('WETH')
|
||||
|
||||
// Reopen review modal and continue swap
|
||||
cy.get('#swap-button').click()
|
||||
cy.contains('Confirm swap').click()
|
||||
|
||||
// Approve WETH spend
|
||||
cy.wait('@eth_sendRawTransaction')
|
||||
cy.hardhat().then((hardhat) => hardhat.mine())
|
||||
@ -235,10 +236,15 @@ describe('UniswapX Eth Input', () => {
|
||||
|
||||
// Verify swap success
|
||||
cy.contains('Swapped')
|
||||
|
||||
// Close modal
|
||||
cy.get(getTestSelector('confirmation-close-icon')).click()
|
||||
// The input currency should now be WETH
|
||||
cy.contains('WETH')
|
||||
})
|
||||
})
|
||||
|
||||
describe('UniswapX activity history', () => {
|
||||
describe.skip('UniswapX activity history', () => {
|
||||
beforeEach(() => {
|
||||
cy.intercept(QuoteEndpoint, { fixture: QuoteWhereUniswapXIsBetter })
|
||||
cy.intercept(OrderSubmissionEndpoint, { fixture: 'uniswapx/orderResponse.json' })
|
||||
@ -255,7 +261,6 @@ describe('UniswapX activity history', () => {
|
||||
it('can view UniswapX order status progress in activity', () => {
|
||||
// Setup a swap
|
||||
cy.get('#swap-currency-input .token-amount-input').type('300')
|
||||
cy.contains('Try it now').click()
|
||||
|
||||
// Submit uniswapx order signature
|
||||
cy.get('#swap-button').click()
|
||||
@ -283,7 +288,6 @@ describe('UniswapX activity history', () => {
|
||||
it('can view UniswapX order status progress in activity upon expiry', () => {
|
||||
// Setup a swap
|
||||
cy.get('#swap-currency-input .token-amount-input').type('300')
|
||||
cy.contains('Try it now').click()
|
||||
|
||||
// Submit uniswapx order signature
|
||||
cy.get('#swap-button').click()
|
||||
@ -310,7 +314,6 @@ describe('UniswapX activity history', () => {
|
||||
it('deduplicates remote vs local uniswapx orders', () => {
|
||||
// Setup a swap
|
||||
cy.get('#swap-currency-input .token-amount-input').type('300')
|
||||
cy.contains('Try it now').click()
|
||||
|
||||
// Submit uniswapx order signature
|
||||
cy.get('#swap-button').click()
|
||||
@ -335,14 +338,13 @@ describe('UniswapX activity history', () => {
|
||||
// Open activity history
|
||||
cy.get(getTestSelector('mini-portfolio-navbar')).contains('Activity').click()
|
||||
|
||||
// Ensure gql and local order have been deduped, such that there is only one swap activity listed
|
||||
// Ensure gql and local order have been deduped, such that there is one swap activity listed
|
||||
cy.get(getTestSelector('activity-content')).contains('Swapped').should('have.length', 1)
|
||||
})
|
||||
|
||||
it('balances should refetch after uniswapx swap', () => {
|
||||
// Setup a swap
|
||||
cy.get('#swap-currency-input .token-amount-input').type('300')
|
||||
cy.contains('Try it now').click()
|
||||
|
||||
const gqlSpy = cy.spy().as('gqlSpy')
|
||||
cy.intercept(/graphql/, (req) => {
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { ChainId, WETH9 } from '@uniswap/sdk-core'
|
||||
import { FeatureFlag } from 'featureFlags'
|
||||
|
||||
import { ARB, UNI } from '../../src/constants/tokens'
|
||||
import { getTestSelector } from '../utils'
|
||||
@ -14,8 +15,9 @@ describe('Token details', () => {
|
||||
|
||||
it('Uniswap token should have all information populated', () => {
|
||||
// Uniswap token
|
||||
cy.visit(`/tokens/ethereum/${UNI_ADDRESS}`)
|
||||
|
||||
cy.visit(`/tokens/ethereum/${UNI_ADDRESS}`, {
|
||||
featureFlags: [{ name: FeatureFlag.infoTDP, value: false }],
|
||||
})
|
||||
// Price chart should be filled in
|
||||
cy.get('[data-cy="chart-header"]').should('include.text', '$')
|
||||
cy.get('[data-cy="price-chart"]').should('exist')
|
||||
@ -47,12 +49,28 @@ describe('Token details', () => {
|
||||
cy.contains(UNI_ADDRESS).should('exist')
|
||||
})
|
||||
|
||||
it('Uniswap token should have correct stats boxes if infoTDP flag on', () => {
|
||||
// Uniswap token
|
||||
cy.visit(`/tokens/ethereum/${UNI_ADDRESS}`, {
|
||||
featureFlags: [{ name: FeatureFlag.infoTDP, value: true }],
|
||||
})
|
||||
|
||||
// Stats should have: TVL, FDV, market cap, 24H volume
|
||||
cy.get(getTestSelector('token-details-stats')).should('exist')
|
||||
cy.get(getTestSelector('token-details-stats')).within(() => {
|
||||
cy.get('[data-cy="tvl"]').should('include.text', '$')
|
||||
cy.get('[data-cy="fdv"]').should('include.text', '$')
|
||||
cy.get('[data-cy="market-cap"]').should('include.text', '$')
|
||||
cy.get('[data-cy="volume-24h"]').should('include.text', '$')
|
||||
})
|
||||
})
|
||||
|
||||
it('token with warning and low trading volume should have all information populated', () => {
|
||||
// Shiba predator token, low trading volume and also has warning modal
|
||||
cy.visit('/tokens/ethereum/0xa71d0588EAf47f12B13cF8eC750430d21DF04974')
|
||||
// Null token created for this test, 0 trading volume and has warning modal
|
||||
cy.visit('/tokens/ethereum/0x1eFBB78C8b917f67986BcE54cE575069c0143681')
|
||||
|
||||
// Should have missing price chart when price unavailable (expected for this token)
|
||||
if (cy.get('[data-cy="chart-header"]').contains('Price Unavailable')) {
|
||||
if (cy.get('[data-cy="chart-header"]').contains('Price unavailable')) {
|
||||
cy.get('[data-cy="missing-chart"]').should('exist')
|
||||
}
|
||||
|
||||
@ -61,22 +79,20 @@ describe('Token details', () => {
|
||||
|
||||
// About section should have description of token
|
||||
cy.get(getTestSelector('token-details-about-section')).should('exist')
|
||||
cy.contains('QOM is the Shiba Predator').should('exist')
|
||||
cy.contains('No token information available').should('exist')
|
||||
|
||||
// Links section should link out to Etherscan, More analytics, Website, Twitter
|
||||
// Links section should link out to Etherscan, More analytics
|
||||
cy.get('[data-cy="resources-container"]').within(() => {
|
||||
cy.contains('Etherscan')
|
||||
.should('have.attr', 'href')
|
||||
.and('include', 'etherscan.io/address/0xa71d0588EAf47f12B13cF8eC750430d21DF04974')
|
||||
.and('include', 'etherscan.io/address/0x1eFBB78C8b917f67986BcE54cE575069c0143681')
|
||||
cy.contains('More analytics')
|
||||
.should('have.attr', 'href')
|
||||
.and('include', 'info.uniswap.org/#/tokens/0xa71d0588EAf47f12B13cF8eC750430d21DF04974')
|
||||
cy.contains('Website').should('have.attr', 'href').and('include', 'qom')
|
||||
cy.contains('Twitter').should('have.attr', 'href').and('include', 'twitter.com/ShibaPredator1')
|
||||
.and('include', 'info.uniswap.org/#/tokens/0x1eFBB78C8b917f67986BcE54cE575069c0143681')
|
||||
})
|
||||
|
||||
// Contract address should be displayed
|
||||
cy.contains('0xa71d0588EAf47f12B13cF8eC750430d21DF04974').should('exist')
|
||||
cy.contains('0x1eFBB78C8b917f67986BcE54cE575069c0143681').should('exist')
|
||||
|
||||
// Warning label should show if relevant ([spec](https://www.notion.so/3f7fce6f93694be08a94a6984d50298e))
|
||||
cy.get('[data-cy="token-safety-message"]')
|
||||
|
@ -59,9 +59,7 @@ describe('Token explore', () => {
|
||||
// in metamask modal using plain cypress. this is a workaround.
|
||||
cy.visit('/tokens/polygon')
|
||||
cy.get(getTestSelector('tokens-network-filter-selected')).should('contain', 'Polygon')
|
||||
cy.get(getTestSelector('token-table-row-NATIVE'))
|
||||
.find(getTestSelector('name-cell'))
|
||||
.should('include.text', 'Polygon Matic')
|
||||
cy.get(getTestSelector('token-table-row-NATIVE')).find(getTestSelector('name-cell')).should('include.text', 'Matic')
|
||||
})
|
||||
|
||||
it('should update when token explore table network changed', () => {
|
||||
@ -69,6 +67,6 @@ describe('Token explore', () => {
|
||||
cy.get(getTestSelector('tokens-network-filter-selected')).click()
|
||||
cy.get(getTestSelector('tokens-network-filter-option-optimism')).click()
|
||||
cy.get(getTestSelector('tokens-network-filter-selected')).should('contain', 'Optimism')
|
||||
cy.get(getTestSelector('chain-selector-logo')).invoke('attr', 'alt').should('eq', 'Ethereum')
|
||||
cy.get(getTestSelector('chain-selector-logo')).find('title').should('include.text', 'Ethereum logo')
|
||||
})
|
||||
})
|
||||
|
@ -65,7 +65,7 @@ describe('Universal search bar', () => {
|
||||
cy.get(getTestSelector('searchbar-token-row-ETHEREUM-NATIVE'))
|
||||
|
||||
// Validate that we go to the searched/selected result.
|
||||
getSearchBar().type('{enter}')
|
||||
cy.get(getTestSelector('searchbar-token-row-ETHEREUM-NATIVE')).click()
|
||||
cy.url().should('contain', 'tokens/ethereum/NATIVE')
|
||||
}
|
||||
)
|
||||
|
@ -19,7 +19,7 @@ describe('disconnect wallet', () => {
|
||||
// Verify wallet has disconnected
|
||||
cy.contains('Connect a wallet').should('exist')
|
||||
cy.get(getTestSelector('navbar-connect-wallet')).contains('Connect')
|
||||
cy.contains('Connect Wallet')
|
||||
cy.contains('Connect wallet')
|
||||
|
||||
// Verify swap input is cleared
|
||||
cy.get('#swap-currency-input .token-amount-input').should('have.value', '1')
|
||||
|
@ -2,7 +2,7 @@ import { createDeferredPromise } from '../../../src/test-utils/promise'
|
||||
import { getTestSelector } from '../../utils'
|
||||
|
||||
function waitsForActiveChain(chain: string) {
|
||||
cy.get(getTestSelector('chain-selector-logo')).invoke('attr', 'alt').should('eq', chain)
|
||||
cy.get(getTestSelector('chain-selector-logo')).find('title').should('include.text', `${chain} logo`)
|
||||
}
|
||||
|
||||
function switchChain(chain: string) {
|
||||
|
@ -49,11 +49,39 @@ describe('Wallet Dropdown', () => {
|
||||
})
|
||||
itChangesTheme()
|
||||
itChangesLocale()
|
||||
|
||||
it('should not show buy crypto button in uk', () => {
|
||||
cy.document().then((doc) => {
|
||||
const meta = document.createElement('meta')
|
||||
meta.setAttribute('property', 'x:blocked-paths')
|
||||
meta.setAttribute('content', '/,/nfts,/buy')
|
||||
doc.head.appendChild(meta)
|
||||
})
|
||||
cy.get(getTestSelector('wallet-buy-crypto')).should('not.exist')
|
||||
})
|
||||
})
|
||||
|
||||
describe('do not render buy button when /buy is blocked', () => {
|
||||
beforeEach(() => {
|
||||
cy.document().then((doc) => {
|
||||
const meta = document.createElement('meta')
|
||||
meta.setAttribute('property', 'x:blocked-paths')
|
||||
meta.setAttribute('content', '/buy')
|
||||
doc.head.appendChild(meta)
|
||||
})
|
||||
cy.visit('/')
|
||||
cy.get(getTestSelector('web3-status-connected')).click()
|
||||
cy.get(getTestSelector('wallet-settings')).click()
|
||||
})
|
||||
|
||||
it('should not render buy button', () => {
|
||||
cy.get(getTestSelector('wallet-buy-crypto')).should('not.exist')
|
||||
})
|
||||
})
|
||||
|
||||
describe('should change locale with feature flag', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/', { featureFlags: [FeatureFlag.currencyConversion] })
|
||||
cy.visit('/', { featureFlags: [{ name: FeatureFlag.currencyConversion, value: true }] })
|
||||
cy.get(getTestSelector('web3-status-connected')).click()
|
||||
cy.get(getTestSelector('wallet-settings')).click()
|
||||
})
|
||||
@ -147,19 +175,19 @@ describe('Wallet Dropdown', () => {
|
||||
|
||||
describe('local currency', () => {
|
||||
it('loads local currency from the query param', () => {
|
||||
cy.visit('/', { featureFlags: [FeatureFlag.currencyConversion] })
|
||||
cy.visit('/', { featureFlags: [{ name: FeatureFlag.currencyConversion, value: true }] })
|
||||
cy.get(getTestSelector('web3-status-connected')).click()
|
||||
cy.get(getTestSelector('wallet-settings')).click()
|
||||
cy.contains('USD')
|
||||
|
||||
cy.visit('/?cur=AUD', { featureFlags: [FeatureFlag.currencyConversion] })
|
||||
cy.visit('/?cur=AUD', { featureFlags: [{ name: FeatureFlag.currencyConversion, value: true }] })
|
||||
cy.get(getTestSelector('web3-status-connected')).click()
|
||||
cy.get(getTestSelector('wallet-settings')).click()
|
||||
cy.contains('AUD')
|
||||
})
|
||||
|
||||
it('loads local currency from menu', () => {
|
||||
cy.visit('/', { featureFlags: [FeatureFlag.currencyConversion] })
|
||||
cy.visit('/', { featureFlags: [{ name: FeatureFlag.currencyConversion, value: true }] })
|
||||
cy.get(getTestSelector('web3-status-connected')).click()
|
||||
cy.get(getTestSelector('wallet-settings')).click()
|
||||
cy.contains('USD')
|
||||
|
5
cypress/fixtures/insufficientLiquidity.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"errorCode": "QUOTE_ERROR",
|
||||
"detail": "No quotes available",
|
||||
"id": "63363cc1-d474-4584-b386-7c356814b79f"
|
||||
}
|
562
cypress/fixtures/uniswapx/feeQuote.json
Normal file
@ -0,0 +1,562 @@
|
||||
{
|
||||
"routing": "DUTCH_LIMIT",
|
||||
"quote": {
|
||||
"orderInfo": {
|
||||
"chainId": 1,
|
||||
"permit2Address": "0x000000000022d473030f116ddee9f6b43ac78ba3",
|
||||
"reactor": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4",
|
||||
"swapper": "0x0938a82F93D5DAB110Dc6277FC236b5b082DC10F",
|
||||
"nonce": "1993353164669688581970088190602701610528397285201889446578254799128576197633",
|
||||
"deadline": 1697481666,
|
||||
"additionalValidationContract": "0x0000000000000000000000000000000000000000",
|
||||
"additionalValidationData": "0x",
|
||||
"decayStartTime": 1697481594,
|
||||
"decayEndTime": 1697481654,
|
||||
"exclusiveFiller": "0xaAFb85ad4a412dd8adC49611496a7695A22f4aeb",
|
||||
"exclusivityOverrideBps": "100",
|
||||
"input": {
|
||||
"token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
||||
"startAmount": "200000000",
|
||||
"endAmount": "200000000"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"token": "0x0000000000000000000000000000000000000000",
|
||||
"startAmount": "123803169993201727",
|
||||
"endAmount": "117908377342236273",
|
||||
"recipient": "0x0938a82F93D5DAB110Dc6277FC236b5b082DC10F"
|
||||
},
|
||||
{
|
||||
"token": "0x0000000000000000000000000000000000000000",
|
||||
"startAmount": "185983730585681",
|
||||
"endAmount": "177128258400955",
|
||||
"recipient": "0x37a8f295612602f2774d331e562be9e61B83a327"
|
||||
}
|
||||
]
|
||||
},
|
||||
"encodedOrder": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000652d837a00000000000000000000000000000000000000000000000000000000652d83b6000000000000000000000000aafb85ad4a412dd8adc49611496a7695a22f4aeb0000000000000000000000000000000000000000000000000000000000000064000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000000bebc200000000000000000000000000000000000000000000000000000000000bebc20000000000000000000000000000000000000000000000000000000000000002000000000000000000000000006000da47483062a0d734ba3dc7576ce6a0b645c40000000000000000000000000938a82f93d5dab110dc6277fc236b5b082dc10f046832aa305880d33daa871e5041a0cd4853599a9ead518917239e206765040100000000000000000000000000000000000000000000000000000000652d83c2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b7d653c183183f00000000000000000000000000000000000000000000000001a2e50b6386d6710000000000000000000000000938a82f93d5dab110dc6277fc236b5b082dc10f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a926b63210510000000000000000000000000000000000000000000000000000a118e2ebf2bb00000000000000000000000037a8f295612602f2774d331e562be9e61b83a327",
|
||||
"quoteId": "7b924043-f2d8-4f2e-abaa-9f65fbe5f890",
|
||||
"requestId": "a02ca0ca-7855-4dd0-9330-8b818aaeb59f",
|
||||
"orderHash": "0xb5b4e3be188f6eb9dbe7e1489595829184a9ebfb5389185ed7ba7c03142278c9",
|
||||
"startTimeBufferSecs": 45,
|
||||
"auctionPeriodSecs": 60,
|
||||
"deadlineBufferSecs": 12,
|
||||
"slippageTolerance": "0.5",
|
||||
"permitData": {
|
||||
"domain": {
|
||||
"name": "Permit2",
|
||||
"chainId": 1,
|
||||
"verifyingContract": "0x000000000022d473030f116ddee9f6b43ac78ba3"
|
||||
},
|
||||
"types": {
|
||||
"PermitWitnessTransferFrom": [
|
||||
{
|
||||
"name": "permitted",
|
||||
"type": "TokenPermissions"
|
||||
},
|
||||
{
|
||||
"name": "spender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "nonce",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "deadline",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "witness",
|
||||
"type": "ExclusiveDutchOrder"
|
||||
}
|
||||
],
|
||||
"TokenPermissions": [
|
||||
{
|
||||
"name": "token",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "amount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"ExclusiveDutchOrder": [
|
||||
{
|
||||
"name": "info",
|
||||
"type": "OrderInfo"
|
||||
},
|
||||
{
|
||||
"name": "decayStartTime",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "decayEndTime",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "exclusiveFiller",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "exclusivityOverrideBps",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "inputToken",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "inputStartAmount",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "inputEndAmount",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "outputs",
|
||||
"type": "DutchOutput[]"
|
||||
}
|
||||
],
|
||||
"OrderInfo": [
|
||||
{
|
||||
"name": "reactor",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "swapper",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "nonce",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "deadline",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "additionalValidationContract",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "additionalValidationData",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"DutchOutput": [
|
||||
{
|
||||
"name": "token",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "startAmount",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "endAmount",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
}
|
||||
]
|
||||
},
|
||||
"values": {
|
||||
"permitted": {
|
||||
"token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
||||
"amount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x0bebc200"
|
||||
}
|
||||
},
|
||||
"spender": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4",
|
||||
"nonce": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x046832aa305880d33daa871e5041a0cd4853599a9ead518917239e2067650401"
|
||||
},
|
||||
"deadline": 1697481666,
|
||||
"witness": {
|
||||
"info": {
|
||||
"reactor": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4",
|
||||
"swapper": "0x0938a82F93D5DAB110Dc6277FC236b5b082DC10F",
|
||||
"nonce": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x046832aa305880d33daa871e5041a0cd4853599a9ead518917239e2067650401"
|
||||
},
|
||||
"deadline": 1697481666,
|
||||
"additionalValidationContract": "0x0000000000000000000000000000000000000000",
|
||||
"additionalValidationData": "0x"
|
||||
},
|
||||
"decayStartTime": 1697481594,
|
||||
"decayEndTime": 1697481654,
|
||||
"exclusiveFiller": "0xaAFb85ad4a412dd8adC49611496a7695A22f4aeb",
|
||||
"exclusivityOverrideBps": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x64"
|
||||
},
|
||||
"inputToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
||||
"inputStartAmount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x0bebc200"
|
||||
},
|
||||
"inputEndAmount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x0bebc200"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"token": "0x0000000000000000000000000000000000000000",
|
||||
"startAmount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x01b7d653c183183f"
|
||||
},
|
||||
"endAmount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x01a2e50b6386d671"
|
||||
},
|
||||
"recipient": "0x0938a82F93D5DAB110Dc6277FC236b5b082DC10F"
|
||||
},
|
||||
{
|
||||
"token": "0x0000000000000000000000000000000000000000",
|
||||
"startAmount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0xa926b6321051"
|
||||
},
|
||||
"endAmount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0xa118e2ebf2bb"
|
||||
},
|
||||
"recipient": "0x37a8f295612602f2774d331e562be9e61B83a327"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"portionBips": 15,
|
||||
"portionAmount": "185983730585681",
|
||||
"portionRecipient": "0x37a8f295612602f2774d331e562be9e61B83a327"
|
||||
},
|
||||
"requestId": "a02ca0ca-7855-4dd0-9330-8b818aaeb59f",
|
||||
"allQuotes": [
|
||||
{
|
||||
"routing": "DUTCH_LIMIT",
|
||||
"quote": {
|
||||
"orderInfo": {
|
||||
"chainId": 1,
|
||||
"permit2Address": "0x000000000022d473030f116ddee9f6b43ac78ba3",
|
||||
"reactor": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4",
|
||||
"swapper": "0x0938a82F93D5DAB110Dc6277FC236b5b082DC10F",
|
||||
"nonce": "1993353164669688581970088190602701610528397285201889446578254799128576197633",
|
||||
"deadline": 1697481666,
|
||||
"additionalValidationContract": "0x0000000000000000000000000000000000000000",
|
||||
"additionalValidationData": "0x",
|
||||
"decayStartTime": 1697481594,
|
||||
"decayEndTime": 1697481654,
|
||||
"exclusiveFiller": "0xaAFb85ad4a412dd8adC49611496a7695A22f4aeb",
|
||||
"exclusivityOverrideBps": "100",
|
||||
"input": {
|
||||
"token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
||||
"startAmount": "200000000",
|
||||
"endAmount": "200000000"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"token": "0x0000000000000000000000000000000000000000",
|
||||
"startAmount": "123803169993201727",
|
||||
"endAmount": "117908377342236273",
|
||||
"recipient": "0x0938a82F93D5DAB110Dc6277FC236b5b082DC10F"
|
||||
},
|
||||
{
|
||||
"token": "0x0000000000000000000000000000000000000000",
|
||||
"startAmount": "185983730585681",
|
||||
"endAmount": "177128258400955",
|
||||
"recipient": "0x37a8f295612602f2774d331e562be9e61B83a327"
|
||||
}
|
||||
]
|
||||
},
|
||||
"encodedOrder": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000652d837a00000000000000000000000000000000000000000000000000000000652d83b6000000000000000000000000aafb85ad4a412dd8adc49611496a7695a22f4aeb0000000000000000000000000000000000000000000000000000000000000064000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000000bebc200000000000000000000000000000000000000000000000000000000000bebc20000000000000000000000000000000000000000000000000000000000000002000000000000000000000000006000da47483062a0d734ba3dc7576ce6a0b645c40000000000000000000000000938a82f93d5dab110dc6277fc236b5b082dc10f046832aa305880d33daa871e5041a0cd4853599a9ead518917239e206765040100000000000000000000000000000000000000000000000000000000652d83c2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b7d653c183183f00000000000000000000000000000000000000000000000001a2e50b6386d6710000000000000000000000000938a82f93d5dab110dc6277fc236b5b082dc10f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a926b63210510000000000000000000000000000000000000000000000000000a118e2ebf2bb00000000000000000000000037a8f295612602f2774d331e562be9e61b83a327",
|
||||
"quoteId": "7b924043-f2d8-4f2e-abaa-9f65fbe5f890",
|
||||
"requestId": "a02ca0ca-7855-4dd0-9330-8b818aaeb59f",
|
||||
"orderHash": "0xb5b4e3be188f6eb9dbe7e1489595829184a9ebfb5389185ed7ba7c03142278c9",
|
||||
"startTimeBufferSecs": 45,
|
||||
"auctionPeriodSecs": 60,
|
||||
"deadlineBufferSecs": 12,
|
||||
"slippageTolerance": "0.5",
|
||||
"permitData": {
|
||||
"domain": {
|
||||
"name": "Permit2",
|
||||
"chainId": 1,
|
||||
"verifyingContract": "0x000000000022d473030f116ddee9f6b43ac78ba3"
|
||||
},
|
||||
"types": {
|
||||
"PermitWitnessTransferFrom": [
|
||||
{
|
||||
"name": "permitted",
|
||||
"type": "TokenPermissions"
|
||||
},
|
||||
{
|
||||
"name": "spender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "nonce",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "deadline",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "witness",
|
||||
"type": "ExclusiveDutchOrder"
|
||||
}
|
||||
],
|
||||
"TokenPermissions": [
|
||||
{
|
||||
"name": "token",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "amount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"ExclusiveDutchOrder": [
|
||||
{
|
||||
"name": "info",
|
||||
"type": "OrderInfo"
|
||||
},
|
||||
{
|
||||
"name": "decayStartTime",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "decayEndTime",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "exclusiveFiller",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "exclusivityOverrideBps",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "inputToken",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "inputStartAmount",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "inputEndAmount",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "outputs",
|
||||
"type": "DutchOutput[]"
|
||||
}
|
||||
],
|
||||
"OrderInfo": [
|
||||
{
|
||||
"name": "reactor",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "swapper",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "nonce",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "deadline",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "additionalValidationContract",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "additionalValidationData",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"DutchOutput": [
|
||||
{
|
||||
"name": "token",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "startAmount",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "endAmount",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
}
|
||||
]
|
||||
},
|
||||
"values": {
|
||||
"permitted": {
|
||||
"token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
||||
"amount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x0bebc200"
|
||||
}
|
||||
},
|
||||
"spender": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4",
|
||||
"nonce": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x046832aa305880d33daa871e5041a0cd4853599a9ead518917239e2067650401"
|
||||
},
|
||||
"deadline": 1697481666,
|
||||
"witness": {
|
||||
"info": {
|
||||
"reactor": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4",
|
||||
"swapper": "0x0938a82F93D5DAB110Dc6277FC236b5b082DC10F",
|
||||
"nonce": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x046832aa305880d33daa871e5041a0cd4853599a9ead518917239e2067650401"
|
||||
},
|
||||
"deadline": 1697481666,
|
||||
"additionalValidationContract": "0x0000000000000000000000000000000000000000",
|
||||
"additionalValidationData": "0x"
|
||||
},
|
||||
"decayStartTime": 1697481594,
|
||||
"decayEndTime": 1697481654,
|
||||
"exclusiveFiller": "0xaAFb85ad4a412dd8adC49611496a7695A22f4aeb",
|
||||
"exclusivityOverrideBps": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x64"
|
||||
},
|
||||
"inputToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
||||
"inputStartAmount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x0bebc200"
|
||||
},
|
||||
"inputEndAmount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x0bebc200"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"token": "0x0000000000000000000000000000000000000000",
|
||||
"startAmount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x01b7d653c183183f"
|
||||
},
|
||||
"endAmount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x01a2e50b6386d671"
|
||||
},
|
||||
"recipient": "0x0938a82F93D5DAB110Dc6277FC236b5b082DC10F"
|
||||
},
|
||||
{
|
||||
"token": "0x0000000000000000000000000000000000000000",
|
||||
"startAmount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0xa926b6321051"
|
||||
},
|
||||
"endAmount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0xa118e2ebf2bb"
|
||||
},
|
||||
"recipient": "0x37a8f295612602f2774d331e562be9e61B83a327"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"portionBips": 15,
|
||||
"portionAmount": "185983730585681",
|
||||
"portionRecipient": "0x37a8f295612602f2774d331e562be9e61B83a327"
|
||||
}
|
||||
},
|
||||
{
|
||||
"routing": "CLASSIC",
|
||||
"quote": {
|
||||
"methodParameters": {
|
||||
"calldata": "0x3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000652d85d0000000000000000000000000000000000000000000000000000000000000000308060c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000bebc20000000000000000000000000000000000000000000000000001bdf1285753b47400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000037a8f295612602f2774d331e562be9e61b83a327000000000000000000000000000000000000000000000000000000000000000f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000938a82f93d5dab110dc6277fc236b5b082dc10f00000000000000000000000000000000000000000000000001bd45ea74e458eb",
|
||||
"value": "0x00",
|
||||
"to": "0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD"
|
||||
},
|
||||
"blockNumber": "18364784",
|
||||
"amount": "200000000",
|
||||
"amountDecimals": "200",
|
||||
"quote": "126149127803342909",
|
||||
"quoteDecimals": "0.126149127803342909",
|
||||
"quoteGasAdjusted": "122888348391508943",
|
||||
"quoteGasAdjustedDecimals": "0.122888348391508943",
|
||||
"quoteGasAndPortionAdjusted": "122699124699803928",
|
||||
"quoteGasAndPortionAdjustedDecimals": "0.122699124699803928",
|
||||
"gasUseEstimateQuote": "3260779411833966",
|
||||
"gasUseEstimateQuoteDecimals": "0.003260779411833966",
|
||||
"gasUseEstimate": "240911",
|
||||
"gasUseEstimateUSD": "5.153332510477604328",
|
||||
"simulationStatus": "SUCCESS",
|
||||
"simulationError": false,
|
||||
"gasPriceWei": "13535203506",
|
||||
"route": [
|
||||
[
|
||||
{
|
||||
"type": "v2-pool",
|
||||
"address": "0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc",
|
||||
"tokenIn": {
|
||||
"chainId": 1,
|
||||
"decimals": "6",
|
||||
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
||||
"symbol": "USDC"
|
||||
},
|
||||
"tokenOut": {
|
||||
"chainId": 1,
|
||||
"decimals": "18",
|
||||
"address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
||||
"symbol": "WETH"
|
||||
},
|
||||
"reserve0": {
|
||||
"token": {
|
||||
"chainId": 1,
|
||||
"decimals": "6",
|
||||
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
||||
"symbol": "USDC"
|
||||
},
|
||||
"quotient": "27487668611269"
|
||||
},
|
||||
"reserve1": {
|
||||
"token": {
|
||||
"chainId": 1,
|
||||
"decimals": "18",
|
||||
"address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
||||
"symbol": "WETH"
|
||||
},
|
||||
"quotient": "17390022942803382004255"
|
||||
},
|
||||
"amountIn": "200000000",
|
||||
"amountOut": "125959904111637894"
|
||||
}
|
||||
]
|
||||
],
|
||||
"routeString": "[V2] 100.00% = USDC -- [0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc] --> WETH",
|
||||
"quoteId": "f46cf31c-251e-470c-bd57-13209015694e",
|
||||
"portionBips": 15,
|
||||
"portionRecipient": "0x37a8f295612602f2774d331e562be9e61B83a327",
|
||||
"portionAmount": "189223691705014",
|
||||
"portionAmountDecimals": "0.000189223691705014",
|
||||
"requestId": "a02ca0ca-7855-4dd0-9330-8b818aaeb59f",
|
||||
"tradeType": "EXACT_INPUT",
|
||||
"slippage": 0.5
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -24,7 +24,7 @@ declare global {
|
||||
}
|
||||
interface VisitOptions {
|
||||
serviceWorker?: true
|
||||
featureFlags?: Array<FeatureFlag>
|
||||
featureFlags?: Array<{ name: FeatureFlag; value: boolean }>
|
||||
/**
|
||||
* Initial user state.
|
||||
* @default {@type import('../utils/user-state').CONNECTED_WALLET_USER_STATE}
|
||||
@ -59,7 +59,10 @@ Cypress.Commands.overwrite(
|
||||
|
||||
// Set feature flags, if configured.
|
||||
if (options?.featureFlags) {
|
||||
const featureFlags = options.featureFlags.reduce((flags, flag) => ({ ...flags, [flag]: 'enabled' }), {})
|
||||
const featureFlags = options.featureFlags.reduce(
|
||||
(flags, flag) => ({ ...flags, [flag.name]: flag.value ? 'enabled' : 'control' }),
|
||||
{}
|
||||
)
|
||||
win.localStorage.setItem('featureFlags', JSON.stringify(featureFlags))
|
||||
}
|
||||
|
||||
@ -71,18 +74,14 @@ Cypress.Commands.overwrite(
|
||||
}
|
||||
)
|
||||
|
||||
Cypress.Commands.add('waitForAmplitudeEvent', (eventName, timeout = 5000 /* 5s */) => {
|
||||
const startTime = new Date().getTime()
|
||||
|
||||
Cypress.Commands.add('waitForAmplitudeEvent', (eventName) => {
|
||||
function checkRequest() {
|
||||
return cy.wait('@amplitude', { timeout }).then((interception) => {
|
||||
return cy.wait('@amplitude').then((interception) => {
|
||||
const events = interception.request.body.events
|
||||
const event = events.find((event: any) => event.event_type === eventName)
|
||||
|
||||
if (event) {
|
||||
return cy.wrap(event)
|
||||
} else if (new Date().getTime() - startTime > timeout) {
|
||||
throw new Error(`Event ${eventName} not found within the specified timeout`)
|
||||
} else {
|
||||
return checkRequest()
|
||||
}
|
||||
|
@ -9,8 +9,9 @@ beforeEach(() => {
|
||||
req.headers['origin'] = 'https://app.uniswap.org'
|
||||
})
|
||||
|
||||
// Infura is disabled for cypress tests - calls should be routed through the connected wallet instead.
|
||||
// Network RPCs are disabled for cypress tests - calls should be routed through the connected wallet instead.
|
||||
cy.intercept(/infura.io/, { statusCode: 404 })
|
||||
cy.intercept(/quiknode.pro/, { statusCode: 404 })
|
||||
|
||||
// Log requests to hardhat.
|
||||
cy.intercept(/:8545/, logJsonRpc)
|
||||
@ -26,10 +27,16 @@ beforeEach(() => {
|
||||
server_upload_time: Date.now(),
|
||||
payload_size_bytes: byteSize,
|
||||
events_ingested: req.body.events.length,
|
||||
})
|
||||
}),
|
||||
{
|
||||
'origin-country': 'US',
|
||||
}
|
||||
)
|
||||
}).intercept('https://*.sentry.io', { statusCode: 200 })
|
||||
|
||||
// Mock statsig to allow us to mock flags.
|
||||
cy.intercept(/statsig/, { statusCode: 409 })
|
||||
|
||||
// Mock our own token list responses to avoid the latency of IPFS.
|
||||
cy.intercept('https://gateway.ipfs.io/ipns/tokens.uniswap.org', TokenListJSON)
|
||||
.intercept('https://gateway.ipfs.io/ipns/extendedtokens.uniswap.org', { statusCode: 404 })
|
||||
|
@ -5,7 +5,7 @@
|
||||
"incremental": true,
|
||||
"isolatedModules": false,
|
||||
"noImplicitAny": false,
|
||||
"target": "ES5",
|
||||
"target": "ES6",
|
||||
"tsBuildInfoFile": "../node_modules/.cache/tsbuildinfo/cypress", // avoid clobbering the build tsbuildinfo
|
||||
"types": ["cypress", "node"],
|
||||
},
|
||||
|
@ -11,7 +11,7 @@ export const onRequest: PagesFunction = async ({ request, next }) => {
|
||||
}
|
||||
const res = next()
|
||||
try {
|
||||
return new HTMLRewriter().on('head', new MetaTagInjector(data)).transform(await res)
|
||||
return new HTMLRewriter().on('head', new MetaTagInjector(data, request)).transform(await res)
|
||||
} catch (e) {
|
||||
return res
|
||||
}
|
||||
|
@ -7,19 +7,19 @@ const collectionImageUrls = [
|
||||
'http://127.0.0.1:3000/api/image/nfts/collection/0x49cf6f5d44e70224e2e23fdcdd2c053f30ada28b',
|
||||
]
|
||||
|
||||
const nonexistentImageUrls = [
|
||||
'http://127.0.0.1:3000/api/image/nfts/collection/0xed5af388653567af2f388e6224dc7c4b3241c545',
|
||||
]
|
||||
|
||||
test.each([...collectionImageUrls, ...nonexistentImageUrls])('collectionImageUrl', async (url) => {
|
||||
test.each([...collectionImageUrls])('collectionImageUrl', async (url) => {
|
||||
const response = await fetch(new Request(url))
|
||||
expect(response.status).toBe(200)
|
||||
expect(response.headers.get('content-type')).toBe('image/png')
|
||||
})
|
||||
|
||||
const nonexistentImageUrls = [
|
||||
'http://127.0.0.1:3000/api/image/nfts/collection/0xed5af388653567af2f388e6224dc7c4b3241c545',
|
||||
]
|
||||
|
||||
const invalidCollectionImageUrls = ['http://127.0.0.1:3000/api/image/nfts/collection/0xd3adb33f']
|
||||
|
||||
test.each(invalidCollectionImageUrls)('invalidAssetImageUrl', async (url) => {
|
||||
test.each([...invalidCollectionImageUrls, ...nonexistentImageUrls])('invalidAssetImageUrl', async (url) => {
|
||||
const response = await fetch(new Request(url))
|
||||
expect(response.status).toBeOneOf([404, 500])
|
||||
})
|
||||
|
@ -6,12 +6,15 @@ test('should append meta tag to element', () => {
|
||||
} as unknown as Element
|
||||
const property = 'property'
|
||||
const content = 'content'
|
||||
const injector = new MetaTagInjector({
|
||||
title: 'test',
|
||||
url: 'testUrl',
|
||||
image: 'testImage',
|
||||
description: 'testDescription',
|
||||
})
|
||||
const injector = new MetaTagInjector(
|
||||
{
|
||||
title: 'test',
|
||||
url: 'testUrl',
|
||||
image: 'testImage',
|
||||
description: 'testDescription',
|
||||
},
|
||||
new Request('http://localhost')
|
||||
)
|
||||
injector.append(element, property, content)
|
||||
expect(element.append).toHaveBeenCalledWith(`<meta property="${property}" content="${content}"/>`, { html: true })
|
||||
|
||||
@ -36,3 +39,22 @@ test('should append meta tag to element', () => {
|
||||
|
||||
expect(element.append).toHaveBeenCalledTimes(13)
|
||||
})
|
||||
|
||||
test('should pass through header blocked paths', () => {
|
||||
const element = {
|
||||
append: jest.fn(),
|
||||
} as unknown as Element
|
||||
const request = new Request('http://localhost')
|
||||
request.headers.set('x-blocked-paths', '/')
|
||||
const injector = new MetaTagInjector(
|
||||
{
|
||||
title: 'test',
|
||||
url: 'testUrl',
|
||||
image: 'testImage',
|
||||
description: 'testDescription',
|
||||
},
|
||||
request
|
||||
)
|
||||
injector.element(element)
|
||||
expect(element.append).toHaveBeenCalledWith(`<meta property="x:blocked-paths" content="/"/>`, { html: true })
|
||||
})
|
||||
|
@ -10,7 +10,7 @@ type MetaTagInjectorInput = {
|
||||
* to inject meta tags into the <head> of an HTML document.
|
||||
*/
|
||||
export class MetaTagInjector implements HTMLRewriterElementContentHandlers {
|
||||
constructor(private input: MetaTagInjectorInput) {}
|
||||
constructor(private input: MetaTagInjectorInput, private request: Request) {}
|
||||
|
||||
append(element: Element, property: string, content: string) {
|
||||
element.append(`<meta property="${property}" content="${content}"/>`, { html: true })
|
||||
@ -38,5 +38,10 @@ export class MetaTagInjector implements HTMLRewriterElementContentHandlers {
|
||||
this.append(element, 'twitter:image', this.input.image)
|
||||
this.append(element, 'twitter:image:alt', this.input.title)
|
||||
}
|
||||
|
||||
const blockedPaths = this.request.headers.get('x-blocked-paths')
|
||||
if (blockedPaths) {
|
||||
this.append(element, 'x:blocked-paths', blockedPaths)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ export const onRequest: PagesFunction = async ({ params, request, next }) => {
|
||||
const { index } = params
|
||||
const collectionAddress = index[0]?.toString()
|
||||
const tokenId = index[1]?.toString()
|
||||
return getMetadataRequest(res, request.url, () => getAsset(collectionAddress, tokenId, request.url))
|
||||
return getMetadataRequest(res, request, () => getAsset(collectionAddress, tokenId, request.url))
|
||||
} catch (e) {
|
||||
return res
|
||||
}
|
||||
|
@ -41,8 +41,9 @@ exports[`should inject metadata for valid assets 1`] = `
|
||||
<link rel="preconnect" href="https://mainnet.infura.io/" crossorigin/>
|
||||
|
||||
<link rel="preload" href="/fonts/Basel-Book.woff" as="font" type="font/woff" crossorigin />
|
||||
<link rel="preload" href="/fonts/Basel-Book.woff2" as="font" type="font/woff2" crossorigin />
|
||||
<link rel="preload" href="/fonts/Basel-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
<link rel="preload" href="/fonts/Basel-Medium.woff2" as="font" type="font/woff2" crossorigin />
|
||||
|
||||
<style>
|
||||
* {
|
||||
@ -58,9 +59,9 @@ exports[`should inject metadata for valid assets 1`] = `
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Medium.woff) format('woff');
|
||||
url('/fonts/Basel-Medium.woff2') format('woff2'),
|
||||
url('/fonts/Basel-Medium.woff') format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
@ -68,15 +69,14 @@ exports[`should inject metadata for valid assets 1`] = `
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Book.woff) format('woff');
|
||||
url('/fonts/Basel-Book.woff') format('woff2'),
|
||||
url('/fonts/Basel-Book.woff') format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,8 +189,9 @@ exports[`should inject metadata for valid assets 2`] = `
|
||||
<link rel="preconnect" href="https://mainnet.infura.io/" crossorigin/>
|
||||
|
||||
<link rel="preload" href="/fonts/Basel-Book.woff" as="font" type="font/woff" crossorigin />
|
||||
<link rel="preload" href="/fonts/Basel-Book.woff2" as="font" type="font/woff2" crossorigin />
|
||||
<link rel="preload" href="/fonts/Basel-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
<link rel="preload" href="/fonts/Basel-Medium.woff2" as="font" type="font/woff2" crossorigin />
|
||||
|
||||
<style>
|
||||
* {
|
||||
@ -206,9 +207,9 @@ exports[`should inject metadata for valid assets 2`] = `
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Medium.woff) format('woff');
|
||||
url('/fonts/Basel-Medium.woff2') format('woff2'),
|
||||
url('/fonts/Basel-Medium.woff') format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
@ -216,15 +217,14 @@ exports[`should inject metadata for valid assets 2`] = `
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Book.woff) format('woff');
|
||||
url('/fonts/Basel-Book.woff') format('woff2'),
|
||||
url('/fonts/Basel-Book.woff') format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -337,8 +337,9 @@ exports[`should inject metadata for valid assets 3`] = `
|
||||
<link rel="preconnect" href="https://mainnet.infura.io/" crossorigin/>
|
||||
|
||||
<link rel="preload" href="/fonts/Basel-Book.woff" as="font" type="font/woff" crossorigin />
|
||||
<link rel="preload" href="/fonts/Basel-Book.woff2" as="font" type="font/woff2" crossorigin />
|
||||
<link rel="preload" href="/fonts/Basel-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
<link rel="preload" href="/fonts/Basel-Medium.woff2" as="font" type="font/woff2" crossorigin />
|
||||
|
||||
<style>
|
||||
* {
|
||||
@ -354,9 +355,9 @@ exports[`should inject metadata for valid assets 3`] = `
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Medium.woff) format('woff');
|
||||
url('/fonts/Basel-Medium.woff2') format('woff2'),
|
||||
url('/fonts/Basel-Medium.woff') format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
@ -364,15 +365,14 @@ exports[`should inject metadata for valid assets 3`] = `
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Book.woff) format('woff');
|
||||
url('/fonts/Basel-Book.woff') format('woff2'),
|
||||
url('/fonts/Basel-Book.woff') format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ export const onRequest: PagesFunction = async ({ params, request, next }) => {
|
||||
try {
|
||||
const { index } = params
|
||||
const collectionAddress = index?.toString()
|
||||
return getMetadataRequest(res, request.url, () => getCollection(collectionAddress, request.url))
|
||||
return getMetadataRequest(res, request, () => getCollection(collectionAddress, request.url))
|
||||
} catch (e) {
|
||||
return res
|
||||
}
|
||||
|
@ -41,8 +41,9 @@ exports[`should inject metadata for collections 1`] = `
|
||||
<link rel="preconnect" href="https://mainnet.infura.io/" crossorigin/>
|
||||
|
||||
<link rel="preload" href="/fonts/Basel-Book.woff" as="font" type="font/woff" crossorigin />
|
||||
<link rel="preload" href="/fonts/Basel-Book.woff2" as="font" type="font/woff2" crossorigin />
|
||||
<link rel="preload" href="/fonts/Basel-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
<link rel="preload" href="/fonts/Basel-Medium.woff2" as="font" type="font/woff2" crossorigin />
|
||||
|
||||
<style>
|
||||
* {
|
||||
@ -58,9 +59,9 @@ exports[`should inject metadata for collections 1`] = `
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Medium.woff) format('woff');
|
||||
url('/fonts/Basel-Medium.woff2') format('woff2'),
|
||||
url('/fonts/Basel-Medium.woff') format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
@ -68,15 +69,14 @@ exports[`should inject metadata for collections 1`] = `
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Book.woff) format('woff');
|
||||
url('/fonts/Basel-Book.woff') format('woff2'),
|
||||
url('/fonts/Basel-Book.woff') format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,8 +189,9 @@ exports[`should inject metadata for collections 2`] = `
|
||||
<link rel="preconnect" href="https://mainnet.infura.io/" crossorigin/>
|
||||
|
||||
<link rel="preload" href="/fonts/Basel-Book.woff" as="font" type="font/woff" crossorigin />
|
||||
<link rel="preload" href="/fonts/Basel-Book.woff2" as="font" type="font/woff2" crossorigin />
|
||||
<link rel="preload" href="/fonts/Basel-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
<link rel="preload" href="/fonts/Basel-Medium.woff2" as="font" type="font/woff2" crossorigin />
|
||||
|
||||
<style>
|
||||
* {
|
||||
@ -206,9 +207,9 @@ exports[`should inject metadata for collections 2`] = `
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Medium.woff) format('woff');
|
||||
url('/fonts/Basel-Medium.woff2') format('woff2'),
|
||||
url('/fonts/Basel-Medium.woff') format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
@ -216,15 +217,14 @@ exports[`should inject metadata for collections 2`] = `
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Book.woff) format('woff');
|
||||
url('/fonts/Basel-Book.woff') format('woff2'),
|
||||
url('/fonts/Basel-Book.woff') format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -337,8 +337,9 @@ exports[`should inject metadata for collections 3`] = `
|
||||
<link rel="preconnect" href="https://mainnet.infura.io/" crossorigin/>
|
||||
|
||||
<link rel="preload" href="/fonts/Basel-Book.woff" as="font" type="font/woff" crossorigin />
|
||||
<link rel="preload" href="/fonts/Basel-Book.woff2" as="font" type="font/woff2" crossorigin />
|
||||
<link rel="preload" href="/fonts/Basel-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
<link rel="preload" href="/fonts/Basel-Medium.woff2" as="font" type="font/woff2" crossorigin />
|
||||
|
||||
<style>
|
||||
* {
|
||||
@ -354,9 +355,9 @@ exports[`should inject metadata for collections 3`] = `
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Medium.woff) format('woff');
|
||||
url('/fonts/Basel-Medium.woff2') format('woff2'),
|
||||
url('/fonts/Basel-Medium.woff') format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
@ -364,15 +365,14 @@ exports[`should inject metadata for collections 3`] = `
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Book.woff) format('woff');
|
||||
url('/fonts/Basel-Book.woff') format('woff2'),
|
||||
url('/fonts/Basel-Book.woff') format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -443,151 +443,3 @@ exports[`should inject metadata for collections 3`] = `
|
||||
</html>
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`should inject metadata for collections 4`] = `
|
||||
"<!DOCTYPE html>
|
||||
<html translate="no">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<title>Uniswap Interface</title>
|
||||
|
||||
<!--
|
||||
will be replaced with the URL of the \`public\` folder during build.
|
||||
Only files inside the \`public\` folder can be referenced from the HTML.
|
||||
-->
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="/images/192x192_App_Icon.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="/images/512x512_App_Icon.png" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta name="theme-color" content="#fff" />
|
||||
<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
|
||||
content="script-src 'self' 'unsafe-inline'"
|
||||
|
||||
/>
|
||||
|
||||
<!--
|
||||
Apple Smart App Banner for Safari on iOS
|
||||
https://developer.apple.com/documentation/webkit/promoting_apps_with_smart_app_banners
|
||||
-->
|
||||
<meta name="apple-itunes-app" content="app-id=6443944476">
|
||||
|
||||
<!--
|
||||
manifest.json provides metadata used when the app is installed as a PWA.
|
||||
See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
|
||||
<link rel="preconnect" href="https://api.uniswap.org/" crossorigin/>
|
||||
<link rel="preconnect" href="https://mainnet.infura.io/" crossorigin/>
|
||||
|
||||
<link rel="preload" href="/fonts/Basel-Book.woff" as="font" type="font/woff" crossorigin />
|
||||
<link rel="preload" href="/fonts/Basel-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
|
||||
<style>
|
||||
* {
|
||||
font-family: 'Basel', sans-serif;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/**
|
||||
Explicitly load Basel var from public/ so it does not block LCP's critical path.
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Basel';
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Medium.woff) format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Basel';
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Book.woff) format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
button {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
font-weight: 485;
|
||||
font-variant: none;
|
||||
font-smooth: always;
|
||||
text-rendering: optimizeLegibility !important;
|
||||
-webkit-font-smoothing: antialiased !important;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/* Use this to apply network-specific gradient backgrounds, in RadialGradientByChainUpdater.ts */
|
||||
#background-radial-gradient {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
pointer-events: none;
|
||||
width: 200vw;
|
||||
height: 200vh;
|
||||
transform: translate(-50vw, -100vh);
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html {
|
||||
background: linear-gradient(rgb(19, 19, 19) 0%, rgb(19, 19, 19) 100%);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
html {
|
||||
background: radial-gradient(100% 100% at 50% 0%, rgba(255, 184, 226, 0) 0%, rgba(255, 255, 255, 0) 100%), rgb(255, 255, 255);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script defer src="/static/js/bundle.js"></script><meta property="og:title" content="0xed5af388653567af2f388e6224dc7c4b3241c545 on Uniswap"/><meta property="og:image" content="http://127.0.0.1:3000/api/image/nfts/collection/0xed5af388653567af2f388e6224dc7c4b3241c545"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="0xed5af388653567af2f388e6224dc7c4b3241c545 on Uniswap"/><meta property="og:type" content="website"/><meta property="og:url" content="http://127.0.0.1:3000/nfts/collection/0xed5af388653567af2f388e6224dc7c4b3241c545"/><meta property="twitter:card" content="summary_large_image"/><meta property="twitter:title" content="0xed5af388653567af2f388e6224dc7c4b3241c545 on Uniswap"/><meta property="twitter:image" content="http://127.0.0.1:3000/api/image/nfts/collection/0xed5af388653567af2f388e6224dc7c4b3241c545"/><meta property="twitter:image:alt" content="0xed5af388653567af2f388e6224dc7c4b3241c545 on Uniswap"/></head>
|
||||
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
|
||||
<div id="root">
|
||||
<!-- Triggers the font to load immediately and then is replaced by the app -->
|
||||
<div> </div>
|
||||
</div>
|
||||
|
||||
<div id="background-radial-gradient"></div>
|
||||
</body>
|
||||
</html>
|
||||
"
|
||||
`;
|
||||
|
@ -16,15 +16,7 @@ const collections = [
|
||||
},
|
||||
]
|
||||
|
||||
const nonexistentCollections = [
|
||||
{
|
||||
address: '0xed5af388653567af2f388e6224dc7c4b3241c545',
|
||||
collectionName: '0xed5af388653567af2f388e6224dc7c4b3241c545',
|
||||
image: 'http://127.0.0.1:3000/api/image/nfts/collection/0xed5af388653567af2f388e6224dc7c4b3241c545',
|
||||
},
|
||||
]
|
||||
|
||||
test.each([...collections, ...nonexistentCollections])('should inject metadata for collections', async (collection) => {
|
||||
test.each([...collections])('should inject metadata for collections', async (collection) => {
|
||||
const url = 'http://127.0.0.1:3000/nfts/collection/' + collection.address
|
||||
const body = await fetch(new Request(url)).then((res) => res.text())
|
||||
expect(body).toMatchSnapshot()
|
||||
@ -42,24 +34,33 @@ test.each([...collections, ...nonexistentCollections])('should inject metadata f
|
||||
expect(body).toContain(`<meta property="twitter:image:alt" content="${collection.collectionName} on Uniswap"/>`)
|
||||
})
|
||||
|
||||
const nonexistentCollections = [
|
||||
{
|
||||
address: '0xed5af388653567af2f388e6224dc7c4b3241c545',
|
||||
},
|
||||
]
|
||||
|
||||
const invalidCollections = [
|
||||
{
|
||||
address: '0xd3adb33f',
|
||||
},
|
||||
]
|
||||
|
||||
test.each(invalidCollections)('should not inject metadata for nonexistent collections', async (collection) => {
|
||||
const url = 'http://127.0.0.1:3000/nfts/collection/' + collection.address
|
||||
const body = await fetch(new Request(url)).then((res) => res.text())
|
||||
expect(body).not.toContain('og:title')
|
||||
expect(body).not.toContain('og:image')
|
||||
expect(body).not.toContain('og:image:width')
|
||||
expect(body).not.toContain('og:image:height')
|
||||
expect(body).not.toContain('og:type')
|
||||
expect(body).not.toContain('og:url')
|
||||
expect(body).not.toContain('og:image:alt')
|
||||
expect(body).not.toContain('twitter:card')
|
||||
expect(body).not.toContain('twitter:title')
|
||||
expect(body).not.toContain('twitter:image')
|
||||
expect(body).not.toContain('twitter:image:alt')
|
||||
})
|
||||
test.each([...invalidCollections, ...nonexistentCollections])(
|
||||
'should not inject metadata for nonexistent collections',
|
||||
async (collection) => {
|
||||
const url = 'http://127.0.0.1:3000/nfts/collection/' + collection.address
|
||||
const body = await fetch(new Request(url)).then((res) => res.text())
|
||||
expect(body).not.toContain('og:title')
|
||||
expect(body).not.toContain('og:image')
|
||||
expect(body).not.toContain('og:image:width')
|
||||
expect(body).not.toContain('og:image:height')
|
||||
expect(body).not.toContain('og:type')
|
||||
expect(body).not.toContain('og:url')
|
||||
expect(body).not.toContain('og:image:alt')
|
||||
expect(body).not.toContain('twitter:card')
|
||||
expect(body).not.toContain('twitter:title')
|
||||
expect(body).not.toContain('twitter:image')
|
||||
expect(body).not.toContain('twitter:image:alt')
|
||||
}
|
||||
)
|
||||
|
@ -11,7 +11,7 @@ export const onRequest: PagesFunction = async ({ params, request, next }) => {
|
||||
if (!tokenAddress) {
|
||||
return res
|
||||
}
|
||||
return getMetadataRequest(res, request.url, () => getToken(networkName, tokenAddress, request.url))
|
||||
return getMetadataRequest(res, request, () => getToken(networkName, tokenAddress, request.url))
|
||||
} catch (e) {
|
||||
return res
|
||||
}
|
||||
|
@ -41,8 +41,9 @@ exports[`should inject metadata for valid tokens 1`] = `
|
||||
<link rel="preconnect" href="https://mainnet.infura.io/" crossorigin/>
|
||||
|
||||
<link rel="preload" href="/fonts/Basel-Book.woff" as="font" type="font/woff" crossorigin />
|
||||
<link rel="preload" href="/fonts/Basel-Book.woff2" as="font" type="font/woff2" crossorigin />
|
||||
<link rel="preload" href="/fonts/Basel-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
<link rel="preload" href="/fonts/Basel-Medium.woff2" as="font" type="font/woff2" crossorigin />
|
||||
|
||||
<style>
|
||||
* {
|
||||
@ -58,9 +59,9 @@ exports[`should inject metadata for valid tokens 1`] = `
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Medium.woff) format('woff');
|
||||
url('/fonts/Basel-Medium.woff2') format('woff2'),
|
||||
url('/fonts/Basel-Medium.woff') format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
@ -68,15 +69,14 @@ exports[`should inject metadata for valid tokens 1`] = `
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Book.woff) format('woff');
|
||||
url('/fonts/Basel-Book.woff') format('woff2'),
|
||||
url('/fonts/Basel-Book.woff') format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,8 +189,9 @@ exports[`should inject metadata for valid tokens 2`] = `
|
||||
<link rel="preconnect" href="https://mainnet.infura.io/" crossorigin/>
|
||||
|
||||
<link rel="preload" href="/fonts/Basel-Book.woff" as="font" type="font/woff" crossorigin />
|
||||
<link rel="preload" href="/fonts/Basel-Book.woff2" as="font" type="font/woff2" crossorigin />
|
||||
<link rel="preload" href="/fonts/Basel-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
<link rel="preload" href="/fonts/Basel-Medium.woff2" as="font" type="font/woff2" crossorigin />
|
||||
|
||||
<style>
|
||||
* {
|
||||
@ -206,9 +207,9 @@ exports[`should inject metadata for valid tokens 2`] = `
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Medium.woff) format('woff');
|
||||
url('/fonts/Basel-Medium.woff2') format('woff2'),
|
||||
url('/fonts/Basel-Medium.woff') format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
@ -216,15 +217,14 @@ exports[`should inject metadata for valid tokens 2`] = `
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Book.woff) format('woff');
|
||||
url('/fonts/Basel-Book.woff') format('woff2'),
|
||||
url('/fonts/Basel-Book.woff') format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -337,8 +337,9 @@ exports[`should inject metadata for valid tokens 3`] = `
|
||||
<link rel="preconnect" href="https://mainnet.infura.io/" crossorigin/>
|
||||
|
||||
<link rel="preload" href="/fonts/Basel-Book.woff" as="font" type="font/woff" crossorigin />
|
||||
<link rel="preload" href="/fonts/Basel-Book.woff2" as="font" type="font/woff2" crossorigin />
|
||||
<link rel="preload" href="/fonts/Basel-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
<link rel="preload" href="/fonts/Basel-Medium.woff2" as="font" type="font/woff2" crossorigin />
|
||||
|
||||
<style>
|
||||
* {
|
||||
@ -354,9 +355,9 @@ exports[`should inject metadata for valid tokens 3`] = `
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Medium.woff) format('woff');
|
||||
url('/fonts/Basel-Medium.woff2') format('woff2'),
|
||||
url('/fonts/Basel-Medium.woff') format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
@ -364,15 +365,14 @@ exports[`should inject metadata for valid tokens 3`] = `
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Book.woff) format('woff');
|
||||
url('/fonts/Basel-Book.woff') format('woff2'),
|
||||
url('/fonts/Basel-Book.woff') format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -485,8 +485,9 @@ exports[`should inject metadata for valid tokens 4`] = `
|
||||
<link rel="preconnect" href="https://mainnet.infura.io/" crossorigin/>
|
||||
|
||||
<link rel="preload" href="/fonts/Basel-Book.woff" as="font" type="font/woff" crossorigin />
|
||||
<link rel="preload" href="/fonts/Basel-Book.woff2" as="font" type="font/woff2" crossorigin />
|
||||
<link rel="preload" href="/fonts/Basel-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
<link rel="preload" href="/fonts/Basel-Medium.woff2" as="font" type="font/woff2" crossorigin />
|
||||
|
||||
<style>
|
||||
* {
|
||||
@ -502,9 +503,9 @@ exports[`should inject metadata for valid tokens 4`] = `
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Medium.woff) format('woff');
|
||||
url('/fonts/Basel-Medium.woff2') format('woff2'),
|
||||
url('/fonts/Basel-Medium.woff') format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
@ -512,15 +513,14 @@ exports[`should inject metadata for valid tokens 4`] = `
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Book.woff) format('woff');
|
||||
url('/fonts/Basel-Book.woff') format('woff2'),
|
||||
url('/fonts/Basel-Book.woff') format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,13 +4,13 @@ import { Data } from './cache'
|
||||
|
||||
export async function getMetadataRequest(
|
||||
res: Promise<Response>,
|
||||
url: string,
|
||||
request: Request,
|
||||
getData: () => Promise<Data | undefined>
|
||||
) {
|
||||
try {
|
||||
const cachedData = await getRequest(url, getData, (data): data is Data => true)
|
||||
const cachedData = await getRequest(request.url, getData, (data): data is Data => true)
|
||||
if (cachedData) {
|
||||
return new HTMLRewriter().on('head', new MetaTagInjector(cachedData)).transform(await res)
|
||||
return new HTMLRewriter().on('head', new MetaTagInjector(cachedData, request)).transform(await res)
|
||||
} else {
|
||||
return res
|
||||
}
|
||||
|
@ -13,7 +13,8 @@ const forkingConfig = {
|
||||
const forks = {
|
||||
[ChainId.MAINNET]: {
|
||||
url: `https://mainnet.infura.io/v3/${process.env.REACT_APP_INFURA_KEY}`,
|
||||
blockNumber: UNIVERSAL_ROUTER_CREATION_BLOCK(ChainId.MAINNET),
|
||||
// Temporarily hardcoding this to fix e2e tests as we investigate source of swap tests failing on older blocknumbers
|
||||
blockNumber: 18537387,
|
||||
...forkingConfig,
|
||||
},
|
||||
[ChainId.POLYGON]: {
|
||||
|
@ -28,7 +28,6 @@ const linguiConfig = {
|
||||
'ca-ES',
|
||||
'cs-CZ',
|
||||
'da-DK',
|
||||
'de-DE',
|
||||
'el-GR',
|
||||
'en-US',
|
||||
'es-ES',
|
||||
|
47
package.json
@ -13,6 +13,7 @@
|
||||
"graphql:generate:thegraph": "graphql-codegen --config graphql.thegraph.codegen.config.ts",
|
||||
"graphql:generate": "yarn graphql:generate:data && yarn graphql:generate:thegraph",
|
||||
"graphql": "yarn graphql:fetch && yarn graphql:generate",
|
||||
"sitemap:generate": "node scripts/generate-sitemap.js",
|
||||
"i18n:extract": "lingui extract --locale en-US",
|
||||
"i18n:compile": "lingui compile",
|
||||
"i18n": "yarn i18n:extract --clean && yarn i18n:compile",
|
||||
@ -114,7 +115,8 @@
|
||||
"@types/ua-parser-js": "^0.7.36",
|
||||
"@types/uuid": "^8.3.4",
|
||||
"@types/wcag-contrast": "^3.0.0",
|
||||
"@uniswap/default-token-list": "^11.2.0",
|
||||
"@types/xml2js": "^0.4.12",
|
||||
"@uniswap/default-token-list": "^11.8.0",
|
||||
"@uniswap/eslint-config": "^1.2.0",
|
||||
"@vanilla-extract/jest-transform": "^1.1.1",
|
||||
"@vanilla-extract/webpack-plugin": "^2.2.0",
|
||||
@ -127,7 +129,7 @@
|
||||
"cypress": "12.12.0",
|
||||
"cypress-hardhat": "^2.5.0",
|
||||
"env-cmd": "^10.1.0",
|
||||
"eslint": "^7.11.0",
|
||||
"eslint": "8.44.0",
|
||||
"eslint-plugin-import": "^2.27",
|
||||
"eslint-plugin-rulesdir": "^0.2.2",
|
||||
"hardhat": "^2.14.0",
|
||||
@ -155,7 +157,6 @@
|
||||
"terser": "^5.19.4",
|
||||
"terser-webpack-plugin": "^5.3.9",
|
||||
"ts-jest": "^29.1.1",
|
||||
"ts-transform-graphql-tag": "^0.2.1",
|
||||
"tsafe": "^1.6.4",
|
||||
"typechain": "^5.0.0",
|
||||
"typescript": "^4.9.4",
|
||||
@ -164,6 +165,9 @@
|
||||
"wrangler": "^3.7.0",
|
||||
"yarn-deduplicate": "^6.0.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"@uniswap/sdk-core": "4.0.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.7.2",
|
||||
"@coinbase/wallet-sdk": "^3.6.4",
|
||||
@ -189,20 +193,21 @@
|
||||
"@sentry/react": "^7.45.0",
|
||||
"@sentry/tracing": "^7.45.0",
|
||||
"@sentry/types": "^7.45.0",
|
||||
"@types/react-helmet": "^6.1.7",
|
||||
"@types/react-window-infinite-loader": "^1.0.6",
|
||||
"@uniswap/analytics": "^1.4.0",
|
||||
"@uniswap/analytics-events": "^2.23.0",
|
||||
"@uniswap/analytics": "1.5.0",
|
||||
"@uniswap/analytics-events": "^2.28.0",
|
||||
"@uniswap/governance": "^1.0.2",
|
||||
"@uniswap/liquidity-staker": "^1.0.2",
|
||||
"@uniswap/merkle-distributor": "^1.0.1",
|
||||
"@uniswap/permit2-sdk": "^1.2.0",
|
||||
"@uniswap/redux-multicall": "^1.1.8",
|
||||
"@uniswap/router-sdk": "^1.6.0",
|
||||
"@uniswap/sdk-core": "^4.0.3",
|
||||
"@uniswap/router-sdk": "^1.7.1",
|
||||
"@uniswap/sdk-core": "4.0.7",
|
||||
"@uniswap/smart-order-router": "^3.15.0",
|
||||
"@uniswap/token-lists": "^1.0.0-beta.33",
|
||||
"@uniswap/uniswapx-sdk": "^1.3.0",
|
||||
"@uniswap/universal-router-sdk": "^1.5.6",
|
||||
"@uniswap/uniswapx-sdk": "^1.4.1",
|
||||
"@uniswap/universal-router-sdk": "^1.5.8",
|
||||
"@uniswap/v2-core": "^1.0.1",
|
||||
"@uniswap/v2-periphery": "^1.1.0-beta.0",
|
||||
"@uniswap/v2-sdk": "^3.2.0",
|
||||
@ -220,16 +225,16 @@
|
||||
"@visx/react-spring": "^2.12.2",
|
||||
"@visx/responsive": "^2.10.0",
|
||||
"@visx/shape": "^2.11.1",
|
||||
"@web3-react/coinbase-wallet": "^8.2.2",
|
||||
"@web3-react/core": "^8.2.2",
|
||||
"@web3-react/eip1193": "^8.2.2",
|
||||
"@web3-react/empty": "^8.2.2",
|
||||
"@web3-react/gnosis-safe": "^8.2.3",
|
||||
"@web3-react/metamask": "^8.2.3",
|
||||
"@web3-react/network": "^8.2.2",
|
||||
"@web3-react/types": "^8.2.2",
|
||||
"@web3-react/url": "^8.2.2",
|
||||
"@web3-react/walletconnect-v2": "^8.5.0",
|
||||
"@web3-react/coinbase-wallet": "^8.2.3",
|
||||
"@web3-react/core": "^8.2.3",
|
||||
"@web3-react/eip1193": "^8.2.3",
|
||||
"@web3-react/empty": "^8.2.3",
|
||||
"@web3-react/gnosis-safe": "^8.2.4",
|
||||
"@web3-react/metamask": "^8.2.4",
|
||||
"@web3-react/network": "^8.2.3",
|
||||
"@web3-react/types": "^8.2.3",
|
||||
"@web3-react/url": "^8.2.3",
|
||||
"@web3-react/walletconnect-v2": "^8.5.1",
|
||||
"ajv": "^8.11.0",
|
||||
"ajv-formats": "^2.1.1",
|
||||
"array.prototype.flat": "^1.2.4",
|
||||
@ -253,6 +258,8 @@
|
||||
"ms": "^2.1.3",
|
||||
"multicodec": "^3.0.1",
|
||||
"multihashes": "^4.0.2",
|
||||
"nock": "^13.3.3",
|
||||
"node-fetch": "^3.3.2",
|
||||
"node-vibrant": "^3.2.1-alpha.1",
|
||||
"numbro": "^2.3.6",
|
||||
"polished": "^3.3.2",
|
||||
@ -263,6 +270,7 @@
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-feather": "^2.0.8",
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-infinite-scroll-component": "^6.1.0",
|
||||
"react-is": "^17.0.2",
|
||||
"react-markdown": "^4.3.1",
|
||||
@ -292,6 +300,7 @@
|
||||
"workbox-navigation-preload": "^6.1.0",
|
||||
"workbox-precaching": "^6.1.0",
|
||||
"workbox-routing": "^6.1.0",
|
||||
"xml2js": "^0.6.2",
|
||||
"zustand": "^4.3.6"
|
||||
},
|
||||
"engines": {
|
||||
|
0
patches/@web3-react+walletconnect-v2+8.5.0.patch → patches/@web3-react+walletconnect-v2+8.5.1.patch
@ -3,27 +3,27 @@
|
||||
"relation": ["delegate_permission/common.handle_all_urls"],
|
||||
"target": {
|
||||
"namespace": "android_app",
|
||||
"package_name": "com.uniswap",
|
||||
"package_name": "com.uniswap.mobile",
|
||||
"sha256_cert_fingerprints":
|
||||
["97:A5:81:51:DA:AF:8F:6E:65:3A:90:1E:82:12:6C:FB:61:2D:36:C7:CF:20:61:6B:A3:4C:52:CA:BC:58:43:8E", "F9:E9:E3:F0:04:28:66:62:81:44:50:7E:D6:A9:5F:B9:65:39:02:70:1D:13:74:15:D3:E1:A3:1B:D4:38:3A:1F"]
|
||||
["49:D9:3D:5D:FB:AA:64:A4:64:80:85:0F:39:A8:C1:D9:25:D3:D4:BC:8E:6B:1F:45:0C:EA:AF:B1:0C:27:DF:B8", "F9:E9:E3:F0:04:28:66:62:81:44:50:7E:D6:A9:5F:B9:65:39:02:70:1D:13:74:15:D3:E1:A3:1B:D4:38:3A:1F"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"relation": ["delegate_permission/common.handle_all_urls"],
|
||||
"target": {
|
||||
"namespace": "android_app",
|
||||
"package_name": "com.uniswap.beta",
|
||||
"package_name": "com.uniswap.mobile.beta",
|
||||
"sha256_cert_fingerprints":
|
||||
["E5:39:87:DC:4D:FD:4C:1B:A6:74:36:7D:3A:3B:6B:ED:9E:B3:66:89:92:8A:1B:B8:FC:1B:22:56:56:B4:46:A3", "54:4B:62:33:17:9B:5F:A8:E6:5D:D3:A6:E5:9D:80:5F:A5:02:7F:E2:14:B8:C1:7A:AC:4B:8D:E0:65:49:87:41"]
|
||||
["75:41:9C:2D:01:4A:88:4E:8D:C6:EF:E5:51:54:28:6B:99:05:31:43:AD:84:B4:EB:39:28:B8:C3:C4:CE:48:E3", "54:4B:62:33:17:9B:5F:A8:E6:5D:D3:A6:E5:9D:80:5F:A5:02:7F:E2:14:B8:C1:7A:AC:4B:8D:E0:65:49:87:41"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"relation": ["delegate_permission/common.handle_all_urls"],
|
||||
"target": {
|
||||
"namespace": "android_app",
|
||||
"package_name": "com.uniswap.dev",
|
||||
"package_name": "com.uniswap.mobile.dev",
|
||||
"sha256_cert_fingerprints":
|
||||
["5A:6D:23:50:2F:1E:0D:01:DC:96:65:F3:3A:18:4C:4C:8C:67:E0:09:99:9B:B1:9B:BF:44:99:D0:D1:D0:FC:5E", "02:E6:1C:76:8C:75:C3:78:C8:8C:FE:7B:2E:8F:4B:E1:FA:47:F2:F6:1A:DB:57:69:4A:41:99:C6:71:2C:AB:E3", "FA:C6:17:45:DC:09:03:78:6F:B9:ED:E6:2A:96:2B:39:9F:73:48:F0:BB:6F:89:9B:83:32:66:75:91:03:3B:9C"]
|
||||
["45:F8:15:02:C5:4F:AD:82:E7:51:F0:9C:D1:CA:77:C8:C9:BF:06:A6:D9:5A:55:4F:9E:B8:5F:81:33:2B:D0:DB", "02:E6:1C:76:8C:75:C3:78:C8:8C:FE:7B:2E:8F:4B:E1:FA:47:F2:F6:1A:DB:57:69:4A:41:99:C6:71:2C:AB:E3", "FA:C6:17:45:DC:09:03:78:6F:B9:ED:E6:2A:96:2B:39:9F:73:48:F0:BB:6F:89:9B:83:32:66:75:91:03:3B:9C"]
|
||||
}
|
||||
}
|
||||
]
|
99
public/app-sitemap.xml
Normal file
@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/</loc>
|
||||
<lastmod>2023-10-11T19:57:27.976Z</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>1.0</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/tokens</loc>
|
||||
<lastmod>2023-10-11T19:57:27.976Z</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/send</loc>
|
||||
<lastmod>2023-10-11T19:57:27.976Z</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/swap</loc>
|
||||
<lastmod>2023-10-11T19:57:27.976Z</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.9</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/pool/v2/find</loc>
|
||||
<lastmod>2023-10-11T19:57:27.976Z</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/pool/v2</loc>
|
||||
<lastmod>2023-10-11T19:57:27.976Z</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/pool</loc>
|
||||
<lastmod>2023-10-11T19:57:27.976Z</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/pools/v2/find</loc>
|
||||
<lastmod>2023-10-11T19:57:27.976Z</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/pools/v2</loc>
|
||||
<lastmod>2023-10-11T19:57:27.976Z</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/pools</loc>
|
||||
<lastmod>2023-10-11T19:57:27.976Z</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/add/v2</loc>
|
||||
<lastmod>2023-10-11T19:57:27.976Z</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/add</loc>
|
||||
<lastmod>2023-10-11T19:57:27.976Z</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/migrate/v2</loc>
|
||||
<lastmod>2023-10-11T19:57:27.976Z</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts</loc>
|
||||
<lastmod>2023-10-11T19:57:27.976Z</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/profile</loc>
|
||||
<lastmod>2023-10-11T19:57:27.976Z</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.6</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/create-proposal</loc>
|
||||
<lastmod>2023-10-11T19:57:27.976Z</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.5</priority>
|
||||
</url>
|
||||
</urlset>
|
BIN
public/fonts/Basel-Book.woff2
Normal file
BIN
public/fonts/Basel-Medium.woff2
Normal file
@ -40,8 +40,9 @@
|
||||
<link rel="preconnect" href="https://mainnet.infura.io/" crossorigin/>
|
||||
|
||||
<link rel="preload" href="%PUBLIC_URL%/fonts/Basel-Book.woff" as="font" type="font/woff" crossorigin />
|
||||
<link rel="preload" href="%PUBLIC_URL%/fonts/Basel-Book.woff2" as="font" type="font/woff2" crossorigin />
|
||||
<link rel="preload" href="%PUBLIC_URL%/fonts/Basel-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
<link rel="preload" href="%PUBLIC_URL%/fonts/Basel-Medium.woff2" as="font" type="font/woff2" crossorigin />
|
||||
|
||||
<style>
|
||||
* {
|
||||
@ -57,9 +58,9 @@
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(%PUBLIC_URL%/fonts/Basel-Medium.woff) format('woff');
|
||||
url('%PUBLIC_URL%/fonts/Basel-Medium.woff2') format('woff2'),
|
||||
url('%PUBLIC_URL%/fonts/Basel-Medium.woff') format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
@ -67,15 +68,14 @@
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(%PUBLIC_URL%/fonts/Basel-Book.woff) format('woff');
|
||||
url('%PUBLIC_URL%/fonts/Basel-Book.woff') format('woff2'),
|
||||
url('%PUBLIC_URL%/fonts/Basel-Book.woff') format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
518
public/nfts-sitemap.xml
Normal file
@ -0,0 +1,518 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x60e4d786628fea6478f785a6d7e704777c86a7c6</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xed5af388653567af2f388e6224dc7c4b3241c544</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x34d85c9cdeb23fa97cb08333b511ac86e1c4e258</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x99a9b7c1116f9ceeb1652de04d5969cce509b069</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x49cf6f5d44e70224e2e23fdcdd2c053f30ada28b</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xb7f7f6c52f2e2fdb1963eab30438024864c313f6</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x23581767a106ae21c074b2276d25e5c3e136a68b</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x8a90cab2b38dba80c64b7734e58ee1db38b8992e</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xba30e5f9bb24caa003e9f2f0497ad287fdf95623</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xbd3531da5cf5857e7cfaa92426877b022e612cf8</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x7bd29408f11d2bfc23c34f18275bbf23bb716bc7</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x306b1ea3ecdf94ab739f1910bbda052ed4a9f949</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x1a92f7381b9f03921564a437210bb9396471050c</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x5cc5b05a8a13e3fbdb0bb9fccd98d38e50f90c38</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x5af0d9827e0c53e4799bb226655a1de152a425a5</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x3bf2922f4520a8ba0c2efc3d2a1539678dad5e9d</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xe785e82358879f061bc3dcac6f0444462d4b5330</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x76be3b62873462d2142405439777e971754e8e77</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xfd43af6d3fe1b916c026f6ac35b3ede068d1ca01</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x1cb1a5e65610aeff2551a50f76a87a7d3fb649c6</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xff9c1b15b16263c61d017ee9f65c50e4ae0113d7</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x6339e5e072086621540d0362c4e3cea0d643e114</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xb932a70a57673d89f4acffbe830e8ed7f75fb9e0</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x79fcdef22feed20eddacbb2587640e45491b757f</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xa3aee8bce55beea1951ef834b99f3ac60d1abeeb</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x769272677fab02575e84945f03eca517acc544cc</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x4db1f25d3d98600140dfc18deb7515be5bd293af</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x34eebee6942d8def3c125458d1a86e0a897fd6f9</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x59468516a8259058bad1ca5f8f4bff190d30e066</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x394e3d3044fc89fcdd966d3cb35ac0b32b0cda91</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x60bb1e2aa1c9acafb4d34f71585d7e959f387769</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x28472a58a490c5e09a238847f66a68a47cc76f0f</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x341a1c534248966c4b6afad165b98daed4b964ef</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x82c7a8f707110f5fbb16184a5933e9f78a34c6ab</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xccc441ac31f02cd96c153db6fd5fe0a2f4e6a68d</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x764aeebcf425d56800ef2c84f2578689415a2daa</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x160c404b2b49cbc3240055ceaee026df1e8497a0</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xd2f668a8461d6761115daf8aeb3cdf5f40c532c6</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x39ee2c7b3cb80254225884ca001f57118c8f21b6</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xd774557b647330c91bf44cfeab205095f7e6c367</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x1792a96e5668ad7c167ab804a100ce42395ce54d</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xf87e31492faf9a91b02ee0deaad50d51d56d5d4d</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x04afa589e2b933f9463c5639f412b183ec062505</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xe75512aa3bec8f00434bbd6ad8b0a3fbff100ad6</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x348fc118bcc65a92dc033a951af153d14d945312</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x892848074ddea461a15f337250da3ce55580ca85</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x5946aeaab44e65eb370ffaa6a7ef2218cff9b47d</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x282bdd42f4eb70e7a9d9f40c8fea0825b7f68c5d</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x4b15a9c28034dc83db40cd810001427d3bd7163d</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x7ea3cca10668b8346aec0bf1844a49e995527c8b</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xb852c6b5892256c264cc2c888ea462189154d8d7</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x9378368ba6b85c1fba5b131b530f5f5bedf21a18</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x2acab3dea77832c09420663b0e1cb386031ba17b</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x0c2e57efddba8c768147d1fdf9176a0a6ebd5d83</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x08d7c0242953446436f34b4c78fe9da38c73668d</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x8943c7bac1914c9a7aba750bf2b6b09fd21037e0</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x364c828ee171616a39897688a831c2499ad972ec</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x7f36182dee28c45de6072a34d29855bae76dbe2f</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xf61f24c2d93bf2de187546b14425bf631f28d6dc</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x797a48c46be32aafcedcfd3d8992493d8a1f256b</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x123b30e25973fecd8354dd5f41cc45a3065ef88c</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x6632a9d63e142f17a668064d41a21193b49b41a0</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xf4ee95274741437636e748ddac70818b4ed7d043</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x57a204aa1042f6e66dd7730813f4024114d74f37</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xd1258db6ac08eb0e625b75b371c023da478e94a9</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x75e95ba5997eb235f40ecf8347cdb11f18ff640b</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xd532b88607b1877fe20c181cba2550e3bbd6b31c</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xa1d4657e0e6507d5a94d06da93e94dc7c8c44b51</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xedb61f74b0d09b2558f1eeb79b247c1f363ae452</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x7d8820fa92eb1584636f4f5b8515b5476b75171a</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x231d3559aa848bf10366fb9868590f01d34bf240</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xad9fd7cb4fc7a0fbce08d64068f60cbde22ed34c</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x0e9d6552b85be180d941f1ca73ae3e318d2d4f1f</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xb716600ed99b4710152582a124c697a7fe78adbf</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xaadc2d4261199ce24a4b0a57370c4fcf43bb60aa</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x4e1f41613c9084fdb9e34e11fae9412427480e56</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x79986af15539de2db9a5086382daeda917a9cf0c</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xc99c679c50033bbc5321eb88752e89a93e9e83c5</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xc36cf0cfcb5d905b8b513860db0cfe63f6cf9f5c</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x9c8ff314c9bc7f6e59a9d9225fb22946427edc03</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x3110ef5f612208724ca51f5761a69081809f03b7</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x036721e5a769cc48b3189efbb9cce4471e8a48b1</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x524cab2ec69124574082676e6f654a18df49a048</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x7ab2352b1d2e185560494d5e577f9d3c238b78c5</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x32973908faee0bf825a343000fe412ebe56f802a</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x7daec605e9e2a1717326eedfd660601e2753a057</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xc1caf0c19a8ac28c41fe59ba6c754e4b9bd54de9</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x33fd426905f149f8376e227d0c9d3340aad17af1</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x466cfcd0525189b573e794f554b8a751279213ac</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x6be69b2a9b153737887cfcdca7781ed1511c7e36</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x80336ad7a747236ef41f47ed2c7641828a480baa</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x9401518f4ebba857baa879d9f76e1cc8b31ed197</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x4b61413d4392c806e6d0ff5ee91e6073c21d6430</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xc3f733ca98e0dad0386979eb96fb1722a1a05e69</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x09233d553058c2f42ba751c87816a8e9fae7ef10</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x960b7a6bcd451c9968473f7bbfd9be826efd549a</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x36d30b3b85255473d27dd0f7fd8f35e36a9d6f06</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x698fbaaca64944376e2cdc4cad86eaa91362cf54</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x497a9a79e82e6fc0ff10a16f6f75e6fcd5ae65a8</loc>
|
||||
<lastmod>2023-10-11T23:24:32.127Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x41a322b28d0ff354040e2cbc676f0320d8c8850d</loc>
|
||||
<lastmod>2023-10-16T18:42:53.632Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0xa9c0a07a7cb84ad1f2ffab06de3e55aab7d523e8</loc>
|
||||
<lastmod>2023-10-16T18:42:53.632Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://app.uniswap.org/nfts/collection/0x942bc2d3e7a589fe5bd4a5c6ef9727dfd82f5c8a</loc>
|
||||
<lastmod>2023-10-16T18:42:53.632Z</lastmod>
|
||||
<priority>0.7</priority>
|
||||
</url>
|
||||
</urlset>
|
6
public/robots.txt
Normal file
@ -0,0 +1,6 @@
|
||||
# *
|
||||
User-agent: *
|
||||
Disallow:
|
||||
|
||||
# Sitemaps
|
||||
Sitemap: https://app.uniswap.org/sitemap.xml
|
12
public/sitemap.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<sitemap>
|
||||
<loc>https://app.uniswap.org/app-sitemap.xml</loc>
|
||||
</sitemap>
|
||||
<sitemap>
|
||||
<loc>https://app.uniswap.org/tokens-sitemap.xml</loc>
|
||||
</sitemap>
|
||||
<sitemap>
|
||||
<loc>https://app.uniswap.org/nfts-sitemap.xml</loc>
|
||||
</sitemap>
|
||||
</sitemapindex>
|
1663
public/tokens-sitemap.xml
Normal file
@ -9,19 +9,13 @@ const thegraphConfig = require('../graphql.thegraph.config')
|
||||
|
||||
const exec = promisify(child_process.exec)
|
||||
|
||||
function fetchSchema(url, outputFile) {
|
||||
exec(`yarn --silent get-graphql-schema --h Origin=https://app.uniswap.org ${url}`)
|
||||
.then(({ stderr, stdout }) => {
|
||||
if (stderr) {
|
||||
throw new Error(stderr)
|
||||
} else {
|
||||
fs.writeFile(outputFile, stdout)
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
console.error(`Failed to fetch schema from ${url}`)
|
||||
})
|
||||
async function fetchSchema(url, outputFile) {
|
||||
try {
|
||||
const { stdout } = await exec(`yarn --silent get-graphql-schema --h Origin=https://app.uniswap.org ${url}`);
|
||||
await fs.writeFile(outputFile, stdout);
|
||||
} catch(err){
|
||||
console.error(`Failed to fetch schema from ${url}`)
|
||||
}
|
||||
}
|
||||
|
||||
fetchSchema(process.env.THE_GRAPH_SCHEMA_ENDPOINT, thegraphConfig.schema)
|
||||
|
141
scripts/generate-sitemap.js
Normal file
@ -0,0 +1,141 @@
|
||||
/* eslint-env node */
|
||||
|
||||
const fs = require('fs')
|
||||
const { parseStringPromise, Builder } = require('xml2js')
|
||||
|
||||
const weekMs = 7 * 24 * 60 * 60 * 1000
|
||||
const nowISO = new Date().toISOString()
|
||||
|
||||
const getTopTokensQuery = (chain) => `
|
||||
query {
|
||||
topTokens(pageSize: 100, page: 1, chain: ${chain}, orderBy: VOLUME) {
|
||||
address
|
||||
}
|
||||
}
|
||||
`
|
||||
const chains = ['ETHEREUM', 'ARBITRUM', 'OPTIMISM', 'POLYGON', 'BASE', 'BNB', 'CELO']
|
||||
|
||||
const nftTopCollectionsQuery = `
|
||||
query {
|
||||
topCollections(first: 100, duration: MAX) {
|
||||
edges {
|
||||
node {
|
||||
nftContracts {
|
||||
address
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
fs.readFile('./public/tokens-sitemap.xml', 'utf8', async (err, data) => {
|
||||
const tokenURLs = {}
|
||||
try {
|
||||
const sitemap = await parseStringPromise(data)
|
||||
if (sitemap.urlset.url) {
|
||||
sitemap.urlset.url.forEach((url) => {
|
||||
const lastMod = new Date(url.lastmod).getTime()
|
||||
if (lastMod < Date.now() - weekMs) {
|
||||
url.lastmod = nowISO
|
||||
}
|
||||
tokenURLs[url.loc] = true
|
||||
})
|
||||
}
|
||||
|
||||
for (const chainName of chains) {
|
||||
const tokensResponse = await fetch('https://api.uniswap.org/v1/graphql', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Origin: 'https://app.uniswap.org',
|
||||
},
|
||||
body: JSON.stringify({ query: getTopTokensQuery(chainName) }),
|
||||
})
|
||||
const tokensJSON = await tokensResponse.json()
|
||||
const tokenAddresses = tokensJSON.data.topTokens.map((token) => token.address.toLowerCase())
|
||||
|
||||
tokenAddresses.forEach((address) => {
|
||||
const tokenURL = `https://app.uniswap.org/tokens/${chainName.toLowerCase()}/${address}`
|
||||
if (!(tokenURL in tokenURLs)) {
|
||||
sitemap.urlset.url.push({
|
||||
loc: [tokenURL],
|
||||
lastmod: [nowISO],
|
||||
priority: [0.8],
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const builder = new Builder()
|
||||
const xml = builder.buildObject(sitemap)
|
||||
const path = './public/tokens-sitemap.xml'
|
||||
fs.writeFile(path, xml, (error) => {
|
||||
if (error) throw error
|
||||
const stats = fs.statSync(path)
|
||||
const fileSizeBytes = stats.size
|
||||
const fileSizeMegabytes = fileSizeBytes / (1024 * 1024)
|
||||
|
||||
if (fileSizeMegabytes > 50) {
|
||||
throw new Error('Generated tokens-sitemap.xml file size exceeds 50MB')
|
||||
}
|
||||
console.log('Tokens sitemap updated')
|
||||
})
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
})
|
||||
|
||||
fs.readFile('./public/nfts-sitemap.xml', 'utf8', async (err, data) => {
|
||||
const collectionURLs = {}
|
||||
try {
|
||||
const sitemap = await parseStringPromise(data)
|
||||
if (sitemap.urlset.url) {
|
||||
sitemap.urlset.url.forEach((url) => {
|
||||
const lastMod = new Date(url.lastmod).getTime()
|
||||
if (lastMod < Date.now() - weekMs) {
|
||||
url.lastmod = nowISO
|
||||
}
|
||||
collectionURLs[url.loc] = true
|
||||
})
|
||||
}
|
||||
|
||||
const nftResponse = await fetch('https://api.uniswap.org/v1/graphql', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Origin: 'https://app.uniswap.org',
|
||||
},
|
||||
body: JSON.stringify({ query: nftTopCollectionsQuery }),
|
||||
})
|
||||
const nftJSON = await nftResponse.json()
|
||||
const collectionAddresses = nftJSON.data.topCollections.edges.map((edge) => edge.node.nftContracts[0].address)
|
||||
collectionAddresses.forEach((address) => {
|
||||
const collectionURL = `https://app.uniswap.org/nfts/collection/${address}`
|
||||
if (!(collectionURL in collectionURLs)) {
|
||||
sitemap.urlset.url.push({
|
||||
loc: [collectionURL],
|
||||
lastmod: [nowISO],
|
||||
priority: [0.7],
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const builder = new Builder()
|
||||
const xml = builder.buildObject(sitemap)
|
||||
const path = './public/nfts-sitemap.xml'
|
||||
fs.writeFile(path, xml, (error) => {
|
||||
if (error) throw error
|
||||
const stats = fs.statSync(path)
|
||||
const fileSizeBytes = stats.size
|
||||
const fileSizeMegabytes = fileSizeBytes / (1024 * 1024)
|
||||
|
||||
if (fileSizeMegabytes > 50) {
|
||||
throw new Error('Generated nfts-sitemap.xml file size exceeds 50MB')
|
||||
}
|
||||
console.log('NFT collections sitemap updated')
|
||||
})
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
})
|
@ -52,3 +52,8 @@ export const sendAnalyticsEvent: typeof sendAnalyticsTraceEvent = (event, proper
|
||||
sendAnalyticsTraceEvent(event, properties)
|
||||
}
|
||||
}
|
||||
|
||||
// This is only used for initial page load so we can get the user's country
|
||||
export const sendInitializationEvent: typeof sendAnalyticsTraceEvent = (event, properties) => {
|
||||
sendAnalyticsTraceEvent(event, properties)
|
||||
}
|
||||
|
BIN
src/assets/images/AndroidWallet-Thumbnail-Dark.png
Normal file
After ![]() (image error) Size: 11 KiB |
BIN
src/assets/images/AndroidWallet-Thumbnail-Light.png
Normal file
After ![]() (image error) Size: 9.8 KiB |
BIN
src/assets/images/androidAnnouncementBannerQR.png
Normal file
After ![]() (image error) Size: 1.2 KiB |
@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 2496 2496" style="enable-background:new 0 0 2496 2496;" xml:space="preserve">
|
||||
<g>
|
||||
<path style="fill-rule:evenodd;clip-rule:evenodd;fill:#F0B90B;" d="M1248,0c689.3,0,1248,558.7,1248,1248s-558.7,1248-1248,1248
|
||||
S0,1937.3,0,1248S558.7,0,1248,0L1248,0z"/>
|
||||
<path style="fill:#FFFFFF;" d="M685.9,1248l0.9,330l280.4,165v193.2l-444.5-260.7v-524L685.9,1248L685.9,1248z M685.9,918v192.3
|
||||
l-163.3-96.6V821.4l163.3-96.6l164.1,96.6L685.9,918L685.9,918z M1084.3,821.4l163.3-96.6l164.1,96.6L1247.6,918L1084.3,821.4
|
||||
L1084.3,821.4z"/>
|
||||
<path style="fill:#FFFFFF;" d="M803.9,1509.6v-193.2l163.3,96.6v192.3L803.9,1509.6L803.9,1509.6z M1084.3,1812.2l163.3,96.6
|
||||
l164.1-96.6v192.3l-164.1,96.6l-163.3-96.6V1812.2L1084.3,1812.2z M1645.9,821.4l163.3-96.6l164.1,96.6v192.3l-164.1,96.6V918
|
||||
L1645.9,821.4L1645.9,821.4L1645.9,821.4z M1809.2,1578l0.9-330l163.3-96.6v524l-444.5,260.7v-193.2L1809.2,1578L1809.2,1578
|
||||
L1809.2,1578z"/>
|
||||
<polygon style="fill:#FFFFFF;" points="1692.1,1509.6 1528.8,1605.3 1528.8,1413 1692.1,1316.4 1692.1,1509.6 "/>
|
||||
<path style="fill:#FFFFFF;" d="M1692.1,986.4l0.9,193.2l-281.2,165v330.8l-163.3,95.7l-163.3-95.7v-330.8l-281.2-165V986.4
|
||||
L968,889.8l279.5,165.8l281.2-165.8l164.1,96.6H1692.1L1692.1,986.4z M803.9,656.5l443.7-261.6l444.5,261.6l-163.3,96.6
|
||||
l-281.2-165.8L967.2,753.1L803.9,656.5L803.9,656.5z"/>
|
||||
</g>
|
||||
</svg>
|
Before (image error) Size: 1.6 KiB |
Before ![]() (image error) Size: 1.5 KiB |
Before ![]() (image error) Size: 1.5 KiB |
@ -1,77 +0,0 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 22.773 22.773" style="enable-background:new 0 0 22.773 22.773;" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<path d="M15.769,0c0.053,0,0.106,0,0.162,0c0.13,1.606-0.483,2.806-1.228,3.675c-0.731,0.863-1.732,1.7-3.351,1.573
|
||||
c-0.108-1.583,0.506-2.694,1.25-3.561C13.292,0.879,14.557,0.16,15.769,0z"/>
|
||||
<path d="M20.67,16.716c0,0.016,0,0.03,0,0.045c-0.455,1.378-1.104,2.559-1.896,3.655c-0.723,0.995-1.609,2.334-3.191,2.334
|
||||
c-1.367,0-2.275-0.879-3.676-0.903c-1.482-0.024-2.297,0.735-3.652,0.926c-0.155,0-0.31,0-0.462,0
|
||||
c-0.995-0.144-1.798-0.932-2.383-1.642c-1.725-2.098-3.058-4.808-3.306-8.276c0-0.34,0-0.679,0-1.019
|
||||
c0.105-2.482,1.311-4.5,2.914-5.478c0.846-0.52,2.009-0.963,3.304-0.765c0.555,0.086,1.122,0.276,1.619,0.464
|
||||
c0.471,0.181,1.06,0.502,1.618,0.485c0.378-0.011,0.754-0.208,1.135-0.347c1.116-0.403,2.21-0.865,3.652-0.648
|
||||
c1.733,0.262,2.963,1.032,3.723,2.22c-1.466,0.933-2.625,2.339-2.427,4.74C17.818,14.688,19.086,15.964,20.67,16.716z"/>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
Before (image error) Size: 1.6 KiB |
@ -1,9 +0,0 @@
|
||||
<svg width="14" height="16" viewBox="0 0 14 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0.53125 5.04465V10.9554C0.53125 11.3328 0.742546 11.6817 1.08477 11.8698L6.44755 14.8258C6.78977 15.0139 7.21107 15.0139 7.55329 14.8258L12.9161 11.8698C13.2583 11.6817 13.4696 11.3328 13.4696 10.9554V5.04465C13.4696 4.66726 13.2583 4.31833 12.9161 4.13026L7.55329 1.17426C7.21107 0.986184 6.78977 0.986184 6.44755 1.17426L1.08347 4.13026C0.74125 4.31833 0.53125 4.66726 0.53125 5.04465Z" fill="#213147"/>
|
||||
<path d="M8.17051 9.14643L7.40569 11.1484C7.38495 11.2041 7.38495 11.2648 7.40569 11.3204L8.72143 14.7652L10.2433 13.9263L8.4168 9.14643C8.37532 9.03631 8.21199 9.03631 8.17051 9.14643Z" fill="#12AAFF"/>
|
||||
<path d="M9.70391 5.77961C9.66243 5.66949 9.4991 5.66949 9.45762 5.77961L8.6928 7.78162C8.67206 7.83731 8.67206 7.89793 8.6928 7.95361L10.8485 13.5934L12.3704 12.7545L9.70391 5.77961Z" fill="#12AAFF"/>
|
||||
<path d="M7 1.39574C7.03759 1.39574 7.07519 1.40564 7.10889 1.42296L12.9124 4.62147C12.9798 4.65859 13.0213 4.72789 13.0213 4.80089V11.1967C13.0213 11.2709 12.9798 11.339 12.9124 11.3761L7.10889 14.5746C7.07648 14.5932 7.03759 14.6018 7 14.6018C6.96241 14.6018 6.92482 14.5919 6.89111 14.5746L1.08759 11.3786C1.02019 11.3415 0.978704 11.2722 0.978704 11.1992V4.80213C0.978704 4.72789 1.02019 4.65983 1.08759 4.62271L6.89111 1.4242C6.92482 1.40564 6.96241 1.39574 7 1.39574ZM7 0.461548C6.79389 0.461548 6.58648 0.512279 6.40111 0.614978L0.598889 3.81226C0.228148 4.01642 0 4.3938 0 4.80213V11.1979C0 11.6062 0.228148 11.9836 0.598889 12.1878L6.40241 15.3863C6.58778 15.4878 6.79389 15.5397 7.0013 15.5397C7.20741 15.5397 7.41482 15.489 7.60019 15.3863L13.4037 12.1878C13.7744 11.9836 14.0026 11.6062 14.0026 11.1979V4.80213C14.0026 4.3938 13.7744 4.01642 13.4037 3.81226L7.59889 0.614978C7.41352 0.512279 7.20611 0.461548 7 0.461548Z" fill="#9DCCED"/>
|
||||
<path d="M3.16162 13.6008L3.6957 12.2051L4.77033 13.0576L3.7657 13.9336L3.16162 13.6008Z" fill="#213147"/>
|
||||
<path d="M6.51113 4.3443H5.03983C4.92965 4.3443 4.83113 4.40988 4.79354 4.50887L1.63965 12.7619L3.1615 13.6008L6.63428 4.51258C6.66669 4.43091 6.60317 4.3443 6.51113 4.3443Z" fill="white"/>
|
||||
<path d="M9.08579 4.3443H7.6145C7.50431 4.3443 7.40579 4.40988 7.3682 4.50887L3.76709 13.9324L5.28894 14.7713L9.20894 4.51258C9.24005 4.43091 9.17653 4.3443 9.08579 4.3443Z" fill="white"/>
|
||||
</svg>
|
Before (image error) Size: 2.3 KiB |
@ -1,11 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_298_130193)">
|
||||
<path d="M12.9346 2.74121H3.05566V11.7259H12.9346V2.74121Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.9998 0C15.9998 4.41538 15.9998 15.9947 15.9998 15.9947C11.5844 15.9947 0.00590861 15.9947 0.00590861 15.9947L0.00488281 5.43594e-05C4.42027 5.43594e-05 15.9998 0 15.9998 0ZM5.73493 11.1815H4.18339C3.85736 11.1815 3.69632 11.1815 3.59813 11.1187C3.49207 11.0499 3.42726 10.936 3.4194 10.8103C3.41351 10.6945 3.49404 10.553 3.65508 10.2702L7.48603 3.51765C7.64905 3.2309 7.73153 3.08753 7.83562 3.03451C7.94756 2.97755 8.08112 2.97755 8.19307 3.03451C8.29716 3.08753 8.37965 3.2309 8.54265 3.51765L9.33022 4.89243L9.33423 4.89945C9.51029 5.20707 9.59958 5.36307 9.63856 5.52679C9.68176 5.70552 9.68176 5.89406 9.63856 6.07278C9.59928 6.23775 9.5109 6.39488 9.33218 6.70715L7.31987 10.2643L7.31466 10.2734C7.13744 10.5836 7.04762 10.7408 6.92315 10.8594C6.78763 10.9891 6.62462 11.0833 6.44589 11.1364C6.28288 11.1815 6.10024 11.1815 5.73493 11.1815ZM9.65309 11.1815H11.8763C12.2043 11.1815 12.3693 11.1815 12.4675 11.1168C12.5735 11.048 12.6403 10.9321 12.6463 10.8065C12.6519 10.6944 12.5731 10.5584 12.4188 10.2921C12.4134 10.283 12.4081 10.2738 12.4027 10.2644L11.2891 8.35932L11.2764 8.33787C11.1199 8.07325 11.0409 7.93962 10.9395 7.88797C10.8276 7.831 10.6959 7.831 10.584 7.88797C10.4819 7.94099 10.3994 8.08044 10.2364 8.36128L9.12674 10.2663L9.12294 10.2729C8.9605 10.5533 8.87932 10.6934 8.88518 10.8084C8.89303 10.9341 8.95784 11.0499 9.06389 11.1187C9.16014 11.1815 9.32511 11.1815 9.65309 11.1815Z" fill="#E84142"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_298_130193">
|
||||
<rect width="16" height="16" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
Before (image error) Size: 1.8 KiB |
@ -1,11 +0,0 @@
|
||||
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 14C0 6.26801 6.26801 0 14 0V0C21.732 0 28 6.26801 28 14V14C28 21.732 21.732 28 14 28V28C6.26801 28 0 21.732 0 14V14Z" fill="#0052FF"/>
|
||||
<g clip-path="url(#clip0_13924_33076)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.3332 14.0003C23.3332 19.155 19.1472 23.3337 13.9836 23.3337C9.08459 23.3337 5.06565 19.5724 4.6665 14.7849H17.0245V13.2158H4.6665C5.06565 8.42825 9.08459 4.66699 13.9836 4.66699C19.1472 4.66699 23.3332 8.84566 23.3332 14.0003Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_13924_33076">
|
||||
<rect width="18.6667" height="18.6667" fill="white" transform="translate(4.66675 4.66699)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
Before (image error) Size: 745 B |
@ -1,11 +0,0 @@
|
||||
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="28" height="28" rx="8" fill="#0052FF"/>
|
||||
<g clip-path="url(#clip0_13921_13252)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.3332 14.0003C23.3332 19.155 19.1472 23.3337 13.9836 23.3337C9.08459 23.3337 5.06565 19.5724 4.6665 14.7849H17.0245V13.2158H4.6665C5.06565 8.42825 9.08459 4.66699 13.9836 4.66699C19.1472 4.66699 23.3332 8.84566 23.3332 14.0003Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_13921_13252">
|
||||
<rect width="18.6667" height="18.6667" fill="white" transform="translate(4.66675 4.66699)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
Before (image error) Size: 651 B |
@ -1,21 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect x="0" y="0" width="16" height="16" rx="3" fill="#F0B90B"/>
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 2496 2496" style="enable-background:new 0 0 2496 2496;" xml:space="preserve">
|
||||
<g>
|
||||
<path style="fill-rule:evenodd;clip-rule:evenodd;fill:#F0B90B;" d="M1248,0c689.3,0,1248,558.7,1248,1248s-558.7,1248-1248,1248
|
||||
S0,1937.3,0,1248S558.7,0,1248,0L1248,0z"/>
|
||||
<path style="fill:#FFFFFF;" d="M685.9,1248l0.9,330l280.4,165v193.2l-444.5-260.7v-524L685.9,1248L685.9,1248z M685.9,918v192.3
|
||||
l-163.3-96.6V821.4l163.3-96.6l164.1,96.6L685.9,918L685.9,918z M1084.3,821.4l163.3-96.6l164.1,96.6L1247.6,918L1084.3,821.4
|
||||
L1084.3,821.4z"/>
|
||||
<path style="fill:#FFFFFF;" d="M803.9,1509.6v-193.2l163.3,96.6v192.3L803.9,1509.6L803.9,1509.6z M1084.3,1812.2l163.3,96.6
|
||||
l164.1-96.6v192.3l-164.1,96.6l-163.3-96.6V1812.2L1084.3,1812.2z M1645.9,821.4l163.3-96.6l164.1,96.6v192.3l-164.1,96.6V918
|
||||
L1645.9,821.4L1645.9,821.4L1645.9,821.4z M1809.2,1578l0.9-330l163.3-96.6v524l-444.5,260.7v-193.2L1809.2,1578L1809.2,1578
|
||||
L1809.2,1578z"/>
|
||||
<polygon style="fill:#FFFFFF;" points="1692.1,1509.6 1528.8,1605.3 1528.8,1413 1692.1,1316.4 1692.1,1509.6 "/>
|
||||
<path style="fill:#FFFFFF;" d="M1692.1,986.4l0.9,193.2l-281.2,165v330.8l-163.3,95.7l-163.3-95.7v-330.8l-281.2-165V986.4
|
||||
L968,889.8l279.5,165.8l281.2-165.8l164.1,96.6H1692.1L1692.1,986.4z M803.9,656.5l443.7-261.6l444.5,261.6l-163.3,96.6
|
||||
l-281.2-165.8L967.2,753.1L803.9,656.5L803.9,656.5z"/>
|
||||
</g>
|
||||
</svg>
|
||||
</svg>
|
Before (image error) Size: 1.6 KiB |
@ -1,5 +0,0 @@
|
||||
<svg width="250" height="250" viewBox="0 0 250 250" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect width="250" height="250" rx="40" fill="#FCFF52"/>
|
||||
<path style="fill:black;" d="M188.9,60.7H60.7v128.2h128.2v-44.8h-21.3c-7.3,16.3-23.8,27.7-42.7,27.7c-26,0-47.1-21.3-47.1-47.1c0-25.9,21.1-47,47.1-47
|
||||
c19.3,0,35.8,11.7,43.1,28.4h20.9V60.7z"/>
|
||||
</svg>
|
Before (image error) Size: 398 B |
@ -1,16 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect x="0" y="0" width="16" height="16" rx="3" fill="#627EEA"/>
|
||||
<circle cx="8" cy="8" r="8"/>
|
||||
<g clip-path="url(#clip0_12246_121533)">
|
||||
<circle cx="8" cy="8" r="8" fill="url(#pattern0)"/>
|
||||
</g>
|
||||
<defs>
|
||||
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0_12246_121533" transform="scale(0.0078125)"/>
|
||||
</pattern>
|
||||
<clipPath id="clip0_12246_121533">
|
||||
<rect x="0" y="0" width="16" height="16" rx="8" fill="white"/>
|
||||
</clipPath>
|
||||
<image id="image0_12246_121533" width="128" height="128" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAADd9JREFUeNrtXdtzE+cV38kweWpm+tI8JZP8EZ0pL+UhferkfyAzFqEpadq0hbRNUlsYQ2ycBEgCgQQIgVxMbC6BAHbEJZg7dW4OpeCWwDTNDOyuLFuybMsXfT2/tWVkWavd1e5K58g6M9+Q8cTS+ju//b5z/R1Nq0F5Ppr46cpm8xcroubyFU3m+oYmY39Do97d0KRfoH/76d/b9K9JP89Yy/pv62f9s/9PN34Hv4vPwGfhM7W68JNVUfWTp9fqv440Ge2RRqOXFHiPFKhCWfTZ+A58F74T313XQIUlGlUP0lv5RCRqtkQa9YukjMnQFO6w8N3WM9Cz4JnwbHUNhSQrovGlkSZ9K216vFoKdwGIOJ4Rz1rXWADyTDTxeCSqv0wbe5Or0kuA4SaeHX9DXZMepSFq/Jw28FBDo5GVpviFy8hafwv9TXXNOh3zzfov6Qjtka90u1NB78HfWNd0gUTWmr+yLPgaVfwCIMCToL+5/sZH44+Qa9W5WBRfxK3sxB4sRlduSSRqrKYjMbVolX//WkhhL7Ani+O4j+rL6Ai8ttgVX+RauIa9qfG3Xm+tDcs+RI+B9qjmToNVLfFHKWJ2vq5gt6eBfr5mbIPIWuNJK9lSV6zXZWLvJB/5D1AApK1+5PsOIrVhL8UlbMiy7agrMKArgfZSTKKpoc14iHLpMUkb/OZHQ6pxa5x5zID2lPaWefIm9TC5M32SlP/MOl0Zg1PqWG9aUY6fu6vY99yG1M94GnsticfozhqQdryeOJ9W09NZ9cU/Rq2TQIBdMIC9ZvfmS1T+39+Kq6mp7BwATl8dVX/caIoAAfaczZ0v7djPrYE7EwqSAwDW/u6UlMhhX9VtAlim0gy+3Np9KKlykg8ArPXvDApJJhmxqnkHlp8v1NV77hVDJUembQHQfSFtGYeCXMTKxwlmgjwy/erevlGVL4UAwHqna1hS+VlbFcK7MiN8698dVNls1hEAWC+8bsqJGFYqbIzEjtTY/oqorn64O6kKxQ4AB0+NIF8vJncA3YSf0hWc1YOFX0zsAIDVvichKosYaip5Jp8vU/l/ftVUY+NZzwCIXRpVz24wBOUN9NbQKnkkZ/a+vD6u7KQUALDeP5KUVlSyLISjX24Z16Z9Q6qUOAEA6+U344KuAuNaoFcBoWqNVOX/pllXOiV7/ALg6NkR9XRUVC3BmsBKtyVX70JxTuIGAFhvfDgkKDagpwIpKyPLskuq8l98I64mJ7OBAeD0lVH1fJshySvo8t2xI7mS5vr3GeVG3AIA6+MTKVF74KsDSXK7FkK5bsULALCatw9KMgh7y27UlKp8+O1DqenQAIAiEhiXYiKg5TSkSu7SxV3tRbwCAGt7p6Rkkd7jze2jXnapysfxDIWGDQCs1a+ZcvbGCz/BDDmDyEZLdefHCeVVygXAgZicZBF06rK+L/G41JDvh8eSqhwpFwBYbbsTYkLEruhqwGsjUfko5hwdm644AGKX0mrVehmxAejWTdh3QCIArvSPqXLFDwCwdh9OSrkGbjqFfZdKVP6rlLP3I34BgPXiFhnJopIUduC4k6b8ldTNc9ecrDoAjpwZsSqOBBjKW+0bOhmTMNqtw6dHlF8JAgBYSDsLuAbiRUvJQXUqTfl/3WyqiYksGwCcogDU71sNAdeA+UQR699skQaA7/6dUUFIUADAgivK3xswW4qlfS9KUv62/cMqKAkSAFjRbbyTRdD1/FJvoj2vJuu217WqxVCDw1NsAXD8XNoyThnbAZPzqO7BfS/p7f/8YloFKUEDAGtrB2+DEDrPj/23S1F+07a452RPNQBwhlrNUYrO+BRoF1n4ceuHiUCVjzax67cy6pOeVOAg6Pw8xdgOyCsUCXXMSoAL9flBSYbcR/QKwHWDsta+PahadyXU3qNJq54gKBBs2MnUICSdW8rHMCQJyod/PTI67VvxQ8lpdfGbsQVKBgByC/wAOw8Mqx6yNfwCAPbKb1t47qk1CAsTsSQA4MLXY74U/6M+qc5SW/gZG0XlAyC31lFxyVtkzKG03A8Idh7kWT0E3dP9bz7FXfk4msuVgTsZetud3+RiAMhfm/YlrDu9XBAgaskwIrgc+f8NrN0VSrDg7fUiE9QL8PUNut8vuz/CnQCQWxupAOSDz5IWoZQXACBnwa16CLrXZocqsgVAVyzlWvGgfbn07ZirN75cAMzZCUQ0sYuO9pgHO+G195lVD5HuWVf/riGGjvGMs89/15hUvV/a3+9hACC3mncMqm1kJxxzYSecujxq8ROxqhbmnAP45sZ4ScX/578ZdSYgl61cAOSvzWQnHIiVthP2HU3yygk0YF4uU/7eYjJJxI7f3oT/ng40aBMEAHKr/b2ElRW0sxMY8RL3a7NDk9nx95qJ+ckexACufDcWaJAmLADk1gayE3YfGlYnL80HKxteYtK9xpHwCdm0nNyLT6lzX83E1sNQfJgAmIsnUGBp+/4hdbz3PhCY8BKb2uz4dHb8vbf/NxG60isFgDmDkQJLW4hj4OCpFA9eYtI9OwAcOzcyF5+v5KoEAObZCXvIaPxgiAEAmF0BSKGCzq3WAfA3KiNn0GFssjQCc02ex3rTNQcAXHG/40I7N2sE9nMOA2+hYxIBFOkAQJ0g7nxm4WDLDbwggd17z6dJsQAA5zDLcTSke5wA3XL6AOIWf68UALxEJFVcawFmVze7ZJBT2hRH6Cs7E6rnAt9IICJ9bhpE/lBtxjErGcQsHbyRwqiXKaPnxL6BaCF6A05f5QOAKC14MU73fO5KA41dVesBmsz1aAlbzu1ogvWPmj3k0J1cJRhWHx1PVR0AuJ5WNjuWYltkk4hzcIgEWgUhHEvCYP3nqn+RE8Cb7vQ7OHaPfjFScQDArXvWBUEE3FqEuPFdqHHg4A1YJWFci0L/sokYP8bvF4HeuJ2xegKcBkKg6OLk5fABALfODWsorrL8knPQz3NpILWKQjmXhReSPaKBA/kBpw3EG7mLsnBhAQCFKk7E0Whfe/fAwmdYt2OQiwt4T0RjCEq4CyVNqWHc+06EDPC/u2KpwAAAo81pmhieCYwlsUsLvRSMqmPZGMK5NQxvkh6fsi31dlNnhzp/sHuWCwDYF25KuWAPgCnEjm5+JSN20XmtYdybQ3FsIkVsJ6gAdoofYPNhedsVlNi5dX9qd3brYAugAsiWZfwqvwlk85pDJbSHoya/lIAWHlY2TgynDiPU5TkBAEaoU4s3XFR0ATvFIl7fy6saeEF7uASCCLyFbujf0fq1y0Unzks0AubTvON6LnxLP3cCERbKvbpdRCM7GNLLLyCIkEIRg+M4lXbXH/g9VRS1OMwABqgQeUT/HlxMN6FZXDUHTrqLNyBczXHiWFGKGCkkUYikeWn9Rk8hgOMUVnbyKJDDf++wt4wko+pfZ5IoSTRxqA/wIpgXCHewHNoW+Pub93mvSeBKJ29LEyeJKBIWfbERsE4Cd9JLDB5eQDlVSchhcJ0wZksUKY0qFj53uRyB/yRGkFJzAJHR6yizLhGJHqcrhy1V7GxQ6KYUEMCd88MLhJxBfn0eijd2dA77yiqilV0sWbREuviv/jXuizgCXgVoYXLegB/lc+r7K5suXtrACIRo/XIGBsEShiCUU55AxMAIiSNjQNrghzpuMdDFux4ZI3Vo1Gdn01UDAJM+v9LLy9AoiWPjVkTL5xD0AwDkKLgPjvI8Nk7q4MgXCqqIwgYAcv4i6OHLGRwpdXSsl5GxfgHAprrHbeHHYhke7ZVTsBwAoORMwl74Gh49Wy/YKQ0ASOfei0+FBgBUH6+UMDuYdKf5FQodPkJGREoaCHA8T05lAwcAij/WCBgZC51Bd1oQEokaqyVeBU5VROUAgB3Xn23Uz1itBSWUPlxCxsQ1aQCwqohuZQIDwMcnUjL+btIVdKYFKRRHXiZxpjAyc2AQ9QsAq7pHxIhYIwtdaWEIfXCrxKsAJBN+AYD0s4yjX2/VwpKZq0A/LxEEpaqInADw9idCXD7STeBHf6Gsaok/ypFb0E8VUSkAHDrFt7qnkPAJutEqIZG1xpMS7QFUAWWKVBHZAQCnRtW5/Nze+6QTrZJC6cU2iVfB3iJVRHYAABOJDG/HaNMqLXTXPEC+ZodEEGBYlBMA9h5JSvH3O6ALrRqC8mLimYlJA0BhFVEhAPhX98xx/MRsS7wrJQ1txkMUeOiTBoK2vCqiQgCA7kVAsKcPe69xkGeiqYfJEBmQBgK0bBcCAJ1HAoy+Aey5xkkiLYnHpIEgV0WUA4CE6h7sMfZa4yhApbTrAH37YBxBdQ+neT52xz67N7+YTSDNMEQfH1i8uBt8bO58N96BVBeRsav3oCZJrDiBFSySFzFkFeGjPayanx9c2Fhe7oBDbL/i4d0wE0hSs4jVyupVLLFTwSthyUw9Qf1KcCjmaA09pVvVK4GqVSSWl1WijCu0Sh6OpwGhfY3EauMwqnexFzX91pcsOW/UuxbxXd8VWOm26GuBulcktqH5adfy3bFTkycCNTFK60r22qVbdqPmYhL0ss+QVNSCx2AFcw557s+vywxdzQxnkbxUs5W1o2d3TctSF0eDcSk47jiTWeLZ8IyOVGx18ZdoAtUp+G5BelxNlnN8t/UM9Cx4JnEJm5oIMxPtObjvMQDB8iTCHH9Dn21Z8PRd+M4FlOt14SEYhoSJWJFG8ylrLiINSIQFPkuJ3z87MNvE+HRrWf9t/ax/5lQhTwS/Q7+Lz8BnzQ1YqjH5P29N0rBVv2N5AAAAAElFTkSuQmCC"/>
|
||||
</defs>
|
||||
</svg>
|
Before (image error) Size: 5.4 KiB |
3
src/assets/svg/expando-icon-closed.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.6376 8.86202C11.8982 9.12269 11.8982 9.54407 11.6376 9.80473L8.97089 12.4714C8.84089 12.6014 8.6702 12.6667 8.49954 12.6667C8.32887 12.6667 8.15818 12.6014 8.02818 12.4714L5.36152 9.80473C5.10085 9.54407 5.10085 9.12269 5.36152 8.86202C5.62218 8.60136 6.04356 8.60136 6.30422 8.86202L8.49954 11.0573L10.6948 8.86202C10.9555 8.60136 11.3769 8.60136 11.6376 8.86202ZM6.30422 7.13807L8.49954 4.94275L10.6948 7.13807C10.8248 7.26807 10.9955 7.33338 11.1662 7.33338C11.3369 7.33338 11.5076 7.26807 11.6376 7.13807C11.8982 6.8774 11.8982 6.45602 11.6376 6.19536L8.97089 3.52869C8.71022 3.26802 8.28885 3.26802 8.02818 3.52869L5.36152 6.19536C5.10085 6.45602 5.10085 6.8774 5.36152 7.13807C5.62218 7.39873 6.04356 7.39873 6.30422 7.13807Z" fill="#5E5E5E"/>
|
||||
</svg>
|
After (image error) Size: 866 B |
3
src/assets/svg/expando-icon-opened.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.1376 11.5287C11.3982 11.7894 11.3982 12.2107 11.1376 12.4714C11.0076 12.6014 10.8369 12.6667 10.6662 12.6667C10.4955 12.6667 10.3248 12.6014 10.1948 12.4714L7.99954 10.2761L5.80422 12.4714C5.54356 12.7321 5.12218 12.7321 4.86152 12.4714C4.60085 12.2107 4.60085 11.7894 4.86152 11.5287L7.52818 8.86202C7.78885 8.60136 8.21022 8.60136 8.47089 8.86202L11.1376 11.5287ZM7.52818 7.13807C7.65818 7.26807 7.82887 7.33338 7.99954 7.33338C8.1702 7.33338 8.34089 7.26807 8.47089 7.13807L11.1376 4.4714C11.3982 4.21073 11.3982 3.78936 11.1376 3.52869C10.8769 3.26802 10.4555 3.26802 10.1948 3.52869L7.99954 5.724L5.80422 3.52869C5.54356 3.26802 5.12218 3.26802 4.86152 3.52869C4.60085 3.78936 4.60085 4.21073 4.86152 4.4714L7.52818 7.13807Z" fill="#5E5E5E"/>
|
||||
</svg>
|
After (image error) Size: 864 B |
@ -1,4 +1,15 @@
|
||||
<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="512" cy="512" r="512" fill="#8247E5"/>
|
||||
<path d="M681.469 402.456C669.189 395.312 653.224 395.312 639.716 402.456L543.928 457.228L478.842 492.949L383.055 547.721C370.774 554.865 354.81 554.865 341.301 547.721L265.162 504.856C252.882 497.712 244.286 484.614 244.286 470.325V385.786C244.286 371.498 251.654 358.4 265.162 351.256L340.073 309.581C352.353 302.437 368.318 302.437 381.827 309.581L456.737 351.256C469.018 358.4 477.614 371.498 477.614 385.786V440.558L542.7 403.646V348.874C542.7 334.586 535.332 321.488 521.824 314.344L383.055 235.758C370.774 228.614 354.81 228.614 341.301 235.758L200.076 314.344C186.567 321.488 179.199 334.586 179.199 348.874V507.237C179.199 521.525 186.567 534.623 200.076 541.767L341.301 620.353C353.582 627.498 369.546 627.498 383.055 620.353L478.842 566.772L543.928 529.86L639.716 476.279C651.996 469.135 667.961 469.135 681.469 476.279L756.38 517.953C768.66 525.098 777.257 538.195 777.257 552.484V637.023C777.257 651.312 769.888 664.409 756.38 671.553L681.469 714.419C669.189 721.563 653.224 721.563 639.716 714.419L564.805 672.744C552.525 665.6 543.928 652.502 543.928 638.214V583.442L478.842 620.353V675.125C478.842 689.414 486.21 702.512 499.719 709.656L640.944 788.242C653.224 795.386 669.189 795.386 682.697 788.242L823.922 709.656C836.203 702.512 844.799 689.414 844.799 675.125V516.763C844.799 502.474 837.431 489.377 823.922 482.232L681.469 402.456Z" fill="white"/>
|
||||
<svg width="490" height="490" viewBox="0 0 490 490" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_7383_35741)">
|
||||
<circle cx="245" cy="245" r="245" fill="url(#paint0_linear_7383_35741)"/>
|
||||
<path d="M315.83 297.85L385.12 257.84C388.79 255.72 391.06 251.78 391.06 247.54V167.53C391.06 163.3 388.78 159.35 385.12 157.23L315.83 117.22C312.16 115.1 307.61 115.11 303.94 117.22L234.65 157.23C230.98 159.35 228.71 163.3 228.71 167.53V310.52L180.12 338.57L131.53 310.52V254.41L180.12 226.36L212.17 244.86V207.22L186.06 192.15C184.26 191.11 182.2 190.56 180.11 190.56C178.02 190.56 175.96 191.11 174.17 192.15L104.88 232.16C101.21 234.28 98.9404 238.22 98.9404 242.46V322.47C98.9404 326.7 101.22 330.65 104.88 332.77L174.17 372.78C177.83 374.89 182.39 374.89 186.06 372.78L255.35 332.78C259.02 330.66 261.29 326.71 261.29 322.48V179.49L262.17 178.99L309.88 151.44L358.47 179.49V235.6L309.88 263.65L277.88 245.17V282.81L303.94 297.86C307.61 299.97 312.16 299.97 315.83 297.86V297.85Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_7383_35741" x1="-175" y1="4.36391e-07" x2="416" y2="367" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#A229C5"/>
|
||||
<stop offset="1" stop-color="#7B3FE4"/>
|
||||
</linearGradient>
|
||||
<clipPath id="clip0_7383_35741">
|
||||
<rect width="490" height="490" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before (image error) Size: 1.5 KiB After (image error) Size: 1.3 KiB |
Before (image error) Size: 32 KiB |
@ -1,5 +0,0 @@
|
||||
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="250" cy="250" r="250" fill="#FF0420"/>
|
||||
<path d="M177.133 316.446C162.247 316.446 150.051 312.943 140.544 305.938C131.162 298.808 126.471 288.676 126.471 275.541C126.471 272.789 126.784 269.411 127.409 265.408C129.036 256.402 131.35 245.581 134.352 232.947C142.858 198.547 164.812 181.347 200.213 181.347C209.845 181.347 218.476 182.973 226.107 186.225C233.738 189.352 239.742 194.106 244.12 200.486C248.498 206.74 250.688 214.246 250.688 223.002C250.688 225.629 250.375 228.944 249.749 232.947C247.873 244.08 245.621 254.901 242.994 265.408C238.616 282.546 231.048 295.368 220.29 303.874C209.532 312.255 195.147 316.446 177.133 316.446ZM179.76 289.426C186.766 289.426 192.707 287.362 197.586 283.234C202.59 279.106 206.155 272.789 208.281 264.283C211.158 252.524 213.348 242.266 214.849 233.51C215.349 230.883 215.599 228.194 215.599 225.441C215.599 214.058 209.657 208.366 197.774 208.366C190.768 208.366 184.764 210.43 179.76 214.558C174.882 218.687 171.379 225.004 169.253 233.51C167.001 241.891 164.749 252.149 162.498 264.283C161.997 266.784 161.747 269.411 161.747 272.163C161.747 283.672 167.752 289.426 179.76 289.426Z" fill="white"/>
|
||||
<path d="M259.303 314.57C257.927 314.57 256.863 314.132 256.113 313.256C255.487 312.255 255.3 311.13 255.55 309.879L281.444 187.914C281.694 186.538 282.382 185.412 283.508 184.536C284.634 183.661 285.822 183.223 287.073 183.223H336.985C350.87 183.223 362.003 186.1 370.384 191.854C378.891 197.609 383.144 205.927 383.144 216.81C383.144 219.937 382.769 223.19 382.018 226.567C378.891 240.953 372.574 251.586 363.067 258.466C353.685 265.346 340.8 268.786 324.413 268.786H299.082L290.451 309.879C290.2 311.255 289.512 312.38 288.387 313.256C287.261 314.132 286.072 314.57 284.822 314.57H259.303ZM325.727 242.892C330.98 242.892 335.546 241.453 339.424 238.576C343.427 235.699 346.054 231.571 347.305 226.192C347.68 224.065 347.868 222.189 347.868 220.563C347.868 216.935 346.805 214.183 344.678 212.307C342.551 210.305 338.924 209.305 333.795 209.305H311.278L304.148 242.892H325.727Z" fill="white"/>
|
||||
</svg>
|
Before (image error) Size: 2.1 KiB |
@ -1,16 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 38.4 33.5" style="enable-background:new 0 0 38.4 33.5;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#8247E5;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M29,10.2c-0.7-0.4-1.6-0.4-2.4,0L21,13.5l-3.8,2.1l-5.5,3.3c-0.7,0.4-1.6,0.4-2.4,0L5,16.3
|
||||
c-0.7-0.4-1.2-1.2-1.2-2.1v-5c0-0.8,0.4-1.6,1.2-2.1l4.3-2.5c0.7-0.4,1.6-0.4,2.4,0L16,7.2c0.7,0.4,1.2,1.2,1.2,2.1v3.3l3.8-2.2V7
|
||||
c0-0.8-0.4-1.6-1.2-2.1l-8-4.7c-0.7-0.4-1.6-0.4-2.4,0L1.2,5C0.4,5.4,0,6.2,0,7v9.4c0,0.8,0.4,1.6,1.2,2.1l8.1,4.7
|
||||
c0.7,0.4,1.6,0.4,2.4,0l5.5-3.2l3.8-2.2l5.5-3.2c0.7-0.4,1.6-0.4,2.4,0l4.3,2.5c0.7,0.4,1.2,1.2,1.2,2.1v5c0,0.8-0.4,1.6-1.2,2.1
|
||||
L29,28.8c-0.7,0.4-1.6,0.4-2.4,0l-4.3-2.5c-0.7-0.4-1.2-1.2-1.2-2.1V21l-3.8,2.2v3.3c0,0.8,0.4,1.6,1.2,2.1l8.1,4.7
|
||||
c0.7,0.4,1.6,0.4,2.4,0l8.1-4.7c0.7-0.4,1.2-1.2,1.2-2.1V17c0-0.8-0.4-1.6-1.2-2.1L29,10.2z"/>
|
||||
</g>
|
||||
</svg>
|
Before (image error) Size: 1.1 KiB |
Before (image error) Size: 26 KiB |
85
src/assets/svg/uniswap_app_logo.svg
Normal file
@ -0,0 +1,85 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_2450_35919)">
|
||||
<rect width="20" height="20" rx="4.60595" fill="#FFFBFF"/>
|
||||
<rect width="20" height="20" rx="4.60595" fill="url(#paint0_linear_2450_35919)"/>
|
||||
<g filter="url(#filter0_f_2450_35919)">
|
||||
<ellipse cx="9.99967" cy="12.0001" rx="9.66667" ry="7.66667" fill="url(#paint1_radial_2450_35919)" fill-opacity="0.8"/>
|
||||
</g>
|
||||
<g filter="url(#filter1_i_2450_35919)">
|
||||
<path d="M14.4974 4.34199C14.5183 3.97475 14.5683 3.73252 14.6689 3.51131C14.7087 3.42374 14.746 3.35208 14.7518 3.35208C14.7575 3.35208 14.7402 3.41671 14.7133 3.49569C14.6402 3.71038 14.6282 4.00402 14.6786 4.34566C14.7425 4.77915 14.7788 4.84169 15.239 5.30995C15.4549 5.52958 15.706 5.80659 15.797 5.92551L15.9625 6.14176L15.797 5.98722C15.5946 5.79823 15.1292 5.42966 15.0263 5.37698C14.9574 5.34164 14.9472 5.34225 14.9046 5.38439C14.8655 5.42322 14.8572 5.48156 14.8518 5.75737C14.8433 6.18723 14.7844 6.46314 14.6424 6.73903C14.5656 6.88824 14.5535 6.8564 14.623 6.68797C14.6749 6.56222 14.6802 6.50694 14.6798 6.0908C14.679 5.25469 14.5793 5.05368 13.9946 4.70934C13.8465 4.62211 13.6024 4.4963 13.4522 4.42976C13.3021 4.36322 13.1828 4.30526 13.1871 4.30093C13.2037 4.28452 13.7739 4.45022 14.0034 4.53811C14.3448 4.66886 14.4012 4.6858 14.4426 4.67003C14.4704 4.65946 14.4839 4.57887 14.4974 4.34199Z" fill="url(#paint2_linear_2450_35919)"/>
|
||||
<path d="M7.28422 3.12561C7.0817 3.09439 7.07316 3.09073 7.16846 3.07618C7.3511 3.04826 7.78237 3.0863 8.07956 3.15653C8.77336 3.32041 9.40468 3.74022 10.0786 4.48582L10.2576 4.68389L10.5137 4.64298C11.5927 4.47068 12.6903 4.60761 13.6084 5.02906C13.8609 5.14501 14.2592 5.3758 14.3089 5.43511C14.3248 5.45402 14.3539 5.57569 14.3736 5.70552C14.4418 6.1547 14.4076 6.499 14.2694 6.75616C14.1941 6.8961 14.19 6.94045 14.2405 7.06021C14.2809 7.15577 14.3935 7.22651 14.5049 7.22636C14.7331 7.22605 14.9787 6.85956 15.0924 6.34963L15.1376 6.14707L15.2272 6.24785C15.7183 6.80076 16.104 7.5548 16.1703 8.09153L16.1875 8.23147L16.105 8.10426C15.9629 7.88534 15.8202 7.73632 15.6374 7.61612C15.3079 7.39947 14.9595 7.32574 14.0368 7.27742C13.2034 7.23379 12.7318 7.16305 12.2641 7.01151C11.4684 6.75372 11.0673 6.41038 10.1221 5.17811C9.70233 4.63077 9.44285 4.32794 9.18474 4.08407C8.59823 3.52993 8.02193 3.23932 7.28422 3.12561Z" fill="url(#paint3_linear_2450_35919)"/>
|
||||
<path d="M7.67762 5.77618C7.26647 5.2137 7.01209 4.3513 7.06716 3.70661L7.08419 3.50711L7.17778 3.52408C7.35352 3.55594 7.65655 3.66801 7.79844 3.75366C8.18783 3.98865 8.3564 4.29805 8.5279 5.09252C8.57814 5.32522 8.64404 5.58856 8.67437 5.67772C8.7232 5.82122 8.90769 6.15641 9.05769 6.3741C9.16573 6.53088 9.09396 6.60518 8.85514 6.58376C8.49039 6.55104 7.99634 6.21221 7.67762 5.77618Z" fill="url(#paint4_linear_2450_35919)"/>
|
||||
<path d="M13.9982 9.96242C12.0768 9.19367 11.4001 8.52639 11.4001 7.40049C11.4001 7.2348 11.4058 7.09924 11.4128 7.09924C11.4198 7.09924 11.4941 7.15392 11.578 7.22076C11.9676 7.5313 12.4039 7.66393 13.6118 7.83903C14.3225 7.94208 14.7225 8.0253 15.0915 8.1469C16.2642 8.53338 16.9898 9.3177 17.1628 10.386C17.2131 10.6964 17.1836 11.2785 17.1021 11.5853C17.0377 11.8276 16.8413 12.2644 16.7892 12.2812C16.7748 12.2858 16.7606 12.2308 16.7569 12.156C16.7372 11.7549 16.5332 11.3643 16.1906 11.0718C15.8011 10.7392 15.2777 10.4744 13.9982 9.96242Z" fill="url(#paint5_linear_2450_35919)"/>
|
||||
<path d="M12.6493 10.2818C12.6252 10.1394 12.5835 9.95763 12.5565 9.87779L12.5075 9.73264L12.5985 9.83421C12.7246 9.97475 12.8241 10.1546 12.9085 10.3942C12.973 10.577 12.9802 10.6314 12.9797 10.9285C12.9792 11.2202 12.9712 11.2813 12.9117 11.4459C12.8179 11.7054 12.7015 11.8894 12.5062 12.0869C12.1552 12.4419 11.704 12.6384 11.0528 12.7199C10.9396 12.734 10.6097 12.7579 10.3197 12.7729C9.58873 12.8107 9.10767 12.8887 8.6754 13.0395C8.61325 13.0612 8.55776 13.0744 8.55213 13.0688C8.53464 13.0515 8.82895 12.8772 9.07204 12.7608C9.41481 12.5968 9.75602 12.5072 10.5205 12.3807C10.8982 12.3182 11.2882 12.2424 11.3872 12.2122C12.3224 11.9273 12.8031 11.1919 12.6493 10.2818Z" fill="url(#paint6_linear_2450_35919)"/>
|
||||
<path d="M13.5301 11.8362C13.2748 11.2909 13.2162 10.7643 13.356 10.2733C13.371 10.2208 13.3951 10.1779 13.4095 10.1779C13.424 10.1779 13.4842 10.2103 13.5434 10.2498C13.661 10.3285 13.897 10.461 14.5255 10.8016C15.3099 11.2265 15.7571 11.5556 16.0612 11.9316C16.3276 12.2608 16.4924 12.6358 16.5717 13.0931C16.6166 13.3521 16.5903 13.9753 16.5234 14.2361C16.3125 15.0585 15.8224 15.7045 15.1233 16.0814C15.0209 16.1366 14.9289 16.182 14.919 16.1822C14.909 16.1824 14.9464 16.0881 15.0019 15.9726C15.2371 15.4841 15.2639 15.0089 15.0861 14.48C14.9772 14.1562 14.7552 13.761 14.3071 13.0932C13.786 12.3167 13.6583 12.11 13.5301 11.8362Z" fill="url(#paint7_linear_2450_35919)"/>
|
||||
<path d="M6.31312 14.7786C7.02613 14.1803 7.9133 13.7553 8.72142 13.6248C9.0697 13.5686 9.64988 13.5909 9.97238 13.673C10.4893 13.8044 10.9518 14.0989 11.1923 14.4497C11.4273 14.7926 11.5281 15.0914 11.6331 15.7561C11.6745 16.0184 11.7196 16.2817 11.7332 16.3413C11.8121 16.6859 11.9655 16.9613 12.1556 17.0996C12.4576 17.3192 12.9776 17.3329 13.4891 17.1346C13.5759 17.1009 13.6513 17.0777 13.6566 17.0829C13.6751 17.1012 13.4175 17.2726 13.2358 17.3628C12.9913 17.4841 12.7969 17.531 12.5386 17.531C12.0701 17.531 11.6811 17.2942 11.3566 16.8113C11.2927 16.7163 11.1491 16.4316 11.0376 16.1788C10.6949 15.4021 10.5257 15.1655 10.1278 14.9066C9.78156 14.6813 9.33501 14.6409 8.99908 14.8046C8.55782 15.0196 8.4347 15.58 8.75075 15.9351C8.87636 16.0762 9.1106 16.198 9.30214 16.2216C9.66047 16.2659 9.96842 15.995 9.96842 15.6355C9.96842 15.4021 9.87813 15.2689 9.65083 15.1669C9.34039 15.0277 9.0067 15.1905 9.0083 15.4803C9.00899 15.6038 9.06314 15.6814 9.1878 15.7375C9.26777 15.7734 9.26963 15.7763 9.20442 15.7628C8.91957 15.7041 8.85285 15.3629 9.08187 15.1364C9.35683 14.8644 9.92541 14.9844 10.1207 15.3556C10.2027 15.5116 10.2122 15.8221 10.1407 16.0096C9.98064 16.4293 9.51395 16.65 9.04053 16.5299C8.71821 16.4481 8.58696 16.3596 8.19835 15.9618C7.52307 15.2706 7.26092 15.1366 6.28739 14.9856L6.10084 14.9567L6.31312 14.7786Z" fill="url(#paint8_linear_2450_35919)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.14462 2.40696C5.39974 5.12681 6.95295 6.24897 7.12556 6.48605C7.26807 6.68181 7.21443 6.85781 6.97029 6.99574C6.83452 7.07242 6.55538 7.15013 6.41563 7.15013C6.25755 7.15013 6.20328 7.08953 6.20328 7.08953C6.11163 7.00315 6.06001 7.01826 5.58934 6.18804C4.9359 5.18048 4.38905 4.34467 4.37413 4.33067C4.33964 4.29831 4.34023 4.2994 5.52271 6.40187C5.71377 6.84008 5.56071 7.00093 5.56071 7.06334C5.56071 7.1903 5.52586 7.25704 5.36825 7.43173C5.1055 7.72301 4.98805 8.05029 4.90326 8.72762C4.80821 9.4869 4.54094 10.0233 3.80024 10.9412C3.36666 11.4785 3.29572 11.577 3.18631 11.7936C3.04851 12.0663 3.01062 12.2191 2.99526 12.5635C2.97903 12.9276 3.01064 13.1628 3.12259 13.511C3.2206 13.8158 3.32291 14.017 3.58444 14.4196C3.81014 14.767 3.9401 15.0251 3.9401 15.1261C3.9401 15.2064 3.95554 15.2065 4.30528 15.1281C5.14226 14.9402 5.82189 14.6099 6.20412 14.2051C6.44068 13.9545 6.49622 13.8162 6.49802 13.4728C6.4992 13.2482 6.49125 13.2012 6.43016 13.072C6.33071 12.8617 6.14967 12.6869 5.75064 12.4158C5.2278 12.0606 5.00448 11.7747 4.9428 11.3815C4.8922 11.0588 4.9509 10.8312 5.24014 10.2288C5.53952 9.60524 5.61371 9.33953 5.66389 8.71103C5.69631 8.30498 5.74119 8.14484 5.8586 8.0163C5.98104 7.88226 6.09127 7.83687 6.3943 7.79573C6.88833 7.72866 7.20291 7.60165 7.46149 7.36487C7.6858 7.15946 7.77966 6.96154 7.79407 6.6636L7.805 6.43776L7.67965 6.29253C7.2257 5.76656 2.84061 1.9935 2.81267 1.9935C2.8067 1.9935 2.95609 2.17957 3.14462 2.40696ZM4.19493 12.9755C4.29756 12.7949 4.24303 12.5627 4.07135 12.4492C3.90913 12.342 3.65714 12.3925 3.65714 12.5322C3.65714 12.5748 3.68086 12.6058 3.73431 12.6332C3.82432 12.6792 3.83085 12.731 3.76003 12.8367C3.68832 12.9439 3.6941 13.038 3.77637 13.102C3.90895 13.2052 4.09663 13.1485 4.19493 12.9755Z" fill="url(#paint9_linear_2450_35919)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.11678 7.91419C7.88485 7.98498 7.6594 8.22923 7.58962 8.48535C7.54704 8.6416 7.5712 8.91567 7.63497 9.00032C7.73799 9.13703 7.83762 9.17306 8.10739 9.17117C8.63556 9.16751 9.0947 8.94241 9.14808 8.66101C9.19184 8.43034 8.99019 8.11067 8.71242 7.97032C8.56908 7.89793 8.26425 7.86921 8.11678 7.91419ZM8.7342 8.39395C8.81565 8.27895 8.78002 8.15466 8.64149 8.07059C8.3777 7.91053 7.97877 8.04299 7.97877 8.29063C7.97877 8.4139 8.1868 8.5484 8.37749 8.5484C8.50441 8.5484 8.6781 8.47319 8.7342 8.39395Z" fill="url(#paint10_linear_2450_35919)"/>
|
||||
</g>
|
||||
</g>
|
||||
<rect x="0.0205078" y="0.0205078" width="19.959" height="19.959" rx="4.58544" stroke="black" stroke-opacity="0.1" stroke-width="0.0410156"/>
|
||||
<defs>
|
||||
<filter id="filter0_f_2450_35919" x="-3.16699" y="0.833389" width="26.333" height="22.3333" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feGaussianBlur stdDeviation="1.75" result="effect1_foregroundBlur_2450_35919"/>
|
||||
</filter>
|
||||
<filter id="filter1_i_2450_35919" x="2.8125" y="1.9935" width="14.375" height="15.5376" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset/>
|
||||
<feGaussianBlur stdDeviation="0.47168"/>
|
||||
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0.864916 0 0 0 0 0.401042 0 0 0 0 0.875 0 0 0 1 0"/>
|
||||
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_2450_35919"/>
|
||||
</filter>
|
||||
<linearGradient id="paint0_linear_2450_35919" x1="7.66667" y1="20" x2="7.66667" y2="0" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FFF1FF"/>
|
||||
<stop offset="1" stop-color="white" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="paint1_radial_2450_35919" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(10.0123 11.9901) rotate(35.9783) scale(9.71138 9.26994)">
|
||||
<stop stop-color="white"/>
|
||||
<stop offset="1" stop-color="#FFE3FF"/>
|
||||
</radialGradient>
|
||||
<linearGradient id="paint2_linear_2450_35919" x1="16.4648" y1="15.099" x2="7.33333" y2="7.33334" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FC72FF"/>
|
||||
<stop offset="1" stop-color="#FF41F4"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint3_linear_2450_35919" x1="16.4648" y1="15.099" x2="7.33333" y2="7.33334" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FC72FF"/>
|
||||
<stop offset="1" stop-color="#FF41F4"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint4_linear_2450_35919" x1="16.4648" y1="15.099" x2="7.33333" y2="7.33334" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FC72FF"/>
|
||||
<stop offset="1" stop-color="#FF41F4"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint5_linear_2450_35919" x1="16.4648" y1="15.099" x2="7.33333" y2="7.33334" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FC72FF"/>
|
||||
<stop offset="1" stop-color="#FF41F4"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint6_linear_2450_35919" x1="16.4648" y1="15.099" x2="7.33333" y2="7.33334" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FC72FF"/>
|
||||
<stop offset="1" stop-color="#FF41F4"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint7_linear_2450_35919" x1="16.4648" y1="15.099" x2="7.33333" y2="7.33334" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FC72FF"/>
|
||||
<stop offset="1" stop-color="#FF41F4"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint8_linear_2450_35919" x1="16.4648" y1="15.099" x2="7.33333" y2="7.33334" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FC72FF"/>
|
||||
<stop offset="1" stop-color="#FF41F4"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint9_linear_2450_35919" x1="16.4648" y1="15.099" x2="7.33333" y2="7.33334" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FC72FF"/>
|
||||
<stop offset="1" stop-color="#FF41F4"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint10_linear_2450_35919" x1="16.4648" y1="15.099" x2="7.33333" y2="7.33334" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FC72FF"/>
|
||||
<stop offset="1" stop-color="#FF41F4"/>
|
||||
</linearGradient>
|
||||
<clipPath id="clip0_2450_35919">
|
||||
<rect width="20" height="20" rx="4.60595" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After (image error) Size: 12 KiB |
@ -9,7 +9,7 @@ import { Power } from 'components/Icons/Power'
|
||||
import { Settings } from 'components/Icons/Settings'
|
||||
import { AutoRow } from 'components/Row'
|
||||
import { LoadingBubble } from 'components/Tokens/loading'
|
||||
import { DeltaArrow, formatDelta } from 'components/Tokens/TokenDetails/Delta'
|
||||
import { DeltaArrow } from 'components/Tokens/TokenDetails/Delta'
|
||||
import Tooltip from 'components/Tooltip'
|
||||
import { getConnection } from 'connection'
|
||||
import { useDisableNFTRoutes } from 'hooks/useDisableNFTRoutes'
|
||||
@ -25,6 +25,7 @@ import { updateSelectedWallet } from 'state/user/reducer'
|
||||
import styled from 'styled-components'
|
||||
import { CopyHelper, ExternalLink, ThemedText } from 'theme/components'
|
||||
import { shortenAddress } from 'utils'
|
||||
import { isPathBlocked } from 'utils/blockedPaths'
|
||||
import { NumberType, useFormatter } from 'utils/formatNumbers'
|
||||
|
||||
import { useCloseModal, useFiatOnrampAvailability, useOpenModal, useToggleModal } from '../../state/application/hooks'
|
||||
@ -159,7 +160,8 @@ export default function AuthenticatedHeader({ account, openSettings }: { account
|
||||
const resetSellAssets = useSellAsset((state) => state.reset)
|
||||
const clearCollectionFilters = useWalletCollections((state) => state.clearCollectionFilters)
|
||||
const isClaimAvailable = useIsNftClaimAvailable((state) => state.isClaimAvailable)
|
||||
const { formatNumber } = useFormatter()
|
||||
const shouldShowBuyFiatButton = !isPathBlocked('/buy')
|
||||
const { formatNumber, formatDelta } = useFormatter()
|
||||
|
||||
const shouldDisableNFTRoutes = useDisableNFTRoutes()
|
||||
|
||||
@ -304,26 +306,28 @@ export default function AuthenticatedHeader({ account, openSettings }: { account
|
||||
<Trans>View and sell NFTs</Trans>
|
||||
</HeaderButton>
|
||||
)}
|
||||
<HeaderButton
|
||||
size={ButtonSize.medium}
|
||||
emphasis={ButtonEmphasis.highSoft}
|
||||
onClick={handleBuyCryptoClick}
|
||||
disabled={disableBuyCryptoButton}
|
||||
data-testid="wallet-buy-crypto"
|
||||
>
|
||||
{error ? (
|
||||
<ThemedText.BodyPrimary>{error}</ThemedText.BodyPrimary>
|
||||
) : (
|
||||
<>
|
||||
{fiatOnrampAvailabilityLoading ? (
|
||||
<StyledLoadingButtonSpinner />
|
||||
) : (
|
||||
<CreditCard height="20px" width="20px" />
|
||||
)}{' '}
|
||||
<Trans>Buy crypto</Trans>
|
||||
</>
|
||||
)}
|
||||
</HeaderButton>
|
||||
{shouldShowBuyFiatButton && (
|
||||
<HeaderButton
|
||||
size={ButtonSize.medium}
|
||||
emphasis={ButtonEmphasis.highSoft}
|
||||
onClick={handleBuyCryptoClick}
|
||||
disabled={disableBuyCryptoButton}
|
||||
data-testid="wallet-buy-crypto"
|
||||
>
|
||||
{error ? (
|
||||
<ThemedText.BodyPrimary>{error}</ThemedText.BodyPrimary>
|
||||
) : (
|
||||
<>
|
||||
{fiatOnrampAvailabilityLoading ? (
|
||||
<StyledLoadingButtonSpinner />
|
||||
) : (
|
||||
<CreditCard height="20px" width="20px" />
|
||||
)}{' '}
|
||||
<Trans>Buy crypto</Trans>
|
||||
</>
|
||||
)}
|
||||
</HeaderButton>
|
||||
)}
|
||||
{Boolean(!fiatOnrampAvailable && fiatOnrampAvailabilityChecked) && (
|
||||
<FiatOnrampNotAvailableText marginTop="8px">
|
||||
<Trans>Not available in your region</Trans>
|
||||
|
@ -31,7 +31,7 @@ function BaseButton({ onClick, branded, children }: PropsWithChildren<{ onClick?
|
||||
)
|
||||
}
|
||||
|
||||
// Launches App Store if on an iOS device, else navigates to Uniswap Wallet microsite
|
||||
// Launches App/Play Store if on an iOS/Android device, else navigates to Uniswap Wallet microsite
|
||||
export function DownloadButton({
|
||||
onClick,
|
||||
text = 'Download',
|
||||
|
@ -90,7 +90,7 @@ const DescriptionText = styled(ThemedText.LabelMicro)`
|
||||
|
||||
function useOrderAmounts(
|
||||
orderDetails?: UniswapXOrderDetails
|
||||
): Pick<InterfaceTrade, 'inputAmount' | 'postTaxOutputAmount'> | undefined {
|
||||
): Pick<InterfaceTrade, 'inputAmount' | 'outputAmount'> | undefined {
|
||||
const inputCurrency = useCurrency(orderDetails?.swapInfo?.inputCurrencyId, orderDetails?.chainId)
|
||||
const outputCurrency = useCurrency(orderDetails?.swapInfo?.outputCurrencyId, orderDetails?.chainId)
|
||||
|
||||
@ -106,7 +106,7 @@ function useOrderAmounts(
|
||||
if (swapInfo.tradeType === TradeType.EXACT_INPUT) {
|
||||
return {
|
||||
inputAmount: CurrencyAmount.fromRawAmount(inputCurrency, swapInfo.inputCurrencyAmountRaw),
|
||||
postTaxOutputAmount: CurrencyAmount.fromRawAmount(
|
||||
outputAmount: CurrencyAmount.fromRawAmount(
|
||||
outputCurrency,
|
||||
swapInfo.settledOutputCurrencyAmountRaw ?? swapInfo.expectedOutputCurrencyAmountRaw
|
||||
),
|
||||
@ -114,7 +114,7 @@ function useOrderAmounts(
|
||||
} else {
|
||||
return {
|
||||
inputAmount: CurrencyAmount.fromRawAmount(inputCurrency, swapInfo.expectedInputCurrencyAmountRaw),
|
||||
postTaxOutputAmount: CurrencyAmount.fromRawAmount(outputCurrency, swapInfo.outputCurrencyAmountRaw),
|
||||
outputAmount: CurrencyAmount.fromRawAmount(outputCurrency, swapInfo.outputCurrencyAmountRaw),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
400
src/components/AccountDrawer/MiniPortfolio/Activity/__snapshots__/parseRemote.test.tsx.snap
Normal file
@ -0,0 +1,400 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`parseRemote parseRemoteActivities should parse NFT approval 1`] = `
|
||||
Object {
|
||||
"chainId": 1,
|
||||
"descriptor": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
|
||||
"from": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3",
|
||||
"hash": "someHash",
|
||||
"logos": Array [],
|
||||
"nonce": 12345,
|
||||
"status": "CONFIRMED",
|
||||
"timestamp": 10000,
|
||||
"title": "Unknown Approval",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`parseRemote parseRemoteActivities should parse NFT approval for all 1`] = `
|
||||
Object {
|
||||
"chainId": 1,
|
||||
"descriptor": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
|
||||
"from": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3",
|
||||
"hash": "someHash",
|
||||
"logos": Array [],
|
||||
"nonce": 12345,
|
||||
"status": "CONFIRMED",
|
||||
"timestamp": 10000,
|
||||
"title": "Unknown Approval",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`parseRemote parseRemoteActivities should parse NFT receive 1`] = `
|
||||
Object {
|
||||
"chainId": 1,
|
||||
"currencies": undefined,
|
||||
"descriptor": "1 SomeCollectionName from ",
|
||||
"from": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3",
|
||||
"hash": "someHash",
|
||||
"logos": Array [
|
||||
"imageUrl",
|
||||
],
|
||||
"nonce": 12345,
|
||||
"otherAccount": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3",
|
||||
"status": "CONFIRMED",
|
||||
"timestamp": 10000,
|
||||
"title": "Received",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`parseRemote parseRemoteActivities should parse NFT transfer 1`] = `
|
||||
Object {
|
||||
"chainId": 1,
|
||||
"descriptor": "1 SomeCollectionName",
|
||||
"from": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3",
|
||||
"hash": "someHash",
|
||||
"logos": Array [
|
||||
"imageUrl",
|
||||
],
|
||||
"nonce": 12345,
|
||||
"status": "CONFIRMED",
|
||||
"timestamp": 10000,
|
||||
"title": "Minted",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`parseRemote parseRemoteActivities should parse closed UniswapX order 1`] = `
|
||||
Object {
|
||||
"chainId": 1,
|
||||
"currencies": Array [
|
||||
Token {
|
||||
"address": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
|
||||
"buyFeeBps": undefined,
|
||||
"chainId": 1,
|
||||
"decimals": 18,
|
||||
"isNative": false,
|
||||
"isToken": true,
|
||||
"name": "DAI",
|
||||
"sellFeeBps": undefined,
|
||||
"symbol": "DAI",
|
||||
},
|
||||
Token {
|
||||
"address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
||||
"buyFeeBps": undefined,
|
||||
"chainId": 1,
|
||||
"decimals": 18,
|
||||
"isNative": false,
|
||||
"isToken": true,
|
||||
"name": "Wrapped Ether",
|
||||
"sellFeeBps": undefined,
|
||||
"symbol": "WETH",
|
||||
},
|
||||
],
|
||||
"descriptor": "100 DAI for 200 WETH",
|
||||
"from": "someOfferer",
|
||||
"hash": "someHash",
|
||||
"logos": Array [
|
||||
"someUrl",
|
||||
"someUrl",
|
||||
],
|
||||
"offchainOrderStatus": "expired",
|
||||
"prefixIconSrc": "bolt.svg",
|
||||
"status": "FAILED",
|
||||
"statusMessage": "Your swap could not be fulfilled at this time. Please try again.",
|
||||
"timestamp": 10000,
|
||||
"title": "Swap expired",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`parseRemote parseRemoteActivities should parse eth wrap 1`] = `
|
||||
Object {
|
||||
"chainId": 1,
|
||||
"currencies": Array [
|
||||
ExtendedEther {
|
||||
"chainId": 1,
|
||||
"decimals": 18,
|
||||
"isNative": true,
|
||||
"isToken": false,
|
||||
"name": "Ether",
|
||||
"symbol": "ETH",
|
||||
},
|
||||
Token {
|
||||
"address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
||||
"buyFeeBps": undefined,
|
||||
"chainId": 1,
|
||||
"decimals": 18,
|
||||
"isNative": false,
|
||||
"isToken": true,
|
||||
"name": "Wrapped Ether",
|
||||
"sellFeeBps": undefined,
|
||||
"symbol": "WETH",
|
||||
},
|
||||
],
|
||||
"descriptor": "100 ETH for 100 WETH",
|
||||
"from": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3",
|
||||
"hash": "someHash",
|
||||
"logos": Array [
|
||||
"https://token-icons.s3.amazonaws.com/eth.png",
|
||||
"https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/logo.png",
|
||||
],
|
||||
"nonce": 12345,
|
||||
"status": "CONFIRMED",
|
||||
"timestamp": 10000,
|
||||
"title": "Wrapped",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`parseRemote parseRemoteActivities should parse moonpay purchase 1`] = `
|
||||
Object {
|
||||
"chainId": 1,
|
||||
"currencies": Array [
|
||||
Token {
|
||||
"address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
||||
"buyFeeBps": undefined,
|
||||
"chainId": 1,
|
||||
"decimals": 18,
|
||||
"isNative": false,
|
||||
"isToken": true,
|
||||
"name": "Wrapped Ether",
|
||||
"sellFeeBps": undefined,
|
||||
"symbol": "WETH",
|
||||
},
|
||||
],
|
||||
"descriptor": "100 WETH for 100",
|
||||
"from": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3",
|
||||
"hash": "someHash",
|
||||
"logos": Array [
|
||||
"moonpay.svg",
|
||||
],
|
||||
"nonce": 12345,
|
||||
"status": "CONFIRMED",
|
||||
"timestamp": 10000,
|
||||
"title": "Purchased",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`parseRemote parseRemoteActivities should parse nft purchase 1`] = `
|
||||
Object {
|
||||
"chainId": 1,
|
||||
"descriptor": "1 SomeCollectionName",
|
||||
"from": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3",
|
||||
"hash": "someHash",
|
||||
"logos": Array [
|
||||
"imageUrl",
|
||||
],
|
||||
"nonce": 12345,
|
||||
"status": "CONFIRMED",
|
||||
"timestamp": 10000,
|
||||
"title": "Bought",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`parseRemote parseRemoteActivities should parse receive 1`] = `
|
||||
Object {
|
||||
"chainId": 1,
|
||||
"currencies": Array [
|
||||
Token {
|
||||
"address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
||||
"buyFeeBps": undefined,
|
||||
"chainId": 1,
|
||||
"decimals": 18,
|
||||
"isNative": false,
|
||||
"isToken": true,
|
||||
"name": "Wrapped Ether",
|
||||
"sellFeeBps": undefined,
|
||||
"symbol": "WETH",
|
||||
},
|
||||
],
|
||||
"descriptor": "100 WETH from ",
|
||||
"from": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3",
|
||||
"hash": "someHash",
|
||||
"logos": Array [
|
||||
"logoUrl",
|
||||
],
|
||||
"nonce": 12345,
|
||||
"otherAccount": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3",
|
||||
"status": "CONFIRMED",
|
||||
"timestamp": 10000,
|
||||
"title": "Received",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`parseRemote parseRemoteActivities should parse remove liquidity 1`] = `
|
||||
Object {
|
||||
"chainId": 1,
|
||||
"currencies": Array [
|
||||
Token {
|
||||
"address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
||||
"buyFeeBps": undefined,
|
||||
"chainId": 1,
|
||||
"decimals": 18,
|
||||
"isNative": false,
|
||||
"isToken": true,
|
||||
"name": "Wrapped Ether",
|
||||
"sellFeeBps": undefined,
|
||||
"symbol": "WETH",
|
||||
},
|
||||
Token {
|
||||
"address": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
|
||||
"buyFeeBps": undefined,
|
||||
"chainId": 1,
|
||||
"decimals": 18,
|
||||
"isNative": false,
|
||||
"isToken": true,
|
||||
"name": "DAI",
|
||||
"sellFeeBps": undefined,
|
||||
"symbol": "DAI",
|
||||
},
|
||||
],
|
||||
"descriptor": "100 WETH and 100 DAI",
|
||||
"from": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3",
|
||||
"hash": "someHash",
|
||||
"logos": Array [
|
||||
"logoUrl",
|
||||
"logoUrl",
|
||||
],
|
||||
"nonce": 12345,
|
||||
"status": "CONFIRMED",
|
||||
"timestamp": 10000,
|
||||
"title": "Removed Liquidity",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`parseRemote parseRemoteActivities should parse send 1`] = `
|
||||
Object {
|
||||
"chainId": 1,
|
||||
"currencies": Array [
|
||||
Token {
|
||||
"address": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
|
||||
"buyFeeBps": undefined,
|
||||
"chainId": 1,
|
||||
"decimals": 18,
|
||||
"isNative": false,
|
||||
"isToken": true,
|
||||
"name": "DAI",
|
||||
"sellFeeBps": undefined,
|
||||
"symbol": "DAI",
|
||||
},
|
||||
],
|
||||
"descriptor": "100 DAI to ",
|
||||
"from": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3",
|
||||
"hash": "someHash",
|
||||
"logos": Array [
|
||||
"logoUrl",
|
||||
],
|
||||
"nonce": 12345,
|
||||
"otherAccount": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
|
||||
"status": "CONFIRMED",
|
||||
"timestamp": 10000,
|
||||
"title": "Sent",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`parseRemote parseRemoteActivities should parse swap 1`] = `
|
||||
Object {
|
||||
"chainId": 1,
|
||||
"currencies": Array [
|
||||
Token {
|
||||
"address": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
|
||||
"buyFeeBps": undefined,
|
||||
"chainId": 1,
|
||||
"decimals": 18,
|
||||
"isNative": false,
|
||||
"isToken": true,
|
||||
"name": "DAI",
|
||||
"sellFeeBps": undefined,
|
||||
"symbol": "DAI",
|
||||
},
|
||||
Token {
|
||||
"address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
||||
"buyFeeBps": undefined,
|
||||
"chainId": 1,
|
||||
"decimals": 18,
|
||||
"isNative": false,
|
||||
"isToken": true,
|
||||
"name": "Wrapped Ether",
|
||||
"sellFeeBps": undefined,
|
||||
"symbol": "WETH",
|
||||
},
|
||||
],
|
||||
"descriptor": "100 DAI for 100 WETH",
|
||||
"from": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3",
|
||||
"hash": "someHash",
|
||||
"logos": Array [
|
||||
"logoUrl",
|
||||
],
|
||||
"nonce": 12345,
|
||||
"status": "CONFIRMED",
|
||||
"timestamp": 10000,
|
||||
"title": "Swapped",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`parseRemote parseRemoteActivities should parse swap order 1`] = `
|
||||
Object {
|
||||
"chainId": 1,
|
||||
"currencies": Array [
|
||||
Token {
|
||||
"address": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
|
||||
"buyFeeBps": undefined,
|
||||
"chainId": 1,
|
||||
"decimals": 18,
|
||||
"isNative": false,
|
||||
"isToken": true,
|
||||
"name": "DAI",
|
||||
"sellFeeBps": undefined,
|
||||
"symbol": "DAI",
|
||||
},
|
||||
Token {
|
||||
"address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
||||
"buyFeeBps": undefined,
|
||||
"chainId": 1,
|
||||
"decimals": 18,
|
||||
"isNative": false,
|
||||
"isToken": true,
|
||||
"name": "Wrapped Ether",
|
||||
"sellFeeBps": undefined,
|
||||
"symbol": "WETH",
|
||||
},
|
||||
],
|
||||
"descriptor": "100 DAI for 100 WETH",
|
||||
"from": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3",
|
||||
"hash": "someHash",
|
||||
"logos": Array [
|
||||
"logoUrl",
|
||||
],
|
||||
"nonce": 12345,
|
||||
"prefixIconSrc": "bolt.svg",
|
||||
"status": "CONFIRMED",
|
||||
"timestamp": 10000,
|
||||
"title": "Swapped",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`parseRemote parseRemoteActivities should parse token approval 1`] = `
|
||||
Object {
|
||||
"chainId": 1,
|
||||
"currencies": Array [
|
||||
Token {
|
||||
"address": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
|
||||
"buyFeeBps": undefined,
|
||||
"chainId": 1,
|
||||
"decimals": 18,
|
||||
"isNative": false,
|
||||
"isToken": true,
|
||||
"name": "DAI",
|
||||
"sellFeeBps": undefined,
|
||||
"symbol": "DAI",
|
||||
},
|
||||
],
|
||||
"descriptor": "DAI",
|
||||
"from": "0x50EC05ADe8280758E2077fcBC08D878D4aef79C3",
|
||||
"hash": "someHash",
|
||||
"logos": Array [
|
||||
"logoUrl",
|
||||
],
|
||||
"nonce": 12345,
|
||||
"status": "CONFIRMED",
|
||||
"timestamp": 10000,
|
||||
"title": "Approved",
|
||||
}
|
||||
`;
|
@ -0,0 +1,522 @@
|
||||
import { ChainId, NONFUNGIBLE_POSITION_MANAGER_ADDRESSES, WETH9 } from '@uniswap/sdk-core'
|
||||
import { DAI } from 'constants/tokens'
|
||||
import {
|
||||
AssetActivityPartsFragment,
|
||||
Chain,
|
||||
Currency,
|
||||
NftStandard,
|
||||
SwapOrderStatus,
|
||||
TokenStandard,
|
||||
TransactionDirection,
|
||||
TransactionStatus,
|
||||
TransactionType,
|
||||
} from 'graphql/data/__generated__/types-and-hooks'
|
||||
|
||||
import { MOONPAY_SENDER_ADDRESSES } from '../../constants'
|
||||
|
||||
const MockOrderTimestamp = 10000
|
||||
const MockRecipientAddress = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
|
||||
const MockSenderAddress = '0x50EC05ADe8280758E2077fcBC08D878D4aef79C3'
|
||||
|
||||
const mockAssetActivityPartsFragment = {
|
||||
__typename: 'AssetActivity',
|
||||
id: 'activityId',
|
||||
timestamp: MockOrderTimestamp,
|
||||
chain: Chain.Ethereum,
|
||||
details: {
|
||||
__typename: 'SwapOrderDetails',
|
||||
id: 'detailsId',
|
||||
offerer: 'offererId',
|
||||
hash: 'someHash',
|
||||
inputTokenQuantity: '100',
|
||||
outputTokenQuantity: '200',
|
||||
orderStatus: SwapOrderStatus.Open,
|
||||
inputToken: {
|
||||
__typename: 'Token',
|
||||
id: 'tokenId',
|
||||
chain: Chain.Ethereum,
|
||||
standard: TokenStandard.Erc20,
|
||||
},
|
||||
outputToken: {
|
||||
__typename: 'Token',
|
||||
id: 'tokenId',
|
||||
chain: Chain.Ethereum,
|
||||
standard: TokenStandard.Erc20,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const mockSwapOrderDetailsPartsFragment = {
|
||||
__typename: 'SwapOrderDetails',
|
||||
id: 'someId',
|
||||
offerer: 'someOfferer',
|
||||
hash: 'someHash',
|
||||
inputTokenQuantity: '100',
|
||||
outputTokenQuantity: '200',
|
||||
orderStatus: SwapOrderStatus.Open,
|
||||
inputToken: {
|
||||
__typename: 'Token',
|
||||
id: DAI.address,
|
||||
name: 'DAI',
|
||||
symbol: DAI.symbol,
|
||||
address: DAI.address,
|
||||
decimals: 18,
|
||||
chain: Chain.Ethereum,
|
||||
standard: TokenStandard.Erc20,
|
||||
project: {
|
||||
__typename: 'TokenProject',
|
||||
id: 'projectId',
|
||||
isSpam: false,
|
||||
logo: {
|
||||
__typename: 'Image',
|
||||
id: 'imageId',
|
||||
url: 'someUrl',
|
||||
},
|
||||
},
|
||||
},
|
||||
outputToken: {
|
||||
__typename: 'Token',
|
||||
id: WETH9[1].address,
|
||||
name: 'Wrapped Ether',
|
||||
symbol: 'WETH',
|
||||
address: WETH9[1].address,
|
||||
decimals: 18,
|
||||
chain: Chain.Ethereum,
|
||||
standard: TokenStandard.Erc20,
|
||||
project: {
|
||||
__typename: 'TokenProject',
|
||||
id: 'projectId',
|
||||
isSpam: false,
|
||||
logo: {
|
||||
__typename: 'Image',
|
||||
id: 'imageId',
|
||||
url: 'someUrl',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const mockNftApprovalPartsFragment = {
|
||||
__typename: 'NftApproval',
|
||||
id: 'approvalId',
|
||||
nftStandard: NftStandard.Erc721, // Replace with actual enum value
|
||||
approvedAddress: '0xApprovedAddress',
|
||||
asset: {
|
||||
__typename: 'NftAsset',
|
||||
id: 'assetId',
|
||||
name: 'SomeNftName',
|
||||
tokenId: 'tokenId123',
|
||||
nftContract: {
|
||||
__typename: 'NftContract',
|
||||
id: 'nftContractId',
|
||||
chain: Chain.Ethereum, // Replace with actual enum value
|
||||
address: '0xContractAddress',
|
||||
},
|
||||
image: {
|
||||
__typename: 'Image',
|
||||
id: 'imageId',
|
||||
url: 'imageUrl',
|
||||
},
|
||||
collection: {
|
||||
__typename: 'NftCollection',
|
||||
id: 'collectionId',
|
||||
name: 'SomeCollectionName',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const mockNftApproveForAllPartsFragment = {
|
||||
__typename: 'NftApproveForAll',
|
||||
id: 'approveForAllId',
|
||||
nftStandard: NftStandard.Erc721, // Replace with actual enum value
|
||||
operatorAddress: '0xOperatorAddress',
|
||||
approved: true,
|
||||
asset: {
|
||||
__typename: 'NftAsset',
|
||||
id: 'assetId',
|
||||
name: 'SomeNftName',
|
||||
tokenId: 'tokenId123',
|
||||
nftContract: {
|
||||
__typename: 'NftContract',
|
||||
id: 'nftContractId',
|
||||
chain: Chain.Ethereum, // Replace with actual enum value
|
||||
address: '0xContractAddress',
|
||||
},
|
||||
image: {
|
||||
__typename: 'Image',
|
||||
id: 'imageId',
|
||||
url: 'imageUrl',
|
||||
},
|
||||
collection: {
|
||||
__typename: 'NftCollection',
|
||||
id: 'collectionId',
|
||||
name: 'SomeCollectionName',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const mockNftTransferPartsFragment = {
|
||||
__typename: 'NftTransfer',
|
||||
id: 'transferId',
|
||||
nftStandard: NftStandard.Erc721,
|
||||
sender: MockSenderAddress,
|
||||
recipient: MockRecipientAddress,
|
||||
direction: TransactionDirection.Out,
|
||||
asset: {
|
||||
__typename: 'NftAsset',
|
||||
id: 'assetId',
|
||||
name: 'SomeNftName',
|
||||
tokenId: 'tokenId123',
|
||||
nftContract: {
|
||||
__typename: 'NftContract',
|
||||
id: 'nftContractId',
|
||||
chain: Chain.Ethereum,
|
||||
address: '0xContractAddress',
|
||||
},
|
||||
image: {
|
||||
__typename: 'Image',
|
||||
id: 'imageId',
|
||||
url: 'imageUrl',
|
||||
},
|
||||
collection: {
|
||||
__typename: 'NftCollection',
|
||||
id: 'collectionId',
|
||||
name: 'SomeCollectionName',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const mockTokenTransferOutPartsFragment = {
|
||||
__typename: 'TokenTransfer',
|
||||
id: 'tokenTransferId',
|
||||
tokenStandard: TokenStandard.Erc20,
|
||||
quantity: '100',
|
||||
sender: MockSenderAddress,
|
||||
recipient: MockRecipientAddress,
|
||||
direction: TransactionDirection.Out,
|
||||
asset: {
|
||||
__typename: 'Token',
|
||||
id: DAI.address,
|
||||
name: 'DAI',
|
||||
symbol: 'DAI',
|
||||
address: DAI.address,
|
||||
decimals: 18,
|
||||
chain: Chain.Ethereum,
|
||||
standard: TokenStandard.Erc20,
|
||||
project: {
|
||||
__typename: 'TokenProject',
|
||||
id: 'projectId',
|
||||
isSpam: false,
|
||||
logo: {
|
||||
__typename: 'Image',
|
||||
id: 'logoId',
|
||||
url: 'logoUrl',
|
||||
},
|
||||
},
|
||||
},
|
||||
transactedValue: {
|
||||
__typename: 'Amount',
|
||||
id: 'amountId',
|
||||
currency: Currency.Usd,
|
||||
value: 100,
|
||||
},
|
||||
}
|
||||
|
||||
const mockNativeTokenTransferOutPartsFragment = {
|
||||
__typename: 'TokenTransfer',
|
||||
id: 'tokenTransferId',
|
||||
asset: {
|
||||
__typename: 'Token',
|
||||
id: 'ETH',
|
||||
name: 'Ether',
|
||||
symbol: 'ETH',
|
||||
address: null,
|
||||
decimals: 18,
|
||||
chain: 'ETHEREUM',
|
||||
standard: null,
|
||||
project: {
|
||||
__typename: 'TokenProject',
|
||||
id: 'Ethereum',
|
||||
isSpam: false,
|
||||
logo: {
|
||||
__typename: 'Image',
|
||||
id: 'ETH_logo',
|
||||
url: 'https://token-icons.s3.amazonaws.com/eth.png',
|
||||
},
|
||||
},
|
||||
},
|
||||
tokenStandard: 'NATIVE',
|
||||
quantity: '0.25',
|
||||
sender: MockSenderAddress,
|
||||
recipient: MockRecipientAddress,
|
||||
direction: 'OUT',
|
||||
transactedValue: {
|
||||
__typename: 'Amount',
|
||||
id: 'ETH_amount',
|
||||
currency: 'USD',
|
||||
value: 399.0225,
|
||||
},
|
||||
}
|
||||
|
||||
const mockWrappedEthTransferInPartsFragment = {
|
||||
__typename: 'TokenTransfer',
|
||||
id: 'tokenTransferId',
|
||||
asset: {
|
||||
__typename: 'Token',
|
||||
id: 'WETH',
|
||||
name: 'Wrapped Ether',
|
||||
symbol: 'WETH',
|
||||
address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
|
||||
decimals: 18,
|
||||
chain: 'ETHEREUM',
|
||||
standard: 'ERC20',
|
||||
project: {
|
||||
__typename: 'TokenProject',
|
||||
id: 'weth_project_id',
|
||||
isSpam: false,
|
||||
logo: {
|
||||
__typename: 'Image',
|
||||
id: 'weth_image',
|
||||
url: 'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/logo.png',
|
||||
},
|
||||
},
|
||||
},
|
||||
tokenStandard: 'ERC20',
|
||||
quantity: '0.25',
|
||||
sender: MockSenderAddress,
|
||||
recipient: MockRecipientAddress,
|
||||
direction: 'IN',
|
||||
transactedValue: {
|
||||
__typename: 'Amount',
|
||||
id: 'mockWethAmountId',
|
||||
currency: 'USD',
|
||||
value: 399.1334007875,
|
||||
},
|
||||
}
|
||||
|
||||
const mockTokenTransferInPartsFragment = {
|
||||
__typename: 'TokenTransfer',
|
||||
id: 'tokenTransferId',
|
||||
tokenStandard: TokenStandard.Erc20,
|
||||
quantity: '1',
|
||||
sender: MockSenderAddress,
|
||||
recipient: MockRecipientAddress,
|
||||
direction: TransactionDirection.In,
|
||||
asset: {
|
||||
__typename: 'Token',
|
||||
id: WETH9[1].address,
|
||||
name: 'Wrapped Ether',
|
||||
symbol: 'WETH',
|
||||
address: WETH9[1].address,
|
||||
decimals: 18,
|
||||
chain: Chain.Ethereum,
|
||||
standard: TokenStandard.Erc20,
|
||||
project: {
|
||||
__typename: 'TokenProject',
|
||||
id: 'projectId',
|
||||
isSpam: false,
|
||||
logo: {
|
||||
__typename: 'Image',
|
||||
id: 'logoId',
|
||||
url: 'logoUrl',
|
||||
},
|
||||
},
|
||||
},
|
||||
transactedValue: {
|
||||
__typename: 'Amount',
|
||||
id: 'amountId',
|
||||
currency: Currency.Usd,
|
||||
value: 100,
|
||||
},
|
||||
}
|
||||
|
||||
const mockTokenApprovalPartsFragment = {
|
||||
__typename: 'TokenApproval',
|
||||
id: 'tokenApprovalId',
|
||||
tokenStandard: TokenStandard.Erc20,
|
||||
approvedAddress: DAI.address,
|
||||
quantity: '50',
|
||||
asset: {
|
||||
__typename: 'Token',
|
||||
id: 'tokenId',
|
||||
name: 'DAI',
|
||||
symbol: 'DAI',
|
||||
address: DAI.address,
|
||||
decimals: 18,
|
||||
chain: Chain.Ethereum,
|
||||
standard: TokenStandard.Erc20,
|
||||
project: {
|
||||
__typename: 'TokenProject',
|
||||
id: 'projectId',
|
||||
isSpam: false,
|
||||
logo: {
|
||||
__typename: 'Image',
|
||||
id: 'logoId',
|
||||
url: 'logoUrl',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const MockOpenUniswapXOrder = {
|
||||
...mockAssetActivityPartsFragment,
|
||||
details: mockSwapOrderDetailsPartsFragment,
|
||||
} as AssetActivityPartsFragment
|
||||
|
||||
export const MockClosedUniswapXOrder = {
|
||||
...mockAssetActivityPartsFragment,
|
||||
details: {
|
||||
...mockSwapOrderDetailsPartsFragment,
|
||||
orderStatus: SwapOrderStatus.Expired,
|
||||
},
|
||||
} as AssetActivityPartsFragment
|
||||
|
||||
const commonTransactionDetailsFields = {
|
||||
__typename: 'TransactionDetails',
|
||||
from: MockSenderAddress,
|
||||
hash: 'someHash',
|
||||
id: 'transactionId',
|
||||
nonce: 12345,
|
||||
status: TransactionStatus.Confirmed,
|
||||
to: MockRecipientAddress,
|
||||
}
|
||||
|
||||
export const MockNFTApproval = {
|
||||
...mockAssetActivityPartsFragment,
|
||||
details: {
|
||||
...commonTransactionDetailsFields,
|
||||
type: TransactionType.Approve,
|
||||
assetChanges: [mockNftApprovalPartsFragment],
|
||||
},
|
||||
} as AssetActivityPartsFragment
|
||||
|
||||
export const MockNFTApprovalForAll = {
|
||||
...mockAssetActivityPartsFragment,
|
||||
details: {
|
||||
...commonTransactionDetailsFields,
|
||||
type: TransactionType.Approve,
|
||||
assetChanges: [mockNftApproveForAllPartsFragment],
|
||||
},
|
||||
} as AssetActivityPartsFragment
|
||||
|
||||
export const MockNFTTransfer = {
|
||||
...mockAssetActivityPartsFragment,
|
||||
details: {
|
||||
...commonTransactionDetailsFields,
|
||||
type: TransactionType.Mint,
|
||||
assetChanges: [mockNftTransferPartsFragment],
|
||||
},
|
||||
} as AssetActivityPartsFragment
|
||||
|
||||
export const MockTokenTransfer = {
|
||||
...mockAssetActivityPartsFragment,
|
||||
details: {
|
||||
...commonTransactionDetailsFields,
|
||||
type: TransactionType.Swap,
|
||||
assetChanges: [mockTokenTransferOutPartsFragment, mockTokenTransferInPartsFragment],
|
||||
},
|
||||
} as AssetActivityPartsFragment
|
||||
|
||||
export const MockSwapOrder = {
|
||||
...mockAssetActivityPartsFragment,
|
||||
details: {
|
||||
...commonTransactionDetailsFields,
|
||||
type: TransactionType.SwapOrder,
|
||||
assetChanges: [mockTokenTransferOutPartsFragment, mockTokenTransferInPartsFragment],
|
||||
},
|
||||
} as AssetActivityPartsFragment
|
||||
|
||||
export const MockTokenApproval = {
|
||||
...mockAssetActivityPartsFragment,
|
||||
details: {
|
||||
...commonTransactionDetailsFields,
|
||||
type: TransactionType.Approve,
|
||||
assetChanges: [mockTokenApprovalPartsFragment],
|
||||
},
|
||||
} as AssetActivityPartsFragment
|
||||
|
||||
export const MockTokenSend = {
|
||||
...mockAssetActivityPartsFragment,
|
||||
details: {
|
||||
...commonTransactionDetailsFields,
|
||||
type: TransactionType.Send,
|
||||
assetChanges: [mockTokenTransferOutPartsFragment],
|
||||
},
|
||||
} as AssetActivityPartsFragment
|
||||
|
||||
export const MockTokenReceive = {
|
||||
...mockAssetActivityPartsFragment,
|
||||
details: {
|
||||
...commonTransactionDetailsFields,
|
||||
type: TransactionType.Receive,
|
||||
assetChanges: [mockTokenTransferInPartsFragment],
|
||||
},
|
||||
} as AssetActivityPartsFragment
|
||||
|
||||
export const MockRemoveLiquidity = {
|
||||
...mockAssetActivityPartsFragment,
|
||||
details: {
|
||||
...commonTransactionDetailsFields,
|
||||
to: NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[ChainId.MAINNET],
|
||||
type: TransactionType.Receive,
|
||||
assetChanges: [
|
||||
mockTokenTransferInPartsFragment,
|
||||
{
|
||||
...mockTokenTransferOutPartsFragment,
|
||||
direction: TransactionDirection.In,
|
||||
},
|
||||
],
|
||||
},
|
||||
} as AssetActivityPartsFragment
|
||||
|
||||
export const MockMoonpayPurchase = {
|
||||
...mockAssetActivityPartsFragment,
|
||||
details: {
|
||||
...commonTransactionDetailsFields,
|
||||
type: TransactionType.Receive,
|
||||
assetChanges: [
|
||||
{
|
||||
...mockTokenTransferInPartsFragment,
|
||||
sender: MOONPAY_SENDER_ADDRESSES[0],
|
||||
},
|
||||
],
|
||||
},
|
||||
} as AssetActivityPartsFragment
|
||||
|
||||
export const MockNFTReceive = {
|
||||
...mockAssetActivityPartsFragment,
|
||||
details: {
|
||||
...commonTransactionDetailsFields,
|
||||
type: TransactionType.Receive,
|
||||
assetChanges: [
|
||||
{
|
||||
...mockNftTransferPartsFragment,
|
||||
direction: TransactionDirection.In,
|
||||
},
|
||||
],
|
||||
},
|
||||
} as AssetActivityPartsFragment
|
||||
|
||||
export const MockNFTPurchase = {
|
||||
...mockAssetActivityPartsFragment,
|
||||
details: {
|
||||
...commonTransactionDetailsFields,
|
||||
type: TransactionType.Swap,
|
||||
assetChanges: [
|
||||
mockTokenTransferOutPartsFragment,
|
||||
{
|
||||
...mockNftTransferPartsFragment,
|
||||
direction: TransactionDirection.In,
|
||||
},
|
||||
],
|
||||
},
|
||||
} as AssetActivityPartsFragment
|
||||
|
||||
export const MockWrap = {
|
||||
...mockAssetActivityPartsFragment,
|
||||
details: {
|
||||
...commonTransactionDetailsFields,
|
||||
type: TransactionType.Lend,
|
||||
assetChanges: [mockNativeTokenTransferOutPartsFragment, mockWrappedEthTransferInPartsFragment],
|
||||
},
|
||||
} as AssetActivityPartsFragment
|
@ -0,0 +1,131 @@
|
||||
import { act, renderHook } from '@testing-library/react'
|
||||
import ms from 'ms'
|
||||
|
||||
import {
|
||||
MockClosedUniswapXOrder,
|
||||
MockMoonpayPurchase,
|
||||
MockNFTApproval,
|
||||
MockNFTApprovalForAll,
|
||||
MockNFTPurchase,
|
||||
MockNFTReceive,
|
||||
MockNFTTransfer,
|
||||
MockOpenUniswapXOrder,
|
||||
MockRemoveLiquidity,
|
||||
MockSwapOrder,
|
||||
MockTokenApproval,
|
||||
MockTokenReceive,
|
||||
MockTokenSend,
|
||||
MockTokenTransfer,
|
||||
MockWrap,
|
||||
} from './fixtures/activity'
|
||||
import { parseRemoteActivities, useTimeSince } from './parseRemote'
|
||||
|
||||
describe('parseRemote', () => {
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers()
|
||||
})
|
||||
describe('parseRemoteActivities', () => {
|
||||
it('should not parse open UniswapX order', () => {
|
||||
const result = parseRemoteActivities(jest.fn(), [MockOpenUniswapXOrder])
|
||||
expect(result).toEqual({})
|
||||
})
|
||||
it('should parse closed UniswapX order', () => {
|
||||
const result = parseRemoteActivities(jest.fn(), [MockClosedUniswapXOrder])
|
||||
expect(result?.['someHash']).toMatchSnapshot()
|
||||
})
|
||||
it('should parse NFT approval', () => {
|
||||
const result = parseRemoteActivities(jest.fn(), [MockNFTApproval])
|
||||
expect(result?.['someHash']).toMatchSnapshot()
|
||||
})
|
||||
it('should parse NFT approval for all', () => {
|
||||
const result = parseRemoteActivities(jest.fn(), [MockNFTApprovalForAll])
|
||||
expect(result?.['someHash']).toMatchSnapshot()
|
||||
})
|
||||
it('should parse NFT transfer', () => {
|
||||
const result = parseRemoteActivities(jest.fn(), [MockNFTTransfer])
|
||||
expect(result?.['someHash']).toMatchSnapshot()
|
||||
})
|
||||
it('should parse swap', () => {
|
||||
const result = parseRemoteActivities(jest.fn().mockReturnValue('100'), [MockTokenTransfer])
|
||||
expect(result?.['someHash']).toMatchSnapshot()
|
||||
})
|
||||
it('should parse nft purchase', () => {
|
||||
const result = parseRemoteActivities(jest.fn().mockReturnValue('100'), [MockNFTPurchase])
|
||||
expect(result?.['someHash']).toMatchSnapshot()
|
||||
})
|
||||
it('should parse token approval', () => {
|
||||
const result = parseRemoteActivities(jest.fn(), [MockTokenApproval])
|
||||
expect(result?.['someHash']).toMatchSnapshot()
|
||||
})
|
||||
it('should parse send', () => {
|
||||
const result = parseRemoteActivities(jest.fn().mockReturnValue(100), [MockTokenSend])
|
||||
expect(result?.['someHash']).toMatchSnapshot()
|
||||
})
|
||||
it('should parse receive', () => {
|
||||
const result = parseRemoteActivities(jest.fn().mockReturnValue(100), [MockTokenReceive])
|
||||
expect(result?.['someHash']).toMatchSnapshot()
|
||||
})
|
||||
it('should parse NFT receive', () => {
|
||||
const result = parseRemoteActivities(jest.fn().mockReturnValue(100), [MockNFTReceive])
|
||||
expect(result?.['someHash']).toMatchSnapshot()
|
||||
})
|
||||
it('should parse remove liquidity', () => {
|
||||
const result = parseRemoteActivities(jest.fn().mockReturnValue(100), [MockRemoveLiquidity])
|
||||
expect(result?.['someHash']).toMatchSnapshot()
|
||||
})
|
||||
it('should parse moonpay purchase', () => {
|
||||
const result = parseRemoteActivities(jest.fn().mockReturnValue('100'), [MockMoonpayPurchase])
|
||||
expect(result?.['someHash']).toMatchSnapshot()
|
||||
})
|
||||
it('should parse swap order', () => {
|
||||
const result = parseRemoteActivities(jest.fn().mockReturnValue('100'), [MockSwapOrder])
|
||||
expect(result?.['someHash']).toMatchSnapshot()
|
||||
})
|
||||
it('should parse eth wrap', () => {
|
||||
const result = parseRemoteActivities(jest.fn().mockReturnValue('100'), [MockWrap])
|
||||
expect(result?.['someHash']).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
|
||||
describe('useTimeSince', () => {
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
jest.useRealTimers()
|
||||
})
|
||||
|
||||
it('should initialize with the correct time since', () => {
|
||||
const timestamp = Math.floor(Date.now() / 1000) - 60 // 60 seconds ago
|
||||
const { result } = renderHook(() => useTimeSince(timestamp))
|
||||
|
||||
expect(result.current).toBe('1m')
|
||||
})
|
||||
|
||||
it('should update time since every second', async () => {
|
||||
const timestamp = Math.floor(Date.now() / 1000) - 50 // 50 seconds ago
|
||||
const { result, rerender } = renderHook(() => useTimeSince(timestamp))
|
||||
|
||||
act(() => {
|
||||
jest.advanceTimersByTime(ms('1.1s'))
|
||||
})
|
||||
rerender()
|
||||
|
||||
expect(result.current).toBe('51s')
|
||||
})
|
||||
|
||||
it('should stop updating after 61 seconds', () => {
|
||||
const timestamp = Math.floor(Date.now() / 1000) - 61 // 61 seconds ago
|
||||
const { result, rerender } = renderHook(() => useTimeSince(timestamp))
|
||||
|
||||
act(() => {
|
||||
jest.advanceTimersByTime(ms('121.1s'))
|
||||
})
|
||||
rerender()
|
||||
|
||||
// maxes out at 1m
|
||||
expect(result.current).toBe('1m')
|
||||
})
|
||||
})
|
||||
})
|