Compare commits

..

3 Commits

Author SHA1 Message Date
Charles Bachmeier
7524086b25
fix: Cherrypick main fixes to staging (#7166)
* fix: token margin in searchbar (#7155)

fix: token margin is searchbar

* feat: Add base support to Explore & Search (#7165)

* filter search results

* feat: add full base TDP support

* add base to uni wallet supported chains

* fix: test id based on address & chain instead of ticker (#7167)

* fix: test id based on address instead of ticker

* add chain to test id

* use token address

* lowercase

---------

Co-authored-by: Jack Short <john.short.tj@gmail.com>
2023-08-15 11:32:47 -07:00
UL Service Account
2f711225ac ci: add global CODEOWNERS 2023-08-11 23:48:10 +00:00
UL Service Account
aff7da65a0 ci(t9n): download translations from crowdin 2023-08-11 23:48:10 +00:00
913 changed files with 136821 additions and 52240 deletions

13
.env
View File

@ -1,16 +1,17 @@
# 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://null.null"
REACT_APP_AMPLITUDE_PROXY_URL="https://api.uniswap.org/v1/amplitude-proxy"
REACT_APP_AWS_API_REGION="us-east-2"
REACT_APP_AWS_API_ENDPOINT="https://null.null"
REACT_APP_AWS_API_ENDPOINT="https://beta.api.uniswap.org/v1/graphql"
REACT_APP_BNB_RPC_URL="https://rough-sleek-hill.bsc.quiknode.pro/413cc98cbc776cda8fdf1d0f47003583ff73d9bf"
REACT_APP_BASE_GOERLI_RPC_URL="https://wiser-compatible-mansion.base-goerli.quiknode.pro/5874f36248e17020a1006149e7f68c63967e1f45/"
REACT_APP_BASE_MAINNET_RPC_URL="https://cool-white-diagram.base-mainnet.quiknode.pro/d8f036f35dfab2c68f32dfa822cd971e7a25a117/"
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://null.null"
REACT_APP_TEMP_API_URL="https://null.null"
REACT_APP_UNISWAP_API_URL="https://null.null"
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_WALLET_CONNECT_PROJECT_ID="c6c9bacd35afa3eb9e6cccf6d8464395"

View File

@ -1,16 +1,15 @@
# These API keys are intentionally public. Please do not report them - thank you for your concern.
REACT_APP_AMPLITUDE_PROXY_URL="https://null.null"
REACT_APP_AWS_API_ENDPOINT="https://null.null"
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_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://null.null"
REACT_APP_MOONPAY_LINK="https://us-central1-uniswap-mobile.cloudfunctions.net/signMoonpayLinkV2?platform=web&env=production"
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://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"
REACT_APP_STATSIG_PROXY_URL="https://api.uniswap.org/v1/statsig-proxy"
THE_GRAPH_SCHEMA_ENDPOINT="https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3"

View File

@ -28,20 +28,7 @@ module.exports = {
{
files: ['**/*.ts', '**/*.tsx'],
rules: {
'@typescript-eslint/no-restricted-imports': [
'error',
{
...restrictedImports,
paths: [
...restrictedImports.paths,
{
name: '@uniswap/smart-order-router',
message: 'Only import types, unless you are in the client-side SOR, to preserve lazy-loading.',
allowTypeImports: true,
},
],
},
],
'@typescript-eslint/no-restricted-imports': ['error', restrictedImports],
'import/no-restricted-paths': [
'error',
{
@ -70,13 +57,6 @@ module.exports = {
],
},
],
'no-restricted-syntax': [
'error',
{
selector: ':matches(ExportAllDeclaration)',
message: 'Barrel exports bloat the bundle size by preventing tree-shaking.',
},
],
},
},
{

1
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1 @@
@uniswap/web-admins

22
.github/ISSUE_TEMPLATE/bug-report.md vendored Normal file
View File

@ -0,0 +1,22 @@
---
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 Normal file
View File

@ -0,0 +1,8 @@
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

View File

@ -0,0 +1,19 @@
---
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 Normal file
View File

@ -0,0 +1,48 @@
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 Normal file
View File

@ -0,0 +1,49 @@
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 Normal file
View File

@ -0,0 +1,12 @@
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 Normal file
View File

@ -0,0 +1,52 @@
<!-- 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 Normal file
View File

@ -0,0 +1,73 @@
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

View File

@ -0,0 +1,64 @@
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 Normal file
View File

@ -0,0 +1,42 @@
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 Normal file
View File

@ -0,0 +1,111 @@
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 Normal file
View File

@ -0,0 +1,17 @@
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 Normal file
View File

@ -0,0 +1,26 @@
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 }}

View File

@ -0,0 +1,91 @@
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

270
.github/workflows/test.yml vendored Normal file
View File

@ -0,0 +1,270 @@
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 }}
# TODO(WEB-2537): Setup CodeCOV
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-
- run: yarn test:cloud --coverage --maxWorkers=100%
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]
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' }}

View File

@ -1,4 +0,0 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx lint-staged

25
.snyk Normal file
View File

@ -0,0 +1,25 @@
# 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: {}

1
CODEOWNERS Normal file
View File

@ -0,0 +1 @@
@uniswap/web-admins

View File

@ -9,7 +9,6 @@ ignore:
- "**/styled.tsx"
- "**/constants/**/*"
- "constants/**/*"
- "src/dev/*"
coverage:
status:
@ -29,10 +28,6 @@ flag_management:
target: 50%
individual_flags:
- name: unit-tests
- name: cloud-tests
statuses:
- type: project
target: 80%
comment:
layout: flags

View File

@ -1,5 +1,5 @@
overrideExisting: true
schema: 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3?source=uniswap'
schema: 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3'
generates:
./src/graphql/thegraph/schema/schema.graphql:
plugins:

View File

@ -5,6 +5,7 @@ const { execSync } = require('child_process')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const path = require('path')
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin')
const TerserPlugin = require('terser-webpack-plugin')
const { IgnorePlugin, ProvidePlugin } = require('webpack')
const { RetryChunkLoadPlugin } = require('webpack-retry-chunk-load-plugin')
@ -55,10 +56,10 @@ module.exports = {
'\\.css\\.ts$': '@vanilla-extract/jest-transform',
'\\.(t|j)sx?$': '@swc/jest',
},
// Use d3-arrays's build directly, as jest does not support its exports.
transformIgnorePatterns: ['d3-array'],
// Use @uniswap/conedison's build directly, as jest does not support its exports.
transformIgnorePatterns: ['@uniswap/conedison/provider'],
moduleNameMapper: {
'd3-array': 'd3-array/dist/d3-array.min.js',
'@uniswap/conedison/provider': '@uniswap/conedison/dist/provider',
},
})
},
@ -130,12 +131,6 @@ module.exports = {
},
})
// Retain source maps for node_modules packages:
webpackConfig.module.rules[0] = {
...webpackConfig.module.rules[0],
exclude: /node_modules/,
}
// Configure webpack transpilation (create-react-app specifies transpilation rules in a oneOf):
webpackConfig.module.rules[1].oneOf = webpackConfig.module.rules[1].oneOf.map((rule) => {
if (rule.loader && rule.loader.match(/babel-loader/)) {
@ -145,20 +140,18 @@ module.exports = {
return rule
})
// Run terser compression on node_modules before tree-shaking, so that tree-shaking is more effective.
// This works by eliminating dead code, so that webpack can identify unused imports and tree-shake them;
// it is only necessary for node_modules - it is done through linting for our own source code -
// see https://medium.com/engineering-housing/dead-code-elimination-and-tree-shaking-at-housing-part-1-307a94b30f23#7e03:
webpackConfig.module.rules.push({
enforce: 'post',
test: /node_modules.*\.(js)$/,
loader: path.join(__dirname, 'scripts/terser-loader.js'),
options: { compress: true, mangle: false },
})
// Configure webpack optimization:
webpackConfig.optimization = Object.assign(
webpackConfig.optimization,
{
minimize: isProduction,
minimizer: [
new TerserPlugin({
minify: TerserPlugin.swcMinify,
parallel: require('os').cpus().length,
}),
],
},
isProduction
? {
splitChunks: {
@ -177,6 +170,13 @@ module.exports = {
// Configure webpack resolution. webpackConfig.cache is unused with swc-loader, but the resolver can still cache:
webpackConfig.resolve = Object.assign(webpackConfig.resolve, { unsafeCache: true })
webpackConfig.ignoreWarnings = [
// Source mappings for a package will fail if the package does not provide them, but the build will still succeed,
// so it is unnecessary (and bothersome) to log it. This should be turned off when debugging missing sourcemaps.
// See https://webpack.js.org/loaders/source-map-loader#ignoring-warnings.
/Failed to parse source map/,
]
return webpackConfig
},
},

View File

@ -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 : 1 },
retries: { runMode: 2 },
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) {

View File

@ -4,7 +4,7 @@ import { aliasQuery, hasQuery } from '../utils/graphql-test-utils'
describe('Add Liquidity', () => {
beforeEach(() => {
cy.intercept('POST', '/subgraphs/name/uniswap/uniswap-v3?source=uniswap', (req) => {
cy.intercept('POST', '/subgraphs/name/uniswap/uniswap-v3', (req) => {
aliasQuery(req, 'feeTierDistribution')
})
})
@ -16,16 +16,6 @@ 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')
@ -39,30 +29,26 @@ describe('Add Liquidity', () => {
it('loads fee tier distribution', () => {
cy.fixture('feeTierDistribution.json').then((feeTierDistribution) => {
cy.intercept(
'POST',
'/subgraphs/name/uniswap/uniswap-v3?source=uniswap',
(req: CyHttpMessages.IncomingHttpRequest) => {
if (hasQuery(req, 'FeeTierDistribution')) {
req.alias = 'FeeTierDistribution'
cy.intercept('POST', '/subgraphs/name/uniswap/uniswap-v3', (req: CyHttpMessages.IncomingHttpRequest) => {
if (hasQuery(req, 'FeeTierDistribution')) {
req.alias = 'FeeTierDistribution'
req.reply({
body: {
data: {
...feeTierDistribution,
},
req.reply({
body: {
data: {
...feeTierDistribution,
},
headers: {
'access-control-allow-origin': '*',
},
})
}
},
headers: {
'access-control-allow-origin': '*',
},
})
}
)
})
cy.visit('/add/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984/ETH')
cy.wait('@FeeTierDistribution')
cy.get('#add-liquidity-selected-fee .selected-fee-label').should('contain.text', '0.30% fee tier')
cy.get('#add-liquidity-selected-fee .selected-fee-label').should('contain.text', '0.3% fee tier')
cy.get('#add-liquidity-selected-fee .selected-fee-percentage').should('contain.text', '40% select')
})
})

View File

@ -1,8 +1,9 @@
import { FeatureFlag } from '../../src/featureFlags'
import { getTestSelector } from '../utils'
describe('Buy Crypto Modal', () => {
it('should open and close', () => {
cy.visit('/')
cy.visit('/', { featureFlags: [FeatureFlag.fiatOnRampButtonOnSwap] })
// Open the fiat onramp modal
cy.get(getTestSelector('buy-fiat-button')).click()
@ -15,7 +16,7 @@ describe('Buy Crypto Modal', () => {
it('should open and close, mobile viewport', () => {
cy.viewport('iphone-6')
cy.visit('/')
cy.visit('/', { featureFlags: [FeatureFlag.fiatOnRampButtonOnSwap] })
// Open the fiat onramp modal
cy.get(getTestSelector('buy-fiat-button')).click()

View File

@ -39,50 +39,4 @@ 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')
})
})

View File

@ -2,48 +2,30 @@ import { getTestSelector } from '../../utils'
describe('Mini Portfolio account drawer', () => {
beforeEach(() => {
const portfolioSpy = cy.spy().as('portfolioSpy')
cy.intercept(/api.uniswap.org\/v1\/graphql/, (req) => {
if (req.body.operationName === 'PortfolioBalances') {
portfolioSpy(req)
}
})
cy.intercept(/api.uniswap.org\/v1\/graphql/, cy.spy().as('gqlSpy'))
cy.visit('/swap')
})
it('fetches balances when account button is first hovered', () => {
// The balances should not be fetched before the account button is hovered
cy.get('@portfolioSpy').should('not.have.been.called')
cy.get('@gqlSpy').should('not.have.been.called')
// Balances should have been fetched once after hover
cy.get(getTestSelector('web3-status-connected')).trigger('mouseover')
cy.get('@portfolioSpy').should('have.been.calledOnce')
})
it('should not re-fetch balances on second hover', () => {
// The balances should not be fetched before the account button is hovered
cy.get('@portfolioSpy').should('not.have.been.called')
// Balances should have been fetched once after hover
cy.get(getTestSelector('web3-status-connected')).trigger('mouseover')
cy.get('@portfolioSpy').should('have.been.calledOnce')
cy.get('@gqlSpy').should('have.been.calledOnce')
// Balances should not be refetched upon second hover
cy.get(getTestSelector('web3-status-connected')).trigger('mouseover')
cy.get('@portfolioSpy').should('have.been.calledOnce')
})
it('should not re-fetch balances when the account drawer is opened', () => {
// The balances should not be fetched before the account button is hovered
cy.get('@portfolioSpy').should('not.have.been.called')
// Balances should have been fetched once after hover
cy.get(getTestSelector('web3-status-connected')).trigger('mouseover')
cy.get('@portfolioSpy').should('have.been.calledOnce')
cy.get('@gqlSpy').should('have.been.calledOnce')
// Balances should not be refetched upon opening drawer
cy.get(getTestSelector('web3-status-connected')).click()
cy.get('@portfolioSpy').should('have.been.calledOnce')
cy.get('@gqlSpy').should('have.been.calledOnce')
// Balances should not be refetched upon closing & reopening drawer
cy.get(getTestSelector('close-account-drawer')).click()
cy.get(getTestSelector('web3-status-connected')).click()
cy.get('@gqlSpy').should('have.been.calledOnce')
})
it('fetches account information', () => {
@ -53,18 +35,17 @@ 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 (197)')
cy.get(getTestSelector('mini-portfolio-page')).contains('Hidden (201)')
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')
// 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/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.intercept(/graphql/, { fixture: 'mini-portfolio/activity.json' })
cy.get(getTestSelector('mini-portfolio-navbar')).contains('Activity').click()
cy.get(getTestSelector('mini-portfolio-page')).contains('Contract Interaction')
})

View File

@ -146,26 +146,6 @@ describe('Permit2', () => {
cy.contains('Swap success!')
cy.get(getTestSelector('popups')).contains('Swapped')
})
it('swaps USDT with existing permit, and existing and sufficient token approval', () => {
cy.hardhat().then(async (hardhat) => {
await hardhat.fund(hardhat.wallet, CurrencyAmount.fromRawAmount(USDT, 2e6))
await hardhat.mine()
await hardhat.approval.setTokenAllowanceForPermit2({ owner: hardhat.wallet, token: USDT }, 1e6)
await hardhat.mine()
await hardhat.approval.setPermit2Allowance({ owner: hardhat.wallet, token: USDT })
await hardhat.mine()
})
setupInputs(USDT, USDC_MAINNET)
cy.get('#swap-currency-input .token-amount-input').clear().type('1')
initiateSwap()
// Verify transaction
cy.wait('@eth_sendRawTransaction')
cy.hardhat().then((hardhat) => hardhat.mine())
cy.contains('Swap success!')
cy.get(getTestSelector('popups')).contains('Swapped')
})
})
it('swaps when user has already approved token and permit2', () => {

View File

@ -1,33 +1,7 @@
import { ChainId, MaxUint256, UNI_ADDRESSES } from '@uniswap/sdk-core'
const UNI_MAINNET = UNI_ADDRESSES[ChainId.MAINNET]
describe('Remove Liquidity', () => {
it('loads the token pair in v2', () => {
cy.visit(`/remove/v2/ETH/${UNI_MAINNET}`)
it('loads the token pair', () => {
cy.visit('/remove/v2/ETH/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984')
cy.get('#remove-liquidity-tokena-symbol').should('contain.text', 'ETH')
cy.get('#remove-liquidity-tokenb-symbol').should('contain.text', 'UNI')
})
it('loads the token pair in v3', () => {
cy.visit(`/remove/1`)
cy.get('#remove-liquidity-tokens').should('contain.text', 'UNI/ETH')
cy.get('#remove-pooled-tokena-symbol').should('contain.text', 'Pooled UNI')
cy.get('#remove-pooled-tokenb-symbol').should('contain.text', 'Pooled ETH')
})
it('should redirect to error pages if pool does not exist', () => {
// Duplicate-token v2 pools redirect to position unavailable
cy.visit(`/remove/v2/ETH/ETH`)
cy.contains('Position unavailable')
// Single-token pools don't exist
cy.visit('/remove/v2/ETH')
cy.url().should('match', /\/not-found/)
// Nonexistent v3 pool
cy.visit(`/remove/${MaxUint256}`)
cy.contains('Position unavailable')
})
})

View File

@ -1,5 +1,4 @@
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'
@ -87,7 +86,6 @@ 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')
@ -118,18 +116,4 @@ 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('-')
})
})

View File

@ -1,146 +0,0 @@
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%)')
})
})
})

View File

@ -1,76 +0,0 @@
import { SwapEventName } from '@uniswap/analytics-events'
import { USDC_MAINNET } from '../../../src/constants/tokens'
import { getTestSelector } from '../../utils'
describe('swap flow logging', () => {
it('completes two swaps and verifies the TTS logging for the first, plus all intermediate steps along the way', () => {
cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${USDC_MAINNET.address}`)
cy.hardhat()
// First swap in the session:
// 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 first swap action
cy.waitForAmplitudeEvent(SwapEventName.SWAP_FIRST_ACTION).then((event: any) => {
cy.wrap(event.event_properties).should('have.property', 'time_to_first_swap_action')
cy.wrap(event.event_properties.time_to_first_swap_action).should('be.a', 'number')
cy.wrap(event.event_properties.time_to_first_swap_action).should('be.gte', 0)
})
// Verify Swap Quote
cy.waitForAmplitudeEvent(SwapEventName.SWAP_QUOTE_FETCH).then((event: any) => {
// Price quotes don't include these values, so we only verify the types if they exist
if (event.event_properties.time_to_first_quote_request) {
cy.wrap(event.event_properties.time_to_first_quote_request).should('be.a', 'number')
cy.wrap(event.event_properties.time_to_first_quote_request).should('be.gte', 0)
cy.wrap(event.event_properties.time_to_first_quote_request_since_first_input).should('be.a', 'number')
cy.wrap(event.event_properties.time_to_first_quote_request_since_first_input).should('be.gte', 0)
}
})
// Submit transaction
cy.get('#swap-button').click()
cy.contains('Confirm swap').click()
cy.get(getTestSelector('confirmation-close-icon')).click()
cy.get(getTestSelector('popups')).contains('Swapped')
// Verify logging
cy.waitForAmplitudeEvent(SwapEventName.SWAP_TRANSACTION_COMPLETED).then((event: any) => {
cy.wrap(event.event_properties).should('have.property', 'time_to_swap')
cy.wrap(event.event_properties.time_to_swap).should('be.a', 'number')
cy.wrap(event.event_properties.time_to_swap).should('be.gte', 0)
cy.wrap(event.event_properties).should('have.property', 'time_to_swap_since_first_input')
cy.wrap(event.event_properties.time_to_swap_since_first_input).should('be.a', 'number')
cy.wrap(event.event_properties.time_to_swap_since_first_input).should('be.gte', 0)
})
// Second swap in the session:
// Enter amount to swap (different from first trade, to trigger a new quote request)
cy.get('#swap-currency-output .token-amount-input').clear().type('10').should('have.value', '10')
cy.get('#swap-currency-input .token-amount-input').should('not.have.value', '')
// Verify second Swap Quote
cy.waitForAmplitudeEvent(SwapEventName.SWAP_QUOTE_FETCH).then((event: any) => {
// Price quotes don't include these values, so we only verify the types if they exist
if (event.event_properties.time_to_first_quote_request) {
cy.wrap(event.event_properties.time_to_first_quote_request).should('be.undefined')
cy.wrap(event.event_properties.time_to_first_quote_request_since_first_input).should('be.undefined')
}
})
// Submit transaction
cy.get('#swap-button').click()
cy.contains('Confirm swap').click()
cy.get(getTestSelector('confirmation-close-icon')).click()
cy.get(getTestSelector('popups')).contains('Swapped')
cy.waitForAmplitudeEvent(SwapEventName.SWAP_TRANSACTION_COMPLETED).then((event: any) => {
cy.wrap(event.event_properties).should('not.have.property', 'time_to_swap')
cy.wrap(event.event_properties).should('not.have.property', 'time_to_swap_since_first_input')
})
})
})

View File

@ -1,34 +1,29 @@
import { FeatureFlag } from '../../../src/featureFlags'
import { getTestSelector } from '../../utils'
describe('Swap settings', () => {
it('Opens and closes the settings menu', () => {
cy.visit('/swap')
cy.visit('/swap', { featureFlags: [FeatureFlag.uniswapXEnabled] })
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')
})
it('should open the mobile settings menu', () => {
// Set viewport to iPhone 6
cy.viewport('iphone-6')
cy.visit('/swap')
// Click the button to open the settings dialog
cy.get(getTestSelector('open-settings-dialog-button')).click({ waitForAnimations: true })
// Verify the mobile settings menu and its contents
cy.get(getTestSelector('mobile-settings-menu'))
.should('exist')
.within(() => {
cy.contains('Max. slippage').should('exist')
cy.contains('UniswapX').should('exist')
cy.contains('Transaction deadline').should('exist')
cy.get(getTestSelector('mobile-settings-close')).click()
})
cy.visit('/swap', { featureFlags: [FeatureFlag.uniswapXEnabled] })
cy.get(getTestSelector('open-settings-dialog-button')).click()
cy.get(getTestSelector('mobile-settings-menu')).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('mobile-settings-scrim')).click()
})
})

View File

@ -1,4 +1,3 @@
import { SwapEventName } from '@uniswap/analytics-events'
import { ChainId } from '@uniswap/sdk-core'
import { UNI, USDC_MAINNET } from '../../../src/constants/tokens'
@ -65,13 +64,6 @@ describe('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)
})
// Submit transaction
cy.get('#swap-button').click()
cy.contains('Review swap')

View File

@ -0,0 +1,45 @@
import { SwapEventName } from '@uniswap/analytics-events'
import { USDC_MAINNET } from '../../../src/constants/tokens'
import { getTestSelector } from '../../utils'
describe('time-to-swap logging', () => {
it('completes two swaps and verifies the TTS logging for the first', () => {
cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${USDC_MAINNET.address}`)
cy.hardhat()
// First swap in the session:
// 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', '')
// Submit transaction
cy.get('#swap-button').click()
cy.contains('Confirm swap').click()
cy.get(getTestSelector('confirmation-close-icon')).click()
cy.get(getTestSelector('popups')).contains('Swapped')
// Verify logging
cy.waitForAmplitudeEvent(SwapEventName.SWAP_TRANSACTION_COMPLETED).then((event: any) => {
cy.wrap(event.event_properties).should('have.property', 'time_to_swap')
cy.wrap(event.event_properties.time_to_swap).should('be.a', 'number')
cy.wrap(event.event_properties.time_to_swap).should('be.gte', 0)
})
// Second swap in the session:
// Enter amount to swap
cy.get('#swap-currency-output .token-amount-input').clear().type('1').should('have.value', '1')
cy.get('#swap-currency-input .token-amount-input').should('not.have.value', '')
// Submit transaction
cy.get('#swap-button').click()
cy.contains('Confirm swap').click()
cy.get(getTestSelector('confirmation-close-icon')).click()
cy.get(getTestSelector('popups')).contains('Swapped')
cy.waitForAmplitudeEvent(SwapEventName.SWAP_TRANSACTION_COMPLETED).then((event: any) => {
cy.wrap(event.event_properties).should('not.have.property', 'time_to_swap')
})
})
})

View File

@ -1,376 +0,0 @@
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 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) => {
cy.fixture('uniswapx/fillTransactionReceipt.json').then((mockTxReceipt) => {
const getTransactionReceiptStub = cy.stub(hardhat.provider, 'getTransactionReceipt').log(false)
getTransactionReceiptStub.withArgs(mockTxReceipt.transactionHash).resolves(mockTxReceipt)
getTransactionReceiptStub.callThrough()
})
})
}
// TODO: FIX THESE TESTS where we should NOT stub for pricing requests
describe.skip('UniswapX Toggle', () => {
beforeEach(() => {
stubNonPriceQuoteWith(QuoteWhereUniswapXIsBetter)
cy.visit(`/swap/?inputCurrency=${USDC_MAINNET.address}&outputCurrency=${DAI.address}`)
})
it('displays uniswapx ui when setting is on', () => {
// Setup a swap
cy.get('#swap-currency-input .token-amount-input').type('300')
cy.wait('@quote')
// UniswapX UI should be visible
cy.get(getTestSelector('gas-estimate-uniswapx-icon')).should('exist')
})
})
describe.skip('UniswapX Orders', () => {
beforeEach(() => {
stubNonPriceQuoteWith(QuoteWhereUniswapXIsBetter)
cy.intercept(OrderSubmissionEndpoint, { fixture: 'uniswapx/orderResponse.json' })
cy.intercept(OrderStatusEndpoint, { fixture: 'uniswapx/openStatusResponse.json' })
stubSwapTxReceipt()
cy.hardhat().then((hardhat) => hardhat.fund(hardhat.wallet, CurrencyAmount.fromRawAmount(USDC_MAINNET, 3e8)))
cy.visit(`/swap/?inputCurrency=${USDC_MAINNET.address}&outputCurrency=${DAI.address}`)
})
it('can swap exact-in trades using uniswapX', () => {
// Setup a swap
cy.get('#swap-currency-input .token-amount-input').type('300')
cy.wait('@quote')
// Submit uniswapx order signature
cy.get('#swap-button').click()
cy.contains('Confirm swap').click()
cy.wait('@eth_signTypedData_v4')
cy.contains('Swap submitted')
cy.contains('Learn more about swapping with UniswapX')
// Return filled order status from uniswapx api
cy.intercept(OrderStatusEndpoint, { fixture: 'uniswapx/filledStatusResponse.json' })
// Verify swap success
cy.contains('Swapped')
})
it('can swap exact-out trades using uniswapX', () => {
// Setup a swap
cy.get('#swap-currency-output .token-amount-input').type('300')
cy.wait('@quote')
// Submit uniswapx order signature
cy.get('#swap-button').click()
cy.contains('Confirm swap').click()
cy.wait('@eth_signTypedData_v4')
cy.contains('Swap submitted')
cy.contains('Learn more about swapping with UniswapX')
// Return filled order status from uniswapx api
cy.intercept(OrderStatusEndpoint, { fixture: 'uniswapx/filledStatusResponse.json' })
// Verify swap success
cy.contains('Swapped')
})
it('renders proper view if uniswapx order expires', () => {
// Setup a swap
cy.get('#swap-currency-input .token-amount-input').type('300')
cy.wait('@quote')
// Submit uniswapx order signature
cy.get('#swap-button').click()
cy.contains('Confirm swap').click()
// Return expired order status from uniswapx api
cy.intercept(OrderStatusEndpoint, { fixture: 'uniswapx/expiredStatusResponse.json' })
// Verify swap failure message
cy.contains('Swap expired')
})
it('renders proper view if uniswapx order has insufficient funds', () => {
// Setup a swap
cy.get('#swap-currency-input .token-amount-input').type('300')
cy.wait('@quote')
// Submit uniswapx order signature
cy.get('#swap-button').click()
cy.contains('Confirm swap').click()
// Return insufficient_funds order status from uniswapx api
cy.intercept(OrderStatusEndpoint, { fixture: 'uniswapx/insufficientFundsStatusResponse.json' })
// Verify swap failure message
cy.contains('Insufficient funds')
})
})
describe.skip('UniswapX Eth Input', () => {
beforeEach(() => {
stubNonPriceQuoteWith(QuoteWithEthInput)
cy.intercept(OrderSubmissionEndpoint, { fixture: 'uniswapx/orderResponse.json' })
cy.intercept(OrderStatusEndpoint, { fixture: 'uniswapx/openStatusResponse.json' })
// Turn off automine so that intermediate screens are available to assert on.
cy.hardhat({ automine: false }).then(async (hardhat) => {
await hardhat.fund(hardhat.wallet, CurrencyAmount.fromRawAmount(nativeOnChain(ChainId.MAINNET), 2e18))
await hardhat.mine()
})
stubSwapTxReceipt()
cy.visit(`/swap/?inputCurrency=ETH&outputCurrency=${DAI.address}`)
})
it('can swap using uniswapX with ETH as input', () => {
// Setup a swap
cy.get('#swap-currency-input .token-amount-input').type('1')
cy.wait('@quote')
// Prompt ETH wrap to use for order
cy.get('#swap-button').click()
cy.contains('Confirm swap').click()
cy.contains('Wrap ETH')
// Wrap ETH
cy.wait('@eth_sendRawTransaction')
cy.contains('Pending...')
cy.hardhat().then((hardhat) => hardhat.mine())
cy.contains('Wrapped')
// Approve WETH spend
cy.wait('@eth_sendRawTransaction')
cy.hardhat().then((hardhat) => hardhat.mine())
// Verify signed order submission
cy.wait('@eth_signTypedData_v4')
cy.contains('Swap submitted')
cy.contains('Learn more about swapping with UniswapX')
// Return filled order status from uniswapx api
cy.intercept(OrderStatusEndpoint, { fixture: 'uniswapx/filledStatusResponse.json' })
// Verify swap success
cy.contains('Swapped')
})
it('keeps ETH as the input currency before wrap completes', () => {
// 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')
// 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')
// Approve WETH spend
cy.wait('@eth_sendRawTransaction')
cy.hardhat().then((hardhat) => hardhat.mine())
// Submit uniswapx order signature
cy.wait('@eth_signTypedData_v4')
cy.contains('Swap submitted')
cy.contains('Learn more about swapping with UniswapX')
// Return filled order status from uniswapx api
cy.intercept(OrderStatusEndpoint, { fixture: 'uniswapx/filledStatusResponse.json' })
// 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.skip('UniswapX activity history', () => {
beforeEach(() => {
cy.intercept(QuoteEndpoint, { fixture: QuoteWhereUniswapXIsBetter })
cy.intercept(OrderSubmissionEndpoint, { fixture: 'uniswapx/orderResponse.json' })
cy.intercept(OrderStatusEndpoint, { fixture: 'uniswapx/openStatusResponse.json' })
stubSwapTxReceipt()
cy.hardhat().then(async (hardhat) => {
await hardhat.fund(hardhat.wallet, CurrencyAmount.fromRawAmount(USDC_MAINNET, 3e8))
})
cy.visit(`/swap/?inputCurrency=${USDC_MAINNET.address}&outputCurrency=${DAI.address}`)
})
it('can view UniswapX order status progress in activity', () => {
// Setup a swap
cy.get('#swap-currency-input .token-amount-input').type('300')
// Submit uniswapx order signature
cy.get('#swap-button').click()
cy.contains('Confirm swap').click()
cy.wait('@eth_signTypedData_v4')
cy.get(getTestSelector('confirmation-close-icon')).click()
// Open mini portfolio and navigate to activity history
cy.get(getTestSelector('web3-status-connected')).click()
cy.intercept(/graphql/, { fixture: 'mini-portfolio/empty_activity.json' })
cy.get(getTestSelector('mini-portfolio-navbar')).contains('Activity').click()
// Open pending order modal
cy.contains('Swapping').click()
cy.get(getTestSelector('offchain-activity-modal')).contains('Swapping')
cy.get(getTestSelector('offchain-activity-modal')).contains('Learn more about swapping with UniswapX')
// Return filled order status from uniswapx api
cy.intercept(OrderStatusEndpoint, { fixture: 'uniswapx/filledStatusResponse.json' })
cy.get(getTestSelector('offchain-activity-modal')).contains('Swapped')
cy.get(getTestSelector('offchain-activity-modal')).contains('View on Explorer')
})
it('can view UniswapX order status progress in activity upon expiry', () => {
// Setup a swap
cy.get('#swap-currency-input .token-amount-input').type('300')
// Submit uniswapx order signature
cy.get('#swap-button').click()
cy.contains('Confirm swap').click()
cy.wait('@eth_signTypedData_v4')
cy.get(getTestSelector('confirmation-close-icon')).click()
// Open mini portfolio and navigate to activity history
cy.get(getTestSelector('web3-status-connected')).click()
cy.intercept(/graphql/, { fixture: 'mini-portfolio/empty_activity.json' })
cy.get(getTestSelector('mini-portfolio-navbar')).contains('Activity').click()
// Open pending order modal
cy.contains('Swapping').click()
cy.get(getTestSelector('offchain-activity-modal')).contains('Swapping')
// Return filled order status from uniswapx api
cy.intercept(OrderStatusEndpoint, { fixture: 'uniswapx/expiredStatusResponse.json' })
cy.get(getTestSelector('offchain-activity-modal')).contains('Swap expired')
cy.get(getTestSelector('offchain-activity-modal')).contains('learn more')
})
it('deduplicates remote vs local uniswapx orders', () => {
// Setup a swap
cy.get('#swap-currency-input .token-amount-input').type('300')
// Submit uniswapx order signature
cy.get('#swap-button').click()
cy.contains('Confirm swap').click()
cy.wait('@eth_signTypedData_v4')
cy.get(getTestSelector('confirmation-close-icon')).click()
// Return filled order status from uniswapx api
cy.intercept(OrderStatusEndpoint, { fixture: 'uniswapx/filledStatusResponse.json' })
cy.contains('Swapped')
// Open mini portfolio
cy.get(getTestSelector('web3-status-connected')).click()
cy.fixture('mini-portfolio/uniswapx_activity.json').then((uniswapXActivity) => {
// Replace fixture's timestamp with current time
uniswapXActivity.data.portfolios[0].assetActivities[0].timestamp = Date.now() / 1000
cy.intercept(/graphql/, uniswapXActivity)
})
// Open activity history
cy.get(getTestSelector('mini-portfolio-navbar')).contains('Activity').click()
// 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')
const gqlSpy = cy.spy().as('gqlSpy')
cy.intercept(/graphql/, (req) => {
// Spy on request frequency
req.on('response', gqlSpy)
// Reply with a fixture to speed up test
req.reply({
fixture: 'mini-portfolio/tokens.json',
})
})
// Expect balances to fetch upon opening mini portfolio
cy.get(getTestSelector('web3-status-connected')).click()
cy.get('@gqlSpy').should('have.been.calledOnce')
// Submit uniswapx order signature
cy.get('#swap-button').click()
cy.contains('Confirm swap').click()
// Expect balances to refetch after approval
cy.get('@gqlSpy').should('have.been.calledTwice')
// Return filled order status from uniswapx api
cy.intercept(OrderStatusEndpoint, { fixture: 'uniswapx/filledStatusResponse.json' })
// Expect balances to refetch after swap
cy.get('@gqlSpy').should('have.been.calledThrice')
})
})

View File

@ -1,5 +1,4 @@
import { ChainId, WETH9 } from '@uniswap/sdk-core'
import { FeatureFlag } from 'featureFlags'
import { ARB, UNI } from '../../src/constants/tokens'
import { getTestSelector } from '../utils'
@ -15,9 +14,8 @@ describe('Token details', () => {
it('Uniswap token should have all information populated', () => {
// Uniswap token
cy.visit(`/tokens/ethereum/${UNI_ADDRESS}`, {
featureFlags: [{ name: FeatureFlag.infoTDP, value: false }],
})
cy.visit(`/tokens/ethereum/${UNI_ADDRESS}`)
// Price chart should be filled in
cy.get('[data-cy="chart-header"]').should('include.text', '$')
cy.get('[data-cy="price-chart"]').should('exist')
@ -49,50 +47,41 @@ 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', () => {
// Null token created for this test, 0 trading volume and has warning modal
cy.visit('/tokens/ethereum/0x1eFBB78C8b917f67986BcE54cE575069c0143681')
// Shiba predator token, low trading volume and also has warning modal
cy.visit('/tokens/ethereum/0xa71d0588EAf47f12B13cF8eC750430d21DF04974')
// 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')
}
// Stats should not exist
cy.get(getTestSelector('token-details-stats')).should('not.exist')
// Stats should have: TVL, 24H Volume, 52W low, 52W high
cy.get(getTestSelector('token-details-stats')).should('exist')
cy.get(getTestSelector('token-details-stats')).within(() => {
cy.get('[data-cy="tvl"]').should('exist')
cy.get('[data-cy="volume-24h"]').should('exist')
cy.get('[data-cy="52w-low"]').should('exist')
cy.get('[data-cy="52w-high"]').should('exist')
})
// About section should have description of token
cy.get(getTestSelector('token-details-about-section')).should('exist')
cy.contains('No token information available').should('exist')
cy.contains('QOM is the Shiba Predator').should('exist')
// Links section should link out to Etherscan, More analytics
// Links section should link out to Etherscan, More analytics, Website, Twitter
cy.get('[data-cy="resources-container"]').within(() => {
cy.contains('Etherscan')
.should('have.attr', 'href')
.and('include', 'etherscan.io/address/0x1eFBB78C8b917f67986BcE54cE575069c0143681')
.and('include', 'etherscan.io/address/0xa71d0588EAf47f12B13cF8eC750430d21DF04974')
cy.contains('More analytics')
.should('have.attr', 'href')
.and('include', 'info.uniswap.org/#/tokens/0x1eFBB78C8b917f67986BcE54cE575069c0143681')
.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')
})
// Contract address should be displayed
cy.contains('0x1eFBB78C8b917f67986BcE54cE575069c0143681').should('exist')
cy.contains('0xa71d0588EAf47f12B13cF8eC750430d21DF04974').should('exist')
// Warning label should show if relevant ([spec](https://www.notion.so/3f7fce6f93694be08a94a6984d50298e))
cy.get('[data-cy="token-safety-message"]')
@ -119,7 +108,7 @@ describe('Token details', () => {
it('should automatically navigate to the new TDP', () => {
cy.get(`#swap-currency-output .open-currency-select-button`).click()
cy.get('[data-reach-dialog-content]').contains('WETH').click()
cy.contains('WETH').click()
cy.url().should('include', `${WETH9[1].address}`)
cy.url().should('not.include', `${UNI_MAINNET.address}`)
})

View File

@ -11,10 +11,6 @@ describe('Token explore filter', () => {
function searchFor(filter: string) {
cy.get('[data-cy="explore-tokens-search-input"]').clear().type(filter).type('{enter}')
// wait for it to finish the filtered render
cy.get('[data-cy="token-name"]').first().contains(filter, {
matchCase: false,
})
}
it('should filter correctly by dao search term', () => {
@ -22,9 +18,7 @@ describe('Token explore filter', () => {
searchFor('dao')
cy.get('@filteredTokens').then((filteredTokens) => {
cy.get('[data-cy="token-name"]').then((tokens) => {
cy.wrap(Array.from(tokens)).should('deep.equal', Array.from(filteredTokens))
})
cy.get('[data-cy="token-name"]').should('deep.equal', filteredTokens)
})
})
})

View File

@ -59,7 +59,9 @@ 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', 'Matic')
cy.get(getTestSelector('token-table-row-NATIVE'))
.find(getTestSelector('name-cell'))
.should('include.text', 'Polygon Matic')
})
it('should update when token explore table network changed', () => {
@ -67,6 +69,5 @@ 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')).find('title').should('include.text', 'Ethereum logo')
})
})

View File

@ -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.
cy.get(getTestSelector('searchbar-token-row-ETHEREUM-NATIVE')).click()
getSearchBar().type('{enter}')
cy.url().should('contain', 'tokens/ethereum/NATIVE')
}
)

View File

@ -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')

View File

@ -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')).find('title').should('include.text', `${chain} logo`)
cy.get(getTestSelector('chain-selector-logo')).invoke('attr', 'alt').should('eq', chain)
}
function switchChain(chain: string) {

View File

@ -1,5 +1,3 @@
import { FeatureFlag } from 'featureFlags'
import { getTestSelector } from '../utils'
describe('Wallet Dropdown', () => {
@ -23,14 +21,10 @@ describe('Wallet Dropdown', () => {
})
}
function itChangesLocale({ featureFlag = false }: { featureFlag?: boolean } = {}) {
function itChangesLocale() {
it('should change locale', () => {
cy.contains('Uniswap available in: English').should('not.exist')
if (featureFlag) {
cy.get(getTestSelector('language-settings-button')).click()
}
cy.get(getTestSelector('wallet-language-item')).contains('Afrikaans').click({ force: true })
cy.location('search').should('match', /\?lng=af-ZA$/)
cy.contains('Uniswap available in: English')
@ -49,43 +43,6 @@ 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: [{ name: FeatureFlag.currencyConversion, value: true }] })
cy.get(getTestSelector('web3-status-connected')).click()
cy.get(getTestSelector('wallet-settings')).click()
})
itChangesLocale({ featureFlag: true })
})
describe('testnet toggle', () => {
@ -143,7 +100,7 @@ describe('Wallet Dropdown', () => {
cy.get(getTestSelector('web3-status-connected')).click()
cy.get(getTestSelector('wallet-settings')).click()
cy.get(getTestSelector('theme-auto')).click()
cy.get(getTestSelector('wallet-header')).should('have.css', 'color', 'rgb(155, 155, 155)')
cy.get(getTestSelector('wallet-header')).should('have.css', 'color', 'rgb(152, 161, 192)')
})
it('should properly use light system theme when auto theme setting is selected', () => {
@ -151,7 +108,7 @@ describe('Wallet Dropdown', () => {
cy.get(getTestSelector('web3-status-connected')).click()
cy.get(getTestSelector('wallet-settings')).click()
cy.get(getTestSelector('theme-auto')).click()
cy.get(getTestSelector('wallet-header')).should('have.css', 'color', 'rgb(125, 125, 125)')
cy.get(getTestSelector('wallet-header')).should('have.css', 'color', 'rgb(119, 128, 160)')
})
})
@ -172,34 +129,4 @@ describe('Wallet Dropdown', () => {
cy.get(getTestSelector('wallet-settings')).should('not.be.visible')
})
})
describe('local currency', () => {
it('loads local currency from the query param', () => {
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: [{ 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: [{ name: FeatureFlag.currencyConversion, value: true }] })
cy.get(getTestSelector('web3-status-connected')).click()
cy.get(getTestSelector('wallet-settings')).click()
cy.contains('USD')
cy.get(getTestSelector('local-currency-settings-button')).click()
cy.get(getTestSelector('wallet-local-currency-item')).contains('AUD').click({ force: true })
cy.location('search').should('match', /\?cur=AUD$/)
cy.contains('AUD')
cy.get(getTestSelector('wallet-local-currency-item')).contains('USD').click({ force: true })
cy.location('search').should('match', /\?cur=USD$/)
cy.contains('USD')
})
})
})

View File

@ -1,5 +0,0 @@
{
"errorCode": "QUOTE_ERROR",
"detail": "No quotes available",
"id": "63363cc1-d474-4584-b386-7c356814b79f"
}

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +0,0 @@
{
"data": {
"portfolios": [
{
"id": "UG9ydGZvbGlvOjB4ZjM5RmQ2ZTUxYWFkODhGNkY0Y2U2YUI4ODI3Mjc5Y2ZmRmI5MjI2Ng==",
"assetActivities": [],
"__typename": "Portfolio"
}
]
},
"errors": []
}

View File

@ -1,580 +0,0 @@
{
"data": {
"portfolios": [
{
"id": "UG9ydGZvbGlvOjB4ZjM5RmQ2ZTUxYWFkODhGNkY0Y2U2YUI4ODI3Mjc5Y2ZmRmI5MjI2Ng==",
"assetActivities": [
{
"id": "QXNzZXRBY3Rpdml0eTpWSEpoYm5OaFkzUnBiMjQ2TUhnM09EQm1NamcwTURSak1qRXpPRGd6TVRVM00yRXdOakJtTVRaaE1UQTNaV0ZtTW1Jd01qazFZbUZqTmpjNU5tUm1ZamN5TW1WbVl6VmpPVE5tTmpRM1h6QjRaak01Wm1RMlpUVXhZV0ZrT0RobU5tWTBZMlUyWVdJNE9ESTNNamM1WTJabVptSTVNakkyTmw4d2VEQXdNREF3TURBek1HWTBPV0ptTW1Vd01ESmxOakJqTm1Wa01UWTJNV1ppTWpNME5tUTRPREk9",
"timestamp": 1684364195,
"chain": "ETHEREUM",
"details": {
"__typename": "TransactionDetails",
"id": "VHJhbnNhY3Rpb246MHg3ODBmMjg0MDRjMjEzODgzMTU3M2EwNjBmMTZhMTA3ZWFmMmIwMjk1YmFjNjc5NmRmYjcyMmVmYzVjOTNmNjQ3XzB4ZjM5ZmQ2ZTUxYWFkODhmNmY0Y2U2YWI4ODI3Mjc5Y2ZmZmI5MjI2Nl8weDAwMDAwMDAzMGY0OWJmMmUwMDJlNjBjNmVkMTY2MWZiMjM0NmQ4ODI=",
"type": "UNKNOWN",
"blockNumber": 17282434,
"hash": "0x780f28404c2138831573a060f16a107eaf2b0295bac6796dfb722efc5c93f647",
"status": "CONFIRMED",
"to": "0x000000030f49bf2e002e60c6ed1661fb2346d882",
"from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"nonce": 465,
"assetChanges": []
},
"__typename": "AssetActivity"
},
{
"id": "QXNzZXRBY3Rpdml0eTpWSEpoYm5OaFkzUnBiMjQ2TUhobFl6QTROMkpoTjJJMk4yUTFPVEEwTVdNMU5XTXdObU16TkdNNVlXVmhPVEUxTkRreVpUYzRNRFl4WldRd016TTBNMlprWmprMU1qa3dPR1U0WTJSa1h6QjRaR0psWmpNM05HWmtaamhrTnpNMVpUYzFPRGxoT1dFNVpUSmpOV0V3T1RGbFlqSmtZbVUxTjE4d2VHWXpPV1prTm1VMU1XRmhaRGc0WmpabU5HTmxObUZpT0RneU56STNPV05tWm1aaU9USXlOalk9",
"timestamp": 1684364135,
"chain": "ETHEREUM",
"details": {
"__typename": "TransactionDetails",
"id": "VHJhbnNhY3Rpb246MHhlYzA4N2JhN2I2N2Q1OTA0MWM1NWMwNmMzNGM5YWVhOTE1NDkyZTc4MDYxZWQwMzM0M2ZkZjk1MjkwOGU4Y2RkXzB4ZGJlZjM3NGZkZjhkNzM1ZTc1ODlhOWE5ZTJjNWEwOTFlYjJkYmU1N18weGYzOWZkNmU1MWFhZDg4ZjZmNGNlNmFiODgyNzI3OWNmZmZiOTIyNjY=",
"type": "RECEIVE",
"blockNumber": 17282429,
"hash": "0xec087ba7b67d59041c55c06c34c9aea915492e78061ed03343fdf952908e8cdd",
"status": "CONFIRMED",
"to": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"from": "0xdbef374fdf8d735e7589a9a9e2c5a091eb2dbe57",
"nonce": 66,
"assetChanges": [
{
"__typename": "TokenTransfer",
"id": "VG9rZW5UcmFuc2ZlcjoweGRiZWYzNzRmZGY4ZDczNWU3NTg5YTlhOWUyYzVhMDkxZWIyZGJlNTdfMHhmMzlmZDZlNTFhYWQ4OGY2ZjRjZTZhYjg4MjcyNzljZmZmYjkyMjY2XzB4ZWMwODdiYTdiNjdkNTkwNDFjNTVjMDZjMzRjOWFlYTkxNTQ5MmU3ODA2MWVkMDMzNDNmZGY5NTI5MDhlOGNkZA==",
"asset": {
"id": "VG9rZW46RVRIRVJFVU1fbnVsbA==",
"name": "Ether",
"symbol": "ETH",
"address": null,
"decimals": 18,
"chain": "ETHEREUM",
"standard": null,
"project": {
"id": "VG9rZW5Qcm9qZWN0OkVUSEVSRVVNX251bGw=",
"isSpam": false,
"logo": {
"id": "SW1hZ2U6aHR0cHM6Ly90b2tlbi1pY29ucy5zMy5hbWF6b25hd3MuY29tL2V0aC5wbmc=",
"url": "https://token-icons.s3.amazonaws.com/eth.png",
"__typename": "Image"
},
"__typename": "TokenProject"
},
"__typename": "Token"
},
"tokenStandard": "NATIVE",
"quantity": "0.001",
"sender": "0xdbef374fdf8d735e7589a9a9e2c5a091eb2dbe57",
"recipient": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"direction": "IN",
"transactedValue": {
"id": "QW1vdW50OjEuODI5NjcwMDAwMDAwMDAwMV9VU0Q=",
"currency": "USD",
"value": 1.8296700000000001,
"__typename": "Amount"
}
}
]
},
"__typename": "AssetActivity"
},
{
"id": "QXNzZXRBY3Rpdml0eTpWSEpoYm5OaFkzUnBiMjQ2TUhoaE9URXdPVFEwT1Rka01UVmpNelpsWWprd1pXUXpZVEkwWW1Wa09ESTBOalpqWmpKaU9URXpNV1l4WkRVMk1EUmlNelppWW1aallqRTBOMkUzTURnNFh6QjRaV1JoTldVeE9ERXhORFppTVdZNVlUZG1OREJtT0RWak1HUmhNek0wT1RNNE5ESXdaRFV4TkY4d2VHWXpPV1prTm1VMU1XRmhaRGc0WmpabU5HTmxObUZpT0RneU56STNPV05tWm1aaU9USXlOalk9",
"timestamp": 1684319903,
"chain": "ETHEREUM",
"details": {
"id": "VHJhbnNhY3Rpb246MHhhOTEwOTQ0OTdkMTVjMzZlYjkwZWQzYTI0YmVkODI0NjZjZjJiOTEzMWYxZDU2MDRiMzZiYmZjYjE0N2E3MDg4XzB4ZWRhNWUxODExNDZiMWY5YTdmNDBmODVjMGRhMzM0OTM4NDIwZDUxNF8weGYzOWZkNmU1MWFhZDg4ZjZmNGNlNmFiODgyNzI3OWNmZmZiOTIyNjY=",
"type": "RECEIVE",
"blockNumber": 17278819,
"hash": "0xa91094497d15c36eb90ed3a24bed82466cf2b9131f1d5604b36bbfcb147a7088",
"status": "CONFIRMED",
"to": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"from": "0xeda5e181146b1f9a7f40f85c0da334938420d514",
"nonce": 5,
"__typename": "TransactionDetails",
"assetChanges": [
{
"__typename": "TokenTransfer",
"id": "VG9rZW5UcmFuc2ZlcjoweGVkYTVlMTgxMTQ2YjFmOWE3ZjQwZjg1YzBkYTMzNDkzODQyMGQ1MTRfMHhmMzlmZDZlNTFhYWQ4OGY2ZjRjZTZhYjg4MjcyNzljZmZmYjkyMjY2XzB4YTkxMDk0NDk3ZDE1YzM2ZWI5MGVkM2EyNGJlZDgyNDY2Y2YyYjkxMzFmMWQ1NjA0YjM2YmJmY2IxNDdhNzA4OA==",
"asset": {
"id": "VG9rZW46RVRIRVJFVU1fbnVsbA==",
"name": "Ether",
"symbol": "ETH",
"address": null,
"decimals": 18,
"chain": "ETHEREUM",
"standard": null,
"project": {
"id": "VG9rZW5Qcm9qZWN0OkVUSEVSRVVNX251bGw=",
"isSpam": false,
"logo": {
"id": "SW1hZ2U6aHR0cHM6Ly90b2tlbi1pY29ucy5zMy5hbWF6b25hd3MuY29tL2V0aC5wbmc=",
"url": "https://token-icons.s3.amazonaws.com/eth.png",
"__typename": "Image"
},
"__typename": "TokenProject"
},
"__typename": "Token"
},
"tokenStandard": "NATIVE",
"quantity": "0.15",
"sender": "0xeda5e181146b1f9a7f40f85c0da334938420d514",
"recipient": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"direction": "IN",
"transactedValue": {
"id": "QW1vdW50OjI3NC40NTA1X1VTRA==",
"currency": "USD",
"value": 274.4505,
"__typename": "Amount"
}
}
]
},
"__typename": "AssetActivity"
},
{
"id": "QXNzZXRBY3Rpdml0eTpWSEpoYm5OaFkzUnBiMjQ2TUhnMFkyUm1Nell6T0dRME1ERXdOV1U1WkRZMVlUZGxObUV6WVdFMlpHTXpNREZpWVRNNVpHTXlNV1ppT0dGaE5USTBNVFppT1ROaE5tWXhOVEUwTWpReVh6QjRaak01Wm1RMlpUVXhZV0ZrT0RobU5tWTBZMlUyWVdJNE9ESTNNamM1WTJabVptSTVNakkyTmw4d2VHUmxOR1F6WVRJME5XUXlZall4WW1WaE1tTmlaREl4TmpVNE1XVXlaR1ZrTmpWbFl6azFNRFE9",
"timestamp": 1684319903,
"chain": "ETHEREUM",
"details": {
"id": "VHJhbnNhY3Rpb246MHg0Y2RmMzYzOGQ0MDEwNWU5ZDY1YTdlNmEzYWE2ZGMzMDFiYTM5ZGMyMWZiOGFhNTI0MTZiOTNhNmYxNTE0MjQyXzB4ZjM5ZmQ2ZTUxYWFkODhmNmY0Y2U2YWI4ODI3Mjc5Y2ZmZmI5MjI2Nl8weGRlNGQzYTI0NWQyYjYxYmVhMmNiZDIxNjU4MWUyZGVkNjVlYzk1MDQ=",
"type": "SEND",
"blockNumber": 17278819,
"hash": "0x4cdf3638d40105e9d65a7e6a3aa6dc301ba39dc21fb8aa52416b93a6f1514242",
"status": "CONFIRMED",
"to": "0xde4d3a245d2b61bea2cbd216581e2ded65ec9504",
"from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"nonce": 464,
"__typename": "TransactionDetails",
"assetChanges": [
{
"__typename": "TokenTransfer",
"id": "VG9rZW5UcmFuc2ZlcjoweGYzOWZkNmU1MWFhZDg4ZjZmNGNlNmFiODgyNzI3OWNmZmZiOTIyNjZfMHhkZTRkM2EyNDVkMmI2MWJlYTJjYmQyMTY1ODFlMmRlZDY1ZWM5NTA0XzB4NGNkZjM2MzhkNDAxMDVlOWQ2NWE3ZTZhM2FhNmRjMzAxYmEzOWRjMjFmYjhhYTUyNDE2YjkzYTZmMTUxNDI0Mg==",
"asset": {
"id": "VG9rZW46RVRIRVJFVU1fbnVsbA==",
"name": "Ether",
"symbol": "ETH",
"address": null,
"decimals": 18,
"chain": "ETHEREUM",
"standard": null,
"project": {
"id": "VG9rZW5Qcm9qZWN0OkVUSEVSRVVNX251bGw=",
"isSpam": false,
"logo": {
"id": "SW1hZ2U6aHR0cHM6Ly90b2tlbi1pY29ucy5zMy5hbWF6b25hd3MuY29tL2V0aC5wbmc=",
"url": "https://token-icons.s3.amazonaws.com/eth.png",
"__typename": "Image"
},
"__typename": "TokenProject"
},
"__typename": "Token"
},
"tokenStandard": "NATIVE",
"quantity": "0.00134999999999999",
"sender": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"recipient": "0xde4d3a245d2b61bea2cbd216581e2ded65ec9504",
"direction": "OUT",
"transactedValue": {
"id": "QW1vdW50OjIuNDcwMDU0NDk5OTk5OTgyX1VTRA==",
"currency": "USD",
"value": 2.470054499999982,
"__typename": "Amount"
}
}
]
},
"__typename": "AssetActivity"
},
{
"id": "QXNzZXRBY3Rpdml0eTpWSEpoYm5OaFkzUnBiMjQ2TUhnM04yRXhPVGRoWmpjek9EUXpNRFk0WVRCaVlqUmlaV1V6WWpabFptWmxaakpsTkdZMFptTXlNR1UxWVRGbVltSTBOak14WXpoak1UQTROMk15WWpjM1h6QjRaak01Wm1RMlpUVXhZV0ZrT0RobU5tWTBZMlUyWVdJNE9ESTNNamM1WTJabVptSTVNakkyTmw4d2VHWTFZekZoTnpCbU5qY3pPV0k1TW1ZNU4yTmtOVE5qTXpFMk1ETTJNbU14TXpBMVpUa3hZVGc9",
"timestamp": 1684202579,
"chain": "ETHEREUM",
"details": {
"id": "VHJhbnNhY3Rpb246MHg3N2ExOTdhZjczODQzMDY4YTBiYjRiZWUzYjZlZmZlZjJlNGY0ZmMyMGU1YTFmYmI0NjMxYzhjMTA4N2MyYjc3XzB4ZjM5ZmQ2ZTUxYWFkODhmNmY0Y2U2YWI4ODI3Mjc5Y2ZmZmI5MjI2Nl8weGY1YzFhNzBmNjczOWI5MmY5N2NkNTNjMzE2MDM2MmMxMzA1ZTkxYTg=",
"type": "SEND",
"blockNumber": 17269191,
"hash": "0x77a197af73843068a0bb4bee3b6effef2e4f4fc20e5a1fbb4631c8c1087c2b77",
"status": "CONFIRMED",
"to": "0xf5c1a70f6739b92f97cd53c3160362c1305e91a8",
"from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"nonce": 463,
"__typename": "TransactionDetails",
"assetChanges": [
{
"__typename": "TokenTransfer",
"id": "VG9rZW5UcmFuc2ZlcjoweGYzOWZkNmU1MWFhZDg4ZjZmNGNlNmFiODgyNzI3OWNmZmZiOTIyNjZfMHhmNWMxYTcwZjY3MzliOTJmOTdjZDUzYzMxNjAzNjJjMTMwNWU5MWE4XzB4NzdhMTk3YWY3Mzg0MzA2OGEwYmI0YmVlM2I2ZWZmZWYyZTRmNGZjMjBlNWExZmJiNDYzMWM4YzEwODdjMmI3Nw==",
"asset": {
"id": "VG9rZW46RVRIRVJFVU1fbnVsbA==",
"name": "Ether",
"symbol": "ETH",
"address": null,
"decimals": 18,
"chain": "ETHEREUM",
"standard": null,
"project": {
"id": "VG9rZW5Qcm9qZWN0OkVUSEVSRVVNX251bGw=",
"isSpam": false,
"logo": {
"id": "SW1hZ2U6aHR0cHM6Ly90b2tlbi1pY29ucy5zMy5hbWF6b25hd3MuY29tL2V0aC5wbmc=",
"url": "https://token-icons.s3.amazonaws.com/eth.png",
"__typename": "Image"
},
"__typename": "TokenProject"
},
"__typename": "Token"
},
"tokenStandard": "NATIVE",
"quantity": "0.001216034894406018",
"sender": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"recipient": "0xf5c1a70f6739b92f97cd53c3160362c1305e91a8",
"direction": "OUT",
"transactedValue": {
"id": "QW1vdW50OjIuMjI0OTQyNTY1MjQ3ODU5X1VTRA==",
"currency": "USD",
"value": 2.224942565247859,
"__typename": "Amount"
}
}
]
},
"__typename": "AssetActivity"
},
{
"id": "QXNzZXRBY3Rpdml0eTpWSEpoYm5OaFkzUnBiMjQ2TUhnMlpXSmtZbVJrTVRZMk0yVmxNV1ZrT0RVeE16TXlZelUyWmpkall6YzJaV1ZqTVROaE5qTm1PVEkxTldOa1ltWXlZVEUxWWpReFl6azBPVGhrWW1Wa1h6QjROREZpTXpBNU1qTTJZemczWWpGaVl6Wm1ZVGhsWWpnMk5UZ3pNMlUwTkRFMU9HWmhPVGt4WVY4d2VHWXpPV1prTm1VMU1XRmhaRGc0WmpabU5HTmxObUZpT0RneU56STNPV05tWm1aaU9USXlOalk9",
"timestamp": 1684202579,
"chain": "ETHEREUM",
"details": {
"id": "VHJhbnNhY3Rpb246MHg2ZWJkYmRkMTY2M2VlMWVkODUxMzMyYzU2ZjdjYzc2ZWVjMTNhNjNmOTI1NWNkYmYyYTE1YjQxYzk0OThkYmVkXzB4NDFiMzA5MjM2Yzg3YjFiYzZmYThlYjg2NTgzM2U0NDE1OGZhOTkxYV8weGYzOWZkNmU1MWFhZDg4ZjZmNGNlNmFiODgyNzI3OWNmZmZiOTIyNjY=",
"type": "RECEIVE",
"blockNumber": 17269191,
"hash": "0x6ebdbdd1663ee1ed851332c56f7cc76eec13a63f9255cdbf2a15b41c9498dbed",
"status": "CONFIRMED",
"to": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"from": "0x41b309236c87b1bc6fa8eb865833e44158fa991a",
"nonce": 111266,
"__typename": "TransactionDetails",
"assetChanges": [
{
"__typename": "TokenTransfer",
"id": "VG9rZW5UcmFuc2ZlcjoweDQxYjMwOTIzNmM4N2IxYmM2ZmE4ZWI4NjU4MzNlNDQxNThmYTk5MWFfMHhmMzlmZDZlNTFhYWQ4OGY2ZjRjZTZhYjg4MjcyNzljZmZmYjkyMjY2XzB4NmViZGJkZDE2NjNlZTFlZDg1MTMzMmM1NmY3Y2M3NmVlYzEzYTYzZjkyNTVjZGJmMmExNWI0MWM5NDk4ZGJlZA==",
"asset": {
"id": "VG9rZW46RVRIRVJFVU1fbnVsbA==",
"name": "Ether",
"symbol": "ETH",
"address": null,
"decimals": 18,
"chain": "ETHEREUM",
"standard": null,
"project": {
"id": "VG9rZW5Qcm9qZWN0OkVUSEVSRVVNX251bGw=",
"isSpam": false,
"logo": {
"id": "SW1hZ2U6aHR0cHM6Ly90b2tlbi1pY29ucy5zMy5hbWF6b25hd3MuY29tL2V0aC5wbmc=",
"url": "https://token-icons.s3.amazonaws.com/eth.png",
"__typename": "Image"
},
"__typename": "TokenProject"
},
"__typename": "Token"
},
"tokenStandard": "NATIVE",
"quantity": "0.00275365",
"sender": "0x41b309236c87b1bc6fa8eb865833e44158fa991a",
"recipient": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"direction": "IN",
"transactedValue": {
"id": "QW1vdW50OjUuMDM4MjcwNzk1NV9VU0Q=",
"currency": "USD",
"value": 5.0382707955,
"__typename": "Amount"
}
}
]
},
"__typename": "AssetActivity"
},
{
"id": "QXNzZXRBY3Rpdml0eTpWSEpoYm5OaFkzUnBiMjQ2TUhnNU5EUmlNR00wTVROa1l6QmpNekU0TUdFelkyTTNZakUyT1RCbVlqZzBNRFExWm1FME9UTXpObUV5WmprNE16VmpORFpqTURsak1UY3lObUUzTm1aalh6QjRaak01Wm1RMlpUVXhZV0ZrT0RobU5tWTBZMlUyWVdJNE9ESTNNamM1WTJabVptSTVNakkyTmw4d2VEWXlNakJsTURoak9XUTJNMkZpTjJKaE1tVTFOalk0TXpsbU5ESTVaV1ZsWm1VeE9UbGlOMlU9",
"timestamp": 1684171943,
"chain": "ETHEREUM",
"details": {
"id": "VHJhbnNhY3Rpb246MHg5NDRiMGM0MTNkYzBjMzE4MGEzY2M3YjE2OTBmYjg0MDQ1ZmE0OTMzNmEyZjk4MzVjNDZjMDljMTcyNmE3NmZjXzB4ZjM5ZmQ2ZTUxYWFkODhmNmY0Y2U2YWI4ODI3Mjc5Y2ZmZmI5MjI2Nl8weDYyMjBlMDhjOWQ2M2FiN2JhMmU1NjY4MzlmNDI5ZWVlZmUxOTliN2U=",
"type": "SEND",
"blockNumber": 17266680,
"hash": "0x944b0c413dc0c3180a3cc7b1690fb84045fa49336a2f9835c46c09c1726a76fc",
"status": "CONFIRMED",
"to": "0x6220e08c9d63ab7ba2e566839f429eeefe199b7e",
"from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"nonce": 462,
"__typename": "TransactionDetails",
"assetChanges": [
{
"__typename": "TokenTransfer",
"id": "VG9rZW5UcmFuc2ZlcjoweGYzOWZkNmU1MWFhZDg4ZjZmNGNlNmFiODgyNzI3OWNmZmZiOTIyNjZfMHg2MjIwZTA4YzlkNjNhYjdiYTJlNTY2ODM5ZjQyOWVlZWZlMTk5YjdlXzB4OTQ0YjBjNDEzZGMwYzMxODBhM2NjN2IxNjkwZmI4NDA0NWZhNDkzMzZhMmY5ODM1YzQ2YzA5YzE3MjZhNzZmYw==",
"asset": {
"id": "VG9rZW46RVRIRVJFVU1fbnVsbA==",
"name": "Ether",
"symbol": "ETH",
"address": null,
"decimals": 18,
"chain": "ETHEREUM",
"standard": null,
"project": {
"id": "VG9rZW5Qcm9qZWN0OkVUSEVSRVVNX251bGw=",
"isSpam": false,
"logo": {
"id": "SW1hZ2U6aHR0cHM6Ly90b2tlbi1pY29ucy5zMy5hbWF6b25hd3MuY29tL2V0aC5wbmc=",
"url": "https://token-icons.s3.amazonaws.com/eth.png",
"__typename": "Image"
},
"__typename": "TokenProject"
},
"__typename": "Token"
},
"tokenStandard": "NATIVE",
"quantity": "0.003476850926189204",
"sender": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"recipient": "0x6220e08c9d63ab7ba2e566839f429eeefe199b7e",
"direction": "OUT",
"transactedValue": {
"id": "QW1vdW50OjYuMzYxNDg5ODM0MTIwNjAxX1VTRA==",
"currency": "USD",
"value": 6.361489834120601,
"__typename": "Amount"
}
}
]
},
"__typename": "AssetActivity"
},
{
"id": "QXNzZXRBY3Rpdml0eTpWSEpoYm5OaFkzUnBiMjQ2TUhneE0yRTRNRGxsT1RZd05USmhOVGxrWlRjNU56WXhObVZrTlRjME1qTTVNakV3WkRJMVpUY3hNRGhqTkRjek9EbG1NbVJoTnpjeU5qTXhZbVZpTUdZMlh6QjRaak01Wm1RMlpUVXhZV0ZrT0RobU5tWTBZMlUyWVdJNE9ESTNNamM1WTJabVptSTVNakkyTmw4d2VEWXlNakJsTURoak9XUTJNMkZpTjJKaE1tVTFOalk0TXpsbU5ESTVaV1ZsWm1VeE9UbGlOMlU9",
"timestamp": 1684171943,
"chain": "ETHEREUM",
"details": {
"id": "VHJhbnNhY3Rpb246MHgxM2E4MDllOTYwNTJhNTlkZTc5NzYxNmVkNTc0MjM5MjEwZDI1ZTcxMDhjNDczODlmMmRhNzcyNjMxYmViMGY2XzB4ZjM5ZmQ2ZTUxYWFkODhmNmY0Y2U2YWI4ODI3Mjc5Y2ZmZmI5MjI2Nl8weDYyMjBlMDhjOWQ2M2FiN2JhMmU1NjY4MzlmNDI5ZWVlZmUxOTliN2U=",
"type": "SEND",
"blockNumber": 17266680,
"hash": "0x13a809e96052a59de797616ed574239210d25e7108c47389f2da772631beb0f6",
"status": "CONFIRMED",
"to": "0x6220e08c9d63ab7ba2e566839f429eeefe199b7e",
"from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"nonce": 461,
"__typename": "TransactionDetails",
"assetChanges": [
{
"__typename": "TokenTransfer",
"id": "VG9rZW5UcmFuc2ZlcjoweGYzOWZkNmU1MWFhZDg4ZjZmNGNlNmFiODgyNzI3OWNmZmZiOTIyNjZfMHg2MjIwZTA4YzlkNjNhYjdiYTJlNTY2ODM5ZjQyOWVlZWZlMTk5YjdlXzB4MTNhODA5ZTk2MDUyYTU5ZGU3OTc2MTZlZDU3NDIzOTIxMGQyNWU3MTA4YzQ3Mzg5ZjJkYTc3MjYzMWJlYjBmNg==",
"asset": {
"id": "VG9rZW46RVRIRVJFVU1fbnVsbA==",
"name": "Ether",
"symbol": "ETH",
"address": null,
"decimals": 18,
"chain": "ETHEREUM",
"standard": null,
"project": {
"id": "VG9rZW5Qcm9qZWN0OkVUSEVSRVVNX251bGw=",
"isSpam": false,
"logo": {
"id": "SW1hZ2U6aHR0cHM6Ly90b2tlbi1pY29ucy5zMy5hbWF6b25hd3MuY29tL2V0aC5wbmc=",
"url": "https://token-icons.s3.amazonaws.com/eth.png",
"__typename": "Image"
},
"__typename": "TokenProject"
},
"__typename": "Token"
},
"tokenStandard": "NATIVE",
"quantity": "0.000900000000000318",
"sender": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"recipient": "0x6220e08c9d63ab7ba2e566839f429eeefe199b7e",
"direction": "OUT",
"transactedValue": {
"id": "QW1vdW50OjEuNjQ2NzAzMDAwMDAwNTgxOF9VU0Q=",
"currency": "USD",
"value": 1.6467030000005818,
"__typename": "Amount"
}
}
]
},
"__typename": "AssetActivity"
},
{
"id": "QXNzZXRBY3Rpdml0eTpWSEpoYm5OaFkzUnBiMjQ2TUhobFkyRTJNVEZrTlRVME1EZGxPVGt6WlRFM1lqWmtaVGhpWVRJMFlqWXlOREpqWVRSbFlXWTBORGN3TkRKbFpHRmtNRFE0TTJNNFptSTJabUU0WkRJNVh6QjROekU0WVRVeE5ESXhNR0kwTnpWaU9USXhOVGd6WldGaU5ERXlaV0ptTUdaaVlXUm1NMkl6T1Y4d2VHWXpPV1prTm1VMU1XRmhaRGc0WmpabU5HTmxObUZpT0RneU56STNPV05tWm1aaU9USXlOalk9",
"timestamp": 1684171931,
"chain": "ETHEREUM",
"details": {
"id": "VHJhbnNhY3Rpb246MHhlY2E2MTFkNTU0MDdlOTkzZTE3YjZkZThiYTI0YjYyNDJjYTRlYWY0NDcwNDJlZGFkMDQ4M2M4ZmI2ZmE4ZDI5XzB4NzE4YTUxNDIxMGI0NzViOTIxNTgzZWFiNDEyZWJmMGZiYWRmM2IzOV8weGYzOWZkNmU1MWFhZDg4ZjZmNGNlNmFiODgyNzI3OWNmZmZiOTIyNjY=",
"type": "RECEIVE",
"blockNumber": 17266679,
"hash": "0xeca611d55407e993e17b6de8ba24b6242ca4eaf447042edad0483c8fb6fa8d29",
"status": "CONFIRMED",
"to": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"from": "0x718a514210b475b921583eab412ebf0fbadf3b39",
"nonce": 92,
"__typename": "TransactionDetails",
"assetChanges": [
{
"__typename": "TokenTransfer",
"id": "VG9rZW5UcmFuc2ZlcjoweDcxOGE1MTQyMTBiNDc1YjkyMTU4M2VhYjQxMmViZjBmYmFkZjNiMzlfMHhmMzlmZDZlNTFhYWQ4OGY2ZjRjZTZhYjg4MjcyNzljZmZmYjkyMjY2XzB4ZWNhNjExZDU1NDA3ZTk5M2UxN2I2ZGU4YmEyNGI2MjQyY2E0ZWFmNDQ3MDQyZWRhZDA0ODNjOGZiNmZhOGQyOQ==",
"asset": {
"id": "VG9rZW46RVRIRVJFVU1fbnVsbA==",
"name": "Ether",
"symbol": "ETH",
"address": null,
"decimals": 18,
"chain": "ETHEREUM",
"standard": null,
"project": {
"id": "VG9rZW5Qcm9qZWN0OkVUSEVSRVVNX251bGw=",
"isSpam": false,
"logo": {
"id": "SW1hZ2U6aHR0cHM6Ly90b2tlbi1pY29ucy5zMy5hbWF6b25hd3MuY29tL2V0aC5wbmc=",
"url": "https://token-icons.s3.amazonaws.com/eth.png",
"__typename": "Image"
},
"__typename": "TokenProject"
},
"__typename": "Token"
},
"tokenStandard": "NATIVE",
"quantity": "0.01",
"sender": "0x718a514210b475b921583eab412ebf0fbadf3b39",
"recipient": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"direction": "IN",
"transactedValue": {
"id": "QW1vdW50OjE4LjI5NjdfVVNE",
"currency": "USD",
"value": 18.2967,
"__typename": "Amount"
}
}
]
},
"__typename": "AssetActivity"
},
{
"id": "QXNzZXRBY3Rpdml0eTpWSEpoYm5OaFkzUnBiMjQ2TUhnMllqTTJNelEwT1daaU1HWTROems0TkRnM1pqWmlOREkwTkRjMFkySXdNbVF5WlRVNE1EZ3dPVEpoWVRneE1EVm1ObUU0T1dOalpHTTBORGRsTURSa1h6QjRaak01Wm1RMlpUVXhZV0ZrT0RobU5tWTBZMlUyWVdJNE9ESTNNamM1WTJabVptSTVNakkyTmw4d2VEQXdNREF3TURBek1HWTBPV0ptTW1Vd01ESmxOakJqTm1Wa01UWTJNV1ppTWpNME5tUTRPREk9",
"timestamp": 1684085063,
"chain": "ETHEREUM",
"details": {
"id": "VHJhbnNhY3Rpb246MHg2YjM2MzQ0OWZiMGY4Nzk4NDg3ZjZiNDI0NDc0Y2IwMmQyZTU4MDgwOTJhYTgxMDVmNmE4OWNjZGM0NDdlMDRkXzB4ZjM5ZmQ2ZTUxYWFkODhmNmY0Y2U2YWI4ODI3Mjc5Y2ZmZmI5MjI2Nl8weDAwMDAwMDAzMGY0OWJmMmUwMDJlNjBjNmVkMTY2MWZiMjM0NmQ4ODI=",
"type": "UNKNOWN",
"blockNumber": 17259555,
"hash": "0x6b363449fb0f8798487f6b424474cb02d2e5808092aa8105f6a89ccdc447e04d",
"status": "CONFIRMED",
"to": "0x000000030f49bf2e002e60c6ed1661fb2346d882",
"from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"nonce": 460,
"__typename": "TransactionDetails",
"assetChanges": []
},
"__typename": "AssetActivity"
},
{
"id": "QXNzZXRBY3Rpdml0eTpWSEpoYm5OaFkzUnBiMjQ2TUhnNFlXRTVNVFJqTkRjeU5qWTNNVGxqWkRFeE1EYzNOMkprTnpZek0yVTFOV1kyWkdWbVpXRmpPVEV4TlRjd09EZzNZVEEyWXpNNE5UTmxaV0kyTldZeVh6QjRaR0V4TTJRMk5HVmpPVFZqWkRZM056VXlPVEZpTVdNek1qRXdNamN4TWpGaVpUSXdPV1JtTUY4d2VHWXpPV1prTm1VMU1XRmhaRGc0WmpabU5HTmxObUZpT0RneU56STNPV05tWm1aaU9USXlOalk9",
"timestamp": 1684085051,
"chain": "ETHEREUM",
"details": {
"id": "VHJhbnNhY3Rpb246MHg4YWE5MTRjNDcyNjY3MTljZDExMDc3N2JkNzYzM2U1NWY2ZGVmZWFjOTExNTcwODg3YTA2YzM4NTNlZWI2NWYyXzB4ZGExM2Q2NGVjOTVjZDY3NzUyOTFiMWMzMjEwMjcxMjFiZTIwOWRmMF8weGYzOWZkNmU1MWFhZDg4ZjZmNGNlNmFiODgyNzI3OWNmZmZiOTIyNjY=",
"type": "RECEIVE",
"blockNumber": 17259554,
"hash": "0x8aa914c47266719cd110777bd7633e55f6defeac911570887a06c3853eeb65f2",
"status": "CONFIRMED",
"to": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"from": "0xda13d64ec95cd6775291b1c321027121be209df0",
"nonce": 832,
"__typename": "TransactionDetails",
"assetChanges": [
{
"__typename": "TokenTransfer",
"id": "VG9rZW5UcmFuc2ZlcjoweGRhMTNkNjRlYzk1Y2Q2Nzc1MjkxYjFjMzIxMDI3MTIxYmUyMDlkZjBfMHhmMzlmZDZlNTFhYWQ4OGY2ZjRjZTZhYjg4MjcyNzljZmZmYjkyMjY2XzB4OGFhOTE0YzQ3MjY2NzE5Y2QxMTA3NzdiZDc2MzNlNTVmNmRlZmVhYzkxMTU3MDg4N2EwNmMzODUzZWViNjVmMg==",
"asset": {
"id": "VG9rZW46RVRIRVJFVU1fbnVsbA==",
"name": "Ether",
"symbol": "ETH",
"address": null,
"decimals": 18,
"chain": "ETHEREUM",
"standard": null,
"project": {
"id": "VG9rZW5Qcm9qZWN0OkVUSEVSRVVNX251bGw=",
"isSpam": false,
"logo": {
"id": "SW1hZ2U6aHR0cHM6Ly90b2tlbi1pY29ucy5zMy5hbWF6b25hd3MuY29tL2V0aC5wbmc=",
"url": "https://token-icons.s3.amazonaws.com/eth.png",
"__typename": "Image"
},
"__typename": "TokenProject"
},
"__typename": "Token"
},
"tokenStandard": "NATIVE",
"quantity": "0.00129866",
"sender": "0xda13d64ec95cd6775291b1c321027121be209df0",
"recipient": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"direction": "IN",
"transactedValue": {
"id": "QW1vdW50OjIuMzc2MTE5MjQyMl9VU0Q=",
"currency": "USD",
"value": 2.3761192422,
"__typename": "Amount"
}
}
]
},
"__typename": "AssetActivity"
},
{
"id": "QXNzZXRBY3Rpdml0eTpWSEpoYm5OaFkzUnBiMjQ2TUhnM00yTXdZMlJpTnpReU9UVTJZVFUxWXpZd016YzBOemd6TkRRNVpUSmpNbVZtTURnM1lqUTVPRFl4TVdGak5EZ3dZalJrTVRFMU1UbGhZemRpTXpZNVh6QjRaak01Wm1RMlpUVXhZV0ZrT0RobU5tWTBZMlUyWVdJNE9ESTNNamM1WTJabVptSTVNakkyTmw4d2VHUXpaR1UwTkRneE5qTXlNakl5TURVME9UazJZVE0yTlRsaE5UTXlNR0k1TWpWbU5qUXhNR1k9",
"timestamp": 1684006019,
"chain": "ETHEREUM",
"details": {
"id": "VHJhbnNhY3Rpb246MHg3M2MwY2RiNzQyOTU2YTU1YzYwMzc0NzgzNDQ5ZTJjMmVmMDg3YjQ5ODYxMWFjNDgwYjRkMTE1MTlhYzdiMzY5XzB4ZjM5ZmQ2ZTUxYWFkODhmNmY0Y2U2YWI4ODI3Mjc5Y2ZmZmI5MjI2Nl8weGQzZGU0NDgxNjMyMjIyMDU0OTk2YTM2NTlhNTMyMGI5MjVmNjQxMGY=",
"type": "SEND",
"blockNumber": 17253116,
"hash": "0x73c0cdb742956a55c60374783449e2c2ef087b498611ac480b4d11519ac7b369",
"status": "CONFIRMED",
"to": "0xd3de4481632222054996a3659a5320b925f6410f",
"from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"nonce": 459,
"__typename": "TransactionDetails",
"assetChanges": [
{
"__typename": "TokenTransfer",
"id": "VG9rZW5UcmFuc2ZlcjoweGYzOWZkNmU1MWFhZDg4ZjZmNGNlNmFiODgyNzI3OWNmZmZiOTIyNjZfMHhiZTgyODI1NjRlYzJiNzAwMDlmMmQ2ODk1NDAxMmViMDlmNDhiYzhkXzB4NzNjMGNkYjc0Mjk1NmE1NWM2MDM3NDc4MzQ0OWUyYzJlZjA4N2I0OTg2MTFhYzQ4MGI0ZDExNTE5YWM3YjM2OQ==",
"asset": {
"id": "VG9rZW46RVRIRVJFVU1fMHhkM2RlNDQ4MTYzMjIyMjA1NDk5NmEzNjU5YTUzMjBiOTI1ZjY0MTBm",
"name": "EL CHAPO",
"symbol": "CHAPO",
"address": "0xd3de4481632222054996a3659a5320b925f6410f",
"decimals": 18,
"chain": "ETHEREUM",
"standard": null,
"project": {
"id": "VG9rZW5Qcm9qZWN0OkVUSEVSRVVNXzB4ZDNkZTQ0ODE2MzIyMjIwNTQ5OTZhMzY1OWE1MzIwYjkyNWY2NDEwZg==",
"isSpam": true,
"logo": null,
"__typename": "TokenProject"
},
"__typename": "Token"
},
"tokenStandard": "ERC20",
"quantity": "50000000000000.002683081102196736",
"sender": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"recipient": "0xbe8282564ec2b70009f2d68954012eb09f48bc8d",
"direction": "OUT",
"transactedValue": null
}
]
},
"__typename": "AssetActivity"
}
],
"__typename": "Portfolio"
}
]
},
"errors": []
}

File diff suppressed because one or more lines are too long

View File

@ -1,102 +0,0 @@
{
"data": {
"portfolios": [
{
"id": "UG9ydGZvbGlvOjB4ZjM5RmQ2ZTUxYWFkODhGNkY0Y2U2YUI4ODI3Mjc5Y2ZmRmI5MjI2Ng==",
"assetActivities": [
{
"id": "QXNzZXRBY3Rpdml0eTpWSEpoYm5OaFkzUnBiMjQ2TUhnNE9EZGpOemN5TlRRNU1qWTVNVEkwWVRkbVpUTXlNams1TjJJNU0yUTJabUV3TjJObE1UQXhOamxrTjJJd1pXUXhObUV6TldabU16SmtOMk13TWpBeVh6QjRaREkzTXpnek1EUTRaalF4WldZMlpXRXhaV1EzWWpBeFltVTVOemRqTjJVME1HSXdaRGswTmw4d2VEUTNZVFF5TVdKalpXTTJORE5oWWpSallURmpZamc0TmpOaU4yWm1PV0ppWm1SaU5HVmlNVE09",
"timestamp": 1691001923,
"type": "SWAP_ORDER",
"chain": "ETHEREUM",
"details": {
"__typename": "TransactionDetails",
"id": "VHJhbnNhY3Rpb246MHg4ODdjNzcyNTQ5MjY5MTI0YTdmZTMyMjk5N2I5M2Q2ZmEwN2NlMTAxNjlkN2IwZWQxNmEzNWZmMzJkN2MwMjAyXzB4ZDI3MzgzMDQ4ZjQxZWY2ZWExZWQ3YjAxYmU5NzdjN2U0MGIwZDk0Nl8weDQ3YTQyMWJjZWM2NDNhYjRjYTFjYjg4NjNiN2ZmOWJiZmRiNGViMTM=",
"type": "SWAP_ORDER",
"from": "0xd27383048f41ef6ea1ed7b01be977c7e40b0d946",
"to": "0x47a421bcec643ab4ca1cb8863b7ff9bbfdb4eb13",
"hash": "0x9f8382a94ee80ca119bc690908ab5f69c4c72f7497ee10f37e9ede0ded83cca6",
"nonce": 439,
"status": "CONFIRMED"
},
"assetChanges": [
{
"__typename": "TokenTransfer",
"id": "VG9rZW5UcmFuc2ZlcjoweDgwYmVjYjgwOGJmYWRlNDE0MzE4M2U1OGQxOGYyMDgwZTg0ZTU3YTFfMHg0N2E0MjFiY2VjNjQzYWI0Y2ExY2I4ODYzYjdmZjliYmZkYjRlYjEzXzB4ODg3Yzc3MjU0OTI2OTEyNGE3ZmUzMjI5OTdiOTNkNmZhMDdjZTEwMTY5ZDdiMGVkMTZhMzVmZjMyZDdjMDIwMg==",
"asset": {
"id": "VG9rZW46RVRIRVJFVU1fMHhhMGI4Njk5MWM2MjE4YjM2YzFkMTlkNGEyZTllYjBjZTM2MDZlYjQ4",
"name": "USD Coin",
"symbol": "USDC",
"address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"decimals": 6,
"chain": "ETHEREUM",
"standard": null,
"project": {
"id": "VG9rZW5Qcm9qZWN0OkVUSEVSRVVNXzB4YTBiODY5OTFjNjIxOGIzNmMxZDE5ZDRhMmU5ZWIwY2UzNjA2ZWI0OA==",
"isSpam": false,
"logo": {
"id": "SW1hZ2U6aHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL1VuaXN3YXAvYXNzZXRzL21hc3Rlci9ibG9ja2NoYWlucy9ldGhlcmV1bS9hc3NldHMvMHhBMGI4Njk5MWM2MjE4YjM2YzFkMTlENGEyZTlFYjBjRTM2MDZlQjQ4L2xvZ28ucG5n",
"url": "https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png",
"__typename": "Image"
},
"__typename": "TokenProject"
},
"__typename": "Token"
},
"tokenStandard": "ERC20",
"quantity": "300.0",
"sender": "0x80becb808bfade4143183e58d18f2080e84e57a1",
"recipient": "0x47a421bcec643ab4ca1cb8863b7ff9bbfdb4eb13",
"direction": "OUT",
"transactedValue": {
"id": "QW1vdW50OjMwMC4xNDkxNTIwOTE5NDE2M19VU0Q=",
"currency": "USD",
"value": 300.14915209194163,
"__typename": "Amount"
}
},
{
"__typename": "TokenTransfer",
"id": "VG9rZW5UcmFuc2ZlcjoweDQ3YTQyMWJjZWM2NDNhYjRjYTFjYjg4NjNiN2ZmOWJiZmRiNGViMTNfMHg4MGJlY2I4MDhiZmFkZTQxNDMxODNlNThkMThmMjA4MGU4NGU1N2ExXzB4ODg3Yzc3MjU0OTI2OTEyNGE3ZmUzMjI5OTdiOTNkNmZhMDdjZTEwMTY5ZDdiMGVkMTZhMzVmZjMyZDdjMDIwMg==",
"asset": {
"id": "VG9rZW46RVRIRVJFVU1fMHg2YjE3NTQ3NGU4OTA5NGM0NGRhOThiOTU0ZWVkZWFjNDk1MjcxZDBm",
"name": "Dai Stablecoin",
"symbol": "DAI",
"address": "0x6b175474e89094c44da98b954eedeac495271d0f",
"decimals": 18,
"chain": "ETHEREUM",
"standard": null,
"project": {
"id": "VG9rZW5Qcm9qZWN0OkVUSEVSRVVNXzB4NmIxNzU0NzRlODkwOTRjNDRkYTk4Yjk1NGVlZGVhYzQ5NTI3MWQwZg==",
"isSpam": false,
"logo": {
"id": "SW1hZ2U6aHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL1VuaXN3YXAvYXNzZXRzL21hc3Rlci9ibG9ja2NoYWlucy9ldGhlcmV1bS9hc3NldHMvMHg2QjE3NTQ3NEU4OTA5NEM0NERhOThiOTU0RWVkZUFDNDk1MjcxZDBGL2xvZ28ucG5n",
"url": "https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0x6B175474E89094C44Da98b954EedeAC495271d0F/logo.png",
"__typename": "Image"
},
"__typename": "TokenProject"
},
"__typename": "Token"
},
"tokenStandard": "ERC20",
"quantity": "280.573117586837733376",
"sender": "0x47a421bcec643ab4ca1cb8863b7ff9bbfdb4eb13",
"recipient": "0x80becb808bfade4143183e58d18f2080e84e57a1",
"direction": "IN",
"transactedValue": {
"id": "QW1vdW50OjI4MC42ODc3OTU0NTg2ODE4X1VTRA==",
"currency": "USD",
"value": 280.6877954586818,
"__typename": "Amount"
}
}
],
"__typename": "AssetActivity"
}
],
"__typename": "Portfolio"
}
]
},
"errors": []
}

View File

@ -1,26 +0,0 @@
{
"orders": [
{
"outputs": [
{
"recipient": "0x80becb808bfade4143183e58d18f2080e84e57a1",
"startAmount": "91371770080538616664",
"endAmount": "90914911230135923580",
"token": "0x6B175474E89094C44Da98b954EedeAC495271d0F"
}
],
"encodedOrder": "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000064837e2a0000000000000000000000000000000000000000000000000000000064837e6600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000bd7f9d0239f81c94b728d827a87b9864972661ec00000000000000000000000080becb808bfade4143183e58d18f2080e84e57a18e32c6335b6f657322448399bd12ff5c22b7b1aa770850ff4eed36c750e2de000000000000000000000000000000000000000000000000000000000064837e66000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000004f409bcc7a52b6358000000000000000000000000000000000000000000000004edb2a613726c737c00000000000000000000000080becb808bfade4143183e58d18f2080e84e57a1",
"signature": "0x973882a290778b5c8aae691ef777385259928cde0513d224ea1131538379258d2db7a69804110320b08558380394879a31ab8dea61152c2dba7623acbfa11d0e1b",
"input": {
"endAmount": "100000000",
"token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"startAmount": "100000000"
},
"orderStatus": "expired",
"createdAt": 1686339087,
"chainId": 1,
"orderHash": "0xa9dd6f05ad6d6c79bee654c31ede4d0d2392862711be0f3bc4a9124af24a6a19",
"type": "Dutch"
}
]
}

View File

@ -1,562 +0,0 @@
{
"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
}
}
]
}

View File

@ -1,114 +0,0 @@
{
"to": "0xbD7F9D0239f81C94b728d827a87b9864972661eC",
"from": "0xa17Fbb0b5a251A7ACA3BD7377e7eCC4F700A2C09",
"contractAddress": null,
"transactionIndex": 61,
"gasUsed": {
"type": "BigNumber",
"hex": "0x03e0c8"
},
"logsBloom":
"0x00000000000000000000008000200100000020000000000000000000000000000000000000000000000000010000000000000000000020000000000001000000000280000000000808000008000000000000000000000000000000000000200010000000100000000008000000000004402000080000000000000010000800000000000000000800000800000000000000000000010000000000000000000000000000000000200000000000005000000000000000000000000000000000000000000002000000000000000000000000040002000000000000000100000000090000000400000000000400000020080000000000000000000000000000000000",
"blockHash": "0x79cf0785f317f984eeaf737c592afff806cabf4fe0c46a84f62a4a0212cfab5c",
"transactionHash": "0x9f8382a94ee80ca119bc690908ab5f69c4c72f7497ee10f37e9ede0ded83cca6",
"logs": [
{
"transactionIndex": 61,
"blockNumber": 17444757,
"transactionHash": "0x9f8382a94ee80ca119bc690908ab5f69c4c72f7497ee10f37e9ede0ded83cca6",
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"topics": [
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"0x00000000000000000000000080becb808bfade4143183e58d18f2080e84e57a1",
"0x000000000000000000000000c59938e2d9ff9a0ecccbedf39031b1600d008eaf"
],
"data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
"logIndex": 103,
"blockHash": "0x79cf0785f317f984eeaf737c592afff806cabf4fe0c46a84f62a4a0212cfab5c"
},
{
"transactionIndex": 61,
"blockNumber": 17444757,
"transactionHash": "0x9f8382a94ee80ca119bc690908ab5f69c4c72f7497ee10f37e9ede0ded83cca6",
"address": "0xbD7F9D0239f81C94b728d827a87b9864972661eC",
"topics": [
"0x78ad7ec0e9f89e74012afa58738b6b661c024cb0fd185ee2f616c0a28924bd66",
"0xd10e1d90145460003d98ba4b788564e9549cc93c65a12c9b297720a9d6a586de",
"0x000000000000000000000000a17fbb0b5a251a7aca3bd7377e7ecc4f700a2c09",
"0x00000000000000000000000080becb808bfade4143183e58d18f2080e84e57a1"
],
"data": "0x8e32c6335b6f657322448399bd12ff5c22b7b1aa770850ff4eed36c750e2de00",
"logIndex": 104,
"blockHash": "0x79cf0785f317f984eeaf737c592afff806cabf4fe0c46a84f62a4a0212cfab5c"
},
{
"transactionIndex": 61,
"blockNumber": 17444757,
"transactionHash": "0x9f8382a94ee80ca119bc690908ab5f69c4c72f7497ee10f37e9ede0ded83cca6",
"address": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
"topics": [
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"0x0000000000000000000000005777d92f208679db4b9778590fa3cab3ac9e2168",
"0x000000000000000000000000c59938e2d9ff9a0ecccbedf39031b1600d008eaf"
],
"data": "0x0000000000000000000000000000000000000000000000056b9a675be430b502",
"logIndex": 105,
"blockHash": "0x79cf0785f317f984eeaf737c592afff806cabf4fe0c46a84f62a4a0212cfab5c"
},
{
"transactionIndex": 61,
"blockNumber": 17444757,
"transactionHash": "0x9f8382a94ee80ca119bc690908ab5f69c4c72f7497ee10f37e9ede0ded83cca6",
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"topics": [
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"0x000000000000000000000000c59938e2d9ff9a0ecccbedf39031b1600d008eaf",
"0x0000000000000000000000005777d92f208679db4b9778590fa3cab3ac9e2168"
],
"data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
"logIndex": 106,
"blockHash": "0x79cf0785f317f984eeaf737c592afff806cabf4fe0c46a84f62a4a0212cfab5c"
},
{
"transactionIndex": 61,
"blockNumber": 17444757,
"transactionHash": "0x9f8382a94ee80ca119bc690908ab5f69c4c72f7497ee10f37e9ede0ded83cca6",
"address": "0x5777d92f208679DB4b9778590Fa3CAB3aC9e2168",
"topics": [
"0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67",
"0x00000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45",
"0x000000000000000000000000c59938e2d9ff9a0ecccbedf39031b1600d008eaf"
],
"data": "0xfffffffffffffffffffffffffffffffffffffffffffffffa946598a41bcf4afe0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000010c7063b90a5e90d13830000000000000000000000000000000000000000000071b57cb2bb0b5b28224ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc89c",
"logIndex": 107,
"blockHash": "0x79cf0785f317f984eeaf737c592afff806cabf4fe0c46a84f62a4a0212cfab5c"
},
{
"transactionIndex": 61,
"blockNumber": 17444757,
"transactionHash": "0x9f8382a94ee80ca119bc690908ab5f69c4c72f7497ee10f37e9ede0ded83cca6",
"address": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
"topics": [
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"0x000000000000000000000000c59938e2d9ff9a0ecccbedf39031b1600d008eaf",
"0x00000000000000000000000080becb808bfade4143183e58d18f2080e84e57a1"
],
"data": "0x000000000000000000000000000000000000000000000004f409bcc7a52b6358",
"logIndex": 108,
"blockHash": "0x79cf0785f317f984eeaf737c592afff806cabf4fe0c46a84f62a4a0212cfab5c"
}
],
"blockNumber": 17444757,
"confirmations": 392238,
"cumulativeGasUsed": {
"type": "BigNumber",
"hex": "0x4065ac"
},
"effectiveGasPrice": {
"type": "BigNumber",
"hex": "0x04aa792df0"
},
"status": 1,
"type": 2,
"byzantium": true
}

View File

@ -1,33 +0,0 @@
{
"orders": [
{
"outputs": [
{
"recipient": "0x80becb808bfade4143183e58d18f2080e84e57a1",
"startAmount": "91371770080538616664",
"endAmount": "90914911230135923580",
"token": "0x6B175474E89094C44Da98b954EedeAC495271d0F"
}
],
"encodedOrder": "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000064837e2a0000000000000000000000000000000000000000000000000000000064837e6600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000bd7f9d0239f81c94b728d827a87b9864972661ec00000000000000000000000080becb808bfade4143183e58d18f2080e84e57a18e32c6335b6f657322448399bd12ff5c22b7b1aa770850ff4eed36c750e2de000000000000000000000000000000000000000000000000000000000064837e66000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000004f409bcc7a52b6358000000000000000000000000000000000000000000000004edb2a613726c737c00000000000000000000000080becb808bfade4143183e58d18f2080e84e57a1",
"signature": "0x973882a290778b5c8aae691ef777385259928cde0513d224ea1131538379258d2db7a69804110320b08558380394879a31ab8dea61152c2dba7623acbfa11d0e1b",
"input": {
"endAmount": "100000000",
"token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"startAmount": "100000000"
},
"settledAmounts": [
{
"tokenOut": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
"amountOut": "91371770080538616664"
}
],
"orderStatus": "filled",
"txHash": "0x9f8382a94ee80ca119bc690908ab5f69c4c72f7497ee10f37e9ede0ded83cca6",
"createdAt": 1686339087,
"chainId": 1,
"orderHash": "0xa9dd6f05ad6d6c79bee654c31ede4d0d2392862711be0f3bc4a9124af24a6a19",
"type": "Dutch"
}
]
}

View File

@ -1,26 +0,0 @@
{
"orders": [
{
"outputs": [
{
"recipient": "0x80becb808bfade4143183e58d18f2080e84e57a1",
"startAmount": "91371770080538616664",
"endAmount": "90914911230135923580",
"token": "0x6B175474E89094C44Da98b954EedeAC495271d0F"
}
],
"encodedOrder": "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000064837e2a0000000000000000000000000000000000000000000000000000000064837e6600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000bd7f9d0239f81c94b728d827a87b9864972661ec00000000000000000000000080becb808bfade4143183e58d18f2080e84e57a18e32c6335b6f657322448399bd12ff5c22b7b1aa770850ff4eed36c750e2de000000000000000000000000000000000000000000000000000000000064837e66000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000004f409bcc7a52b6358000000000000000000000000000000000000000000000004edb2a613726c737c00000000000000000000000080becb808bfade4143183e58d18f2080e84e57a1",
"signature": "0x973882a290778b5c8aae691ef777385259928cde0513d224ea1131538379258d2db7a69804110320b08558380394879a31ab8dea61152c2dba7623acbfa11d0e1b",
"input": {
"endAmount": "100000000",
"token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"startAmount": "100000000"
},
"orderStatus": "insufficient-funds",
"createdAt": 1686339087,
"chainId": 1,
"orderHash": "0xa9dd6f05ad6d6c79bee654c31ede4d0d2392862711be0f3bc4a9124af24a6a19",
"type": "Dutch"
}
]
}

View File

@ -1,26 +0,0 @@
{
"orders": [
{
"outputs": [
{
"recipient": "0x80becb808bfade4143183e58d18f2080e84e57a1",
"startAmount": "91371770080538616664",
"endAmount": "90914911230135923580",
"token": "0x6B175474E89094C44Da98b954EedeAC495271d0F"
}
],
"encodedOrder": "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000064837e2a0000000000000000000000000000000000000000000000000000000064837e6600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000bd7f9d0239f81c94b728d827a87b9864972661ec00000000000000000000000080becb808bfade4143183e58d18f2080e84e57a18e32c6335b6f657322448399bd12ff5c22b7b1aa770850ff4eed36c750e2de000000000000000000000000000000000000000000000000000000000064837e66000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000004f409bcc7a52b6358000000000000000000000000000000000000000000000004edb2a613726c737c00000000000000000000000080becb808bfade4143183e58d18f2080e84e57a1",
"signature": "0x973882a290778b5c8aae691ef777385259928cde0513d224ea1131538379258d2db7a69804110320b08558380394879a31ab8dea61152c2dba7623acbfa11d0e1b",
"input": {
"endAmount": "100000000",
"token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"startAmount": "100000000"
},
"orderStatus": "open",
"createdAt": 1686339087,
"chainId": 1,
"orderHash": "0xa9dd6f05ad6d6c79bee654c31ede4d0d2392862711be0f3bc4a9124af24a6a19",
"type": "Dutch"
}
]
}

View File

@ -1 +0,0 @@
{"hash":"0xa9dd6f05ad6d6c79bee654c31ede4d0d2392862711be0f3bc4a9124af24a6a19"}

View File

@ -1,493 +0,0 @@
{
"routing": "DUTCH_LIMIT",
"quote": {
"orderInfo": {
"chainId": 1,
"permit2Address": "0x000000000022d473030f116ddee9f6b43ac78ba3",
"reactor": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4",
"swapper": "0x67d615D6bccAA1562B1cca9786384b4840597ecD",
"nonce": "57335948072881703373319552024074512292695687510330025934414357004397546394368",
"deadline": 1690902198,
"additionalValidationContract": "0x0000000000000000000000000000000000000000",
"additionalValidationData": "0x",
"decayStartTime": 1690902126,
"decayEndTime": 1690902186,
"exclusiveFiller": "0x0000000000000000000000000000000000000000",
"exclusivityOverrideBps": "0",
"input": {
"token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"startAmount": "300000000",
"endAmount": "300000000"
},
"outputs": [
{
"token": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
"startAmount": "289951120815684452958",
"endAmount": "267060007981523637666",
"recipient": "0x67d615D6bccAA1562B1cca9786384b4840597ecD"
}
]
},
"encodedOrder": "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000064c91e6e0000000000000000000000000000000000000000000000000000000064c91eaa00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000011e1a3000000000000000000000000000000000000000000000000000000000011e1a30000000000000000000000000000000000000000000000000000000000000002000000000000000000000000006000da47483062a0d734ba3dc7576ce6a0b645c400000000000000000000000067d615d6bccaa1562b1cca9786384b4840597ecd7ec2ff20796a08922e11fd828e3871a6aa9a80e6495e30cd41be24b7e37953000000000000000000000000000000000000000000000000000000000064c91eb6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000fb7e15027ad3e025e00000000000000000000000000000000000000000000000e7a33be508bb395a200000000000000000000000067d615d6bccaa1562b1cca9786384b4840597ecd",
"quoteId": "f9f47cd7-a62c-4622-9ac7-51d0e662245a",
"requestId": "2d16f993-6429-4755-ba50-1383789459dc",
"auctionPeriodSecs": 60,
"startTimeBufferSecs": 30,
"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": "0x11e1a300"
}
},
"spender": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4",
"nonce": {
"type": "BigNumber",
"hex": "0x7ec2ff20796a08922e11fd828e3871a6aa9a80e6495e30cd41be24b7e3795300"
},
"deadline": 1690902198,
"witness": {
"info": {
"reactor": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4",
"swapper": "0x67d615D6bccAA1562B1cca9786384b4840597ecD",
"nonce": {
"type": "BigNumber",
"hex": "0x7ec2ff20796a08922e11fd828e3871a6aa9a80e6495e30cd41be24b7e3795300"
},
"deadline": 1690902198,
"additionalValidationContract": "0x0000000000000000000000000000000000000000",
"additionalValidationData": "0x"
},
"decayStartTime": 1690902126,
"decayEndTime": 1690902186,
"exclusiveFiller": "0x0000000000000000000000000000000000000000",
"exclusivityOverrideBps": {
"type": "BigNumber",
"hex": "0x00"
},
"inputToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"inputStartAmount": {
"type": "BigNumber",
"hex": "0x11e1a300"
},
"inputEndAmount": {
"type": "BigNumber",
"hex": "0x11e1a300"
},
"outputs": [
{
"token": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
"startAmount": {
"type": "BigNumber",
"hex": "0x0fb7e15027ad3e025e"
},
"endAmount": {
"type": "BigNumber",
"hex": "0x0e7a33be508bb395a2"
},
"recipient": "0x67d615D6bccAA1562B1cca9786384b4840597ecD"
}
]
}
}
}
},
"requestId": "2d16f993-6429-4755-ba50-1383789459dc",
"allQuotes": [
{
"routing": "DUTCH_LIMIT",
"quote": {
"orderInfo": {
"chainId": 1,
"permit2Address": "0x000000000022d473030f116ddee9f6b43ac78ba3",
"reactor": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4",
"swapper": "0x67d615D6bccAA1562B1cca9786384b4840597ecD",
"nonce": "57335948072881703373319552024074512292695687510330025934414357004397546394368",
"deadline": 1690902198,
"additionalValidationContract": "0x0000000000000000000000000000000000000000",
"additionalValidationData": "0x",
"decayStartTime": 1690902126,
"decayEndTime": 1690902186,
"exclusiveFiller": "0x0000000000000000000000000000000000000000",
"exclusivityOverrideBps": "0",
"input": {
"token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"startAmount": "300000000",
"endAmount": "300000000"
},
"outputs": [
{
"token": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
"startAmount": "289951120815684452958",
"endAmount": "267060007981523637666",
"recipient": "0x67d615D6bccAA1562B1cca9786384b4840597ecD"
}
]
},
"encodedOrder": "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000064c91e6e0000000000000000000000000000000000000000000000000000000064c91eaa00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000011e1a3000000000000000000000000000000000000000000000000000000000011e1a30000000000000000000000000000000000000000000000000000000000000002000000000000000000000000006000da47483062a0d734ba3dc7576ce6a0b645c400000000000000000000000067d615d6bccaa1562b1cca9786384b4840597ecd7ec2ff20796a08922e11fd828e3871a6aa9a80e6495e30cd41be24b7e37953000000000000000000000000000000000000000000000000000000000064c91eb6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000fb7e15027ad3e025e00000000000000000000000000000000000000000000000e7a33be508bb395a200000000000000000000000067d615d6bccaa1562b1cca9786384b4840597ecd",
"quoteId": "f9f47cd7-a62c-4622-9ac7-51d0e662245a",
"requestId": "2d16f993-6429-4755-ba50-1383789459dc",
"auctionPeriodSecs": 60,
"startTimeBufferSecs": 30,
"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": "0x11e1a300"
}
},
"spender": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4",
"nonce": {
"type": "BigNumber",
"hex": "0x7ec2ff20796a08922e11fd828e3871a6aa9a80e6495e30cd41be24b7e3795300"
},
"deadline": 1690902198,
"witness": {
"info": {
"reactor": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4",
"swapper": "0x67d615D6bccAA1562B1cca9786384b4840597ecD",
"nonce": {
"type": "BigNumber",
"hex": "0x7ec2ff20796a08922e11fd828e3871a6aa9a80e6495e30cd41be24b7e3795300"
},
"deadline": 1690902198,
"additionalValidationContract": "0x0000000000000000000000000000000000000000",
"additionalValidationData": "0x"
},
"decayStartTime": 1690902126,
"decayEndTime": 1690902186,
"exclusiveFiller": "0x0000000000000000000000000000000000000000",
"exclusivityOverrideBps": {
"type": "BigNumber",
"hex": "0x00"
},
"inputToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"inputStartAmount": {
"type": "BigNumber",
"hex": "0x11e1a300"
},
"inputEndAmount": {
"type": "BigNumber",
"hex": "0x11e1a300"
},
"outputs": [
{
"token": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
"startAmount": {
"type": "BigNumber",
"hex": "0x0fb7e15027ad3e025e"
},
"endAmount": {
"type": "BigNumber",
"hex": "0x0e7a33be508bb395a2"
},
"recipient": "0x67d615D6bccAA1562B1cca9786384b4840597ecD"
}
]
}
}
}
}
},
{
"routing": "CLASSIC",
"quote": {
"blockNumber": "17820918",
"amount": "300000000",
"amountDecimals": "300",
"quote": "299952256425393549464",
"quoteDecimals": "299.952256425393549464",
"quoteGasAdjusted": "289922128602824170541",
"quoteGasAdjustedDecimals": "289.922128602824170541",
"gasUseEstimateQuote": "10030127822569378922",
"gasUseEstimateQuoteDecimals": "10.030127822569378922",
"gasUseEstimate": "128000",
"gasUseEstimateUSD": "10.031724",
"simulationStatus": "UNATTEMPTED",
"simulationError": false,
"gasPriceWei": "42803167855",
"route": [
[
{
"type": "v3-pool",
"address": "0x5777d92f208679DB4b9778590Fa3CAB3aC9e2168",
"tokenIn": {
"chainId": 1,
"decimals": "6",
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"symbol": "USDC"
},
"tokenOut": {
"chainId": 1,
"decimals": "18",
"address": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
"symbol": "DAI"
},
"fee": "100",
"liquidity": "534676532046235168447130",
"sqrtRatioX96": "79230505815006815109584",
"tickCurrent": "-276324",
"amountIn": "300000000",
"amountOut": "299952256425393549464"
}
]
],
"routeString": "[V3] 100.00% = USDC -- 0.01% [0x5777d92f208679DB4b9778590Fa3CAB3aC9e2168] --> DAI",
"quoteId": "1dd3bd14-780e-41c6-88e1-30a763f97482",
"requestId": "2d16f993-6429-4755-ba50-1383789459dc",
"tradeType": "EXACT_INPUT",
"slippage": 0.5
}
}
]
}

View File

@ -1,493 +0,0 @@
{
"routing": "DUTCH_LIMIT",
"quote": {
"orderInfo": {
"chainId": 1,
"permit2Address": "0x000000000022d473030f116ddee9f6b43ac78ba3",
"reactor": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4",
"swapper": "0x0000000000000000000000000000000000000000",
"nonce": "1993350209834725680308575292465150260730647098062962750049345504775310970881",
"deadline": 1691176812,
"additionalValidationContract": "0x0000000000000000000000000000000000000000",
"additionalValidationData": "0x",
"decayStartTime": 1691176740,
"decayEndTime": 1691176800,
"exclusiveFiller": "0x165D98de005d2818176B99B1A93b9325dBE58181",
"exclusivityOverrideBps": "100",
"input": {
"token": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"startAmount": "1000000000000000000",
"endAmount": "1000000000000000000"
},
"outputs": [
{
"token": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
"startAmount": "929502510517534478575",
"endAmount": "919795986077127665276",
"recipient": "0x0000000000000000000000000000000000000000"
}
]
},
"encodedOrder": "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000064cd4f240000000000000000000000000000000000000000000000000000000064cd4f60000000000000000000000000165d98de005d2818176b99b1a93b9325dbe581810000000000000000000000000000000000000000000000000000000000000064000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000006000da47483062a0d734ba3dc7576ce6a0b645c400000000000000000000000000000000000000000000000000000000000000000468323c9682990e3dc0646f899b437e62fbfb52a63cc8de721280222d8090010000000000000000000000000000000000000000000000000000000064cd4f6c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000092d6c1e31e14520e676a687f0a93788b716beff500000000000000000000000000000000000000000000003263704899af6e50ef000000000000000000000000000000000000000000000031dcbbc80c9555e67c0000000000000000000000000000000000000000000000000000000000000000",
"quoteId": "09ce28b7-1ddf-4317-a28d-d21092be9f84",
"requestId": "f00535d4-461a-4363-afbe-7a5ab7061cd1",
"auctionPeriodSecs": 60,
"startTimeBufferSecs": 30,
"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": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"amount": {
"type": "BigNumber",
"hex": "0x0de0b6b3a7640000"
}
},
"spender": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4",
"nonce": {
"type": "BigNumber",
"hex": "0x0468323c9682990e3dc0646f899b437e62fbfb52a63cc8de721280222d809001"
},
"deadline": 1691176812,
"witness": {
"info": {
"reactor": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4",
"swapper": "0x0000000000000000000000000000000000000000",
"nonce": {
"type": "BigNumber",
"hex": "0x0468323c9682990e3dc0646f899b437e62fbfb52a63cc8de721280222d809001"
},
"deadline": 1691176812,
"additionalValidationContract": "0x0000000000000000000000000000000000000000",
"additionalValidationData": "0x"
},
"decayStartTime": 1691176740,
"decayEndTime": 1691176800,
"exclusiveFiller": "0x165D98de005d2818176B99B1A93b9325dBE58181",
"exclusivityOverrideBps": {
"type": "BigNumber",
"hex": "0x64"
},
"inputToken": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"inputStartAmount": {
"type": "BigNumber",
"hex": "0x0de0b6b3a7640000"
},
"inputEndAmount": {
"type": "BigNumber",
"hex": "0x0de0b6b3a7640000"
},
"outputs": [
{
"token": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
"startAmount": {
"type": "BigNumber",
"hex": "0x3263704899af6e50ef"
},
"endAmount": {
"type": "BigNumber",
"hex": "0x31dcbbc80c9555e67c"
},
"recipient": "0x0000000000000000000000000000000000000000"
}
]
}
}
}
},
"requestId": "f00535d4-461a-4363-afbe-7a5ab7061cd1",
"allQuotes": [
{
"routing": "DUTCH_LIMIT",
"quote": {
"orderInfo": {
"chainId": 1,
"permit2Address": "0x000000000022d473030f116ddee9f6b43ac78ba3",
"reactor": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4",
"swapper": "0x0000000000000000000000000000000000000000",
"nonce": "1993350209834725680308575292465150260730647098062962750049345504775310970881",
"deadline": 1691176812,
"additionalValidationContract": "0x0000000000000000000000000000000000000000",
"additionalValidationData": "0x",
"decayStartTime": 1691176740,
"decayEndTime": 1691176800,
"exclusiveFiller": "0x165D98de005d2818176B99B1A93b9325dBE58181",
"exclusivityOverrideBps": "100",
"input": {
"token": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"startAmount": "1000000000000000000",
"endAmount": "1000000000000000000"
},
"outputs": [
{
"token": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
"startAmount": "929502510517534478575",
"endAmount": "919795986077127665276",
"recipient": "0x0000000000000000000000000000000000000000"
}
]
},
"encodedOrder": "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000064cd4f240000000000000000000000000000000000000000000000000000000064cd4f60000000000000000000000000165d98de005d2818176b99b1a93b9325dbe581810000000000000000000000000000000000000000000000000000000000000064000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000006000da47483062a0d734ba3dc7576ce6a0b645c400000000000000000000000000000000000000000000000000000000000000000468323c9682990e3dc0646f899b437e62fbfb52a63cc8de721280222d8090010000000000000000000000000000000000000000000000000000000064cd4f6c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000092d6c1e31e14520e676a687f0a93788b716beff500000000000000000000000000000000000000000000003263704899af6e50ef000000000000000000000000000000000000000000000031dcbbc80c9555e67c0000000000000000000000000000000000000000000000000000000000000000",
"quoteId": "09ce28b7-1ddf-4317-a28d-d21092be9f84",
"requestId": "f00535d4-461a-4363-afbe-7a5ab7061cd1",
"auctionPeriodSecs": 60,
"startTimeBufferSecs": 30,
"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": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"amount": {
"type": "BigNumber",
"hex": "0x0de0b6b3a7640000"
}
},
"spender": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4",
"nonce": {
"type": "BigNumber",
"hex": "0x0468323c9682990e3dc0646f899b437e62fbfb52a63cc8de721280222d809001"
},
"deadline": 1691176812,
"witness": {
"info": {
"reactor": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4",
"swapper": "0x0000000000000000000000000000000000000000",
"nonce": {
"type": "BigNumber",
"hex": "0x0468323c9682990e3dc0646f899b437e62fbfb52a63cc8de721280222d809001"
},
"deadline": 1691176812,
"additionalValidationContract": "0x0000000000000000000000000000000000000000",
"additionalValidationData": "0x"
},
"decayStartTime": 1691176740,
"decayEndTime": 1691176800,
"exclusiveFiller": "0x165D98de005d2818176B99B1A93b9325dBE58181",
"exclusivityOverrideBps": {
"type": "BigNumber",
"hex": "0x64"
},
"inputToken": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"inputStartAmount": {
"type": "BigNumber",
"hex": "0x0de0b6b3a7640000"
},
"inputEndAmount": {
"type": "BigNumber",
"hex": "0x0de0b6b3a7640000"
},
"outputs": [
{
"token": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
"startAmount": {
"type": "BigNumber",
"hex": "0x3263704899af6e50ef"
},
"endAmount": {
"type": "BigNumber",
"hex": "0x31dcbbc80c9555e67c"
},
"recipient": "0x0000000000000000000000000000000000000000"
}
]
}
}
}
}
},
{
"routing": "CLASSIC",
"quote": {
"blockNumber": "17843654",
"amount": "1000000000000000000",
"amountDecimals": "1",
"quote": "931181529570145926787",
"quoteDecimals": "931.181529570145926787",
"quoteGasAdjusted": "929033336026294051828",
"quoteGasAdjustedDecimals": "929.033336026294051828",
"gasUseEstimateQuote": "2148193543851874958",
"gasUseEstimateQuoteDecimals": "2.148193543851874958",
"gasUseEstimate": "128000",
"gasUseEstimateUSD": "4.174934",
"simulationStatus": "UNATTEMPTED",
"simulationError": false,
"gasPriceWei": "17811260539",
"route": [
[
{
"type": "v3-pool",
"address": "0xD8de6af55F618a7Bc69835D55DDC6582220c36c0",
"tokenIn": {
"chainId": 1,
"decimals": "18",
"address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"symbol": "WETH"
},
"tokenOut": {
"chainId": 1,
"decimals": "18",
"address": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
"symbol": "DAI"
},
"fee": "3000",
"liquidity": "62287359628325896425115",
"sqrtRatioX96": "2591813593283507889384697884",
"tickCurrent": "-68403",
"amountIn": "1000000000000000000",
"amountOut": "931181529570145926787"
}
]
],
"routeString": "[V3] 100.00% = WETH -- 0.3% [0xD8de6af55F618a7Bc69835D55DDC6582220c36c0] --> DAI",
"quoteId": "414e5f1c-120a-4e35-9760-c54d4b09e91d",
"requestId": "f00535d4-461a-4363-afbe-7a5ab7061cd1",
"tradeType": "EXACT_INPUT",
"slippage": 0.5
}
}
]
}

View File

@ -3,8 +3,8 @@ import 'cypress-hardhat/lib/browser'
import { Eip1193Bridge } from '@ethersproject/experimental/lib/eip1193-bridge'
import { FeatureFlag } from '../../src/featureFlags'
import { initialState, UserState } from '../../src/state/user/reducer'
import { CONNECTED_WALLET_USER_STATE, setInitialUserState } from '../utils/user-state'
import { UserState } from '../../src/state/user/reducer'
import { CONNECTED_WALLET_USER_STATE } from '../utils/user-state'
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
@ -24,7 +24,7 @@ declare global {
}
interface VisitOptions {
serviceWorker?: true
featureFlags?: Array<{ name: FeatureFlag; value: boolean }>
featureFlags?: Array<FeatureFlag>
/**
* Initial user state.
* @default {@type import('../utils/user-state').CONNECTED_WALLET_USER_STATE}
@ -41,28 +41,31 @@ Cypress.Commands.overwrite(
(original, url: string | Partial<Cypress.VisitOptions>, options?: Partial<Cypress.VisitOptions>) => {
if (typeof url !== 'string') throw new Error('Invalid arguments. The first argument to cy.visit must be the path.')
// Add a hash in the URL if it is not present (to use hash-based routing correctly with queryParams).
const hashUrl = url.startsWith('/') && url.length > 2 && !url.startsWith('/#') ? `/#${url}` : url
return cy
.intercept('/service-worker.js', options?.serviceWorker ? undefined : { statusCode: 404 })
.provider()
.then((provider) =>
original({
...options,
url,
url: hashUrl,
onBeforeLoad(win) {
options?.onBeforeLoad?.(win)
setInitialUserState(win, {
...initialState,
...CONNECTED_WALLET_USER_STATE,
...(options?.userState ?? {}),
})
// We want to test from a clean state, so we clear the local storage (which clears redux).
win.localStorage.clear()
// Set initial user state.
win.localStorage.setItem(
'redux_localstorage_simple_user', // storage key for the user reducer using 'redux-localstorage-simple'
JSON.stringify({ ...CONNECTED_WALLET_USER_STATE, ...(options?.userState ?? {}) })
)
// Set feature flags, if configured.
if (options?.featureFlags) {
const featureFlags = options.featureFlags.reduce(
(flags, flag) => ({ ...flags, [flag.name]: flag.value ? 'enabled' : 'control' }),
{}
)
const featureFlags = options.featureFlags.reduce((flags, flag) => ({ ...flags, [flag]: 'enabled' }), {})
win.localStorage.setItem('featureFlags', JSON.stringify(featureFlags))
}
@ -74,14 +77,18 @@ Cypress.Commands.overwrite(
}
)
Cypress.Commands.add('waitForAmplitudeEvent', (eventName) => {
Cypress.Commands.add('waitForAmplitudeEvent', (eventName, timeout = 5000 /* 5s */) => {
const startTime = new Date().getTime()
function checkRequest() {
return cy.wait('@amplitude').then((interception) => {
return cy.wait('@amplitude', { timeout }).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()
}

View File

@ -9,9 +9,8 @@ beforeEach(() => {
req.headers['origin'] = 'https://app.uniswap.org'
})
// Network RPCs are disabled for cypress tests - calls should be routed through the connected wallet instead.
// Infura is 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)
@ -27,16 +26,10 @@ 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 })

View File

@ -5,7 +5,7 @@
"incremental": true,
"isolatedModules": false,
"noImplicitAny": false,
"target": "ES6",
"target": "ES5",
"tsBuildInfoFile": "../node_modules/.cache/tsbuildinfo/cypress", // avoid clobbering the build tsbuildinfo
"types": ["cypress", "node"],
},

View File

@ -1,42 +1,6 @@
import { connectionMetaKey } from '../../src/connection/meta'
import { ConnectionType } from '../../src/connection/types'
import { UserState } from '../../src/state/user/reducer'
export const CONNECTED_WALLET_USER_STATE: Partial<UserState> = { selectedWallet: ConnectionType.INJECTED }
export const DISCONNECTED_WALLET_USER_STATE: Partial<UserState> = { selectedWallet: undefined }
/**
* This sets the initial value of the "user" slice in IndexedDB.
* Other persisted slices are not set, so they will be filled with their respective initial values
* when the app runs.
*/
export function setInitialUserState(win: Cypress.AUTWindow, state: UserState) {
// Selected wallet should also be reflected in localStorage, so that eager connections work.
if (state.selectedWallet) {
win.localStorage.setItem(
connectionMetaKey,
JSON.stringify({
type: state.selectedWallet,
})
)
}
win.indexedDB.deleteDatabase('redux')
const dbRequest = win.indexedDB.open('redux')
dbRequest.onsuccess = function () {
const db = dbRequest.result
const transaction = db.transaction('keyvaluepairs', 'readwrite')
const store = transaction.objectStore('keyvaluepairs')
store.put(
{
user: state,
},
'persist:interface'
)
}
dbRequest.onupgradeneeded = function () {
const db = dbRequest.result
db.createObjectStore('keyvaluepairs')
}
}

View File

@ -18,9 +18,9 @@ Currently, there are 2 types of cloudflare functions developed
## Testing
Testing is done utilizing a custom jest environment as well as Cloudflare's local tester: `wrangler`. Wrangler enables testing locally by running a proxy to wrap `localhost`. Tests run against a proxy server, so you'll need to start it before running tests:
- Manually run `yarn start:cloud` to setup wrangler on `localhost:3000`
- Run unit tests with `yarn test:cloud`
Testing is done utilizing a custom jest environment as well as Cloudflare's local tester: `wrangler`. Wrangler enables testing locally by running a proxy to wrap `localhost`. Testing can be done the following ways.
- Manually by running `yarn start:cloud` to setup wrangler on `localhost:3000`
- Automated tests by running `yarn test:cloud` to setup both a jest and wrangler environment and automatically test features
## Deployment

View File

@ -11,7 +11,7 @@ export const onRequest: PagesFunction = async ({ request, next }) => {
}
const res = next()
try {
return new HTMLRewriter().on('head', new MetaTagInjector(data, request)).transform(await res)
return new HTMLRewriter().on('head', new MetaTagInjector(data)).transform(await res)
} catch (e) {
return res
}

View File

@ -2,7 +2,6 @@
import { ImageResponse } from '@vercel/og'
import React from 'react'
import { blocklistedCollections } from '../../../../../src/nft/utils/blocklist'
import { WATERMARK_URL } from '../../../../constants'
import getAsset from '../../../../utils/getAsset'
import getFont from '../../../../utils/getFont'
@ -16,10 +15,6 @@ export const onRequest: PagesFunction = async ({ params, request }) => {
const tokenId = index[1]?.toString()
const cacheUrl = origin + '/nfts/asset/' + collectionAddress + '/' + tokenId
if (blocklistedCollections.includes(collectionAddress)) {
return new Response('Collection unsupported.', { status: 404 })
}
const data = await getRequest(
cacheUrl,
() => getAsset(collectionAddress, tokenId, cacheUrl),
@ -30,7 +25,7 @@ export const onRequest: PagesFunction = async ({ params, request }) => {
return new Response('Asset not found.', { status: 404 })
}
const fontData = await getFont(origin)
const fontData = await getFont()
return new ImageResponse(
(

View File

@ -10,7 +10,7 @@ test.each(assetImageUrl)('assetImageUrl', async (url) => {
})
const invalidAssetImageUrl = [
'http://127.0.0.1:3000/api/image/nfts/asset/0xed5af388653567af2f388e6224dc7c4b3241c544/10001',
'http://127.0.0.1:3000/api/image/nfts/asset/0xed5af388653567af2f388e6224dc7c4b3241c544/100000',
'http://127.0.0.1:3000/api/image/nfts/asset/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d/44700',
]
@ -18,12 +18,3 @@ test.each(invalidAssetImageUrl)('invalidAssetImageUrl', async (url) => {
const response = await fetch(new Request(url))
expect(response.status).toBe(404)
})
const blockedAssetImageUrl = [
'http://127.0.0.1:3000/api/image/nfts/asset/0xd4d871419714b778ebec2e22c7c53572b573706e/276',
]
test.each(blockedAssetImageUrl)('blockedAssetImageUrl', async (url) => {
const response = await fetch(new Request(url))
expect(response.status).toBe(404)
})

View File

@ -2,10 +2,9 @@
import { ImageResponse } from '@vercel/og'
import React from 'react'
import { blocklistedCollections } from '../../../../../src/nft/utils/blocklist'
import { getColor } from '../../../../../src/utils/getColor'
import { CHECK_URL, WATERMARK_URL } from '../../../../constants'
import getCollection from '../../../../utils/getCollection'
import getColor from '../../../../utils/getColor'
import getFont from '../../../../utils/getFont'
import { getRequest } from '../../../../utils/getRequest'
@ -16,10 +15,6 @@ export const onRequest: PagesFunction = async ({ params, request }) => {
const collectionAddress = index?.toString()
const cacheUrl = origin + '/nfts/collection/' + collectionAddress
if (blocklistedCollections.includes(collectionAddress)) {
return new Response('Collection unsupported.', { status: 404 })
}
const data = await getRequest(
cacheUrl,
() => getCollection(collectionAddress, cacheUrl),
@ -28,10 +23,10 @@ export const onRequest: PagesFunction = async ({ params, request }) => {
)
if (!data) {
return new Response('Collection not found.', { status: 404 })
return new Response('Asset not found.', { status: 404 })
}
const [fontData, palette] = await Promise.all([getFont(origin), getColor(data.ogImage)])
const [fontData, palette] = await Promise.all([getFont(), getColor(data.ogImage)])
// Split name into words to wrap them since satori does not support inline text wrapping
const words = data.name.split(' ')

View File

@ -1,34 +1,20 @@
import * as matchers from 'jest-extended'
expect.extend(matchers)
const collectionImageUrls = [
const collectionImageUrl = [
'http://127.0.0.1:3000/api/image/nfts/collection/0xed5af388653567af2f388e6224dc7c4b3241c544',
'http://127.0.0.1:3000/api/image/nfts/collection/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d',
'http://127.0.0.1:3000/api/image/nfts/collection/0x49cf6f5d44e70224e2e23fdcdd2c053f30ada28b',
]
test.each([...collectionImageUrls])('collectionImageUrl', async (url) => {
test.each(collectionImageUrl)('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 = [
const invalidCollectionImageUrl = [
'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, ...nonexistentImageUrls])('invalidAssetImageUrl', async (url) => {
test.each(invalidCollectionImageUrl)('invalidAssetImageUrl', async (url) => {
const response = await fetch(new Request(url))
expect(response.status).toBeOneOf([404, 500])
})
const blockedCollectionImageUrls = [
'http://127.0.0.1:3000/api/image/nfts/collection/0xd4d871419714b778ebec2e22c7c53572b573706e',
]
test.each(blockedCollectionImageUrls)('blockedCollectionImageUrl', async (url) => {
const response = await fetch(new Request(url))
expect(response.status).toBeOneOf([404, 500])
expect(response.status).toBe(404)
})

View File

@ -2,8 +2,8 @@
import { ImageResponse } from '@vercel/og'
import React from 'react'
import { getColor } from '../../../../src/utils/getColor'
import { WATERMARK_URL } from '../../../constants'
import getColor from '../../../utils/getColor'
import getFont from '../../../utils/getFont'
import getNetworkLogoUrl from '../../../utils/getNetworkLogoURL'
import { getRequest } from '../../../utils/getRequest'
@ -25,12 +25,12 @@ export const onRequest: PagesFunction = async ({ params, request }) => {
)
if (!data) {
return new Response('Token not found.', { status: 404 })
return new Response('Asset not found.', { status: 404 })
}
const [fontData, palette] = await Promise.all([getFont(origin), getColor(data.ogImage, true)])
const [fontData, palette] = await Promise.all([getFont(), getColor(data.ogImage)])
const networkLogo = getNetworkLogoUrl(networkName.toUpperCase(), origin)
const networkLogo = getNetworkLogoUrl(networkName.toUpperCase())
// Capitalize name such that each word starts with a capital letter
let words = data.name.split(' ')
@ -123,7 +123,7 @@ export const onRequest: PagesFunction = async ({ params, request }) => {
style={{
fontFamily: 'Inter',
fontSize: '72px',
lineHeight: '72px',
lineHeight: '58px',
marginLeft: '-5px',
marginTop: '24px',
}}
@ -145,10 +145,6 @@ export const onRequest: PagesFunction = async ({ params, request }) => {
fontSize: '168px',
lineHeight: '133px',
marginLeft: '-13px',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
width: '100%',
}}
>
{data.symbol}

View File

@ -13,6 +13,7 @@ const invalidTokenImageUrl = [
'http://127.0.0.1:3000/api/image/tokens/ethereum/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb49',
'http://127.0.0.1:3000/api/image/tokens/ethereum',
'http://127.0.0.1:3000/api/image/tokens/ethereun',
'http://127.0.0.1:3000/api/image/tokens/ethereum/0x0',
'http://127.0.0.1:3000/api/image/tokens/potato/?potato=1',
]

View File

@ -1,60 +0,0 @@
import { MetaTagInjector } from './metaTagInjector'
test('should append meta tag to element', () => {
const element = {
append: jest.fn(),
} as unknown as Element
const property = 'property'
const content = 'content'
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 })
injector.element(element)
expect(element.append).toHaveBeenCalledWith(`<meta property="og:title" content="test"/>`, { html: true })
expect(element.append).toHaveBeenCalledWith(`<meta property="og:description" content="testDescription"/>`, {
html: true,
})
expect(element.append).toHaveBeenCalledWith(`<meta property="og:image" content="testImage"/>`, { html: true })
expect(element.append).toHaveBeenCalledWith(`<meta property="og:image:width" content="1200"/>`, { html: true })
expect(element.append).toHaveBeenCalledWith(`<meta property="og:image:height" content="630"/>`, { html: true })
expect(element.append).toHaveBeenCalledWith(`<meta property="og:image:alt" content="test"/>`, { html: true })
expect(element.append).toHaveBeenCalledWith(`<meta property="og:type" content="website"/>`, { html: true })
expect(element.append).toHaveBeenCalledWith(`<meta property="og:url" content="testUrl"/>`, { html: true })
expect(element.append).toHaveBeenCalledWith(`<meta property="twitter:card" content="summary_large_image"/>`, {
html: true,
})
expect(element.append).toHaveBeenCalledWith(`<meta property="twitter:title" content="test"/>`, { html: true })
expect(element.append).toHaveBeenCalledWith(`<meta property="twitter:image" content="testImage"/>`, { html: true })
expect(element.append).toHaveBeenCalledWith(`<meta property="twitter:image:alt" content="test"/>`, { html: true })
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 })
})

View File

@ -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, private request: Request) {}
constructor(private input: MetaTagInjectorInput) {}
append(element: Element, property: string, content: string) {
element.append(`<meta property="${property}" content="${content}"/>`, { html: true })
@ -38,10 +38,5 @@ 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)
}
}
}

View File

@ -1,2 +1,76 @@
export const WATERMARK_URL = 'https://app.uniswap.org/images/324x74_App_Watermark.png'
export const CHECK_URL = 'https://app.uniswap.org/images/54x54_Verified_Check.svg'
export const DEFAULT_COLOR = [35, 43, 43]
export const predefinedTokenColors: { [key: string]: number[] } = {
// old WBTC
'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599/logo.png':
[240, 146, 65],
// new WBTC
'https://assets.coingecko.com/coins/images/7598/large/wrapped_bitcoin_wbtc.png?1548822744': [240, 146, 65],
// DAI
'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0x6B175474E89094C44Da98b954EedeAC495271d0F/logo.png':
[250, 176, 27],
// UNI
'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984/logo.png':
[230, 53, 140],
// BUSD
'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0x4Fabb145d64652a948d72533023f6E7A623C7C53/logo.png':
[239, 186, 9],
// AI-X
'https://s2.coinmarketcap.com/static/img/coins/64x64/26984.png': [41, 161, 241],
// ETH
'https://token-icons.s3.amazonaws.com/eth.png': [73, 112, 213],
// HARRYPOTTERSHIBAINUBITCOIN
'https://assets.coingecko.com/coins/images/30323/large/hpos10i_logo_casino_night-dexview.png?1684117567': [
222, 49, 16,
],
// PEPE
'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0x6982508145454Ce325dDbE47a25d4ec3d2311933/logo.png':
[62, 174, 20],
// Unibot V2
'https://s2.coinmarketcap.com/static/img/coins/64x64/25436.png': [74, 10, 79],
// UNIBOT v1
'https://assets.coingecko.com/coins/images/30462/small/logonoline_%281%29.png?1687510315': [74, 10, 79],
// USDC
'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png':
[0, 102, 217],
// HEX
'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0x2b591e99afE9f32eAA6214f7B7629768c40Eeb39/logo.png':
[249, 63, 140],
// MONG
'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0x1ce270557C1f68Cfb577b856766310Bf8B47FD9C/logo.png':
[169, 109, 255],
// ARB
'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0xB50721BCf8d664c30412Cfbc6cf7a15145234ad1/logo.png':
[41, 161, 241],
// PSYOP
'https://s2.coinmarketcap.com/static/img/coins/64x64/25422.png': [232, 143, 0],
// MATIC
'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0/logo.png':
[169, 109, 255],
// TURBO
'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0xA35923162C49cF95e6BF26623385eb431ad920D3/logo.png':
[189, 110, 41],
// AIDOGE
'https://assets.coingecko.com/coins/images/29852/large/photo_2023-04-18_14-25-28.jpg?1681799160': [41, 161, 241],
// SIMPSON
'https://assets.coingecko.com/coins/images/30243/large/1111.png?1683692033': [232, 143, 0],
// OX
'https://assets.coingecko.com/coins/images/30604/large/Logo2.png?1685522119': [41, 89, 217],
// ANGLE
'https://assets.coingecko.com/coins/images/19060/large/ANGLE_Token-light.png?1666774221': [255, 85, 85],
// APE
'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0x4d224452801ACEd8B2F0aebE155379bb5D594381/logo.png':
[5, 74, 169],
// GUSD
'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0x056Fd409E1d7A124BD7017459dFEa2F387b6d5Cd/logo.png':
[0, 164, 189],
// OGN
'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0x8207c1FfC5B6804F6024322CcF34F29c3541Ae26/logo.png':
[5, 74, 169],
// RPL
'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0xD33526068D116cE69F19A9ee46F0bd304F21A51f/logo.png':
[255, 123, 79],
}

19
functions/global-setup.ts Normal file
View File

@ -0,0 +1,19 @@
import { setup } from 'jest-dev-server'
module.exports = async function globalSetup() {
globalThis.servers = await setup({
command: `yarn start:cloud`,
port: 3000,
launchTimeout: 80000,
})
// Wait for wrangler to return a request before running tests
for (let i = 0; i < 3; i++) {
const res = await fetch(new Request('http://127.0.0.1:3000/tokens/ethereum/NATIVE'))
if (res.ok) {
return
}
// Set timeout to make sure the server isn't flooded with requests if wrangler is not running
await new Promise((resolve) => setTimeout(resolve, 500 * (i + 1)))
}
throw new Error('Failed to start server')
}

View File

@ -0,0 +1,5 @@
import { teardown } from 'jest-dev-server'
module.exports = async function globalTeardown() {
await teardown(globalThis.servers)
}

6
functions/global.d.ts vendored Normal file
View File

@ -0,0 +1,6 @@
import { setup } from 'jest-dev-server'
declare global {
// eslint-disable-next-line no-var
var servers: Awaited<ReturnType<typeof setup>>
}

View File

@ -1,5 +1,6 @@
{
"setupFilesAfterEnv": ["<rootDir>/setupAfterEnv.ts"],
"globalSetup": "<rootDir>/global-setup.ts",
"globalTeardown": "<rootDir>/global-teardown.ts",
"preset": "ts-jest",
"transform": {
"'^.+\\.(ts|tsx)?$'": "ts-jest",

View File

@ -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, () => getAsset(collectionAddress, tokenId, request.url))
return getMetadataRequest(res, request.url, () => getAsset(collectionAddress, tokenId, request.url))
} catch (e) {
return res
}

View File

@ -17,7 +17,7 @@ exports[`should inject metadata for valid assets 1`] = `
<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 name="theme-color" content="#FC72FF" />
<meta
http-equiv="Content-Security-Policy"
@ -37,46 +37,31 @@ exports[`should inject metadata for valid assets 1`] = `
-->
<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/Inter-roman.var.woff2" as="font" type="font/woff2" 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>
* {
font-family: 'Basel', sans-serif;
font-family: 'Inter', sans-serif;
box-sizing: border-box;
}
/**
Explicitly load Basel var from public/ so it does not block LCP's critical path.
Explicitly load Inter var from public/ so it does not block LCP's critical path.
*/
@font-face {
font-family: 'Basel';
font-weight: 535;
font-family: 'Inter custom';
font-weight: 100 900;
font-style: normal;
font-display: block;
src:
url('/fonts/Basel-Medium.woff2') format('woff2'),
url('/fonts/Basel-Medium.woff') format('woff');
}
@font-face {
font-family: 'Basel';
font-weight: 485;
font-style: normal;
font-display: block;
src:
url('/fonts/Basel-Book.woff') format('woff2'),
url('/fonts/Basel-Book.woff') format('woff');
font-named-instance: 'Regular';
src: url(/fonts/Inter-roman.var.woff2) format('woff2 supports variations(gvar)'),
url(/fonts/Inter-roman.var.woff2) format('woff2-variations'),
url(/fonts/Inter-roman.var.woff2) format('woff2');
}
@supports (font-variation-settings: normal) {
* {
font-family: 'Basel', sans-serif;
font-family: 'Inter custom', sans-serif;
}
}
@ -92,11 +77,9 @@ exports[`should inject metadata for valid assets 1`] = `
html {
font-size: 16px;
font-weight: 485;
font-variant: none;
font-smooth: always;
text-rendering: optimizeLegibility !important;
-webkit-font-smoothing: antialiased !important;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
@ -122,13 +105,13 @@ exports[`should inject metadata for valid assets 1`] = `
@media (prefers-color-scheme: dark) {
html {
background: linear-gradient(rgb(19, 19, 19) 0%, rgb(19, 19, 19) 100%);
background: linear-gradient(180deg, #202738 0%, #070816 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);
background: radial-gradient(100% 100% at 50% 0%, rgba(255, 184, 226, 0.51) 0%, rgba(255, 255, 255, 0) 100%), #FFFFFF
}
}
</style>
@ -165,7 +148,7 @@ exports[`should inject metadata for valid assets 2`] = `
<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 name="theme-color" content="#FC72FF" />
<meta
http-equiv="Content-Security-Policy"
@ -185,46 +168,31 @@ exports[`should inject metadata for valid assets 2`] = `
-->
<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/Inter-roman.var.woff2" as="font" type="font/woff2" 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>
* {
font-family: 'Basel', sans-serif;
font-family: 'Inter', sans-serif;
box-sizing: border-box;
}
/**
Explicitly load Basel var from public/ so it does not block LCP's critical path.
Explicitly load Inter var from public/ so it does not block LCP's critical path.
*/
@font-face {
font-family: 'Basel';
font-weight: 535;
font-family: 'Inter custom';
font-weight: 100 900;
font-style: normal;
font-display: block;
src:
url('/fonts/Basel-Medium.woff2') format('woff2'),
url('/fonts/Basel-Medium.woff') format('woff');
}
@font-face {
font-family: 'Basel';
font-weight: 485;
font-style: normal;
font-display: block;
src:
url('/fonts/Basel-Book.woff') format('woff2'),
url('/fonts/Basel-Book.woff') format('woff');
font-named-instance: 'Regular';
src: url(/fonts/Inter-roman.var.woff2) format('woff2 supports variations(gvar)'),
url(/fonts/Inter-roman.var.woff2) format('woff2-variations'),
url(/fonts/Inter-roman.var.woff2) format('woff2');
}
@supports (font-variation-settings: normal) {
* {
font-family: 'Basel', sans-serif;
font-family: 'Inter custom', sans-serif;
}
}
@ -240,11 +208,9 @@ exports[`should inject metadata for valid assets 2`] = `
html {
font-size: 16px;
font-weight: 485;
font-variant: none;
font-smooth: always;
text-rendering: optimizeLegibility !important;
-webkit-font-smoothing: antialiased !important;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
@ -270,13 +236,13 @@ exports[`should inject metadata for valid assets 2`] = `
@media (prefers-color-scheme: dark) {
html {
background: linear-gradient(rgb(19, 19, 19) 0%, rgb(19, 19, 19) 100%);
background: linear-gradient(180deg, #202738 0%, #070816 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);
background: radial-gradient(100% 100% at 50% 0%, rgba(255, 184, 226, 0.51) 0%, rgba(255, 255, 255, 0) 100%), #FFFFFF
}
}
</style>
@ -313,7 +279,7 @@ exports[`should inject metadata for valid assets 3`] = `
<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 name="theme-color" content="#FC72FF" />
<meta
http-equiv="Content-Security-Policy"
@ -333,46 +299,31 @@ exports[`should inject metadata for valid assets 3`] = `
-->
<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/Inter-roman.var.woff2" as="font" type="font/woff2" 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>
* {
font-family: 'Basel', sans-serif;
font-family: 'Inter', sans-serif;
box-sizing: border-box;
}
/**
Explicitly load Basel var from public/ so it does not block LCP's critical path.
Explicitly load Inter var from public/ so it does not block LCP's critical path.
*/
@font-face {
font-family: 'Basel';
font-weight: 535;
font-family: 'Inter custom';
font-weight: 100 900;
font-style: normal;
font-display: block;
src:
url('/fonts/Basel-Medium.woff2') format('woff2'),
url('/fonts/Basel-Medium.woff') format('woff');
}
@font-face {
font-family: 'Basel';
font-weight: 485;
font-style: normal;
font-display: block;
src:
url('/fonts/Basel-Book.woff') format('woff2'),
url('/fonts/Basel-Book.woff') format('woff');
font-named-instance: 'Regular';
src: url(/fonts/Inter-roman.var.woff2) format('woff2 supports variations(gvar)'),
url(/fonts/Inter-roman.var.woff2) format('woff2-variations'),
url(/fonts/Inter-roman.var.woff2) format('woff2');
}
@supports (font-variation-settings: normal) {
* {
font-family: 'Basel', sans-serif;
font-family: 'Inter custom', sans-serif;
}
}
@ -388,11 +339,9 @@ exports[`should inject metadata for valid assets 3`] = `
html {
font-size: 16px;
font-weight: 485;
font-variant: none;
font-smooth: always;
text-rendering: optimizeLegibility !important;
-webkit-font-smoothing: antialiased !important;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
@ -418,13 +367,13 @@ exports[`should inject metadata for valid assets 3`] = `
@media (prefers-color-scheme: dark) {
html {
background: linear-gradient(rgb(19, 19, 19) 0%, rgb(19, 19, 19) 100%);
background: linear-gradient(180deg, #202738 0%, #070816 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);
background: radial-gradient(100% 100% at 50% 0%, rgba(255, 184, 226, 0.51) 0%, rgba(255, 255, 255, 0) 100%), #FFFFFF
}
}
</style>

View File

@ -7,7 +7,7 @@ export const onRequest: PagesFunction = async ({ params, request, next }) => {
try {
const { index } = params
const collectionAddress = index?.toString()
return getMetadataRequest(res, request, () => getCollection(collectionAddress, request.url))
return getMetadataRequest(res, request.url, () => getCollection(collectionAddress, request.url))
} catch (e) {
return res
}

View File

@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should inject metadata for collections 1`] = `
exports[`should inject metadata for valid collections 1`] = `
"<!DOCTYPE html>
<html translate="no">
<head>
@ -17,7 +17,7 @@ exports[`should inject metadata for collections 1`] = `
<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 name="theme-color" content="#FC72FF" />
<meta
http-equiv="Content-Security-Policy"
@ -37,46 +37,31 @@ exports[`should inject metadata for collections 1`] = `
-->
<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/Inter-roman.var.woff2" as="font" type="font/woff2" 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>
* {
font-family: 'Basel', sans-serif;
font-family: 'Inter', sans-serif;
box-sizing: border-box;
}
/**
Explicitly load Basel var from public/ so it does not block LCP's critical path.
Explicitly load Inter var from public/ so it does not block LCP's critical path.
*/
@font-face {
font-family: 'Basel';
font-weight: 535;
font-family: 'Inter custom';
font-weight: 100 900;
font-style: normal;
font-display: block;
src:
url('/fonts/Basel-Medium.woff2') format('woff2'),
url('/fonts/Basel-Medium.woff') format('woff');
}
@font-face {
font-family: 'Basel';
font-weight: 485;
font-style: normal;
font-display: block;
src:
url('/fonts/Basel-Book.woff') format('woff2'),
url('/fonts/Basel-Book.woff') format('woff');
font-named-instance: 'Regular';
src: url(/fonts/Inter-roman.var.woff2) format('woff2 supports variations(gvar)'),
url(/fonts/Inter-roman.var.woff2) format('woff2-variations'),
url(/fonts/Inter-roman.var.woff2) format('woff2');
}
@supports (font-variation-settings: normal) {
* {
font-family: 'Basel', sans-serif;
font-family: 'Inter custom', sans-serif;
}
}
@ -92,11 +77,9 @@ exports[`should inject metadata for collections 1`] = `
html {
font-size: 16px;
font-weight: 485;
font-variant: none;
font-smooth: always;
text-rendering: optimizeLegibility !important;
-webkit-font-smoothing: antialiased !important;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
@ -122,13 +105,13 @@ exports[`should inject metadata for collections 1`] = `
@media (prefers-color-scheme: dark) {
html {
background: linear-gradient(rgb(19, 19, 19) 0%, rgb(19, 19, 19) 100%);
background: linear-gradient(180deg, #202738 0%, #070816 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);
background: radial-gradient(100% 100% at 50% 0%, rgba(255, 184, 226, 0.51) 0%, rgba(255, 255, 255, 0) 100%), #FFFFFF
}
}
</style>
@ -148,7 +131,7 @@ exports[`should inject metadata for collections 1`] = `
"
`;
exports[`should inject metadata for collections 2`] = `
exports[`should inject metadata for valid collections 2`] = `
"<!DOCTYPE html>
<html translate="no">
<head>
@ -165,7 +148,7 @@ exports[`should inject metadata for collections 2`] = `
<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 name="theme-color" content="#FC72FF" />
<meta
http-equiv="Content-Security-Policy"
@ -185,46 +168,31 @@ exports[`should inject metadata for collections 2`] = `
-->
<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/Inter-roman.var.woff2" as="font" type="font/woff2" 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>
* {
font-family: 'Basel', sans-serif;
font-family: 'Inter', sans-serif;
box-sizing: border-box;
}
/**
Explicitly load Basel var from public/ so it does not block LCP's critical path.
Explicitly load Inter var from public/ so it does not block LCP's critical path.
*/
@font-face {
font-family: 'Basel';
font-weight: 535;
font-family: 'Inter custom';
font-weight: 100 900;
font-style: normal;
font-display: block;
src:
url('/fonts/Basel-Medium.woff2') format('woff2'),
url('/fonts/Basel-Medium.woff') format('woff');
}
@font-face {
font-family: 'Basel';
font-weight: 485;
font-style: normal;
font-display: block;
src:
url('/fonts/Basel-Book.woff') format('woff2'),
url('/fonts/Basel-Book.woff') format('woff');
font-named-instance: 'Regular';
src: url(/fonts/Inter-roman.var.woff2) format('woff2 supports variations(gvar)'),
url(/fonts/Inter-roman.var.woff2) format('woff2-variations'),
url(/fonts/Inter-roman.var.woff2) format('woff2');
}
@supports (font-variation-settings: normal) {
* {
font-family: 'Basel', sans-serif;
font-family: 'Inter custom', sans-serif;
}
}
@ -240,11 +208,9 @@ exports[`should inject metadata for collections 2`] = `
html {
font-size: 16px;
font-weight: 485;
font-variant: none;
font-smooth: always;
text-rendering: optimizeLegibility !important;
-webkit-font-smoothing: antialiased !important;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
@ -270,13 +236,13 @@ exports[`should inject metadata for collections 2`] = `
@media (prefers-color-scheme: dark) {
html {
background: linear-gradient(rgb(19, 19, 19) 0%, rgb(19, 19, 19) 100%);
background: linear-gradient(180deg, #202738 0%, #070816 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);
background: radial-gradient(100% 100% at 50% 0%, rgba(255, 184, 226, 0.51) 0%, rgba(255, 255, 255, 0) 100%), #FFFFFF
}
}
</style>
@ -296,7 +262,7 @@ exports[`should inject metadata for collections 2`] = `
"
`;
exports[`should inject metadata for collections 3`] = `
exports[`should inject metadata for valid collections 3`] = `
"<!DOCTYPE html>
<html translate="no">
<head>
@ -313,7 +279,7 @@ exports[`should inject metadata for collections 3`] = `
<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 name="theme-color" content="#FC72FF" />
<meta
http-equiv="Content-Security-Policy"
@ -333,46 +299,31 @@ exports[`should inject metadata for collections 3`] = `
-->
<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/Inter-roman.var.woff2" as="font" type="font/woff2" 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>
* {
font-family: 'Basel', sans-serif;
font-family: 'Inter', sans-serif;
box-sizing: border-box;
}
/**
Explicitly load Basel var from public/ so it does not block LCP's critical path.
Explicitly load Inter var from public/ so it does not block LCP's critical path.
*/
@font-face {
font-family: 'Basel';
font-weight: 535;
font-family: 'Inter custom';
font-weight: 100 900;
font-style: normal;
font-display: block;
src:
url('/fonts/Basel-Medium.woff2') format('woff2'),
url('/fonts/Basel-Medium.woff') format('woff');
}
@font-face {
font-family: 'Basel';
font-weight: 485;
font-style: normal;
font-display: block;
src:
url('/fonts/Basel-Book.woff') format('woff2'),
url('/fonts/Basel-Book.woff') format('woff');
font-named-instance: 'Regular';
src: url(/fonts/Inter-roman.var.woff2) format('woff2 supports variations(gvar)'),
url(/fonts/Inter-roman.var.woff2) format('woff2-variations'),
url(/fonts/Inter-roman.var.woff2) format('woff2');
}
@supports (font-variation-settings: normal) {
* {
font-family: 'Basel', sans-serif;
font-family: 'Inter custom', sans-serif;
}
}
@ -388,11 +339,9 @@ exports[`should inject metadata for collections 3`] = `
html {
font-size: 16px;
font-weight: 485;
font-variant: none;
font-smooth: always;
text-rendering: optimizeLegibility !important;
-webkit-font-smoothing: antialiased !important;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
@ -418,13 +367,13 @@ exports[`should inject metadata for collections 3`] = `
@media (prefers-color-scheme: dark) {
html {
background: linear-gradient(rgb(19, 19, 19) 0%, rgb(19, 19, 19) 100%);
background: linear-gradient(180deg, #202738 0%, #070816 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);
background: radial-gradient(100% 100% at 50% 0%, rgba(255, 184, 226, 0.51) 0%, rgba(255, 255, 255, 0) 100%), #FFFFFF
}
}
</style>

View File

@ -16,7 +16,7 @@ const collections = [
},
]
test.each([...collections])('should inject metadata for collections', async (collection) => {
test.each(collections)('should inject metadata for valid 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()
@ -34,22 +34,14 @@ test.each([...collections])('should inject metadata for collections', async (col
expect(body).toContain(`<meta property="twitter:image:alt" content="${collection.collectionName} on Uniswap"/>`)
})
const nonexistentCollections = [
{
address: '0xed5af388653567af2f388e6224dc7c4b3241c545',
},
]
const invalidCollections = [
{
address: '0xd3adb33f',
},
'http://127.0.0.1:3000/nfts/collection/0xed5af388653567af2f388e6224dc7c4b3241c545',
'http://127.0.0.1:3000/nfts/collection/0xed5af388653567af2f388e6224dc7c4b3241c545//',
]
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
test.each(invalidCollections)(
'should not inject metadata for invalid collection urls',
async (url) => {
const body = await fetch(new Request(url)).then((res) => res.text())
expect(body).not.toContain('og:title')
expect(body).not.toContain('og:image')
@ -62,5 +54,6 @@ test.each([...invalidCollections, ...nonexistentCollections])(
expect(body).not.toContain('twitter:title')
expect(body).not.toContain('twitter:image')
expect(body).not.toContain('twitter:image:alt')
}
},
50000
)

View File

@ -1 +0,0 @@
jest.retryTimes(3)

View File

@ -11,7 +11,7 @@ export const onRequest: PagesFunction = async ({ params, request, next }) => {
if (!tokenAddress) {
return res
}
return getMetadataRequest(res, request, () => getToken(networkName, tokenAddress, request.url))
return getMetadataRequest(res, request.url, () => getToken(networkName, tokenAddress, request.url))
} catch (e) {
return res
}

View File

@ -17,7 +17,7 @@ exports[`should inject metadata for valid tokens 1`] = `
<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 name="theme-color" content="#FC72FF" />
<meta
http-equiv="Content-Security-Policy"
@ -37,46 +37,31 @@ exports[`should inject metadata for valid tokens 1`] = `
-->
<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/Inter-roman.var.woff2" as="font" type="font/woff2" 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>
* {
font-family: 'Basel', sans-serif;
font-family: 'Inter', sans-serif;
box-sizing: border-box;
}
/**
Explicitly load Basel var from public/ so it does not block LCP's critical path.
Explicitly load Inter var from public/ so it does not block LCP's critical path.
*/
@font-face {
font-family: 'Basel';
font-weight: 535;
font-family: 'Inter custom';
font-weight: 100 900;
font-style: normal;
font-display: block;
src:
url('/fonts/Basel-Medium.woff2') format('woff2'),
url('/fonts/Basel-Medium.woff') format('woff');
}
@font-face {
font-family: 'Basel';
font-weight: 485;
font-style: normal;
font-display: block;
src:
url('/fonts/Basel-Book.woff') format('woff2'),
url('/fonts/Basel-Book.woff') format('woff');
font-named-instance: 'Regular';
src: url(/fonts/Inter-roman.var.woff2) format('woff2 supports variations(gvar)'),
url(/fonts/Inter-roman.var.woff2) format('woff2-variations'),
url(/fonts/Inter-roman.var.woff2) format('woff2');
}
@supports (font-variation-settings: normal) {
* {
font-family: 'Basel', sans-serif;
font-family: 'Inter custom', sans-serif;
}
}
@ -92,11 +77,9 @@ exports[`should inject metadata for valid tokens 1`] = `
html {
font-size: 16px;
font-weight: 485;
font-variant: none;
font-smooth: always;
text-rendering: optimizeLegibility !important;
-webkit-font-smoothing: antialiased !important;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
@ -122,13 +105,13 @@ exports[`should inject metadata for valid tokens 1`] = `
@media (prefers-color-scheme: dark) {
html {
background: linear-gradient(rgb(19, 19, 19) 0%, rgb(19, 19, 19) 100%);
background: linear-gradient(180deg, #202738 0%, #070816 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);
background: radial-gradient(100% 100% at 50% 0%, rgba(255, 184, 226, 0.51) 0%, rgba(255, 255, 255, 0) 100%), #FFFFFF
}
}
</style>
@ -165,7 +148,7 @@ exports[`should inject metadata for valid tokens 2`] = `
<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 name="theme-color" content="#FC72FF" />
<meta
http-equiv="Content-Security-Policy"
@ -185,46 +168,31 @@ exports[`should inject metadata for valid tokens 2`] = `
-->
<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/Inter-roman.var.woff2" as="font" type="font/woff2" 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>
* {
font-family: 'Basel', sans-serif;
font-family: 'Inter', sans-serif;
box-sizing: border-box;
}
/**
Explicitly load Basel var from public/ so it does not block LCP's critical path.
Explicitly load Inter var from public/ so it does not block LCP's critical path.
*/
@font-face {
font-family: 'Basel';
font-weight: 535;
font-family: 'Inter custom';
font-weight: 100 900;
font-style: normal;
font-display: block;
src:
url('/fonts/Basel-Medium.woff2') format('woff2'),
url('/fonts/Basel-Medium.woff') format('woff');
}
@font-face {
font-family: 'Basel';
font-weight: 485;
font-style: normal;
font-display: block;
src:
url('/fonts/Basel-Book.woff') format('woff2'),
url('/fonts/Basel-Book.woff') format('woff');
font-named-instance: 'Regular';
src: url(/fonts/Inter-roman.var.woff2) format('woff2 supports variations(gvar)'),
url(/fonts/Inter-roman.var.woff2) format('woff2-variations'),
url(/fonts/Inter-roman.var.woff2) format('woff2');
}
@supports (font-variation-settings: normal) {
* {
font-family: 'Basel', sans-serif;
font-family: 'Inter custom', sans-serif;
}
}
@ -240,11 +208,9 @@ exports[`should inject metadata for valid tokens 2`] = `
html {
font-size: 16px;
font-weight: 485;
font-variant: none;
font-smooth: always;
text-rendering: optimizeLegibility !important;
-webkit-font-smoothing: antialiased !important;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
@ -270,13 +236,13 @@ exports[`should inject metadata for valid tokens 2`] = `
@media (prefers-color-scheme: dark) {
html {
background: linear-gradient(rgb(19, 19, 19) 0%, rgb(19, 19, 19) 100%);
background: linear-gradient(180deg, #202738 0%, #070816 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);
background: radial-gradient(100% 100% at 50% 0%, rgba(255, 184, 226, 0.51) 0%, rgba(255, 255, 255, 0) 100%), #FFFFFF
}
}
</style>
@ -313,7 +279,7 @@ exports[`should inject metadata for valid tokens 3`] = `
<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 name="theme-color" content="#FC72FF" />
<meta
http-equiv="Content-Security-Policy"
@ -333,46 +299,31 @@ exports[`should inject metadata for valid tokens 3`] = `
-->
<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/Inter-roman.var.woff2" as="font" type="font/woff2" 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>
* {
font-family: 'Basel', sans-serif;
font-family: 'Inter', sans-serif;
box-sizing: border-box;
}
/**
Explicitly load Basel var from public/ so it does not block LCP's critical path.
Explicitly load Inter var from public/ so it does not block LCP's critical path.
*/
@font-face {
font-family: 'Basel';
font-weight: 535;
font-family: 'Inter custom';
font-weight: 100 900;
font-style: normal;
font-display: block;
src:
url('/fonts/Basel-Medium.woff2') format('woff2'),
url('/fonts/Basel-Medium.woff') format('woff');
}
@font-face {
font-family: 'Basel';
font-weight: 485;
font-style: normal;
font-display: block;
src:
url('/fonts/Basel-Book.woff') format('woff2'),
url('/fonts/Basel-Book.woff') format('woff');
font-named-instance: 'Regular';
src: url(/fonts/Inter-roman.var.woff2) format('woff2 supports variations(gvar)'),
url(/fonts/Inter-roman.var.woff2) format('woff2-variations'),
url(/fonts/Inter-roman.var.woff2) format('woff2');
}
@supports (font-variation-settings: normal) {
* {
font-family: 'Basel', sans-serif;
font-family: 'Inter custom', sans-serif;
}
}
@ -388,11 +339,9 @@ exports[`should inject metadata for valid tokens 3`] = `
html {
font-size: 16px;
font-weight: 485;
font-variant: none;
font-smooth: always;
text-rendering: optimizeLegibility !important;
-webkit-font-smoothing: antialiased !important;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
@ -418,13 +367,13 @@ exports[`should inject metadata for valid tokens 3`] = `
@media (prefers-color-scheme: dark) {
html {
background: linear-gradient(rgb(19, 19, 19) 0%, rgb(19, 19, 19) 100%);
background: linear-gradient(180deg, #202738 0%, #070816 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);
background: radial-gradient(100% 100% at 50% 0%, rgba(255, 184, 226, 0.51) 0%, rgba(255, 255, 255, 0) 100%), #FFFFFF
}
}
</style>
@ -461,7 +410,7 @@ exports[`should inject metadata for valid tokens 4`] = `
<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 name="theme-color" content="#FC72FF" />
<meta
http-equiv="Content-Security-Policy"
@ -481,46 +430,31 @@ exports[`should inject metadata for valid tokens 4`] = `
-->
<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/Inter-roman.var.woff2" as="font" type="font/woff2" 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>
* {
font-family: 'Basel', sans-serif;
font-family: 'Inter', sans-serif;
box-sizing: border-box;
}
/**
Explicitly load Basel var from public/ so it does not block LCP's critical path.
Explicitly load Inter var from public/ so it does not block LCP's critical path.
*/
@font-face {
font-family: 'Basel';
font-weight: 535;
font-family: 'Inter custom';
font-weight: 100 900;
font-style: normal;
font-display: block;
src:
url('/fonts/Basel-Medium.woff2') format('woff2'),
url('/fonts/Basel-Medium.woff') format('woff');
}
@font-face {
font-family: 'Basel';
font-weight: 485;
font-style: normal;
font-display: block;
src:
url('/fonts/Basel-Book.woff') format('woff2'),
url('/fonts/Basel-Book.woff') format('woff');
font-named-instance: 'Regular';
src: url(/fonts/Inter-roman.var.woff2) format('woff2 supports variations(gvar)'),
url(/fonts/Inter-roman.var.woff2) format('woff2-variations'),
url(/fonts/Inter-roman.var.woff2) format('woff2');
}
@supports (font-variation-settings: normal) {
* {
font-family: 'Basel', sans-serif;
font-family: 'Inter custom', sans-serif;
}
}
@ -536,11 +470,9 @@ exports[`should inject metadata for valid tokens 4`] = `
html {
font-size: 16px;
font-weight: 485;
font-variant: none;
font-smooth: always;
text-rendering: optimizeLegibility !important;
-webkit-font-smoothing: antialiased !important;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
@ -566,13 +498,13 @@ exports[`should inject metadata for valid tokens 4`] = `
@media (prefers-color-scheme: dark) {
html {
background: linear-gradient(rgb(19, 19, 19) 0%, rgb(19, 19, 19) 100%);
background: linear-gradient(180deg, #202738 0%, #070816 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);
background: radial-gradient(100% 100% at 50% 0%, rgba(255, 184, 226, 0.51) 0%, rgba(255, 255, 255, 0) 100%), #FFFFFF
}
}
</style>

View File

@ -0,0 +1,33 @@
import { DEFAULT_COLOR } from '../constants'
import getColor from './getColor'
test('should return the average color of a black PNG image', async () => {
const image = 'https://static.vecteezy.com/system/resources/previews/001/209/957/original/square-png.png'
const color = await getColor(image)
expect(color).toEqual([0, 0, 0])
})
test('should return the average color of a blue PNG image', async () => {
const image = 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTB2Ztcim-RKbOu57kfjYpXnnS1MO5YMUaUH9Lk5Eg&s'
const color = await getColor(image)
expect(color).toEqual([2, 6, 251])
})
test('should return the average color of a white PNG image', async () => {
const image = 'https://www.cac.cornell.edu/wiki/images/4/44/White_square.png'
const color = await getColor(image)
expect(color).toEqual([255, 255, 255])
})
test('should return the average color of a black JPG image', async () => {
const image =
'https://imageio.forbes.com/specials-images/imageserve/5ed6636cdd5d320006caf841/0x0.jpg?format=jpg&width=1200'
const color = await getColor(image)
expect(color).toEqual([0, 0, 0])
})
test('should return default color for a gif image', async () => {
const image = 'https://thumbs.gfycat.com/AgitatedLiveAgouti-size_restricted.gif'
const color = await getColor(image)
expect(color).toEqual(DEFAULT_COLOR)
})

View File

@ -2,9 +2,9 @@ import { Buffer } from 'buffer'
import JPEG from 'jpeg-js'
import PNG from 'png-ts'
import { DEFAULT_COLOR, predefinedTokenColors } from '../constants/tokenColors'
import { DEFAULT_COLOR, predefinedTokenColors } from '../constants'
export async function getColor(image: string | undefined, checkDistance = false) {
export default async function getColor(image: string | undefined) {
if (!image) {
return DEFAULT_COLOR
}
@ -17,13 +17,13 @@ export async function getColor(image: string | undefined, checkDistance = false)
const arrayBuffer = Buffer.from(buffer)
const type = data.headers.get('content-type') ?? ''
return getAverageColor(arrayBuffer, type, checkDistance)
return getAverageColor(arrayBuffer, type)
} catch (e) {
return DEFAULT_COLOR
}
}
function getAverageColor(arrayBuffer: Uint8Array, type: string, checkDistance: boolean) {
function getAverageColor(arrayBuffer: Uint8Array, type?: string) {
let pixels
switch (type) {
case 'image/png': {
@ -63,13 +63,5 @@ function getAverageColor(arrayBuffer: Uint8Array, type: string, checkDistance: b
g = Math.floor(g / (pixelCount - transparentPixels))
b = Math.floor(b / (pixelCount - transparentPixels))
if (checkDistance) {
const distance = Math.sqrt(Math.pow(r - 255, 2) + Math.pow(g - 255, 2) + Math.pow(b - 255, 2))
if (distance < 50) {
return DEFAULT_COLOR
}
}
return [r, g, b]
}

View File

@ -1,5 +1,6 @@
export default async function getFont(origin: string) {
const url = origin + '/fonts/Inter-normal.var.ttf'
const font = await fetch(url)
const FONT_URL = 'https://fonts.gstatic.com/s/inter/v12/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuI6fAZFhjQ.ttf'
export default async function getFont() {
const font = await fetch(FONT_URL)
return font.arrayBuffer()
}

View File

@ -1,15 +1,15 @@
import { Chain } from '../../src/graphql/data/__generated__/types-and-hooks'
export default function getNetworkLogoUrl(network: string, origin: string) {
export default function getNetworkLogoUrl(network: string) {
switch (network) {
case Chain.Polygon:
return origin + '/images/logos/Polygon_Logo.png'
return 'https://assets.coingecko.com/coins/images/4713/small/matic-token-icon.png?1624446912'
case Chain.Arbitrum:
return origin + '/images/logos/Arbitrum_Logo.png'
return 'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/arbitrum/assets/0x912CE59144191C1204E64559FE8253a0e49E6548/logo.png'
case Chain.Optimism:
return origin + '/images/logos/Optimism_Logo.png'
return 'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/optimism/assets/0x4200000000000000000000000000000000000042/logo.png'
case Chain.Celo:
return origin + '/images/logos/Celo_Logo.png'
return 'https://assets.coingecko.com/coins/images/11090/small/InjXBNx9_400x400.jpg?1674707499'
default:
return ''
}

View File

@ -4,13 +4,13 @@ import { Data } from './cache'
export async function getMetadataRequest(
res: Promise<Response>,
request: Request,
url: string,
getData: () => Promise<Data | undefined>
) {
try {
const cachedData = await getRequest(request.url, getData, (data): data is Data => true)
const cachedData = await getRequest(url, getData, (data): data is Data => true)
if (cachedData) {
return new HTMLRewriter().on('head', new MetaTagInjector(cachedData, request)).transform(await res)
return new HTMLRewriter().on('head', new MetaTagInjector(cachedData)).transform(await res)
} else {
return res
}

View File

@ -13,8 +13,7 @@ const forkingConfig = {
const forks = {
[ChainId.MAINNET]: {
url: `https://mainnet.infura.io/v3/${process.env.REACT_APP_INFURA_KEY}`,
// Temporarily hardcoding this to fix e2e tests as we investigate source of swap tests failing on older blocknumbers
blockNumber: 18537387,
blockNumber: UNIVERSAL_ROUTER_CREATION_BLOCK(ChainId.MAINNET),
...forkingConfig,
},
[ChainId.POLYGON]: {

View File

@ -28,6 +28,7 @@ const linguiConfig = {
'ca-ES',
'cs-CZ',
'da-DK',
'de-DE',
'el-GR',
'en-US',
'es-ES',

View File

@ -13,7 +13,6 @@
"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",
@ -21,29 +20,19 @@
"start": "craco start",
"start:cloud": "NODE_OPTIONS=--dns-result-order=ipv4first PORT=3001 npx wrangler pages dev --compatibility-flags=nodejs_compat --compatibility-date=2023-08-01 --proxy=3001 --port=3000 -- yarn start",
"build": "craco build",
"analyze": "source-map-explorer 'build/static/js/*.js' --no-border-checks --gzip",
"serve": "serve build -s -l 3000",
"analyze": "source-map-explorer 'build/static/js/*.js' --only-mapped",
"serve": "serve build -l 3000",
"lint": "yarn eslint --ignore-path .gitignore --cache --cache-location node_modules/.cache/eslint/ .",
"typecheck": "tsc",
"typecheck:cloud": "tsc -p functions/tsconfig.json",
"typecheck:cypress": "tsc -p cypress/tsconfig.json",
"test": "craco test",
"test:cloud": "yarn jest functions --config=functions/jest.config.json",
"test:cloud": "NODE_OPTIONS=--experimental-vm-modules yarn jest functions --config=functions/jest.config.json",
"cypress:open": "cypress open --browser chrome --e2e",
"cypress:run": "cypress run --browser chrome --e2e",
"deduplicate": "yarn-deduplicate --strategy=highest",
"postinstall": "yarn patch-package"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"yarn.lock": [
"yarn deduplicate"
]
},
"jest": {
"collectCoverageFrom": [
"src/**/*.ts*",
@ -95,7 +84,7 @@
"@types/array.prototype.flat": "^1.2.1",
"@types/array.prototype.flatmap": "^1.2.2",
"@types/d3": "^6.7.1",
"@types/jest": "^27.0.1",
"@types/jest": "^25.2.1",
"@types/lingui__core": "^2.7.1",
"@types/lingui__macro": "^2.7.4",
"@types/lingui__react": "^2.8.3",
@ -115,8 +104,7 @@
"@types/ua-parser-js": "^0.7.36",
"@types/uuid": "^8.3.4",
"@types/wcag-contrast": "^3.0.0",
"@types/xml2js": "^0.4.12",
"@uniswap/default-token-list": "^11.8.0",
"@uniswap/default-token-list": "^11.2.0",
"@uniswap/eslint-config": "^1.2.0",
"@vanilla-extract/jest-transform": "^1.1.1",
"@vanilla-extract/webpack-plugin": "^2.2.0",
@ -129,18 +117,17 @@
"cypress": "12.12.0",
"cypress-hardhat": "^2.5.0",
"env-cmd": "^10.1.0",
"eslint": "8.44.0",
"eslint": "^7.11.0",
"eslint-plugin-import": "^2.27",
"eslint-plugin-rulesdir": "^0.2.2",
"hardhat": "^2.14.0",
"husky": "^8.0.3",
"jest": "^29.6.1",
"jest-dev-server": "^9.0.0",
"jest-extended": "^4.0.1",
"jest-fail-on-console": "^3.1.1",
"jest-fetch-mock": "^3.0.3",
"jest-styled-components": "^7.0.8",
"jpeg-js": "^0.4.4",
"lint-staged": "^14.0.0",
"mini-css-extract-plugin": "^2.7.6",
"patch-package": "^7.0.0",
"path-browserify": "^1.0.1",
@ -152,22 +139,17 @@
"resize-observer-polyfill": "^1.5.1",
"serve": "^11.3.2",
"source-map-explorer": "^2.5.3",
"start-server-and-test": "^2.0.0",
"swc-loader": "^0.2.3",
"terser": "^5.19.4",
"terser-webpack-plugin": "^5.3.9",
"ts-jest": "^29.1.1",
"tsafe": "^1.6.4",
"ts-transform-graphql-tag": "^0.2.1",
"typechain": "^5.0.0",
"typescript": "^4.9.4",
"webpack": "^5.88.2",
"webpack-retry-chunk-load-plugin": "^3.1.1",
"wrangler": "^3.7.0",
"wrangler": "^3.5.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",
@ -193,21 +175,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.5.0",
"@uniswap/analytics-events": "^2.28.0",
"@uniswap/analytics": "^1.4.0",
"@uniswap/analytics-events": "^2.15.0",
"@uniswap/conedison": "^1.8.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.7.1",
"@uniswap/sdk-core": "4.0.7",
"@uniswap/router-sdk": "^1.6.0",
"@uniswap/sdk-core": "^4.0.3",
"@uniswap/smart-order-router": "^3.15.0",
"@uniswap/token-lists": "^1.0.0-beta.33",
"@uniswap/uniswapx-sdk": "^1.4.1",
"@uniswap/universal-router-sdk": "^1.5.8",
"@uniswap/uniswapx-sdk": "^1.2.0",
"@uniswap/universal-router-sdk": "^1.5.6",
"@uniswap/v2-core": "^1.0.1",
"@uniswap/v2-periphery": "^1.1.0-beta.0",
"@uniswap/v2-sdk": "^3.2.0",
@ -225,16 +207,16 @@
"@visx/react-spring": "^2.12.2",
"@visx/responsive": "^2.10.0",
"@visx/shape": "^2.11.1",
"@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",
"@web3-react/coinbase-wallet": "^8.2.0",
"@web3-react/core": "^8.2.0",
"@web3-react/eip1193": "^8.2.0",
"@web3-react/empty": "^8.2.0",
"@web3-react/gnosis-safe": "^8.2.1",
"@web3-react/metamask": "^8.2.0",
"@web3-react/network": "^8.2.0",
"@web3-react/types": "^8.2.0",
"@web3-react/url": "^8.2.0",
"@web3-react/walletconnect-v2": "^8.3.7",
"ajv": "^8.11.0",
"ajv-formats": "^2.1.1",
"array.prototype.flat": "^1.2.4",
@ -253,13 +235,10 @@
"inter-ui": "^3.13.1",
"jotai": "^1.3.7",
"jsbi": "^3.1.4",
"localforage": "^1.10.0",
"make-plural": "^7.0.0",
"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",
@ -270,7 +249,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-feather": "^2.0.8",
"react-helmet": "^6.1.0",
"react-ga4": "^1.4.1",
"react-infinite-scroll-component": "^6.1.0",
"react-is": "^17.0.2",
"react-markdown": "^4.3.1",
@ -286,7 +265,7 @@
"react-window-infinite-loader": "^1.0.8",
"rebass": "^4.0.7",
"redux": "^4.1.2",
"redux-persist": "^6.0.0",
"redux-localstorage-simple": "^2.3.1",
"statsig-react": "^1.22.0",
"styled-components": "^5.3.5",
"tiny-invariant": "^1.2.0",
@ -300,7 +279,6 @@
"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": {

View File

@ -1,5 +1,5 @@
diff --git a/node_modules/@vercel/og/dist/index.edge.js b/node_modules/@vercel/og/dist/index.edge.js
index 5187f88..eda01d0 100644
index 5187f88..c4a1c41 100644
--- a/node_modules/@vercel/og/dist/index.edge.js
+++ b/node_modules/@vercel/og/dist/index.edge.js
@@ -18673,8 +18673,8 @@ var Resvg2 = class extends Resvg {
@ -13,11 +13,12 @@ index 5187f88..eda01d0 100644
// src/emoji/index.ts
var U200D = String.fromCharCode(8205);
@@ -18809,18 +18809,15 @@ async function render(satori, resvg, opts, defaultFonts, element) {
@@ -18809,18 +18809,18 @@ async function render(satori, resvg, opts, defaultFonts, element) {
// src/index.edge.ts
var initializedResvg = initWasm(resvg_wasm);
var initializedYoga = initYoga(yoga_wasm).then((yoga2) => Ll(yoga2));
-var fallbackFont = fetch(new URL("./noto-sans-v27-latin-regular.ttf", import.meta.url)).then((res) => res.arrayBuffer());
+// var fallbackFont = fetch(new URL("https://fonts.gstatic.com/s/notosans/v28/o-0IIpQlx3QUlC5A4PNr6zRF.ttf", import.meta.url)).then((res) => res.arrayBuffer());
var ImageResponse = class {
constructor(element, options = {}) {
const result = new ReadableStream({
@ -25,22 +26,22 @@ index 5187f88..eda01d0 100644
await initializedYoga;
await initializedResvg;
- const fontData = await fallbackFont;
+ // const fontData = await fallbackFont;
const fonts = [
{
name: "sans serif",
- data: fontData,
+ // data: fontData,
weight: 700,
style: "normal"
}
diff --git a/node_modules/@vercel/og/dist/types.d.ts b/node_modules/@vercel/og/dist/types.d.ts
index dde26cc..d075e99 100644
index dde26cc..eb59ff4 100644
--- a/node_modules/@vercel/og/dist/types.d.ts
+++ b/node_modules/@vercel/og/dist/types.d.ts
@@ -28,9 +28,8 @@ declare type ImageOptions = {
* A list of fonts to use.
*
@@ -30,7 +30,7 @@ declare type ImageOptions = {
* @type {{ data: ArrayBuffer; name: string; weight?: 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900; style?: 'normal' | 'italic' }[]}
- * @default Noto Sans Latin Regular.
* @default Noto Sans Latin Regular.
*/
- fonts?: SatoriOptions['fonts'];
+ fonts: SatoriOptions['fonts'];

View File

@ -1,13 +0,0 @@
diff --git a/node_modules/@web3-react/coinbase-wallet/dist/index.js b/node_modules/@web3-react/coinbase-wallet/dist/index.js
index f38d06e..4f8fa19 100644
--- a/node_modules/@web3-react/coinbase-wallet/dist/index.js
+++ b/node_modules/@web3-react/coinbase-wallet/dist/index.js
@@ -62,7 +62,7 @@ class CoinbaseWallet extends types_1.Connector {
return __awaiter(this, void 0, void 0, function* () {
if (this.eagerConnection)
return;
- yield (this.eagerConnection = Promise.resolve().then(() => __importStar(require('@coinbase/wallet-sdk'))).then((m) => {
+ yield (this.eagerConnection = Promise.resolve().then(async () => __importStar(await import('@coinbase/wallet-sdk'))).then((m) => {
const _a = this.options, { url } = _a, options = __rest(_a, ["url"]);
this.coinbaseWallet = new m.default(options);
this.provider = this.coinbaseWallet.makeWeb3Provider(url);

View File

@ -1,15 +0,0 @@
diff --git a/node_modules/@web3-react/gnosis-safe/dist/index.js b/node_modules/@web3-react/gnosis-safe/dist/index.js
index 015a33c..4cd7cde 100644
--- a/node_modules/@web3-react/gnosis-safe/dist/index.js
+++ b/node_modules/@web3-react/gnosis-safe/dist/index.js
@@ -68,8 +68,8 @@ class GnosisSafe extends types_1.Connector {
if (this.eagerConnection)
return;
// kick off import early to minimize waterfalls
- const SafeAppProviderPromise = Promise.resolve().then(() => __importStar(require('@safe-global/safe-apps-provider'))).then(({ SafeAppProvider }) => SafeAppProvider);
- yield (this.eagerConnection = Promise.resolve().then(() => __importStar(require('@safe-global/safe-apps-sdk'))).then((m) => __awaiter(this, void 0, void 0, function* () {
+ const SafeAppProviderPromise = Promise.resolve().then(async () => __importStar(await import('@safe-global/safe-apps-provider'))).then(({ SafeAppProvider }) => SafeAppProvider);
+ yield (this.eagerConnection = Promise.resolve().then(async () => __importStar(await import('@safe-global/safe-apps-sdk'))).then((m) => __awaiter(this, void 0, void 0, function* () {
this.sdk = new m.default(this.options);
const safe = yield Promise.race([
this.sdk.safe.getInfo(),

View File

@ -1,13 +0,0 @@
diff --git a/node_modules/@web3-react/metamask/dist/index.js b/node_modules/@web3-react/metamask/dist/index.js
index c8476dd..c0bfce7 100644
--- a/node_modules/@web3-react/metamask/dist/index.js
+++ b/node_modules/@web3-react/metamask/dist/index.js
@@ -54,7 +54,7 @@ class MetaMask extends types_1.Connector {
return __awaiter(this, void 0, void 0, function* () {
if (this.eagerConnection)
return;
- return (this.eagerConnection = Promise.resolve().then(() => __importStar(require('@metamask/detect-provider'))).then((m) => __awaiter(this, void 0, void 0, function* () {
+ return (this.eagerConnection = Promise.resolve().then(async () => __importStar(await import('@metamask/detect-provider'))).then((m) => __awaiter(this, void 0, void 0, function* () {
var _a, _b;
const provider = yield m.default(this.options);
if (provider) {

Some files were not shown because too many files have changed in this diff Show More