Compare commits
116 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dded1197a6 | ||
|
|
c0d387d9f0 | ||
|
|
b40e0250fd | ||
|
|
d90e1ecf17 | ||
|
|
b6e388c68c | ||
|
|
45a138dec1 | ||
|
|
26d2ab53e8 | ||
|
|
e50ecc8309 | ||
|
|
406d7fe964 | ||
|
|
366f4d98ef | ||
|
|
4eda18a4d5 | ||
|
|
ea66b8b959 | ||
|
|
1eab4291f6 | ||
|
|
bed144b994 | ||
|
|
dac334f975 | ||
|
|
5478cb0c7b | ||
|
|
b47cebd40b | ||
|
|
bb51be545b | ||
|
|
ce8105bf08 | ||
|
|
59db4c5b02 | ||
|
|
1f6f1f1dbd | ||
|
|
1c142bb71f | ||
|
|
3e67982bb4 | ||
|
|
bb79c73416 | ||
|
|
b1da7d87f9 | ||
|
|
a79324f23c | ||
|
|
9008db5166 | ||
|
|
bcc57e4612 | ||
|
|
8c7315760a | ||
|
|
290083b414 | ||
|
|
4bc778ff3e | ||
|
|
49ae6ef6bd | ||
|
|
3dab1da5ea | ||
|
|
6ec9bb7362 | ||
|
|
31d0c3c9b3 | ||
|
|
88b7acf3ae | ||
|
|
877e000da6 | ||
|
|
3f05a88409 | ||
|
|
03ab5c80a8 | ||
|
|
4faaa60aea | ||
|
|
3a94a99293 | ||
|
|
e893bc2685 | ||
|
|
cccf6ac680 | ||
|
|
ea5af12b1d | ||
|
|
bf1f613a4f | ||
|
|
49f1acb52a | ||
|
|
a97005e2e1 | ||
|
|
966b02b2de | ||
|
|
024bbce9a4 | ||
|
|
c960c14170 | ||
|
|
39295e9a33 | ||
|
|
0feddebcc3 | ||
|
|
5e4108fbdc | ||
|
|
38cce46c7b | ||
|
|
69ae42f285 | ||
|
|
ef9619b1bd | ||
|
|
041f3d5ba2 | ||
|
|
666bb79833 | ||
|
|
2736d94432 | ||
|
|
57b098f309 | ||
|
|
c802132bd5 | ||
|
|
485764fe38 | ||
|
|
51dc10b467 | ||
|
|
7cf768b8dd | ||
|
|
59b5e81d16 | ||
|
|
8fc98abb1a | ||
|
|
def4ab3bc0 | ||
|
|
bb6de9056b | ||
|
|
cc52da9fc4 | ||
|
|
b98e62cac8 | ||
|
|
6cd1f04584 | ||
|
|
8ffe4e991b | ||
|
|
2b85852a48 | ||
|
|
94015b279c | ||
|
|
1291887049 | ||
|
|
d4a26a5610 | ||
|
|
1249371397 | ||
|
|
2ce7b08244 | ||
|
|
156254afa9 | ||
|
|
e31f4e549b | ||
|
|
f47e1f16d7 | ||
|
|
9954f9502d | ||
|
|
9fbdc3cab1 | ||
|
|
e04be0711f | ||
|
|
5c3caa7143 | ||
|
|
1ea724609f | ||
|
|
2b6948db94 | ||
|
|
0b8026e6fe | ||
|
|
b14831be12 | ||
|
|
b12a61e2fb | ||
|
|
6f6c9d7174 | ||
|
|
89c3ec7526 | ||
|
|
06c81d9304 | ||
|
|
15c59e8149 | ||
|
|
f6b66c759a | ||
|
|
b1c99d4b37 | ||
|
|
add6df46e6 | ||
|
|
b2dfb29f51 | ||
|
|
097ef6a3df | ||
|
|
984cf81911 | ||
|
|
08501234a8 | ||
|
|
3afe7fe9f2 | ||
|
|
bd573724b9 | ||
|
|
684258dc17 | ||
|
|
a53e773e5d | ||
|
|
5307d113a8 | ||
|
|
9e7d59f1fe | ||
|
|
2ccd228f23 | ||
|
|
a726f67453 | ||
|
|
c9b4016b78 | ||
|
|
a7135c9ab1 | ||
|
|
a1b3776686 | ||
|
|
dc2225a2bc | ||
|
|
41571169c6 | ||
|
|
7506dbb29c | ||
|
|
4f25c4a2bb |
1
.env
@@ -4,7 +4,6 @@ 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://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_MOONPAY_API="https://api.moonpay.com"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* eslint-env node */
|
||||
|
||||
const { node: restrictedImports } = require('@uniswap/eslint-config/restrictedImports')
|
||||
require('@uniswap/eslint-config/load')
|
||||
|
||||
const rulesDirPlugin = require('eslint-plugin-rulesdir')
|
||||
@@ -27,6 +28,7 @@ module.exports = {
|
||||
{
|
||||
files: ['**/*.ts', '**/*.tsx'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-restricted-imports': ['error', restrictedImports],
|
||||
'import/no-restricted-paths': [
|
||||
'error',
|
||||
{
|
||||
|
||||
32
.github/actions/cache-on-main/action.yml
vendored
@@ -1,32 +0,0 @@
|
||||
name: Cache on main
|
||||
description: caches node_modules/.cache, but only saves from main
|
||||
inputs:
|
||||
path:
|
||||
description: 'A list of files, directories, and wildcard patterns to cache and store'
|
||||
required: true
|
||||
key:
|
||||
description: 'An explicit key for restoring and saving the cache'
|
||||
required: true
|
||||
restore-keys:
|
||||
description: 'An ordered list of keys to use for restoring stale cache if no cache hit occured for key. Note `cache-hit` returns false in this case.'
|
||||
required: false
|
||||
|
||||
# Many build steps have their own caches 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 *on main* (by keying on github.run_id), and the most recent available cache is loaded.
|
||||
# Caches are not saved on feature branches because they have limited utility, and extend the runtime of the workflow.
|
||||
# See https://jongleberry.medium.com/speed-up-your-ci-and-dx-with-node-modules-cache-ac8df82b7bb0.
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- uses: actions/cache/restore@v3
|
||||
with:
|
||||
path: ${{ inputs.path }}
|
||||
key: ${{ inputs.key }}
|
||||
restore-keys: ${{ inputs.restore-keys }}
|
||||
- if: github.ref_name == 'main'
|
||||
uses: actions/cache/save@v3
|
||||
with:
|
||||
path: ${{ inputs.path }}
|
||||
key: ${{ inputs.key }}
|
||||
38
.github/actions/setup/action.yml
vendored
@@ -23,9 +23,9 @@ runs:
|
||||
- if: steps.install-cache.outputs.cache-hit != 'true'
|
||||
run: yarn install --frozen-lockfile --ignore-scripts
|
||||
shell: bash
|
||||
|
||||
# Validators compile quickly, so caching can be omitted.
|
||||
- run: yarn ajv
|
||||
|
||||
# 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.
|
||||
@@ -40,30 +40,10 @@ runs:
|
||||
run: yarn contracts
|
||||
shell: bash
|
||||
|
||||
# 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.
|
||||
# TODO(WEB-2498): Cache based on both fetched schema and client-side graphql queries.
|
||||
# This will require some processing: cp all literal graphql tags into a separate file and hash it?
|
||||
- run: yarn graphql
|
||||
shell: bash
|
||||
|
||||
# Messages are extracted from source.
|
||||
# A record of source file content hashes and catalogs is maintained in node_modules/.cache/lingui.
|
||||
# Messages are always extracted, but extraction may short-circuit from the custom extractor's cache.
|
||||
- uses: ./.github/actions/cache-on-main
|
||||
with:
|
||||
path: node_modules/.cache
|
||||
key: ${{ runner.os }}-i18n-extract-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-i18n-extract-
|
||||
- run: yarn i18n:extract
|
||||
shell: bash
|
||||
|
||||
# Translations are compiled from messages. If messages haven't changed, the translations do not need to be re-compiled.
|
||||
- uses: actions/cache@v3
|
||||
id: i18n-compile-cache
|
||||
with:
|
||||
path: src/locales/*.js
|
||||
key: ${{ runner.os }}-i18n-compile-${{ hashFiles('src/locales/*.po') }}
|
||||
- if: steps.i18n-compile-cache.outputs.cache-hit !='true'
|
||||
run: yarn i18n:compile
|
||||
# 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
|
||||
|
||||
71
.github/workflows/test.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup
|
||||
- uses: ./.github/actions/cache-on-main
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: node_modules/.cache
|
||||
key: ${{ runner.os }}-eslint-${{ github.run_id }}
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup
|
||||
- uses: ./.github/actions/cache-on-main
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: node_modules/.cache
|
||||
key: ${{ runner.os }}-tsc-${{ github.run_id }}
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup
|
||||
- uses: ./.github/actions/cache-on-main
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: node_modules/.cache
|
||||
key: ${{ runner.os }}-jest-${{ github.run_id }}
|
||||
@@ -81,22 +81,20 @@ jobs:
|
||||
name: Unit tests
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TEST_REPORTER_WEBHOOK }}
|
||||
|
||||
build-e2e:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup
|
||||
- uses: ./.github/actions/cache-on-main
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: node_modules/.cache
|
||||
key: ${{ runner.os }}-build-e2e-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-build-e2e-
|
||||
- run: yarn build:e2e
|
||||
env:
|
||||
NODE_OPTIONS: "--max_old_space_size=4096"
|
||||
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-e2e
|
||||
name: build
|
||||
path: build
|
||||
if-no-files-found: error
|
||||
|
||||
@@ -105,7 +103,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup
|
||||
- uses: ./.github/actions/cache-on-main
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: node_modules/.cache
|
||||
key: ${{ runner.os }}-cypress-tsc-${{ github.run_id }}
|
||||
@@ -124,7 +122,7 @@ jobs:
|
||||
- run: exit 0
|
||||
|
||||
cypress-test-matrix:
|
||||
needs: [build-e2e, cypress-rerun]
|
||||
needs: [build, cypress-rerun]
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -133,7 +131,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup
|
||||
- uses: ./.github/actions/cache-on-main
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: /root/.cache/Cypress
|
||||
key: ${{ runner.os }}-cypress-${{ hashFiles('**/node_modules/cypress/package.json') }}
|
||||
@@ -143,10 +141,10 @@ jobs:
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: build-e2e
|
||||
name: build
|
||||
path: build
|
||||
|
||||
- uses: ./.github/actions/cache-on-main
|
||||
- uses: actions/cache/restore@v3
|
||||
with:
|
||||
path: cache
|
||||
key: ${{ runner.os }}-hardhat-${{ hashFiles('hardhat.config.js') }}-${{ github.run_id }}
|
||||
@@ -175,23 +173,36 @@ jobs:
|
||||
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 }}
|
||||
- uses: codecov/codecov-action@v3
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
fail_ci_if_error: false
|
||||
flags: e2e-tests
|
||||
- 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: ./.github/actions/cache-on-main
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: node_modules/.cache
|
||||
key: ${{ runner.os }}-cloud-tsc-${{ github.run_id }}
|
||||
@@ -203,23 +214,23 @@ jobs:
|
||||
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: ./.github/actions/cache-on-main
|
||||
- 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%
|
||||
- if: failure() && github.ref_name == 'main'
|
||||
uses: ./.github/actions/report
|
||||
# Only use 1 worker, so the other can be used for the proxy server under test.
|
||||
- run: yarn test:cloud --coverage --maxWorkers=1
|
||||
- uses: codecov/codecov-action@v3
|
||||
with:
|
||||
name: Cloud tests
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TEST_REPORTER_WEBHOOK }}
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
fail_ci_if_error: false
|
||||
flags: cloud-tests
|
||||
|
||||
pre:
|
||||
if: ${{ github.ref_name == 'main' || github.ref_name == 'releases/staging' }}
|
||||
|
||||
3
.gitignore
vendored
@@ -20,6 +20,7 @@ schema.graphql
|
||||
/coverage
|
||||
/cache
|
||||
/functions/coverage
|
||||
/.swc
|
||||
|
||||
# builds
|
||||
/build
|
||||
@@ -52,3 +53,5 @@ cypress/videos
|
||||
cypress/screenshots
|
||||
|
||||
.vercel
|
||||
|
||||
.wrangler
|
||||
|
||||
4
.husky/pre-commit
Normal file
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
npx lint-staged
|
||||
36
.swcrc
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/swcrc",
|
||||
// has to duplicate from package.json, see swc issue: https://swc.rs/docs/configuration/compilation#env
|
||||
// this breaks jest because jest is setting target for some reason
|
||||
// "env": {
|
||||
// "targets": "> 0.5%, not dead"
|
||||
// },
|
||||
"jsc": {
|
||||
// without this swc breaks WalletConnect class super() call
|
||||
"target": "es2020",
|
||||
"keepClassNames": true,
|
||||
"experimental": {
|
||||
"plugins": [
|
||||
[
|
||||
"@lingui/swc-plugin",
|
||||
{}
|
||||
],
|
||||
[
|
||||
"@swc/plugin-styled-components",
|
||||
{
|
||||
"displayName": true
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"parser": {
|
||||
"syntax": "typescript",
|
||||
"tsx": true
|
||||
},
|
||||
"transform": {
|
||||
"react": {
|
||||
"runtime": "automatic"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1
CODEOWNERS
Normal file
@@ -0,0 +1 @@
|
||||
@uniswap/web-admins
|
||||
@@ -1,10 +0,0 @@
|
||||
/* eslint-env node */
|
||||
|
||||
const isDev = process.env.NODE_ENV === 'development'
|
||||
|
||||
module.exports = {
|
||||
styledComponents: {
|
||||
fileName: isDev,
|
||||
displayName: isDev,
|
||||
},
|
||||
}
|
||||
14
codecov.yml
@@ -6,12 +6,12 @@ ignore:
|
||||
- "**/instrumented/**/*"
|
||||
- "**/styles/**/*"
|
||||
- "styles/**/*"
|
||||
- "**/styled.tsx"
|
||||
- "**/constants/**/*"
|
||||
- "constants/**/*"
|
||||
|
||||
coverage:
|
||||
status:
|
||||
# Omit merging unit/e2e reports into the defaults, as it is nonsensical.
|
||||
project: off
|
||||
patch: off
|
||||
|
||||
@@ -25,20 +25,16 @@ flag_management:
|
||||
removed_code_behavior: adjust_base
|
||||
if_ci_failed: error
|
||||
- type: patch
|
||||
target: 80%
|
||||
target: 50%
|
||||
individual_flags:
|
||||
- name: unit-tests
|
||||
- name: e2e-tests
|
||||
# Wait until all machines have reported coverage - e2e tests run across 4 machines.
|
||||
after_n_builds: 4
|
||||
- name: cloud-tests
|
||||
statuses:
|
||||
- type: patch
|
||||
target: 0%
|
||||
- type: project
|
||||
target: 80%
|
||||
|
||||
comment:
|
||||
layout: flags
|
||||
# Wait until all machines have reported coverage - e2e tests run across 4 machines + unit tests across 1.
|
||||
after_n_builds: 5
|
||||
hide_comment_details: false
|
||||
|
||||
github_checks:
|
||||
|
||||
@@ -5,12 +5,15 @@ const { execSync } = require('child_process')
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||
const path = require('path')
|
||||
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin')
|
||||
const { DefinePlugin, IgnorePlugin, ProvidePlugin } = require('webpack')
|
||||
const TerserPlugin = require('terser-webpack-plugin')
|
||||
const { IgnorePlugin, ProvidePlugin } = require('webpack')
|
||||
const { RetryChunkLoadPlugin } = require('webpack-retry-chunk-load-plugin')
|
||||
|
||||
const commitHash = execSync('git rev-parse HEAD').toString().trim()
|
||||
const isProduction = process.env.NODE_ENV === 'production'
|
||||
|
||||
process.env.REACT_APP_GIT_COMMIT_HASH = commitHash
|
||||
|
||||
// Linting and type checking are only necessary as part of development and testing.
|
||||
// Omit them from production builds, as they slow down the feedback loop.
|
||||
const shouldLintOrTypeCheck = !isProduction
|
||||
@@ -21,32 +24,6 @@ function getCacheDirectory(cacheName) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
babel: {
|
||||
plugins: [
|
||||
'@vanilla-extract/babel-plugin',
|
||||
...(process.env.REACT_APP_ADD_COVERAGE_INSTRUMENTATION
|
||||
? [
|
||||
[
|
||||
'istanbul',
|
||||
{
|
||||
all: true,
|
||||
include: ['src/**/*.tsx', 'src/**/*.ts'],
|
||||
exclude: [
|
||||
'src/**/*.css',
|
||||
'src/**/*.css.ts',
|
||||
'src/**/*.test.ts',
|
||||
'src/**/*.test.tsx',
|
||||
'src/**/*.spec.ts',
|
||||
'src/**/*.spec.tsx',
|
||||
'src/**/graphql/**/*',
|
||||
'src/**/*.d.ts',
|
||||
],
|
||||
},
|
||||
],
|
||||
]
|
||||
: []),
|
||||
],
|
||||
},
|
||||
eslint: {
|
||||
enable: shouldLintOrTypeCheck,
|
||||
pluginOptions(eslintConfig) {
|
||||
@@ -69,16 +46,20 @@ module.exports = {
|
||||
configure(jestConfig) {
|
||||
return Object.assign(jestConfig, {
|
||||
cacheDirectory: getCacheDirectory('jest'),
|
||||
transform: Object.assign(jestConfig.transform, {
|
||||
transform: {
|
||||
...Object.entries(jestConfig.transform).reduce((transform, [key, value]) => {
|
||||
if (value.match(/babel/)) return transform
|
||||
return { ...transform, [key]: value }
|
||||
}, {}),
|
||||
// Transform vanilla-extract using its own transformer.
|
||||
// See https://sandroroth.com/blog/vanilla-extract-cra#jest-transform.
|
||||
'\\.css\\.ts$': '@vanilla-extract/jest-transform',
|
||||
}),
|
||||
// Use @uniswap/conedison's build directly, as jest does not support its exports.
|
||||
transformIgnorePatterns: ['@uniswap/conedison/format', '@uniswap/conedison/provider'],
|
||||
'\\.(t|j)sx?$': '@swc/jest',
|
||||
},
|
||||
// Use d3-arrays's build directly, as jest does not support its exports.
|
||||
transformIgnorePatterns: ['d3-array'],
|
||||
moduleNameMapper: {
|
||||
'@uniswap/conedison/format': '@uniswap/conedison/dist/format',
|
||||
'@uniswap/conedison/provider': '@uniswap/conedison/dist/provider',
|
||||
'd3-array': 'd3-array/dist/d3-array.min.js',
|
||||
},
|
||||
})
|
||||
},
|
||||
@@ -88,12 +69,9 @@ module.exports = {
|
||||
// Webpack 5 does not polyfill node globals, so we do so for those necessary:
|
||||
new ProvidePlugin({
|
||||
// - react-markdown requires process.cwd
|
||||
process: 'process/browser',
|
||||
process: 'process/browser.js',
|
||||
}),
|
||||
// vanilla-extract has poor performance on M1 machines with 'debug' identifiers, so we use 'short' instead.
|
||||
// See https://vanilla-extract.style/documentation/integrations/webpack/#identifiers for docs.
|
||||
// See https://github.com/vanilla-extract-css/vanilla-extract/issues/771#issuecomment-1249524366.
|
||||
new VanillaExtractPlugin({ identifiers: 'short' }),
|
||||
new VanillaExtractPlugin(),
|
||||
new RetryChunkLoadPlugin({
|
||||
cacheBust: `function() {
|
||||
return 'cache-bust=' + Date.now();
|
||||
@@ -109,14 +87,6 @@ module.exports = {
|
||||
// Configure webpack plugins:
|
||||
webpackConfig.plugins = webpackConfig.plugins
|
||||
.map((plugin) => {
|
||||
// Extend process.env with dynamic values (eg commit hash).
|
||||
// This will make dynamic values available to JavaScript only, not to interpolated HTML (ie index.html).
|
||||
if (plugin instanceof DefinePlugin) {
|
||||
Object.assign(plugin.definitions['process.env'], {
|
||||
REACT_APP_GIT_COMMIT_HASH: JSON.stringify(commitHash),
|
||||
})
|
||||
}
|
||||
|
||||
// CSS ordering is mitigated through scoping / naming conventions, so we can ignore order warnings.
|
||||
// See https://webpack.js.org/plugins/mini-css-extract-plugin/#remove-order-warnings.
|
||||
if (plugin instanceof MiniCssExtractPlugin) {
|
||||
@@ -163,13 +133,9 @@ module.exports = {
|
||||
|
||||
// Configure webpack transpilation (create-react-app specifies transpilation rules in a oneOf):
|
||||
webpackConfig.module.rules[1].oneOf = webpackConfig.module.rules[1].oneOf.map((rule) => {
|
||||
// The fallback rule (eg for dependencies).
|
||||
if (rule.loader && rule.loader.match(/babel-loader/) && !rule.include) {
|
||||
// Allow not-fully-specified modules so that legacy packages are still able to build.
|
||||
rule.resolve = { fullySpecified: false }
|
||||
|
||||
// The class properties transform is required for @uniswap/analytics to build.
|
||||
rule.options.plugins.push('@babel/plugin-proposal-class-properties')
|
||||
if (rule.loader && rule.loader.match(/babel-loader/)) {
|
||||
rule.loader = 'swc-loader'
|
||||
delete rule.options
|
||||
}
|
||||
return rule
|
||||
})
|
||||
@@ -177,6 +143,15 @@ module.exports = {
|
||||
// Configure webpack optimization:
|
||||
webpackConfig.optimization = Object.assign(
|
||||
webpackConfig.optimization,
|
||||
{
|
||||
minimize: isProduction,
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
minify: TerserPlugin.swcMinify,
|
||||
parallel: require('os').cpus().length,
|
||||
}),
|
||||
],
|
||||
},
|
||||
isProduction
|
||||
? {
|
||||
splitChunks: {
|
||||
@@ -192,16 +167,15 @@ module.exports = {
|
||||
: {}
|
||||
)
|
||||
|
||||
// Configure webpack caching:
|
||||
webpackConfig.cache = Object.assign(webpackConfig.cache, {
|
||||
cacheDirectory: getCacheDirectory('webpack'),
|
||||
})
|
||||
// Configure webpack resolution. webpackConfig.cache is unused with swc-loader, but the resolver can still cache:
|
||||
webpackConfig.resolve = Object.assign(webpackConfig.resolve, { unsafeCache: true })
|
||||
|
||||
// Ignore failed source mappings to avoid spamming the console.
|
||||
// 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.
|
||||
webpackConfig.ignoreWarnings = [/Failed to parse source map/]
|
||||
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
|
||||
},
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import codeCoverageTask from '@cypress/code-coverage/task'
|
||||
import { defineConfig } from 'cypress'
|
||||
import { setupHardhatEvents } from 'cypress-hardhat'
|
||||
|
||||
@@ -7,12 +6,11 @@ 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: 2 },
|
||||
retries: { runMode: process.env.CYPRESS_RETRIES ? +process.env.CYPRESS_RETRIES : 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) {
|
||||
await setupHardhatEvents(on, config)
|
||||
codeCoverageTask(on, config)
|
||||
return config
|
||||
},
|
||||
baseUrl: 'http://localhost:3000',
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { FeatureFlag } from '../../src/featureFlags'
|
||||
import { getTestSelector } from '../utils'
|
||||
|
||||
describe('Buy Crypto Modal', () => {
|
||||
it('should open and close', () => {
|
||||
cy.visit('/', { featureFlags: [FeatureFlag.fiatOnRampButtonOnSwap] })
|
||||
cy.visit('/')
|
||||
|
||||
// Open the fiat onramp modal
|
||||
cy.get(getTestSelector('buy-fiat-button')).click()
|
||||
@@ -16,7 +15,7 @@ describe('Buy Crypto Modal', () => {
|
||||
|
||||
it('should open and close, mobile viewport', () => {
|
||||
cy.viewport('iphone-6')
|
||||
cy.visit('/', { featureFlags: [FeatureFlag.fiatOnRampButtonOnSwap] })
|
||||
cy.visit('/')
|
||||
|
||||
// Open the fiat onramp modal
|
||||
cy.get(getTestSelector('buy-fiat-button')).click()
|
||||
|
||||
@@ -13,17 +13,30 @@ describe('Mini Portfolio account drawer', () => {
|
||||
// Balances should have been fetched once after hover
|
||||
cy.get(getTestSelector('web3-status-connected')).trigger('mouseover')
|
||||
cy.get('@gqlSpy').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('@gqlSpy').should('not.have.been.called')
|
||||
|
||||
// Balances should have been fetched once after hover
|
||||
cy.get(getTestSelector('web3-status-connected')).trigger('mouseover')
|
||||
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('@gqlSpy').should('have.been.calledOnce')
|
||||
})
|
||||
|
||||
// Balances should not be refetched upon opening drawer
|
||||
cy.get(getTestSelector('web3-status-connected')).click()
|
||||
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('@gqlSpy').should('not.have.been.called')
|
||||
|
||||
// Balances should have been fetched once after hover
|
||||
cy.get(getTestSelector('web3-status-connected')).trigger('mouseover')
|
||||
cy.get('@gqlSpy').should('have.been.calledOnce')
|
||||
|
||||
// Balances should not be refetched upon closing & reopening drawer
|
||||
cy.get(getTestSelector('close-account-drawer')).click()
|
||||
// Balances should not be refetched upon opening drawer
|
||||
cy.get(getTestSelector('web3-status-connected')).click()
|
||||
cy.get('@gqlSpy').should('have.been.calledOnce')
|
||||
})
|
||||
@@ -45,7 +58,7 @@ describe('Mini Portfolio account drawer', () => {
|
||||
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/activity.json' })
|
||||
cy.intercept(/graphql/, { fixture: 'mini-portfolio/full_activity.json' })
|
||||
cy.get(getTestSelector('mini-portfolio-navbar')).contains('Activity').click()
|
||||
cy.get(getTestSelector('mini-portfolio-page')).contains('Contract Interaction')
|
||||
})
|
||||
|
||||
@@ -146,6 +146,26 @@ 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', () => {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { FeatureFlag } from '../../../src/featureFlags'
|
||||
import { getTestSelector } from '../../utils'
|
||||
|
||||
describe('Swap settings', () => {
|
||||
it('Opens and closes the settings menu', () => {
|
||||
cy.visit('/swap', { featureFlags: [FeatureFlag.uniswapXEnabled] })
|
||||
cy.visit('/swap')
|
||||
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('Transaction deadline').should('exist')
|
||||
cy.contains('UniswapX').should('exist')
|
||||
@@ -13,4 +13,16 @@ describe('Swap settings', () => {
|
||||
cy.get(getTestSelector('open-settings-dialog-button')).click()
|
||||
cy.contains('Settings').should('not.exist')
|
||||
})
|
||||
|
||||
it('should open the mobile settings menu', () => {
|
||||
cy.viewport('iphone-6')
|
||||
cy.visit('/swap')
|
||||
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({ force: true })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { SwapEventName } from '@uniswap/analytics-events'
|
||||
import { ChainId } from '@uniswap/sdk-core'
|
||||
|
||||
import { UNI, USDC_MAINNET } from '../../../src/constants/tokens'
|
||||
@@ -64,6 +65,13 @@ 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')
|
||||
|
||||
76
cypress/e2e/swap/swapFlowLogging.test.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
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')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,45 +0,0 @@
|
||||
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')
|
||||
})
|
||||
})
|
||||
})
|
||||
27
cypress/e2e/swap/unconnected.test.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { SwapEventName } from '@uniswap/analytics-events'
|
||||
import { USDC_MAINNET } from 'constants/tokens'
|
||||
|
||||
import { getTestSelector } from '../../utils'
|
||||
|
||||
describe('Swap inputs with no wallet connected', () => {
|
||||
it('can input and load a quote with no wallet connected', () => {
|
||||
cy.visit(`/swap?inputCurrency=ETH&outputCurrency=${USDC_MAINNET.address}`)
|
||||
|
||||
cy.get(getTestSelector('web3-status-connected')).click()
|
||||
// click twice, first time to show confirmation, second to confirm
|
||||
cy.get(getTestSelector('wallet-disconnect')).click()
|
||||
cy.get(getTestSelector('wallet-disconnect')).should('contain', 'Disconnect')
|
||||
cy.get(getTestSelector('wallet-disconnect')).click()
|
||||
cy.get(getTestSelector('close-account-drawer')).click()
|
||||
|
||||
// Enter amount to swap
|
||||
cy.get('#swap-currency-output .token-amount-input').type('1').should('have.value', '1')
|
||||
cy.get('#swap-currency-input .token-amount-input').should('not.have.value', '')
|
||||
// Verify logging
|
||||
cy.waitForAmplitudeEvent(SwapEventName.SWAP_QUOTE_RECEIVED).then((event: any) => {
|
||||
cy.wrap(event.event_properties).should('have.property', 'quote_latency_milliseconds')
|
||||
cy.wrap(event.event_properties.quote_latency_milliseconds).should('be.a', 'number')
|
||||
cy.wrap(event.event_properties.quote_latency_milliseconds).should('be.gte', 0)
|
||||
})
|
||||
})
|
||||
})
|
||||
374
cypress/e2e/swap/uniswapx.test.ts
Normal file
@@ -0,0 +1,374 @@
|
||||
import { ChainId, CurrencyAmount } from '@uniswap/sdk-core'
|
||||
|
||||
import { DAI, nativeOnChain, USDC_MAINNET } from '../../../src/constants/tokens'
|
||||
import { getTestSelector } from '../../utils'
|
||||
|
||||
const QuoteEndpoint = 'https://api.uniswap.org/v2/quote'
|
||||
const QuoteWhereUniswapXIsBetter = 'uniswapx/quote1.json'
|
||||
const QuoteWithEthInput = 'uniswapx/quote2.json'
|
||||
|
||||
const OrderSubmissionEndpoint = 'https://api.uniswap.org/v2/order'
|
||||
|
||||
const OrderStatusEndpoint =
|
||||
'https://api.uniswap.org/v2/orders?swapper=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266&orderHashes=0xa9dd6f05ad6d6c79bee654c31ede4d0d2392862711be0f3bc4a9124af24a6a19'
|
||||
|
||||
/** 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()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
describe('UniswapX Toggle', () => {
|
||||
beforeEach(() => {
|
||||
cy.intercept(QuoteEndpoint, { fixture: QuoteWhereUniswapXIsBetter })
|
||||
cy.visit(`/swap/?inputCurrency=${USDC_MAINNET.address}&outputCurrency=${DAI.address}`)
|
||||
})
|
||||
|
||||
it('only displays uniswapx ui when setting is on', () => {
|
||||
// Setup a swap
|
||||
cy.get('#swap-currency-input .token-amount-input').type('300')
|
||||
|
||||
// UniswapX UI should not be visible
|
||||
cy.get(getTestSelector('gas-estimate-uniswapx-icon')).should('not.exist')
|
||||
|
||||
// Opt-in to UniswapX
|
||||
cy.contains('Try it now').click()
|
||||
|
||||
// UniswapX UI should be visible
|
||||
cy.get(getTestSelector('gas-estimate-uniswapx-icon')).should('exist')
|
||||
})
|
||||
|
||||
it('prompts opt-in if UniswapX is better', () => {
|
||||
// Setup a swap
|
||||
cy.get('#swap-currency-input .token-amount-input').type('300')
|
||||
|
||||
// UniswapX should not display in gas estimate row before opt-in
|
||||
cy.get(getTestSelector('gas-estimate-uniswapx-icon')).should('not.exist')
|
||||
|
||||
// UniswapX mustache should be visible
|
||||
cy.contains('Try it now').click()
|
||||
|
||||
// Opt-in dialog should now be hidden
|
||||
cy.contains('Try it now').should('not.be.visible')
|
||||
|
||||
// UniswapX should display in gas estimate row
|
||||
cy.get(getTestSelector('gas-estimate-uniswapx-icon')).should('exist')
|
||||
|
||||
// Opt-in dialog should not reappear if user manually toggles UniswapX off
|
||||
cy.get(getTestSelector('open-settings-dialog-button')).click()
|
||||
cy.get(getTestSelector('toggle-uniswap-x-button')).click()
|
||||
cy.get(getTestSelector('open-settings-dialog-button')).click()
|
||||
cy.contains('Try it now').should('not.be.visible')
|
||||
})
|
||||
})
|
||||
|
||||
describe('UniswapX Orders', () => {
|
||||
beforeEach(() => {
|
||||
cy.intercept(QuoteEndpoint, { fixture: 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.contains('Try it now').click()
|
||||
|
||||
// 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.contains('Try it now').click()
|
||||
|
||||
// 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.contains('Try it now').click()
|
||||
|
||||
// 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.contains('Try it now').click()
|
||||
|
||||
// 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('UniswapX Eth Input', () => {
|
||||
beforeEach(() => {
|
||||
cy.intercept(QuoteEndpoint, { fixture: 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.contains('Try it now').click()
|
||||
|
||||
// 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('switches swap input to WETH after wrap', () => {
|
||||
// Setup a swap
|
||||
cy.get('#swap-currency-input .token-amount-input').type('1')
|
||||
cy.contains('Try it now').click()
|
||||
|
||||
// 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()
|
||||
cy.hardhat().then((hardhat) => hardhat.mine())
|
||||
|
||||
// Confirm wrap is successful and WETH is now input token
|
||||
cy.contains('Wrapped')
|
||||
cy.contains('WETH')
|
||||
|
||||
// Reopen review modal and continue swap
|
||||
cy.get('#swap-button').click()
|
||||
cy.contains('Confirm swap').click()
|
||||
|
||||
// Approve WETH spend
|
||||
cy.wait('@eth_sendRawTransaction')
|
||||
cy.hardhat().then((hardhat) => hardhat.mine())
|
||||
|
||||
// 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')
|
||||
})
|
||||
})
|
||||
|
||||
describe('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')
|
||||
cy.contains('Try it now').click()
|
||||
|
||||
// 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')
|
||||
cy.contains('Try it now').click()
|
||||
|
||||
// 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')
|
||||
cy.contains('Try it now').click()
|
||||
|
||||
// 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 only one swap activity listed
|
||||
cy.get(getTestSelector('activity-content')).contains('Swapped').should('have.length', 1)
|
||||
})
|
||||
|
||||
it('balances should refetch after uniswapx swap', () => {
|
||||
// Setup a swap
|
||||
cy.get('#swap-currency-input .token-amount-input').type('300')
|
||||
cy.contains('Try it now').click()
|
||||
|
||||
const gqlSpy = cy.spy().as('gqlSpy')
|
||||
cy.intercept(/graphql/, (req) => {
|
||||
// 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')
|
||||
})
|
||||
})
|
||||
@@ -108,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.contains('WETH').click()
|
||||
cy.get('[data-reach-dialog-content]').contains('WETH').click()
|
||||
cy.url().should('include', `${WETH9[1].address}`)
|
||||
cy.url().should('not.include', `${UNI_MAINNET.address}`)
|
||||
})
|
||||
|
||||
@@ -11,6 +11,10 @@ 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', () => {
|
||||
@@ -18,7 +22,9 @@ describe('Token explore filter', () => {
|
||||
searchFor('dao')
|
||||
|
||||
cy.get('@filteredTokens').then((filteredTokens) => {
|
||||
cy.get('[data-cy="token-name"]').should('deep.equal', filteredTokens)
|
||||
cy.get('[data-cy="token-name"]').then((tokens) => {
|
||||
cy.wrap(Array.from(tokens)).should('deep.equal', Array.from(filteredTokens))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import { ChainId } from '@uniswap/sdk-core'
|
||||
import { UNI } from 'constants/tokens'
|
||||
|
||||
import { getTestSelector } from '../utils'
|
||||
|
||||
const UNI_ADDRESS = UNI[ChainId.MAINNET].address.toLowerCase()
|
||||
|
||||
describe('Universal search bar', () => {
|
||||
function openSearch() {
|
||||
// can't just type "/" because on mobile it doesn't respond to that
|
||||
@@ -19,7 +24,7 @@ describe('Universal search bar', () => {
|
||||
openSearch()
|
||||
getSearchBar().clear().type('uni')
|
||||
|
||||
cy.get(getTestSelector('searchbar-token-row-UNI'))
|
||||
cy.get(getTestSelector(`searchbar-token-row-ETHEREUM-${UNI_ADDRESS}`))
|
||||
.should('contain.text', 'Uniswap')
|
||||
.and('contain.text', 'UNI')
|
||||
.and('contain.text', '$')
|
||||
@@ -30,24 +35,38 @@ describe('Universal search bar', () => {
|
||||
openSearch()
|
||||
cy.get(getTestSelector('searchbar-dropdown'))
|
||||
.contains(getTestSelector('searchbar-dropdown'), 'Recent searches')
|
||||
.find(getTestSelector('searchbar-token-row-UNI'))
|
||||
.find(getTestSelector(`searchbar-token-row-ETHEREUM-${UNI_ADDRESS}`))
|
||||
.should('exist')
|
||||
})
|
||||
|
||||
it('should go to the selected result when recent results are shown', () => {
|
||||
// Seed recent results with UNI.
|
||||
openSearch()
|
||||
getSearchBar().type('uni')
|
||||
cy.get(getTestSelector('searchbar-token-row-UNI'))
|
||||
getSearchBar().clear().type('{esc}')
|
||||
it(
|
||||
'should go to the selected result when recent results are shown',
|
||||
// this test is experiencing flake despite being correct, i can see the right value in DOM
|
||||
// but for some reason cypress doesn't find it, so adding retries for now :/
|
||||
{
|
||||
// @ts-ignore see https://uniswapteam.slack.com/archives/C047U65H422/p1691455547556309
|
||||
// basically cypress has bad types due to overlap with jest and you just have to deal with it
|
||||
// i tried removing jest types but still happens
|
||||
retries: {
|
||||
runMode: 3,
|
||||
openMode: 3,
|
||||
},
|
||||
},
|
||||
() => {
|
||||
// Seed recent results with UNI.
|
||||
openSearch()
|
||||
getSearchBar().type('uni')
|
||||
cy.get(getTestSelector(`searchbar-token-row-ETHEREUM-${UNI_ADDRESS}`))
|
||||
getSearchBar().clear().type('{esc}')
|
||||
|
||||
// Search a different token by name.
|
||||
openSearch()
|
||||
getSearchBar().type('eth')
|
||||
cy.get(getTestSelector('searchbar-token-row-ETH'))
|
||||
// Search a different token by name.
|
||||
openSearch()
|
||||
getSearchBar().type('eth')
|
||||
cy.get(getTestSelector('searchbar-token-row-ETHEREUM-NATIVE'))
|
||||
|
||||
// Validate that we go to the searched/selected result.
|
||||
getSearchBar().type('{enter}')
|
||||
cy.url().should('contain', 'tokens/ethereum/NATIVE')
|
||||
})
|
||||
// Validate that we go to the searched/selected result.
|
||||
getSearchBar().type('{enter}')
|
||||
cy.url().should('contain', 'tokens/ethereum/NATIVE')
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { FeatureFlag } from 'featureFlags'
|
||||
|
||||
import { getTestSelector } from '../utils'
|
||||
|
||||
describe('Wallet Dropdown', () => {
|
||||
@@ -21,10 +23,14 @@ describe('Wallet Dropdown', () => {
|
||||
})
|
||||
}
|
||||
|
||||
function itChangesLocale() {
|
||||
function itChangesLocale({ featureFlag = false }: { featureFlag?: boolean } = {}) {
|
||||
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('hash').should('match', /\?lng=af-ZA$/)
|
||||
cy.contains('Uniswap available in: English')
|
||||
@@ -45,6 +51,15 @@ describe('Wallet Dropdown', () => {
|
||||
itChangesLocale()
|
||||
})
|
||||
|
||||
describe('should change locale with feature flag', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/', { featureFlags: [FeatureFlag.currencyConversion] })
|
||||
cy.get(getTestSelector('web3-status-connected')).click()
|
||||
cy.get(getTestSelector('wallet-settings')).click()
|
||||
})
|
||||
itChangesLocale({ featureFlag: true })
|
||||
})
|
||||
|
||||
describe('testnet toggle', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/swap')
|
||||
@@ -100,7 +115,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(152, 161, 192)')
|
||||
cy.get(getTestSelector('wallet-header')).should('have.css', 'color', 'rgb(155, 155, 155)')
|
||||
})
|
||||
|
||||
it('should properly use light system theme when auto theme setting is selected', () => {
|
||||
@@ -108,7 +123,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(119, 128, 160)')
|
||||
cy.get(getTestSelector('wallet-header')).should('have.css', 'color', 'rgb(125, 125, 125)')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -129,4 +144,32 @@ 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: [FeatureFlag.currencyConversion] })
|
||||
cy.get(getTestSelector('web3-status-connected')).click()
|
||||
cy.get(getTestSelector('wallet-settings')).click()
|
||||
cy.contains('USD')
|
||||
|
||||
cy.visit('/?cur=AUD', { featureFlags: [FeatureFlag.currencyConversion] })
|
||||
cy.contains('AUD')
|
||||
})
|
||||
|
||||
it('loads local currency from menu', () => {
|
||||
cy.visit('/', { featureFlags: [FeatureFlag.currencyConversion] })
|
||||
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('hash').should('match', /\?cur=AUD$/)
|
||||
cy.contains('AUD')
|
||||
|
||||
cy.get(getTestSelector('wallet-local-currency-item')).contains('USD').click({ force: true })
|
||||
cy.location('hash').should('match', /\?cur=USD$/)
|
||||
cy.contains('USD')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
12
cypress/fixtures/mini-portfolio/empty_activity.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"data": {
|
||||
"portfolios": [
|
||||
{
|
||||
"id": "UG9ydGZvbGlvOjB4ZjM5RmQ2ZTUxYWFkODhGNkY0Y2U2YUI4ODI3Mjc5Y2ZmRmI5MjI2Ng==",
|
||||
"assetActivities": [],
|
||||
"__typename": "Portfolio"
|
||||
}
|
||||
]
|
||||
},
|
||||
"errors": []
|
||||
}
|
||||
580
cypress/fixtures/mini-portfolio/full_activity.json
Normal file
@@ -0,0 +1,580 @@
|
||||
{
|
||||
"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": []
|
||||
}
|
||||
102
cypress/fixtures/mini-portfolio/uniswapx_activity.json
Normal file
@@ -0,0 +1,102 @@
|
||||
{
|
||||
"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": []
|
||||
}
|
||||
26
cypress/fixtures/uniswapx/expiredStatusResponse.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
114
cypress/fixtures/uniswapx/fillTransactionReceipt.json
Normal file
@@ -0,0 +1,114 @@
|
||||
{
|
||||
"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
|
||||
}
|
||||
33
cypress/fixtures/uniswapx/filledStatusResponse.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
26
cypress/fixtures/uniswapx/openStatusResponse.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
1
cypress/fixtures/uniswapx/orderResponse.json
Normal file
@@ -0,0 +1 @@
|
||||
{"hash":"0xa9dd6f05ad6d6c79bee654c31ede4d0d2392862711be0f3bc4a9124af24a6a19"}
|
||||
491
cypress/fixtures/uniswapx/quote1.json
Normal file
@@ -0,0 +1,491 @@
|
||||
{
|
||||
"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,
|
||||
"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,
|
||||
"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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
491
cypress/fixtures/uniswapx/quote2.json
Normal file
@@ -0,0 +1,491 @@
|
||||
{
|
||||
"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,
|
||||
"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,
|
||||
"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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -3,8 +3,8 @@ import 'cypress-hardhat/lib/browser'
|
||||
import { Eip1193Bridge } from '@ethersproject/experimental/lib/eip1193-bridge'
|
||||
|
||||
import { FeatureFlag } from '../../src/featureFlags'
|
||||
import { UserState } from '../../src/state/user/reducer'
|
||||
import { CONNECTED_WALLET_USER_STATE } from '../utils/user-state'
|
||||
import { initialState, UserState } from '../../src/state/user/reducer'
|
||||
import { CONNECTED_WALLET_USER_STATE, setInitialUserState } from '../utils/user-state'
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
@@ -54,14 +54,12 @@ Cypress.Commands.overwrite(
|
||||
onBeforeLoad(win) {
|
||||
options?.onBeforeLoad?.(win)
|
||||
|
||||
// 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 ?? {}) })
|
||||
)
|
||||
setInitialUserState(win, {
|
||||
...initialState,
|
||||
hideUniswapWalletBanner: true,
|
||||
...CONNECTED_WALLET_USER_STATE,
|
||||
...(options?.userState ?? {}),
|
||||
})
|
||||
|
||||
// Set feature flags, if configured.
|
||||
if (options?.featureFlags) {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
import '@cypress/code-coverage/support'
|
||||
import './commands'
|
||||
import './setupTests'
|
||||
|
||||
|
||||
@@ -4,3 +4,31 @@ 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, initialUserState: any) {
|
||||
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: initialUserState,
|
||||
},
|
||||
'persist:interface'
|
||||
)
|
||||
}
|
||||
|
||||
dbRequest.onupgradeneeded = function () {
|
||||
const db = dbRequest.result
|
||||
db.createObjectStore('keyvaluepairs')
|
||||
}
|
||||
}
|
||||
|
||||
18
functions/[[index]].ts
Normal file
@@ -0,0 +1,18 @@
|
||||
/* eslint-disable import/no-unused-modules */
|
||||
import { MetaTagInjector } from './components/metaTagInjector'
|
||||
|
||||
export const onRequest: PagesFunction = async ({ request, next }) => {
|
||||
const imageUri = new URL(request.url).origin + '/images/1200x630_Rich_Link_Preview_Image.png'
|
||||
const data = {
|
||||
title: 'Uniswap Interface',
|
||||
image: imageUri,
|
||||
url: request.url,
|
||||
description: 'Swap or provide liquidity on the Uniswap Protocol',
|
||||
}
|
||||
const res = next()
|
||||
try {
|
||||
return new HTMLRewriter().on('head', new MetaTagInjector(data)).transform(await res)
|
||||
} catch (e) {
|
||||
return res
|
||||
}
|
||||
}
|
||||
439
functions/__snapshots__/default.test.ts.snap
Normal file
@@ -0,0 +1,439 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`should inject metadata for valid collections 1`] = `
|
||||
"<!DOCTYPE html>
|
||||
<html translate="no">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<title>Uniswap Interface</title>
|
||||
<meta name="description" content="Swap or provide liquidity on the Uniswap Protocol" />
|
||||
|
||||
<!--
|
||||
will be replaced with the URL of the \`public\` folder during build.
|
||||
Only files inside the \`public\` folder can be referenced from the HTML.
|
||||
-->
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="/images/192x192_App_Icon.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="/images/512x512_App_Icon.png" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta name="theme-color" content="#FC72FF" />
|
||||
<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
|
||||
content="script-src 'self' 'unsafe-inline'"
|
||||
|
||||
/>
|
||||
|
||||
<!--
|
||||
Apple Smart App Banner for Safari on iOS
|
||||
https://developer.apple.com/documentation/webkit/promoting_apps_with_smart_app_banners
|
||||
-->
|
||||
<meta name="apple-itunes-app" content="app-id=6443944476">
|
||||
|
||||
<!--
|
||||
manifest.json provides metadata used when the app is installed as a PWA.
|
||||
See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
|
||||
<link rel="preload" href="/fonts/Basel-Book.woff" as="font" type="font/woff" crossorigin />
|
||||
<link rel="preload" href="/fonts/Basel-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
|
||||
<style>
|
||||
* {
|
||||
font-family: 'Basel', sans-serif;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/**
|
||||
Explicitly load Basel var from public/ so it does not block LCP's critical path.
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Basel';
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Medium.woff) format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Basel';
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Book.woff) format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
button {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
font-weight: 485;
|
||||
font-variant: none;
|
||||
font-smooth: always;
|
||||
text-rendering: optimizeLegibility !important;
|
||||
-webkit-font-smoothing: antialiased !important;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/* Use this to apply network-specific gradient backgrounds, in RadialGradientByChainUpdater.ts */
|
||||
#background-radial-gradient {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
pointer-events: none;
|
||||
width: 200vw;
|
||||
height: 200vh;
|
||||
transform: translate(-50vw, -100vh);
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html {
|
||||
background: linear-gradient(180deg, #202738 0%, #070816 100%);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
html {
|
||||
background: radial-gradient(100% 100% at 50% 0%, rgba(255, 184, 226, 0.51) 0%, rgba(255, 255, 255, 0) 100%), #FFFFFF
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script defer src="/static/js/bundle.js"></script><meta property="og:title" content="Uniswap Interface"/><meta property="og:image" content="http://127.0.0.1:3000/images/1200x630_Rich_Link_Preview_Image.png"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="Uniswap Interface"/><meta property="og:type" content="website"/><meta property="og:url" content="http://127.0.0.1:3000/"/><meta property="twitter:card" content="summary_large_image"/><meta property="twitter:title" content="Uniswap Interface"/><meta property="twitter:image" content="http://127.0.0.1:3000/images/1200x630_Rich_Link_Preview_Image.png"/><meta property="twitter:image:alt" content="Uniswap Interface"/></head>
|
||||
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
|
||||
<div id="root">
|
||||
<!-- Triggers the font to load immediately and then is replaced by the app -->
|
||||
<div> </div>
|
||||
</div>
|
||||
|
||||
<div id="background-radial-gradient"></div>
|
||||
</body>
|
||||
</html>
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`should inject metadata for valid collections 2`] = `
|
||||
"<!DOCTYPE html>
|
||||
<html translate="no">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<title>Uniswap Interface</title>
|
||||
<meta name="description" content="Swap or provide liquidity on the Uniswap Protocol" />
|
||||
|
||||
<!--
|
||||
will be replaced with the URL of the \`public\` folder during build.
|
||||
Only files inside the \`public\` folder can be referenced from the HTML.
|
||||
-->
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="/images/192x192_App_Icon.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="/images/512x512_App_Icon.png" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta name="theme-color" content="#FC72FF" />
|
||||
<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
|
||||
content="script-src 'self' 'unsafe-inline'"
|
||||
|
||||
/>
|
||||
|
||||
<!--
|
||||
Apple Smart App Banner for Safari on iOS
|
||||
https://developer.apple.com/documentation/webkit/promoting_apps_with_smart_app_banners
|
||||
-->
|
||||
<meta name="apple-itunes-app" content="app-id=6443944476">
|
||||
|
||||
<!--
|
||||
manifest.json provides metadata used when the app is installed as a PWA.
|
||||
See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
|
||||
<link rel="preload" href="/fonts/Basel-Book.woff" as="font" type="font/woff" crossorigin />
|
||||
<link rel="preload" href="/fonts/Basel-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
|
||||
<style>
|
||||
* {
|
||||
font-family: 'Basel', sans-serif;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/**
|
||||
Explicitly load Basel var from public/ so it does not block LCP's critical path.
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Basel';
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Medium.woff) format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Basel';
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Book.woff) format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
button {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
font-weight: 485;
|
||||
font-variant: none;
|
||||
font-smooth: always;
|
||||
text-rendering: optimizeLegibility !important;
|
||||
-webkit-font-smoothing: antialiased !important;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/* Use this to apply network-specific gradient backgrounds, in RadialGradientByChainUpdater.ts */
|
||||
#background-radial-gradient {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
pointer-events: none;
|
||||
width: 200vw;
|
||||
height: 200vh;
|
||||
transform: translate(-50vw, -100vh);
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html {
|
||||
background: linear-gradient(180deg, #202738 0%, #070816 100%);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
html {
|
||||
background: radial-gradient(100% 100% at 50% 0%, rgba(255, 184, 226, 0.51) 0%, rgba(255, 255, 255, 0) 100%), #FFFFFF
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script defer src="/static/js/bundle.js"></script><meta property="og:title" content="Uniswap Interface"/><meta property="og:image" content="http://127.0.0.1:3000/images/1200x630_Rich_Link_Preview_Image.png"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="Uniswap Interface"/><meta property="og:type" content="website"/><meta property="og:url" content="http://127.0.0.1:3000/swap"/><meta property="twitter:card" content="summary_large_image"/><meta property="twitter:title" content="Uniswap Interface"/><meta property="twitter:image" content="http://127.0.0.1:3000/images/1200x630_Rich_Link_Preview_Image.png"/><meta property="twitter:image:alt" content="Uniswap Interface"/></head>
|
||||
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
|
||||
<div id="root">
|
||||
<!-- Triggers the font to load immediately and then is replaced by the app -->
|
||||
<div> </div>
|
||||
</div>
|
||||
|
||||
<div id="background-radial-gradient"></div>
|
||||
</body>
|
||||
</html>
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`should inject metadata for valid collections 3`] = `
|
||||
"<!DOCTYPE html>
|
||||
<html translate="no">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<title>Uniswap Interface</title>
|
||||
<meta name="description" content="Swap or provide liquidity on the Uniswap Protocol" />
|
||||
|
||||
<!--
|
||||
will be replaced with the URL of the \`public\` folder during build.
|
||||
Only files inside the \`public\` folder can be referenced from the HTML.
|
||||
-->
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="/images/192x192_App_Icon.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="/images/512x512_App_Icon.png" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta name="theme-color" content="#FC72FF" />
|
||||
<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
|
||||
content="script-src 'self' 'unsafe-inline'"
|
||||
|
||||
/>
|
||||
|
||||
<!--
|
||||
Apple Smart App Banner for Safari on iOS
|
||||
https://developer.apple.com/documentation/webkit/promoting_apps_with_smart_app_banners
|
||||
-->
|
||||
<meta name="apple-itunes-app" content="app-id=6443944476">
|
||||
|
||||
<!--
|
||||
manifest.json provides metadata used when the app is installed as a PWA.
|
||||
See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
|
||||
<link rel="preload" href="/fonts/Basel-Book.woff" as="font" type="font/woff" crossorigin />
|
||||
<link rel="preload" href="/fonts/Basel-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
|
||||
<style>
|
||||
* {
|
||||
font-family: 'Basel', sans-serif;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/**
|
||||
Explicitly load Basel var from public/ so it does not block LCP's critical path.
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Basel';
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Medium.woff) format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Basel';
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Book.woff) format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
button {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
font-weight: 485;
|
||||
font-variant: none;
|
||||
font-smooth: always;
|
||||
text-rendering: optimizeLegibility !important;
|
||||
-webkit-font-smoothing: antialiased !important;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/* Use this to apply network-specific gradient backgrounds, in RadialGradientByChainUpdater.ts */
|
||||
#background-radial-gradient {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
pointer-events: none;
|
||||
width: 200vw;
|
||||
height: 200vh;
|
||||
transform: translate(-50vw, -100vh);
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html {
|
||||
background: linear-gradient(180deg, #202738 0%, #070816 100%);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
html {
|
||||
background: radial-gradient(100% 100% at 50% 0%, rgba(255, 184, 226, 0.51) 0%, rgba(255, 255, 255, 0) 100%), #FFFFFF
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script defer src="/static/js/bundle.js"></script><meta property="og:title" content="Uniswap Interface"/><meta property="og:image" content="http://127.0.0.1:3000/images/1200x630_Rich_Link_Preview_Image.png"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="Uniswap Interface"/><meta property="og:type" content="website"/><meta property="og:url" content="http://127.0.0.1:3000/pools"/><meta property="twitter:card" content="summary_large_image"/><meta property="twitter:title" content="Uniswap Interface"/><meta property="twitter:image" content="http://127.0.0.1:3000/images/1200x630_Rich_Link_Preview_Image.png"/><meta property="twitter:image:alt" content="Uniswap Interface"/></head>
|
||||
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
|
||||
<div id="root">
|
||||
<!-- Triggers the font to load immediately and then is replaced by the app -->
|
||||
<div> </div>
|
||||
</div>
|
||||
|
||||
<div id="background-radial-gradient"></div>
|
||||
</body>
|
||||
</html>
|
||||
"
|
||||
`;
|
||||
71
functions/api/image/nfts/asset/[[index]].tsx
Normal file
@@ -0,0 +1,71 @@
|
||||
/* eslint-disable import/no-unused-modules */
|
||||
import { ImageResponse } from '@vercel/og'
|
||||
import React from 'react'
|
||||
|
||||
import { WATERMARK_URL } from '../../../../constants'
|
||||
import getAsset from '../../../../utils/getAsset'
|
||||
import getFont from '../../../../utils/getFont'
|
||||
import { getRequest } from '../../../../utils/getRequest'
|
||||
|
||||
export const onRequest: PagesFunction = async ({ params, request }) => {
|
||||
try {
|
||||
const origin = new URL(request.url).origin
|
||||
const { index } = params
|
||||
const collectionAddress = index[0]?.toString()
|
||||
const tokenId = index[1]?.toString()
|
||||
const cacheUrl = origin + '/nfts/asset/' + collectionAddress + '/' + tokenId
|
||||
|
||||
const data = await getRequest(
|
||||
cacheUrl,
|
||||
() => getAsset(collectionAddress, tokenId, cacheUrl),
|
||||
(data): data is NonNullable<Awaited<ReturnType<typeof getAsset>>> => Boolean(data.ogImage)
|
||||
)
|
||||
|
||||
if (!data) {
|
||||
return new Response('Asset not found.', { status: 404 })
|
||||
}
|
||||
|
||||
const fontData = await getFont(origin)
|
||||
|
||||
return new ImageResponse(
|
||||
(
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'column',
|
||||
width: '1200px',
|
||||
height: '630px',
|
||||
}}
|
||||
>
|
||||
<img src={data.ogImage} alt={data.title} width="1200px" />
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
bottom: '72px',
|
||||
right: '72px',
|
||||
display: 'flex',
|
||||
gap: '24px',
|
||||
}}
|
||||
>
|
||||
<img src={WATERMARK_URL} alt="Uniswap" height="72px" width="324px" />
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
{
|
||||
width: 1200,
|
||||
height: 630,
|
||||
fonts: [
|
||||
{
|
||||
name: 'Inter',
|
||||
data: fontData,
|
||||
style: 'normal',
|
||||
},
|
||||
],
|
||||
}
|
||||
) as Response
|
||||
} catch (error: any) {
|
||||
return new Response(error.message || error.toString(), { status: 500 })
|
||||
}
|
||||
}
|
||||
20
functions/api/image/nfts/asset/nftImage.test.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
const assetImageUrl = [
|
||||
'http://127.0.0.1:3000/api/image/nfts/asset/0xed5af388653567af2f388e6224dc7c4b3241c544/804',
|
||||
'http://127.0.0.1:3000/api/image/nfts/asset/0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb/3947',
|
||||
]
|
||||
|
||||
test.each(assetImageUrl)('assetImageUrl', async (url) => {
|
||||
const response = await fetch(new Request(url))
|
||||
expect(response.status).toBe(200)
|
||||
expect(response.headers.get('content-type')).toBe('image/png')
|
||||
})
|
||||
|
||||
const invalidAssetImageUrl = [
|
||||
'http://127.0.0.1:3000/api/image/nfts/asset/0xed5af388653567af2f388e6224dc7c4b3241c544/10001',
|
||||
'http://127.0.0.1:3000/api/image/nfts/asset/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d/44700',
|
||||
]
|
||||
|
||||
test.each(invalidAssetImageUrl)('invalidAssetImageUrl', async (url) => {
|
||||
const response = await fetch(new Request(url))
|
||||
expect(response.status).toBe(404)
|
||||
})
|
||||
117
functions/api/image/nfts/collection/[index].tsx
Normal file
@@ -0,0 +1,117 @@
|
||||
/* eslint-disable import/no-unused-modules */
|
||||
import { ImageResponse } from '@vercel/og'
|
||||
import React from 'react'
|
||||
|
||||
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'
|
||||
|
||||
export const onRequest: PagesFunction = async ({ params, request }) => {
|
||||
try {
|
||||
const origin = new URL(request.url).origin
|
||||
const { index } = params
|
||||
const collectionAddress = index?.toString()
|
||||
const cacheUrl = origin + '/nfts/collection/' + collectionAddress
|
||||
|
||||
const data = await getRequest(
|
||||
cacheUrl,
|
||||
() => getCollection(collectionAddress, cacheUrl),
|
||||
(data): data is NonNullable<Awaited<ReturnType<typeof getCollection>>> =>
|
||||
Boolean(data.ogImage && data.name && data.isVerified)
|
||||
)
|
||||
|
||||
if (!data) {
|
||||
return new Response('Collection not found.', { status: 404 })
|
||||
}
|
||||
|
||||
const [fontData, palette] = await Promise.all([getFont(origin), getColor(data.ogImage)])
|
||||
|
||||
// Split name into words to wrap them since satori does not support inline text wrapping
|
||||
const words = data.name.split(' ')
|
||||
|
||||
return new ImageResponse(
|
||||
(
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: 'black',
|
||||
display: 'flex',
|
||||
width: '1200px',
|
||||
height: '630px',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
backgroundColor: `rgba(${palette[0]}, ${palette[1]}, ${palette[2]}, 0.75)`,
|
||||
padding: '72px',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-end',
|
||||
gap: '48px',
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src={data.ogImage}
|
||||
alt={data.name}
|
||||
width="500px"
|
||||
height="500px"
|
||||
style={{
|
||||
borderRadius: '60px',
|
||||
objectFit: 'cover',
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '32px',
|
||||
width: '45%',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
gap: '12px',
|
||||
fontSize: '72px',
|
||||
fontFamily: 'Inter',
|
||||
color: 'white',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
flexWrap: 'wrap',
|
||||
}}
|
||||
>
|
||||
{words.map((word: string) => (
|
||||
<text key={word + index}>{word}</text>
|
||||
))}
|
||||
{data.isVerified && <img src={CHECK_URL} height="54px" />}
|
||||
</div>
|
||||
<img src={WATERMARK_URL} alt="Uniswap" height="72px" width="324px" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
{
|
||||
width: 1200,
|
||||
height: 630,
|
||||
fonts: [
|
||||
{
|
||||
name: 'Inter',
|
||||
data: fontData,
|
||||
style: 'normal',
|
||||
},
|
||||
],
|
||||
}
|
||||
) as Response
|
||||
} catch (error: any) {
|
||||
return new Response(error.message || error.toString(), { status: 500 })
|
||||
}
|
||||
}
|
||||
20
functions/api/image/nfts/collection/collectionImage.test.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
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(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 invalidCollectionImageUrl = [
|
||||
'http://127.0.0.1:3000/api/image/nfts/collection/0xed5af388653567af2f388e6224dc7c4b3241c545',
|
||||
]
|
||||
|
||||
test.each(invalidCollectionImageUrl)('invalidAssetImageUrl', async (url) => {
|
||||
const response = await fetch(new Request(url))
|
||||
expect(response.status).toBe(404)
|
||||
})
|
||||
177
functions/api/image/tokens/[[index]].tsx
Normal file
@@ -0,0 +1,177 @@
|
||||
/* eslint-disable import/no-unused-modules */
|
||||
import { ImageResponse } from '@vercel/og'
|
||||
import React from 'react'
|
||||
|
||||
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'
|
||||
import getToken from '../../../utils/getToken'
|
||||
|
||||
export const onRequest: PagesFunction = async ({ params, request }) => {
|
||||
try {
|
||||
const origin = new URL(request.url).origin
|
||||
const { index } = params
|
||||
const networkName = String(index[0])
|
||||
const tokenAddress = String(index[1])
|
||||
|
||||
const cacheUrl = origin + '/tokens/' + networkName + '/' + tokenAddress
|
||||
|
||||
const data = await getRequest(
|
||||
cacheUrl,
|
||||
() => getToken(networkName, tokenAddress, cacheUrl),
|
||||
(data): data is NonNullable<Awaited<ReturnType<typeof getToken>>> => Boolean(data.symbol && data.name)
|
||||
)
|
||||
|
||||
if (!data) {
|
||||
return new Response('Token not found.', { status: 404 })
|
||||
}
|
||||
|
||||
const [fontData, palette] = await Promise.all([getFont(origin), getColor(data.ogImage, true)])
|
||||
|
||||
const networkLogo = getNetworkLogoUrl(networkName.toUpperCase(), origin)
|
||||
|
||||
// Capitalize name such that each word starts with a capital letter
|
||||
let words = data.name.split(' ')
|
||||
words = words.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
||||
let name = words.join(' ')
|
||||
name = name.trim()
|
||||
|
||||
return new ImageResponse(
|
||||
(
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: 'black',
|
||||
display: 'flex',
|
||||
width: '1200px',
|
||||
height: '630px',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
backgroundColor: `rgba(${palette[0]}, ${palette[1]}, ${palette[2]})`,
|
||||
alignItems: 'center',
|
||||
height: '100%',
|
||||
padding: '72px',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'flex-start',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
color: 'white',
|
||||
}}
|
||||
>
|
||||
{data.ogImage ? (
|
||||
<img src={data.ogImage} width="144px" style={{ borderRadius: '100%' }}>
|
||||
{networkLogo != '' && (
|
||||
<img
|
||||
src={networkLogo}
|
||||
width="48px"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
right: '2px',
|
||||
bottom: '0px',
|
||||
borderRadius: '100%',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</img>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
width: '144px',
|
||||
height: '144px',
|
||||
borderRadius: '100%',
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.12)',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontFamily: 'Inter',
|
||||
fontSize: '48px',
|
||||
lineHeight: '58px',
|
||||
color: 'white',
|
||||
}}
|
||||
>
|
||||
{data.name.slice(0, 3).toUpperCase()}
|
||||
</div>
|
||||
{networkLogo != '' && (
|
||||
<img
|
||||
src={networkLogo}
|
||||
width="48px"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
right: '2px',
|
||||
bottom: '0px',
|
||||
borderRadius: '100%',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
style={{
|
||||
fontFamily: 'Inter',
|
||||
fontSize: '72px',
|
||||
lineHeight: '72px',
|
||||
marginLeft: '-5px',
|
||||
marginTop: '24px',
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'flex-end',
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontFamily: 'Inter',
|
||||
fontSize: '168px',
|
||||
lineHeight: '133px',
|
||||
marginLeft: '-13px',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
{data.symbol}
|
||||
</div>
|
||||
<img src={WATERMARK_URL} alt="Uniswap" height="72px" width="324px" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
{
|
||||
width: 1200,
|
||||
height: 630,
|
||||
fonts: [
|
||||
{
|
||||
name: 'Inter',
|
||||
data: fontData,
|
||||
style: 'normal',
|
||||
},
|
||||
],
|
||||
}
|
||||
) as Response
|
||||
} catch (error: any) {
|
||||
return new Response(error.message || error.toString(), { status: 500 })
|
||||
}
|
||||
}
|
||||
22
functions/api/image/tokens/tokenImage.test.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
const tokenImageUrl = [
|
||||
'http://127.0.0.1:3000/api/image/tokens/ethereum/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
||||
'http://127.0.0.1:3000/api/image/tokens/ethereum/NATIVE',
|
||||
]
|
||||
|
||||
test.each(tokenImageUrl)('tokenImageUrl', async (url) => {
|
||||
const response = await fetch(new Request(url))
|
||||
expect(response.status).toBe(200)
|
||||
expect(response.headers.get('content-type')).toBe('image/png')
|
||||
})
|
||||
|
||||
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/potato/?potato=1',
|
||||
]
|
||||
|
||||
test.each(invalidTokenImageUrl)('invalidAssetImageUrl', async (url) => {
|
||||
const response = await fetch(new Request(url))
|
||||
expect(response.status).toBe(404)
|
||||
})
|
||||
38
functions/components/metaTagInjector.test.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
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',
|
||||
})
|
||||
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)
|
||||
})
|
||||
@@ -2,6 +2,7 @@ type MetaTagInjectorInput = {
|
||||
title: string
|
||||
image?: string
|
||||
url: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -18,6 +19,9 @@ export class MetaTagInjector implements HTMLRewriterElementContentHandlers {
|
||||
element(element: Element) {
|
||||
//Open Graph Tags
|
||||
this.append(element, 'og:title', this.input.title)
|
||||
if (this.input.description) {
|
||||
this.append(element, 'og:description', this.input.description)
|
||||
}
|
||||
if (this.input.image) {
|
||||
this.append(element, 'og:image', this.input.image)
|
||||
this.append(element, 'og:image:width', '1200')
|
||||
|
||||
76
functions/constants.ts
Normal file
@@ -0,0 +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],
|
||||
}
|
||||
22
functions/default.test.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
const defaultUrls = ['http://127.0.0.1:3000/', 'http://127.0.0.1:3000/swap', 'http://127.0.0.1:3000/pools']
|
||||
|
||||
test.each(defaultUrls)('should inject metadata for valid collections', async (defaultUrl) => {
|
||||
const body = await fetch(new Request(defaultUrl)).then((res) => res.text())
|
||||
expect(body).toContain(`<meta property="og:title" content="Uniswap Interface"/>`)
|
||||
expect(body).toContain(
|
||||
`<meta property="og:description" content="Swap or provide liquidity on the Uniswap Protocol"/>`
|
||||
)
|
||||
expect(body).toContain(
|
||||
`<meta property="og:image" content="http://127.0.0.1:3000/images/1200x630_Rich_Link_Preview_Image.png"/>`
|
||||
)
|
||||
expect(body).toContain(`<meta property="og:image:width" content="1200"/>`)
|
||||
expect(body).toContain(`<meta property="og:image:height" content="630"/>`)
|
||||
expect(body).toContain(`<meta property="og:type" content="website"/>`)
|
||||
expect(body).toContain(`<meta property="og:image:alt" content="Uniswap Interface"/>`)
|
||||
expect(body).toContain(`<meta property="twitter:card" content="summary_large_image"/>`)
|
||||
expect(body).toContain(`<meta property="twitter:title" content="Uniswap Interface"/>`)
|
||||
expect(body).toContain(
|
||||
`<meta property="twitter:image" content="http://127.0.0.1:3000/images/1200x630_Rich_Link_Preview_Image.png"/>`
|
||||
)
|
||||
expect(body).toContain(`<meta property="twitter:image:alt" content="Uniswap Interface"/>`)
|
||||
})
|
||||
@@ -4,6 +4,16 @@ module.exports = async function globalSetup() {
|
||||
globalThis.servers = await setup({
|
||||
command: `yarn start:cloud`,
|
||||
port: 3000,
|
||||
launchTimeout: 50000,
|
||||
launchTimeout: 120000, // takes ~2m on CI
|
||||
})
|
||||
// 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')
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"globalSetup": "<rootDir>/global-setup.ts",
|
||||
"globalTeardown": "<rootDir>/global-teardown.ts",
|
||||
"setupFilesAfterEnv": ["<rootDir>/setupAfterEnv.ts"],
|
||||
"preset": "ts-jest",
|
||||
"transform": {
|
||||
"'^.+\\.(ts|tsx)?$'": "ts-jest",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint-disable import/no-unused-modules */
|
||||
import getAsset from '../../utils/getAsset'
|
||||
import getRequest from '../../utils/getRequest'
|
||||
import { getMetadataRequest } from '../../utils/getRequest'
|
||||
|
||||
export const onRequest: PagesFunction = async ({ params, request, next }) => {
|
||||
const res = next()
|
||||
@@ -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 getRequest(res, request.url, () => getAsset(collectionAddress, tokenId, request.url))
|
||||
return getMetadataRequest(res, request.url, () => getAsset(collectionAddress, tokenId, request.url))
|
||||
} catch (e) {
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -7,15 +7,14 @@ exports[`should inject metadata for valid assets 1`] = `
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<title>Uniswap Interface</title>
|
||||
<meta name="description" content="Swap or provide liquidity on the Uniswap Protocol" />
|
||||
|
||||
<!--
|
||||
. will be replaced with the URL of the \`public\` folder during build.
|
||||
will be replaced with the URL of the \`public\` folder during build.
|
||||
Only files inside the \`public\` folder can be referenced from the HTML.
|
||||
-->
|
||||
<link rel="shortcut icon" type="image/png" href="./favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="./images/192x192_App_Icon.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="./images/512x512_App_Icon.png" />
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="/images/192x192_App_Icon.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="/images/512x512_App_Icon.png" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta name="theme-color" content="#FC72FF" />
|
||||
@@ -36,33 +35,45 @@ exports[`should inject metadata for valid assets 1`] = `
|
||||
manifest.json provides metadata used when the app is installed as a PWA.
|
||||
See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="./manifest.json" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
|
||||
<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-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
|
||||
<style>
|
||||
* {
|
||||
font-family: 'Inter', sans-serif;
|
||||
font-family: 'Basel', sans-serif;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/**
|
||||
Explicitly load Inter var from public/ so it does not block LCP's critical path.
|
||||
Explicitly load Basel var from public/ so it does not block LCP's critical path.
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Inter custom';
|
||||
font-weight: 100 900;
|
||||
font-family: 'Basel';
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
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');
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Medium.woff) format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Basel';
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Book.woff) format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Inter custom', sans-serif;
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,9 +89,11 @@ exports[`should inject metadata for valid assets 1`] = `
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
font-weight: 485;
|
||||
font-variant: none;
|
||||
font-smooth: always;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility !important;
|
||||
-webkit-font-smoothing: antialiased !important;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
@@ -116,7 +129,7 @@ exports[`should inject metadata for valid assets 1`] = `
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script defer src="./static/js/bundle.js"></script><meta property="og:title" content="Azuki #2550"/><meta property="og:image" content="https://cdn.center.app/1/0xED5AF388653567Af2F388E6224dC7C4b3241C544/2550/d268b7f60a56306ced68b9762709ceaff4f1ee939f3150e7363fae300a59da12.png"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="Azuki #2550"/><meta property="og:type" content="website"/><meta property="og:url" content="http://127.0.0.1:3000/nfts/asset/0xed5af388653567af2f388e6224dc7c4b3241c544/2550"/><meta property="twitter:card" content="summary_large_image"/><meta property="twitter:title" content="Azuki #2550"/><meta property="twitter:image" content="https://cdn.center.app/1/0xED5AF388653567Af2F388E6224dC7C4b3241C544/2550/d268b7f60a56306ced68b9762709ceaff4f1ee939f3150e7363fae300a59da12.png"/><meta property="twitter:image:alt" content="Azuki #2550"/></head>
|
||||
<script defer src="/static/js/bundle.js"></script><meta property="og:title" content="Azuki #2550"/><meta property="og:image" content="http://127.0.0.1:3000/api/image/nfts/asset/0xed5af388653567af2f388e6224dc7c4b3241c544/2550"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="Azuki #2550"/><meta property="og:type" content="website"/><meta property="og:url" content="http://127.0.0.1:3000/nfts/asset/0xed5af388653567af2f388e6224dc7c4b3241c544/2550"/><meta property="twitter:card" content="summary_large_image"/><meta property="twitter:title" content="Azuki #2550"/><meta property="twitter:image" content="http://127.0.0.1:3000/api/image/nfts/asset/0xed5af388653567af2f388e6224dc7c4b3241c544/2550"/><meta property="twitter:image:alt" content="Azuki #2550"/></head>
|
||||
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
@@ -139,15 +152,14 @@ exports[`should inject metadata for valid assets 2`] = `
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<title>Uniswap Interface</title>
|
||||
<meta name="description" content="Swap or provide liquidity on the Uniswap Protocol" />
|
||||
|
||||
<!--
|
||||
. will be replaced with the URL of the \`public\` folder during build.
|
||||
will be replaced with the URL of the \`public\` folder during build.
|
||||
Only files inside the \`public\` folder can be referenced from the HTML.
|
||||
-->
|
||||
<link rel="shortcut icon" type="image/png" href="./favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="./images/192x192_App_Icon.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="./images/512x512_App_Icon.png" />
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="/images/192x192_App_Icon.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="/images/512x512_App_Icon.png" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta name="theme-color" content="#FC72FF" />
|
||||
@@ -168,33 +180,45 @@ exports[`should inject metadata for valid assets 2`] = `
|
||||
manifest.json provides metadata used when the app is installed as a PWA.
|
||||
See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="./manifest.json" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
|
||||
<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-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
|
||||
<style>
|
||||
* {
|
||||
font-family: 'Inter', sans-serif;
|
||||
font-family: 'Basel', sans-serif;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/**
|
||||
Explicitly load Inter var from public/ so it does not block LCP's critical path.
|
||||
Explicitly load Basel var from public/ so it does not block LCP's critical path.
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Inter custom';
|
||||
font-weight: 100 900;
|
||||
font-family: 'Basel';
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
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');
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Medium.woff) format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Basel';
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Book.woff) format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Inter custom', sans-serif;
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,9 +234,11 @@ exports[`should inject metadata for valid assets 2`] = `
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
font-weight: 485;
|
||||
font-variant: none;
|
||||
font-smooth: always;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility !important;
|
||||
-webkit-font-smoothing: antialiased !important;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
@@ -248,7 +274,7 @@ exports[`should inject metadata for valid assets 2`] = `
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script defer src="./static/js/bundle.js"></script><meta property="og:title" content="Bored Ape Yacht Club #3735"/><meta property="og:image" content="https://cdn.center.app/v2/1/697f69bb495aaa24c66638cae921977354f0b8274fc2e2814e455f355e67f01d/88c2ac6b73288e41051d3fd58ff3cef1f4908403f05f4a7d2a8435d003758529.png"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="Bored Ape Yacht Club #3735"/><meta property="og:type" content="website"/><meta property="og:url" content="http://127.0.0.1:3000/nfts/asset/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d/3735"/><meta property="twitter:card" content="summary_large_image"/><meta property="twitter:title" content="Bored Ape Yacht Club #3735"/><meta property="twitter:image" content="https://cdn.center.app/v2/1/697f69bb495aaa24c66638cae921977354f0b8274fc2e2814e455f355e67f01d/88c2ac6b73288e41051d3fd58ff3cef1f4908403f05f4a7d2a8435d003758529.png"/><meta property="twitter:image:alt" content="Bored Ape Yacht Club #3735"/></head>
|
||||
<script defer src="/static/js/bundle.js"></script><meta property="og:title" content="Bored Ape Yacht Club #3735"/><meta property="og:image" content="http://127.0.0.1:3000/api/image/nfts/asset/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d/3735"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="Bored Ape Yacht Club #3735"/><meta property="og:type" content="website"/><meta property="og:url" content="http://127.0.0.1:3000/nfts/asset/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d/3735"/><meta property="twitter:card" content="summary_large_image"/><meta property="twitter:title" content="Bored Ape Yacht Club #3735"/><meta property="twitter:image" content="http://127.0.0.1:3000/api/image/nfts/asset/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d/3735"/><meta property="twitter:image:alt" content="Bored Ape Yacht Club #3735"/></head>
|
||||
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
@@ -271,15 +297,14 @@ exports[`should inject metadata for valid assets 3`] = `
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<title>Uniswap Interface</title>
|
||||
<meta name="description" content="Swap or provide liquidity on the Uniswap Protocol" />
|
||||
|
||||
<!--
|
||||
. will be replaced with the URL of the \`public\` folder during build.
|
||||
will be replaced with the URL of the \`public\` folder during build.
|
||||
Only files inside the \`public\` folder can be referenced from the HTML.
|
||||
-->
|
||||
<link rel="shortcut icon" type="image/png" href="./favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="./images/192x192_App_Icon.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="./images/512x512_App_Icon.png" />
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="/images/192x192_App_Icon.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="/images/512x512_App_Icon.png" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta name="theme-color" content="#FC72FF" />
|
||||
@@ -300,33 +325,45 @@ exports[`should inject metadata for valid assets 3`] = `
|
||||
manifest.json provides metadata used when the app is installed as a PWA.
|
||||
See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="./manifest.json" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
|
||||
<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-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
|
||||
<style>
|
||||
* {
|
||||
font-family: 'Inter', sans-serif;
|
||||
font-family: 'Basel', sans-serif;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/**
|
||||
Explicitly load Inter var from public/ so it does not block LCP's critical path.
|
||||
Explicitly load Basel var from public/ so it does not block LCP's critical path.
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Inter custom';
|
||||
font-weight: 100 900;
|
||||
font-family: 'Basel';
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
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');
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Medium.woff) format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Basel';
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Book.woff) format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Inter custom', sans-serif;
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,9 +379,11 @@ exports[`should inject metadata for valid assets 3`] = `
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
font-weight: 485;
|
||||
font-variant: none;
|
||||
font-smooth: always;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility !important;
|
||||
-webkit-font-smoothing: antialiased !important;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
@@ -380,7 +419,7 @@ exports[`should inject metadata for valid assets 3`] = `
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script defer src="./static/js/bundle.js"></script><meta property="og:title" content="CryptoPunk #3947"/><meta property="og:image" content="https://cdn.center.app/1/0xb47e3cd837dDF8e4c57F05d70Ab865de6e193BBB/3947/62319d784e7a816d190aa184ffe58550d6ed8eb2e117b218e2ac02f126538ee6.png"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="CryptoPunk #3947"/><meta property="og:type" content="website"/><meta property="og:url" content="http://127.0.0.1:3000/nfts/asset/0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb/3947"/><meta property="twitter:card" content="summary_large_image"/><meta property="twitter:title" content="CryptoPunk #3947"/><meta property="twitter:image" content="https://cdn.center.app/1/0xb47e3cd837dDF8e4c57F05d70Ab865de6e193BBB/3947/62319d784e7a816d190aa184ffe58550d6ed8eb2e117b218e2ac02f126538ee6.png"/><meta property="twitter:image:alt" content="CryptoPunk #3947"/></head>
|
||||
<script defer src="/static/js/bundle.js"></script><meta property="og:title" content="CryptoPunk #3947"/><meta property="og:image" content="http://127.0.0.1:3000/api/image/nfts/asset/0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb/3947"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="CryptoPunk #3947"/><meta property="og:type" content="website"/><meta property="og:url" content="http://127.0.0.1:3000/nfts/asset/0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb/3947"/><meta property="twitter:card" content="summary_large_image"/><meta property="twitter:title" content="CryptoPunk #3947"/><meta property="twitter:image" content="http://127.0.0.1:3000/api/image/nfts/asset/0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb/3947"/><meta property="twitter:image:alt" content="CryptoPunk #3947"/></head>
|
||||
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
|
||||
@@ -3,22 +3,19 @@ const assets = [
|
||||
address: '0xed5af388653567af2f388e6224dc7c4b3241c544',
|
||||
assetId: '2550',
|
||||
collectionName: 'Azuki',
|
||||
image:
|
||||
'https://cdn.center.app/1/0xED5AF388653567Af2F388E6224dC7C4b3241C544/2550/d268b7f60a56306ced68b9762709ceaff4f1ee939f3150e7363fae300a59da12.png',
|
||||
image: 'http://127.0.0.1:3000/api/image/nfts/asset/0xed5af388653567af2f388e6224dc7c4b3241c544/2550',
|
||||
},
|
||||
{
|
||||
address: '0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d',
|
||||
assetId: '3735',
|
||||
collectionName: 'Bored Ape Yacht Club',
|
||||
image:
|
||||
'https://cdn.center.app/v2/1/697f69bb495aaa24c66638cae921977354f0b8274fc2e2814e455f355e67f01d/88c2ac6b73288e41051d3fd58ff3cef1f4908403f05f4a7d2a8435d003758529.png',
|
||||
image: 'http://127.0.0.1:3000/api/image/nfts/asset/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d/3735',
|
||||
},
|
||||
{
|
||||
address: '0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb',
|
||||
assetId: '3947',
|
||||
collectionName: 'CryptoPunk',
|
||||
image:
|
||||
'https://cdn.center.app/1/0xb47e3cd837dDF8e4c57F05d70Ab865de6e193BBB/3947/62319d784e7a816d190aa184ffe58550d6ed8eb2e117b218e2ac02f126538ee6.png',
|
||||
image: 'http://127.0.0.1:3000/api/image/nfts/asset/0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb/3947',
|
||||
},
|
||||
]
|
||||
|
||||
@@ -27,6 +24,7 @@ test.each(assets)('should inject metadata for valid assets', async (nft) => {
|
||||
const body = await fetch(new Request(url)).then((res) => res.text())
|
||||
expect(body).toMatchSnapshot()
|
||||
expect(body).toContain(`<meta property="og:title" content="${nft.collectionName} #${nft.assetId}"/>`)
|
||||
expect(body).not.toContain(`<meta property="og:description"`)
|
||||
expect(body).toContain(`<meta property="og:image" content="${nft.image}"/>`)
|
||||
expect(body).toContain(`<meta property="og:image:width" content="1200"/>`)
|
||||
expect(body).toContain(`<meta property="og:image:height" content="630"/>`)
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/* eslint-disable import/no-unused-modules */
|
||||
import getCollection from '../../utils/getCollection'
|
||||
import getRequest from '../../utils/getRequest'
|
||||
import { getMetadataRequest } from '../../utils/getRequest'
|
||||
|
||||
export const onRequest: PagesFunction = async ({ params, request, next }) => {
|
||||
const res = next()
|
||||
try {
|
||||
const { index } = params
|
||||
const collectionAddress = index?.toString()
|
||||
return getRequest(res, request.url, () => getCollection(collectionAddress, request.url))
|
||||
return getMetadataRequest(res, request.url, () => getCollection(collectionAddress, request.url))
|
||||
} catch (e) {
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -7,15 +7,14 @@ exports[`should inject metadata for valid collections 1`] = `
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<title>Uniswap Interface</title>
|
||||
<meta name="description" content="Swap or provide liquidity on the Uniswap Protocol" />
|
||||
|
||||
<!--
|
||||
. will be replaced with the URL of the \`public\` folder during build.
|
||||
will be replaced with the URL of the \`public\` folder during build.
|
||||
Only files inside the \`public\` folder can be referenced from the HTML.
|
||||
-->
|
||||
<link rel="shortcut icon" type="image/png" href="./favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="./images/192x192_App_Icon.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="./images/512x512_App_Icon.png" />
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="/images/192x192_App_Icon.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="/images/512x512_App_Icon.png" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta name="theme-color" content="#FC72FF" />
|
||||
@@ -36,33 +35,45 @@ exports[`should inject metadata for valid collections 1`] = `
|
||||
manifest.json provides metadata used when the app is installed as a PWA.
|
||||
See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="./manifest.json" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
|
||||
<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-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
|
||||
<style>
|
||||
* {
|
||||
font-family: 'Inter', sans-serif;
|
||||
font-family: 'Basel', sans-serif;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/**
|
||||
Explicitly load Inter var from public/ so it does not block LCP's critical path.
|
||||
Explicitly load Basel var from public/ so it does not block LCP's critical path.
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Inter custom';
|
||||
font-weight: 100 900;
|
||||
font-family: 'Basel';
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
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');
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Medium.woff) format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Basel';
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Book.woff) format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Inter custom', sans-serif;
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,9 +89,11 @@ exports[`should inject metadata for valid collections 1`] = `
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
font-weight: 485;
|
||||
font-variant: none;
|
||||
font-smooth: always;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility !important;
|
||||
-webkit-font-smoothing: antialiased !important;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
@@ -116,7 +129,7 @@ exports[`should inject metadata for valid collections 1`] = `
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script defer src="./static/js/bundle.js"></script><meta property="og:title" content="Azuki on Uniswap"/><meta property="og:image" content="https://i.seadn.io/gae/H8jOCJuQokNqGBpkBN5wk1oZwO7LM8bNnrHCaekV2nKjnCqw6UB5oaH8XyNeBDj6bA_n1mjejzhFQUP3O1NfjFLHr3FOaeHcTOOT?w=500&auto=format"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="Azuki on Uniswap"/><meta property="og:type" content="website"/><meta property="og:url" content="http://127.0.0.1:3000/nfts/collection/0xed5af388653567af2f388e6224dc7c4b3241c544"/><meta property="twitter:card" content="summary_large_image"/><meta property="twitter:title" content="Azuki on Uniswap"/><meta property="twitter:image" content="https://i.seadn.io/gae/H8jOCJuQokNqGBpkBN5wk1oZwO7LM8bNnrHCaekV2nKjnCqw6UB5oaH8XyNeBDj6bA_n1mjejzhFQUP3O1NfjFLHr3FOaeHcTOOT?w=500&auto=format"/><meta property="twitter:image:alt" content="Azuki on Uniswap"/></head>
|
||||
<script defer src="/static/js/bundle.js"></script><meta property="og:title" content="Azuki on Uniswap"/><meta property="og:image" content="http://127.0.0.1:3000/api/image/nfts/collection/0xed5af388653567af2f388e6224dc7c4b3241c544"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="Azuki on Uniswap"/><meta property="og:type" content="website"/><meta property="og:url" content="http://127.0.0.1:3000/nfts/collection/0xed5af388653567af2f388e6224dc7c4b3241c544"/><meta property="twitter:card" content="summary_large_image"/><meta property="twitter:title" content="Azuki on Uniswap"/><meta property="twitter:image" content="http://127.0.0.1:3000/api/image/nfts/collection/0xed5af388653567af2f388e6224dc7c4b3241c544"/><meta property="twitter:image:alt" content="Azuki on Uniswap"/></head>
|
||||
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
@@ -139,15 +152,14 @@ exports[`should inject metadata for valid collections 2`] = `
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<title>Uniswap Interface</title>
|
||||
<meta name="description" content="Swap or provide liquidity on the Uniswap Protocol" />
|
||||
|
||||
<!--
|
||||
. will be replaced with the URL of the \`public\` folder during build.
|
||||
will be replaced with the URL of the \`public\` folder during build.
|
||||
Only files inside the \`public\` folder can be referenced from the HTML.
|
||||
-->
|
||||
<link rel="shortcut icon" type="image/png" href="./favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="./images/192x192_App_Icon.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="./images/512x512_App_Icon.png" />
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="/images/192x192_App_Icon.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="/images/512x512_App_Icon.png" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta name="theme-color" content="#FC72FF" />
|
||||
@@ -168,33 +180,45 @@ exports[`should inject metadata for valid collections 2`] = `
|
||||
manifest.json provides metadata used when the app is installed as a PWA.
|
||||
See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="./manifest.json" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
|
||||
<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-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
|
||||
<style>
|
||||
* {
|
||||
font-family: 'Inter', sans-serif;
|
||||
font-family: 'Basel', sans-serif;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/**
|
||||
Explicitly load Inter var from public/ so it does not block LCP's critical path.
|
||||
Explicitly load Basel var from public/ so it does not block LCP's critical path.
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Inter custom';
|
||||
font-weight: 100 900;
|
||||
font-family: 'Basel';
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
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');
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Medium.woff) format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Basel';
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Book.woff) format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Inter custom', sans-serif;
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,9 +234,11 @@ exports[`should inject metadata for valid collections 2`] = `
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
font-weight: 485;
|
||||
font-variant: none;
|
||||
font-smooth: always;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility !important;
|
||||
-webkit-font-smoothing: antialiased !important;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
@@ -248,7 +274,7 @@ exports[`should inject metadata for valid collections 2`] = `
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script defer src="./static/js/bundle.js"></script><meta property="og:title" content="Bored Ape Yacht Club on Uniswap"/><meta property="og:image" content="https://i.seadn.io/gae/Ju9CkWtV-1Okvf45wo8UctR-M9He2PjILP0oOvxE89AyiPPGtrR3gysu1Zgy0hjd2xKIgjJJtWIc0ybj4Vd7wv8t3pxDGHoJBzDB?w=500&auto=format"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="Bored Ape Yacht Club on Uniswap"/><meta property="og:type" content="website"/><meta property="og:url" content="http://127.0.0.1:3000/nfts/collection/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d"/><meta property="twitter:card" content="summary_large_image"/><meta property="twitter:title" content="Bored Ape Yacht Club on Uniswap"/><meta property="twitter:image" content="https://i.seadn.io/gae/Ju9CkWtV-1Okvf45wo8UctR-M9He2PjILP0oOvxE89AyiPPGtrR3gysu1Zgy0hjd2xKIgjJJtWIc0ybj4Vd7wv8t3pxDGHoJBzDB?w=500&auto=format"/><meta property="twitter:image:alt" content="Bored Ape Yacht Club on Uniswap"/></head>
|
||||
<script defer src="/static/js/bundle.js"></script><meta property="og:title" content="Bored Ape Yacht Club on Uniswap"/><meta property="og:image" content="http://127.0.0.1:3000/api/image/nfts/collection/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="Bored Ape Yacht Club on Uniswap"/><meta property="og:type" content="website"/><meta property="og:url" content="http://127.0.0.1:3000/nfts/collection/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d"/><meta property="twitter:card" content="summary_large_image"/><meta property="twitter:title" content="Bored Ape Yacht Club on Uniswap"/><meta property="twitter:image" content="http://127.0.0.1:3000/api/image/nfts/collection/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d"/><meta property="twitter:image:alt" content="Bored Ape Yacht Club on Uniswap"/></head>
|
||||
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
@@ -271,15 +297,14 @@ exports[`should inject metadata for valid collections 3`] = `
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<title>Uniswap Interface</title>
|
||||
<meta name="description" content="Swap or provide liquidity on the Uniswap Protocol" />
|
||||
|
||||
<!--
|
||||
. will be replaced with the URL of the \`public\` folder during build.
|
||||
will be replaced with the URL of the \`public\` folder during build.
|
||||
Only files inside the \`public\` folder can be referenced from the HTML.
|
||||
-->
|
||||
<link rel="shortcut icon" type="image/png" href="./favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="./images/192x192_App_Icon.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="./images/512x512_App_Icon.png" />
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="/images/192x192_App_Icon.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="/images/512x512_App_Icon.png" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta name="theme-color" content="#FC72FF" />
|
||||
@@ -300,33 +325,45 @@ exports[`should inject metadata for valid collections 3`] = `
|
||||
manifest.json provides metadata used when the app is installed as a PWA.
|
||||
See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="./manifest.json" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
|
||||
<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-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
|
||||
<style>
|
||||
* {
|
||||
font-family: 'Inter', sans-serif;
|
||||
font-family: 'Basel', sans-serif;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/**
|
||||
Explicitly load Inter var from public/ so it does not block LCP's critical path.
|
||||
Explicitly load Basel var from public/ so it does not block LCP's critical path.
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Inter custom';
|
||||
font-weight: 100 900;
|
||||
font-family: 'Basel';
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
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');
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Medium.woff) format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Basel';
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Book.woff) format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Inter custom', sans-serif;
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,9 +379,11 @@ exports[`should inject metadata for valid collections 3`] = `
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
font-weight: 485;
|
||||
font-variant: none;
|
||||
font-smooth: always;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility !important;
|
||||
-webkit-font-smoothing: antialiased !important;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
@@ -380,7 +419,7 @@ exports[`should inject metadata for valid collections 3`] = `
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script defer src="./static/js/bundle.js"></script><meta property="og:title" content="CLONE X - X TAKASHI MURAKAMI on Uniswap"/><meta property="og:image" content="https://i.seadn.io/gae/XN0XuD8Uh3jyRWNtPTFeXJg_ht8m5ofDx6aHklOiy4amhFuWUa0JaR6It49AH8tlnYS386Q0TW_-Lmedn0UET_ko1a3CbJGeu5iHMg?w=500&auto=format"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="CLONE X - X TAKASHI MURAKAMI on Uniswap"/><meta property="og:type" content="website"/><meta property="og:url" content="http://127.0.0.1:3000/nfts/collection/0x49cf6f5d44e70224e2e23fdcdd2c053f30ada28b"/><meta property="twitter:card" content="summary_large_image"/><meta property="twitter:title" content="CLONE X - X TAKASHI MURAKAMI on Uniswap"/><meta property="twitter:image" content="https://i.seadn.io/gae/XN0XuD8Uh3jyRWNtPTFeXJg_ht8m5ofDx6aHklOiy4amhFuWUa0JaR6It49AH8tlnYS386Q0TW_-Lmedn0UET_ko1a3CbJGeu5iHMg?w=500&auto=format"/><meta property="twitter:image:alt" content="CLONE X - X TAKASHI MURAKAMI on Uniswap"/></head>
|
||||
<script defer src="/static/js/bundle.js"></script><meta property="og:title" content="CLONE X - X TAKASHI MURAKAMI on Uniswap"/><meta property="og:image" content="http://127.0.0.1:3000/api/image/nfts/collection/0x49cf6f5d44e70224e2e23fdcdd2c053f30ada28b"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="CLONE X - X TAKASHI MURAKAMI on Uniswap"/><meta property="og:type" content="website"/><meta property="og:url" content="http://127.0.0.1:3000/nfts/collection/0x49cf6f5d44e70224e2e23fdcdd2c053f30ada28b"/><meta property="twitter:card" content="summary_large_image"/><meta property="twitter:title" content="CLONE X - X TAKASHI MURAKAMI on Uniswap"/><meta property="twitter:image" content="http://127.0.0.1:3000/api/image/nfts/collection/0x49cf6f5d44e70224e2e23fdcdd2c053f30ada28b"/><meta property="twitter:image:alt" content="CLONE X - X TAKASHI MURAKAMI on Uniswap"/></head>
|
||||
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
|
||||
@@ -2,20 +2,17 @@ const collections = [
|
||||
{
|
||||
address: '0xed5af388653567af2f388e6224dc7c4b3241c544',
|
||||
collectionName: 'Azuki',
|
||||
image:
|
||||
'https://i.seadn.io/gae/H8jOCJuQokNqGBpkBN5wk1oZwO7LM8bNnrHCaekV2nKjnCqw6UB5oaH8XyNeBDj6bA_n1mjejzhFQUP3O1NfjFLHr3FOaeHcTOOT?w=500&auto=format',
|
||||
image: 'http://127.0.0.1:3000/api/image/nfts/collection/0xed5af388653567af2f388e6224dc7c4b3241c544',
|
||||
},
|
||||
{
|
||||
address: '0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d',
|
||||
collectionName: 'Bored Ape Yacht Club',
|
||||
image:
|
||||
'https://i.seadn.io/gae/Ju9CkWtV-1Okvf45wo8UctR-M9He2PjILP0oOvxE89AyiPPGtrR3gysu1Zgy0hjd2xKIgjJJtWIc0ybj4Vd7wv8t3pxDGHoJBzDB?w=500&auto=format',
|
||||
image: 'http://127.0.0.1:3000/api/image/nfts/collection/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d',
|
||||
},
|
||||
{
|
||||
address: '0x49cf6f5d44e70224e2e23fdcdd2c053f30ada28b',
|
||||
collectionName: 'CLONE X - X TAKASHI MURAKAMI',
|
||||
image:
|
||||
'https://i.seadn.io/gae/XN0XuD8Uh3jyRWNtPTFeXJg_ht8m5ofDx6aHklOiy4amhFuWUa0JaR6It49AH8tlnYS386Q0TW_-Lmedn0UET_ko1a3CbJGeu5iHMg?w=500&auto=format',
|
||||
image: 'http://127.0.0.1:3000/api/image/nfts/collection/0x49cf6f5d44e70224e2e23fdcdd2c053f30ada28b',
|
||||
},
|
||||
]
|
||||
|
||||
@@ -24,6 +21,7 @@ test.each(collections)('should inject metadata for valid collections', async (co
|
||||
const body = await fetch(new Request(url)).then((res) => res.text())
|
||||
expect(body).toMatchSnapshot()
|
||||
expect(body).toContain(`<meta property="og:title" content="${collection.collectionName} on Uniswap"/>`)
|
||||
expect(body).not.toContain(`<meta property="og:description"`)
|
||||
expect(body).toContain(`<meta property="og:image" content="${collection.image}"/>`)
|
||||
expect(body).toContain(`<meta property="og:image:width" content="1200"/>`)
|
||||
expect(body).toContain(`<meta property="og:image:height" content="630"/>`)
|
||||
@@ -38,9 +36,7 @@ test.each(collections)('should inject metadata for valid collections', async (co
|
||||
|
||||
const invalidCollections = [
|
||||
'http://127.0.0.1:3000/nfts/collection/0xed5af388653567af2f388e6224dc7c4b3241c545',
|
||||
'http://127.0.0.1:3000/nfts/collection/0xed5af388653567af2f388e6224dc7c4b3241c545/10',
|
||||
'http://127.0.0.1:3000/nfts/collection/0xed5af388653567af2f388e6224dc7c4b3241c545//',
|
||||
'http://127.0.0.1:3000/nfts/collection',
|
||||
]
|
||||
|
||||
test.each(invalidCollections)(
|
||||
|
||||
1
functions/setupAfterEnv.ts
Normal file
@@ -0,0 +1 @@
|
||||
jest.retryTimes(3)
|
||||
@@ -1,33 +1,17 @@
|
||||
/* eslint-disable import/no-unused-modules */
|
||||
import { Chain } from '../../src/graphql/data/__generated__/types-and-hooks'
|
||||
import getRequest from '../utils/getRequest'
|
||||
import { getMetadataRequest } from '../utils/getRequest'
|
||||
import getToken from '../utils/getToken'
|
||||
|
||||
const convertTokenAddress = (tokenAddress: string, networkName: string) => {
|
||||
if (tokenAddress === 'NATIVE') {
|
||||
switch (networkName) {
|
||||
case Chain.Celo:
|
||||
return '0x471EcE3750Da237f93B8E339c536989b8978a438'
|
||||
case Chain.Polygon:
|
||||
return '0x0000000000000000000000000000000000001010'
|
||||
default:
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
return tokenAddress
|
||||
}
|
||||
|
||||
export const onRequest: PagesFunction = async ({ params, request, next }) => {
|
||||
const res = next()
|
||||
try {
|
||||
const { index } = params
|
||||
const networkName = index[0]?.toString().toUpperCase()
|
||||
const tokenString = index[1]?.toString()
|
||||
if (!tokenString) {
|
||||
const networkName = index[0]?.toString()
|
||||
const tokenAddress = index[1]?.toString()
|
||||
if (!tokenAddress) {
|
||||
return res
|
||||
}
|
||||
const tokenAddress = convertTokenAddress(tokenString, networkName)
|
||||
return getRequest(res, request.url, () => getToken(networkName, tokenAddress, request.url))
|
||||
return getMetadataRequest(res, request.url, () => getToken(networkName, tokenAddress, request.url))
|
||||
} catch (e) {
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -7,15 +7,14 @@ exports[`should inject metadata for valid tokens 1`] = `
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<title>Uniswap Interface</title>
|
||||
<meta name="description" content="Swap or provide liquidity on the Uniswap Protocol" />
|
||||
|
||||
<!--
|
||||
. will be replaced with the URL of the \`public\` folder during build.
|
||||
will be replaced with the URL of the \`public\` folder during build.
|
||||
Only files inside the \`public\` folder can be referenced from the HTML.
|
||||
-->
|
||||
<link rel="shortcut icon" type="image/png" href="./favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="./images/192x192_App_Icon.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="./images/512x512_App_Icon.png" />
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="/images/192x192_App_Icon.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="/images/512x512_App_Icon.png" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta name="theme-color" content="#FC72FF" />
|
||||
@@ -36,33 +35,45 @@ exports[`should inject metadata for valid tokens 1`] = `
|
||||
manifest.json provides metadata used when the app is installed as a PWA.
|
||||
See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="./manifest.json" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
|
||||
<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-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
|
||||
<style>
|
||||
* {
|
||||
font-family: 'Inter', sans-serif;
|
||||
font-family: 'Basel', sans-serif;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/**
|
||||
Explicitly load Inter var from public/ so it does not block LCP's critical path.
|
||||
Explicitly load Basel var from public/ so it does not block LCP's critical path.
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Inter custom';
|
||||
font-weight: 100 900;
|
||||
font-family: 'Basel';
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
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');
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Medium.woff) format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Basel';
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Book.woff) format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Inter custom', sans-serif;
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,9 +89,11 @@ exports[`should inject metadata for valid tokens 1`] = `
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
font-weight: 485;
|
||||
font-variant: none;
|
||||
font-smooth: always;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility !important;
|
||||
-webkit-font-smoothing: antialiased !important;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
@@ -116,7 +129,7 @@ exports[`should inject metadata for valid tokens 1`] = `
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script defer src="./static/js/bundle.js"></script><meta property="og:title" content="Get USDC on Uniswap"/><meta property="og:image" content="https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="Get USDC on Uniswap"/><meta property="og:type" content="website"/><meta property="og:url" content="http://127.0.0.1:3000/tokens/ethereum/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"/><meta property="twitter:card" content="summary_large_image"/><meta property="twitter:title" content="Get USDC on Uniswap"/><meta property="twitter:image" content="https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png"/><meta property="twitter:image:alt" content="Get USDC on Uniswap"/></head>
|
||||
<script defer src="/static/js/bundle.js"></script><meta property="og:title" content="Get USDC on Uniswap"/><meta property="og:image" content="http://127.0.0.1:3000/api/image/tokens/ethereum/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="Get USDC on Uniswap"/><meta property="og:type" content="website"/><meta property="og:url" content="http://127.0.0.1:3000/tokens/ethereum/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"/><meta property="twitter:card" content="summary_large_image"/><meta property="twitter:title" content="Get USDC on Uniswap"/><meta property="twitter:image" content="http://127.0.0.1:3000/api/image/tokens/ethereum/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"/><meta property="twitter:image:alt" content="Get USDC on Uniswap"/></head>
|
||||
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
@@ -139,15 +152,14 @@ exports[`should inject metadata for valid tokens 2`] = `
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<title>Uniswap Interface</title>
|
||||
<meta name="description" content="Swap or provide liquidity on the Uniswap Protocol" />
|
||||
|
||||
<!--
|
||||
. will be replaced with the URL of the \`public\` folder during build.
|
||||
will be replaced with the URL of the \`public\` folder during build.
|
||||
Only files inside the \`public\` folder can be referenced from the HTML.
|
||||
-->
|
||||
<link rel="shortcut icon" type="image/png" href="./favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="./images/192x192_App_Icon.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="./images/512x512_App_Icon.png" />
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="/images/192x192_App_Icon.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="/images/512x512_App_Icon.png" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta name="theme-color" content="#FC72FF" />
|
||||
@@ -168,33 +180,45 @@ exports[`should inject metadata for valid tokens 2`] = `
|
||||
manifest.json provides metadata used when the app is installed as a PWA.
|
||||
See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="./manifest.json" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
|
||||
<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-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
|
||||
<style>
|
||||
* {
|
||||
font-family: 'Inter', sans-serif;
|
||||
font-family: 'Basel', sans-serif;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/**
|
||||
Explicitly load Inter var from public/ so it does not block LCP's critical path.
|
||||
Explicitly load Basel var from public/ so it does not block LCP's critical path.
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Inter custom';
|
||||
font-weight: 100 900;
|
||||
font-family: 'Basel';
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
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');
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Medium.woff) format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Basel';
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Book.woff) format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Inter custom', sans-serif;
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,9 +234,11 @@ exports[`should inject metadata for valid tokens 2`] = `
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
font-weight: 485;
|
||||
font-variant: none;
|
||||
font-smooth: always;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility !important;
|
||||
-webkit-font-smoothing: antialiased !important;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
@@ -248,7 +274,7 @@ exports[`should inject metadata for valid tokens 2`] = `
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script defer src="./static/js/bundle.js"></script><meta property="og:title" content="Get ETH on Uniswap"/><meta property="og:image" content="https://token-icons.s3.amazonaws.com/eth.png"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="Get ETH on Uniswap"/><meta property="og:type" content="website"/><meta property="og:url" content="http://127.0.0.1:3000/tokens/ethereum/NATIVE"/><meta property="twitter:card" content="summary_large_image"/><meta property="twitter:title" content="Get ETH on Uniswap"/><meta property="twitter:image" content="https://token-icons.s3.amazonaws.com/eth.png"/><meta property="twitter:image:alt" content="Get ETH on Uniswap"/></head>
|
||||
<script defer src="/static/js/bundle.js"></script><meta property="og:title" content="Get ETH on Uniswap"/><meta property="og:image" content="http://127.0.0.1:3000/api/image/tokens/ethereum/NATIVE"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="Get ETH on Uniswap"/><meta property="og:type" content="website"/><meta property="og:url" content="http://127.0.0.1:3000/tokens/ethereum/NATIVE"/><meta property="twitter:card" content="summary_large_image"/><meta property="twitter:title" content="Get ETH on Uniswap"/><meta property="twitter:image" content="http://127.0.0.1:3000/api/image/tokens/ethereum/NATIVE"/><meta property="twitter:image:alt" content="Get ETH on Uniswap"/></head>
|
||||
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
@@ -271,15 +297,14 @@ exports[`should inject metadata for valid tokens 3`] = `
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<title>Uniswap Interface</title>
|
||||
<meta name="description" content="Swap or provide liquidity on the Uniswap Protocol" />
|
||||
|
||||
<!--
|
||||
. will be replaced with the URL of the \`public\` folder during build.
|
||||
will be replaced with the URL of the \`public\` folder during build.
|
||||
Only files inside the \`public\` folder can be referenced from the HTML.
|
||||
-->
|
||||
<link rel="shortcut icon" type="image/png" href="./favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="./images/192x192_App_Icon.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="./images/512x512_App_Icon.png" />
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="/images/192x192_App_Icon.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="/images/512x512_App_Icon.png" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta name="theme-color" content="#FC72FF" />
|
||||
@@ -300,33 +325,45 @@ exports[`should inject metadata for valid tokens 3`] = `
|
||||
manifest.json provides metadata used when the app is installed as a PWA.
|
||||
See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="./manifest.json" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
|
||||
<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-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
|
||||
<style>
|
||||
* {
|
||||
font-family: 'Inter', sans-serif;
|
||||
font-family: 'Basel', sans-serif;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/**
|
||||
Explicitly load Inter var from public/ so it does not block LCP's critical path.
|
||||
Explicitly load Basel var from public/ so it does not block LCP's critical path.
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Inter custom';
|
||||
font-weight: 100 900;
|
||||
font-family: 'Basel';
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
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');
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Medium.woff) format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Basel';
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Book.woff) format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Inter custom', sans-serif;
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,9 +379,11 @@ exports[`should inject metadata for valid tokens 3`] = `
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
font-weight: 485;
|
||||
font-variant: none;
|
||||
font-smooth: always;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility !important;
|
||||
-webkit-font-smoothing: antialiased !important;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
@@ -380,7 +419,7 @@ exports[`should inject metadata for valid tokens 3`] = `
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script defer src="./static/js/bundle.js"></script><meta property="og:title" content="Get MATIC on Uniswap"/><meta property="og:image" content="https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0/logo.png"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="Get MATIC on Uniswap"/><meta property="og:type" content="website"/><meta property="og:url" content="http://127.0.0.1:3000/tokens/polygon/NATIVE"/><meta property="twitter:card" content="summary_large_image"/><meta property="twitter:title" content="Get MATIC on Uniswap"/><meta property="twitter:image" content="https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0/logo.png"/><meta property="twitter:image:alt" content="Get MATIC on Uniswap"/></head>
|
||||
<script defer src="/static/js/bundle.js"></script><meta property="og:title" content="Get MATIC on Uniswap"/><meta property="og:image" content="http://127.0.0.1:3000/api/image/tokens/polygon/NATIVE"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="Get MATIC on Uniswap"/><meta property="og:type" content="website"/><meta property="og:url" content="http://127.0.0.1:3000/tokens/polygon/NATIVE"/><meta property="twitter:card" content="summary_large_image"/><meta property="twitter:title" content="Get MATIC on Uniswap"/><meta property="twitter:image" content="http://127.0.0.1:3000/api/image/tokens/polygon/NATIVE"/><meta property="twitter:image:alt" content="Get MATIC on Uniswap"/></head>
|
||||
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
@@ -403,15 +442,14 @@ exports[`should inject metadata for valid tokens 4`] = `
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<title>Uniswap Interface</title>
|
||||
<meta name="description" content="Swap or provide liquidity on the Uniswap Protocol" />
|
||||
|
||||
<!--
|
||||
. will be replaced with the URL of the \`public\` folder during build.
|
||||
will be replaced with the URL of the \`public\` folder during build.
|
||||
Only files inside the \`public\` folder can be referenced from the HTML.
|
||||
-->
|
||||
<link rel="shortcut icon" type="image/png" href="./favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="./images/192x192_App_Icon.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="./images/512x512_App_Icon.png" />
|
||||
<link rel="shortcut icon" type="image/png" href="/favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="/images/192x192_App_Icon.png" />
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="/images/512x512_App_Icon.png" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta name="theme-color" content="#FC72FF" />
|
||||
@@ -432,33 +470,45 @@ exports[`should inject metadata for valid tokens 4`] = `
|
||||
manifest.json provides metadata used when the app is installed as a PWA.
|
||||
See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="./manifest.json" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
|
||||
<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-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
|
||||
<style>
|
||||
* {
|
||||
font-family: 'Inter', sans-serif;
|
||||
font-family: 'Basel', sans-serif;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/**
|
||||
Explicitly load Inter var from public/ so it does not block LCP's critical path.
|
||||
Explicitly load Basel var from public/ so it does not block LCP's critical path.
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Inter custom';
|
||||
font-weight: 100 900;
|
||||
font-family: 'Basel';
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
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');
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Medium.woff) format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Basel';
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(/fonts/Basel-Book.woff) format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Inter custom', sans-serif;
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -474,9 +524,11 @@ exports[`should inject metadata for valid tokens 4`] = `
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
font-weight: 485;
|
||||
font-variant: none;
|
||||
font-smooth: always;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility !important;
|
||||
-webkit-font-smoothing: antialiased !important;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
@@ -512,7 +564,7 @@ exports[`should inject metadata for valid tokens 4`] = `
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script defer src="./static/js/bundle.js"></script><meta property="og:title" content="Get PEPE on Uniswap"/><meta property="og:image" content="https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0x6982508145454Ce325dDbE47a25d4ec3d2311933/logo.png"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="Get PEPE on Uniswap"/><meta property="og:type" content="website"/><meta property="og:url" content="http://127.0.0.1:3000/tokens/ethereum/0x6982508145454ce325ddbe47a25d4ec3d2311933"/><meta property="twitter:card" content="summary_large_image"/><meta property="twitter:title" content="Get PEPE on Uniswap"/><meta property="twitter:image" content="https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0x6982508145454Ce325dDbE47a25d4ec3d2311933/logo.png"/><meta property="twitter:image:alt" content="Get PEPE on Uniswap"/></head>
|
||||
<script defer src="/static/js/bundle.js"></script><meta property="og:title" content="Get PEPE on Uniswap"/><meta property="og:image" content="http://127.0.0.1:3000/api/image/tokens/ethereum/0x6982508145454ce325ddbe47a25d4ec3d2311933"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:alt" content="Get PEPE on Uniswap"/><meta property="og:type" content="website"/><meta property="og:url" content="http://127.0.0.1:3000/tokens/ethereum/0x6982508145454ce325ddbe47a25d4ec3d2311933"/><meta property="twitter:card" content="summary_large_image"/><meta property="twitter:title" content="Get PEPE on Uniswap"/><meta property="twitter:image" content="http://127.0.0.1:3000/api/image/tokens/ethereum/0x6982508145454ce325ddbe47a25d4ec3d2311933"/><meta property="twitter:image:alt" content="Get PEPE on Uniswap"/></head>
|
||||
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
|
||||
@@ -3,28 +3,25 @@ const tokens = [
|
||||
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
||||
network: 'ethereum',
|
||||
symbol: 'USDC',
|
||||
image:
|
||||
'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png',
|
||||
image: 'http://127.0.0.1:3000/api/image/tokens/ethereum/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
||||
},
|
||||
{
|
||||
address: 'NATIVE',
|
||||
network: 'ethereum',
|
||||
symbol: 'ETH',
|
||||
image: 'https://token-icons.s3.amazonaws.com/eth.png',
|
||||
image: 'http://127.0.0.1:3000/api/image/tokens/ethereum/NATIVE',
|
||||
},
|
||||
{
|
||||
address: 'NATIVE',
|
||||
network: 'polygon',
|
||||
symbol: 'MATIC',
|
||||
image:
|
||||
'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0/logo.png',
|
||||
image: 'http://127.0.0.1:3000/api/image/tokens/polygon/NATIVE',
|
||||
},
|
||||
{
|
||||
address: '0x6982508145454ce325ddbe47a25d4ec3d2311933',
|
||||
network: 'ethereum',
|
||||
symbol: 'PEPE',
|
||||
image:
|
||||
'https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/ethereum/assets/0x6982508145454Ce325dDbE47a25d4ec3d2311933/logo.png',
|
||||
image: 'http://127.0.0.1:3000/api/image/tokens/ethereum/0x6982508145454ce325ddbe47a25d4ec3d2311933',
|
||||
},
|
||||
]
|
||||
|
||||
@@ -33,6 +30,7 @@ test.each(tokens)('should inject metadata for valid tokens', async (token) => {
|
||||
const body = await fetch(new Request(url)).then((res) => res.text())
|
||||
expect(body).toMatchSnapshot()
|
||||
expect(body).toContain(`<meta property="og:title" content="Get ${token.symbol} on Uniswap"/>`)
|
||||
expect(body).not.toContain(`<meta property="og:description"`)
|
||||
expect(body).toContain(`<meta property="og:image" content="${token.image}"/>`)
|
||||
expect(body).toContain(`<meta property="og:image:width" content="1200"/>`)
|
||||
expect(body).toContain(`<meta property="og:image:height" content="630"/>`)
|
||||
|
||||
@@ -1,19 +1,13 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"esModuleInterop": true,
|
||||
"baseUrl": "functions",
|
||||
"composite": false,
|
||||
"incremental": true,
|
||||
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||
"moduleResolution": "node",
|
||||
"module": "esnext",
|
||||
"noEmit": true,
|
||||
"strict": true,
|
||||
"target": "ESNext",
|
||||
"isolatedModules": false,
|
||||
"jsx": "react",
|
||||
"tsBuildInfoFile": "../node_modules/.cache/tsbuildinfo/functions", // avoid clobbering the build tsbuildinfo
|
||||
"types": ["jest", "node", "@cloudflare/workers-types"],
|
||||
"jsx": "react",
|
||||
"skipLibCheck": true,
|
||||
"baseUrl": "functions"
|
||||
},
|
||||
"exclude": ["../node_modules", "../src"],
|
||||
"include": ["**/*.ts"],
|
||||
"include": ["**/*.ts", ".ts", "**/*.tsx"],
|
||||
}
|
||||
1
functions/types.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
declare module 'colorthief/src/color-thief-node'
|
||||
@@ -1,7 +1,11 @@
|
||||
interface Data {
|
||||
export interface Data {
|
||||
title: string
|
||||
image: string
|
||||
url: string
|
||||
name?: string
|
||||
ogImage?: string
|
||||
isVerified?: boolean
|
||||
symbol?: string
|
||||
}
|
||||
|
||||
const CACHE_NAME = 'functions-cache' as const
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { AssetDocument } from '../../src/graphql/data/__generated__/types-and-hooks'
|
||||
import { AssetDocument, AssetQuery } from '../../src/graphql/data/__generated__/types-and-hooks'
|
||||
import client from '../client'
|
||||
|
||||
function formatTitleName(name: string, collectionName: string, tokenId: string) {
|
||||
function formatTitleName(name: string | undefined, collectionName: string | undefined, tokenId: string) {
|
||||
if (name) {
|
||||
return name
|
||||
}
|
||||
@@ -15,7 +15,9 @@ function formatTitleName(name: string, collectionName: string, tokenId: string)
|
||||
}
|
||||
|
||||
export default async function getAsset(collectionAddress: string, tokenId: string, url: string) {
|
||||
const { data } = await client.query({
|
||||
const origin = new URL(url).origin
|
||||
const image = origin + '/api/image/nfts/asset/' + collectionAddress + '/' + tokenId
|
||||
const { data } = await client.query<AssetQuery>({
|
||||
query: AssetDocument,
|
||||
variables: {
|
||||
address: collectionAddress,
|
||||
@@ -31,8 +33,9 @@ export default async function getAsset(collectionAddress: string, tokenId: strin
|
||||
const title = formatTitleName(asset.name, asset.collection?.name, asset.tokenId)
|
||||
const formattedAsset = {
|
||||
title,
|
||||
image: asset.image?.url,
|
||||
image,
|
||||
url,
|
||||
ogImage: asset.image?.url ?? origin + '/images/192x192_App_Icon.png',
|
||||
}
|
||||
return formattedAsset
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { CollectionDocument } from '../../src/graphql/data/__generated__/types-and-hooks'
|
||||
import { CollectionDocument, CollectionQuery } from '../../src/graphql/data/__generated__/types-and-hooks'
|
||||
import client from '../client'
|
||||
|
||||
export default async function getCollection(collectionAddress: string, url: string) {
|
||||
const { data } = await client.query({
|
||||
const origin = new URL(url).origin
|
||||
const image = origin + '/api/image/nfts/collection/' + collectionAddress
|
||||
const { data } = await client.query<CollectionQuery>({
|
||||
query: CollectionDocument,
|
||||
variables: {
|
||||
addresses: collectionAddress,
|
||||
@@ -14,8 +16,11 @@ export default async function getCollection(collectionAddress: string, url: stri
|
||||
}
|
||||
const formattedAsset = {
|
||||
title: collection.name + ' on Uniswap',
|
||||
image: collection.image?.url,
|
||||
image,
|
||||
url,
|
||||
name: collection.name ?? 'Collection',
|
||||
ogImage: collection.image?.url ?? origin + '/images/192x192_App_Icon.png',
|
||||
isVerified: collection.isVerified ?? false,
|
||||
}
|
||||
return formattedAsset
|
||||
}
|
||||
|
||||
39
functions/utils/getColor.test.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
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 white PNG image with whiteness dimmed', async () => {
|
||||
const image = 'https://www.cac.cornell.edu/wiki/images/4/44/White_square.png'
|
||||
const color = await getColor(image, true)
|
||||
expect(color).toEqual(DEFAULT_COLOR)
|
||||
})
|
||||
|
||||
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)
|
||||
})
|
||||
75
functions/utils/getColor.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { Buffer } from 'buffer'
|
||||
import JPEG from 'jpeg-js'
|
||||
import PNG from 'png-ts'
|
||||
|
||||
import { DEFAULT_COLOR, predefinedTokenColors } from '../constants'
|
||||
|
||||
export default async function getColor(image: string | undefined, checkDistance = false) {
|
||||
if (!image) {
|
||||
return DEFAULT_COLOR
|
||||
}
|
||||
if (image in predefinedTokenColors) {
|
||||
return predefinedTokenColors[image]
|
||||
}
|
||||
try {
|
||||
const data = await fetch(image)
|
||||
const buffer = await data.arrayBuffer()
|
||||
const arrayBuffer = Buffer.from(buffer)
|
||||
|
||||
const type = data.headers.get('content-type') ?? ''
|
||||
return getAverageColor(arrayBuffer, type, checkDistance)
|
||||
} catch (e) {
|
||||
return DEFAULT_COLOR
|
||||
}
|
||||
}
|
||||
|
||||
function getAverageColor(arrayBuffer: Uint8Array, type: string, checkDistance: boolean) {
|
||||
let pixels
|
||||
switch (type) {
|
||||
case 'image/png': {
|
||||
const image = PNG.load(arrayBuffer)
|
||||
pixels = image.decode()
|
||||
break
|
||||
}
|
||||
case 'image/jpeg' || 'image/jpg': {
|
||||
const jpeg = JPEG.decode(arrayBuffer, { useTArray: true })
|
||||
pixels = jpeg.data
|
||||
break
|
||||
}
|
||||
default: {
|
||||
return DEFAULT_COLOR
|
||||
}
|
||||
}
|
||||
|
||||
const pixelCount = pixels.length / 4
|
||||
|
||||
let transparentPixels = 0
|
||||
|
||||
let r = 0
|
||||
let g = 0
|
||||
let b = 0
|
||||
|
||||
for (let i = 0; i < pixelCount; i++) {
|
||||
if (pixels[i * 4 + 3] === 0) {
|
||||
transparentPixels++
|
||||
continue
|
||||
}
|
||||
r += pixels[i * 4]
|
||||
g += pixels[i * 4 + 1]
|
||||
b += pixels[i * 4 + 2]
|
||||
}
|
||||
|
||||
r = Math.floor(r / (pixelCount - transparentPixels))
|
||||
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]
|
||||
}
|
||||
5
functions/utils/getFont.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export default async function getFont(origin: string) {
|
||||
const url = origin + '/fonts/Inter-normal.var.ttf'
|
||||
const font = await fetch(url)
|
||||
return font.arrayBuffer()
|
||||
}
|
||||
16
functions/utils/getNetworkLogoURL.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Chain } from '../../src/graphql/data/__generated__/types-and-hooks'
|
||||
|
||||
export default function getNetworkLogoUrl(network: string, origin: string) {
|
||||
switch (network) {
|
||||
case Chain.Polygon:
|
||||
return origin + '/images/logos/Polygon_Logo.png'
|
||||
case Chain.Arbitrum:
|
||||
return origin + '/images/logos/Arbitrum_Logo.png'
|
||||
case Chain.Optimism:
|
||||
return origin + '/images/logos/Optimism_Logo.png'
|
||||
case Chain.Celo:
|
||||
return origin + '/images/logos/Celo_Logo.png'
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,8 @@ import * as matchers from 'jest-extended'
|
||||
expect.extend(matchers)
|
||||
|
||||
import { mocked } from '../../src/test-utils/mocked'
|
||||
import Cache from './cache'
|
||||
import getRequest from './getRequest'
|
||||
import Cache, { Data } from './cache'
|
||||
import { getRequest } from './getRequest'
|
||||
|
||||
jest.mock('./cache', () => ({
|
||||
match: jest.fn(),
|
||||
@@ -17,7 +17,7 @@ test('should call Cache.match before calling getData when request is not cached'
|
||||
image: 'testImage',
|
||||
url: 'testUrl',
|
||||
})
|
||||
await getRequest(Promise.resolve(new Response()), url, getData)
|
||||
await getRequest(url, getData, (data): data is Data => true)
|
||||
expect(Cache.match).toHaveBeenCalledWith(url)
|
||||
expect(getData).toHaveBeenCalled()
|
||||
expect(Cache.match).toHaveBeenCalledBefore(getData)
|
||||
@@ -32,7 +32,7 @@ test('getData should not be called when request is cached', async () => {
|
||||
url: 'testUrl',
|
||||
})
|
||||
const getData = jest.fn()
|
||||
await getRequest(Promise.resolve(new Response()), url, getData)
|
||||
await getRequest(url, getData, (data): data is Data => true)
|
||||
expect(Cache.match).toHaveBeenCalledWith(url)
|
||||
expect(getData).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
@@ -1,31 +1,42 @@
|
||||
import { MetaTagInjector } from '../components/metaTagInjector'
|
||||
import Cache from './cache'
|
||||
import { Data } from './cache'
|
||||
|
||||
export default async function getRequest(
|
||||
export async function getMetadataRequest(
|
||||
res: Promise<Response>,
|
||||
url: string,
|
||||
getData: () => Promise<
|
||||
| {
|
||||
title: string
|
||||
image: string
|
||||
url: string
|
||||
}
|
||||
| undefined
|
||||
>
|
||||
getData: () => Promise<Data | undefined>
|
||||
) {
|
||||
try {
|
||||
const cachedData = await Cache.match(url)
|
||||
const cachedData = await getRequest(url, getData, (data): data is Data => true)
|
||||
if (cachedData) {
|
||||
return new HTMLRewriter().on('head', new MetaTagInjector(cachedData)).transform(await res)
|
||||
} else {
|
||||
const data = await getData()
|
||||
if (!data) {
|
||||
return res
|
||||
}
|
||||
await Cache.put(data, url)
|
||||
return new HTMLRewriter().on('head', new MetaTagInjector(data)).transform(await res)
|
||||
return res
|
||||
}
|
||||
} catch (e) {
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
export async function getRequest<T extends Data>(
|
||||
url: string,
|
||||
getData: () => Promise<T | undefined>,
|
||||
validateData: (data: Data) => data is T
|
||||
): Promise<T | undefined> {
|
||||
try {
|
||||
const cachedData = await Cache.match(url)
|
||||
if (cachedData && validateData(cachedData)) {
|
||||
return cachedData
|
||||
} else {
|
||||
const data = await getData()
|
||||
if (!data) {
|
||||
return undefined
|
||||
}
|
||||
await Cache.put(data, url)
|
||||
return data
|
||||
}
|
||||
} catch (e) {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { TokenDocument } from '../../src/graphql/data/__generated__/types-and-hooks'
|
||||
import { TokenDocument, TokenQuery } from '../../src/graphql/data/__generated__/types-and-hooks'
|
||||
import { Chain } from '../../src/graphql/data/__generated__/types-and-hooks'
|
||||
import client from '../client'
|
||||
|
||||
function formatTitleName(symbol: string, name: string) {
|
||||
function formatTitleName(symbol: string | undefined, name: string | undefined) {
|
||||
if (symbol) {
|
||||
return 'Get ' + symbol + ' on Uniswap'
|
||||
}
|
||||
@@ -11,23 +12,46 @@ function formatTitleName(symbol: string, name: string) {
|
||||
return 'View Token on Uniswap'
|
||||
}
|
||||
|
||||
export default async function getToken(networkName: string, tokenAddress: string | undefined, url: string) {
|
||||
const { data } = await client.query({
|
||||
const convertTokenAddress = (networkName: string, tokenAddress: string) => {
|
||||
if (tokenAddress === 'NATIVE') {
|
||||
switch (networkName) {
|
||||
case Chain.Celo:
|
||||
return '0x471EcE3750Da237f93B8E339c536989b8978a438'
|
||||
case Chain.Polygon:
|
||||
return '0x0000000000000000000000000000000000001010'
|
||||
default:
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
return tokenAddress
|
||||
}
|
||||
|
||||
export default async function getToken(networkName: string, tokenAddress: string, url: string) {
|
||||
const origin = new URL(url).origin
|
||||
const image = origin + '/api/image/tokens/' + networkName + '/' + tokenAddress
|
||||
const uppercaseNetworkName = networkName.toUpperCase()
|
||||
const convertedTokenAddress = convertTokenAddress(uppercaseNetworkName, tokenAddress)
|
||||
const { data } = await client.query<TokenQuery>({
|
||||
query: TokenDocument,
|
||||
variables: {
|
||||
chain: networkName,
|
||||
address: tokenAddress,
|
||||
chain: uppercaseNetworkName,
|
||||
address: convertedTokenAddress,
|
||||
},
|
||||
})
|
||||
const asset = data?.token
|
||||
if (!asset) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const title = formatTitleName(asset.symbol, asset.name)
|
||||
|
||||
const formattedAsset = {
|
||||
title,
|
||||
image: asset.project?.logoUrl,
|
||||
image,
|
||||
url,
|
||||
symbol: asset.symbol ?? 'UNK',
|
||||
ogImage: asset.project?.logoUrl,
|
||||
name: asset.name ?? 'Token',
|
||||
}
|
||||
return formattedAsset
|
||||
}
|
||||
|
||||
@@ -1,64 +1,4 @@
|
||||
/* eslint-env node */
|
||||
import { default as babelExtractor } from '@lingui/cli/api/extractors/babel'
|
||||
import { createHash } from 'crypto'
|
||||
import { mkdirSync, readFileSync, writeFileSync } from 'fs'
|
||||
import { existsSync } from 'fs'
|
||||
import * as path from 'path'
|
||||
|
||||
/** A custom caching extractor built on top of babelExtractor. */
|
||||
const cachingExtractor: typeof babelExtractor = {
|
||||
/** Delegates to babelExtractor.match. */
|
||||
match(filename: string) {
|
||||
return babelExtractor.match(filename)
|
||||
},
|
||||
/**
|
||||
* Checks a cache before extraction, only delegating to babelExtractor.extract if the file has changed.
|
||||
*
|
||||
* The lingui extractor works by extracting JSON (the catalog) from `filename` to `buildDir/filename.json`.
|
||||
* Caching works by man-in-the-middling this:
|
||||
* - File freshness is computed as a hash of `filename` contents.
|
||||
* - Before extracting, we check the cache to see if we already have a fresh catalog for the file.
|
||||
* If we do, we copy it to `localeDir/filename.json`. Copying is significantly faster than extracting.
|
||||
* - After extracting, we copy the catalog to the cache.
|
||||
*/
|
||||
extract(filename: string, localeDir: string, ...options: unknown[]) {
|
||||
// This runs from node_modules/@lingui/conf, so we need to back out to the root.
|
||||
const root = __dirname.split('/node_modules')[0]
|
||||
|
||||
// This logic mimics catalogFilename in @lingui/babel-plugin-extract-messages.
|
||||
const buildDir = path.join(localeDir, '_build')
|
||||
const localePath = path.join(buildDir, filename + '.json')
|
||||
|
||||
const filePath = path.join(root, filename)
|
||||
const fileHash = createHash('sha256').update(readFileSync(filePath)).digest('hex')
|
||||
|
||||
const cacheRoot = path.join(root, 'node_modules/.cache/lingui')
|
||||
const cachePath = path.join(cacheRoot, filename + '.json')
|
||||
|
||||
// If we have a matching cached copy of the catalog, we can copy it to localePath and return early.
|
||||
if (existsSync(cachePath)) {
|
||||
const { hash, catalog } = JSON.parse(readFileSync(cachePath, 'utf8'))
|
||||
if (hash === fileHash) {
|
||||
if (catalog) {
|
||||
mkdirSync(path.dirname(localePath), { recursive: true })
|
||||
writeFileSync(localePath, JSON.stringify(catalog, null, 2))
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
babelExtractor.extract(filename, localeDir, ...options)
|
||||
|
||||
// Cache the extracted catalog.
|
||||
mkdirSync(path.dirname(cachePath), { recursive: true })
|
||||
if (existsSync(localePath)) {
|
||||
const catalog = JSON.parse(readFileSync(localePath, 'utf8'))
|
||||
writeFileSync(cachePath, JSON.stringify({ hash: fileHash, catalog }))
|
||||
} else {
|
||||
writeFileSync(cachePath, JSON.stringify({ hash: fileHash }))
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const linguiConfig = {
|
||||
catalogs: [
|
||||
@@ -120,7 +60,6 @@ const linguiConfig = {
|
||||
rootDir: '.',
|
||||
runtimeConfigModule: ['@lingui/core', 'i18n'],
|
||||
sourceLocale: 'en-US',
|
||||
extractors: [cachingExtractor],
|
||||
}
|
||||
|
||||
export default linguiConfig
|
||||
|
||||
111
package.json
@@ -2,7 +2,6 @@
|
||||
"name": "@uniswap/interface",
|
||||
"version": "1.1.0",
|
||||
"description": "Uniswap Interface",
|
||||
"homepage": ".",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"scripts": {
|
||||
"ajv": "node scripts/compile-ajv-validators.js",
|
||||
@@ -19,9 +18,8 @@
|
||||
"i18n": "yarn i18n:extract --clean && yarn i18n:compile",
|
||||
"prepare": "concurrently \"npm:ajv\" \"npm:contracts\" \"npm:graphql\" \"npm:i18n\"",
|
||||
"start": "craco start",
|
||||
"start:cloud": "NODE_OPTIONS=--dns-result-order=ipv4first PORT=3001 npx wrangler pages dev --node-compat --proxy=3001 --port=3000 -- yarn 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",
|
||||
"build:e2e": "REACT_APP_CSP_ALLOW_UNSAFE_EVAL=true REACT_APP_ADD_COVERAGE_INSTRUMENTATION=true craco build",
|
||||
"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/ .",
|
||||
@@ -32,7 +30,18 @@
|
||||
"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"
|
||||
"deduplicate": "yarn-deduplicate --strategy=highest",
|
||||
"postinstall": "yarn patch-package"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"yarn.lock": [
|
||||
"yarn deduplicate"
|
||||
]
|
||||
},
|
||||
"jest": {
|
||||
"collectCoverageFrom": [
|
||||
@@ -59,9 +68,8 @@
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
">0.5%",
|
||||
"not dead"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
@@ -70,12 +78,15 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
||||
"@babel/preset-env": "^7.22.7",
|
||||
"@cloudflare/workers-types": "^4.20230710.1",
|
||||
"@craco/craco": "^7.1.0",
|
||||
"@ethersproject/experimental": "^5.4.0",
|
||||
"@lingui/cli": "^3.9.0",
|
||||
"@lingui/cli": "^4.3.0",
|
||||
"@lingui/swc-plugin": "^4.0.4",
|
||||
"@swc/core": "^1.3.72",
|
||||
"@swc/jest": "^0.2.27",
|
||||
"@swc/plugin-styled-components": "^1.5.70",
|
||||
"@testing-library/jest-dom": "^5.16.4",
|
||||
"@testing-library/react": "^13.1",
|
||||
"@testing-library/user-event": "^14.4.3",
|
||||
@@ -83,11 +94,11 @@
|
||||
"@types/array.prototype.flat": "^1.2.1",
|
||||
"@types/array.prototype.flatmap": "^1.2.2",
|
||||
"@types/d3": "^6.7.1",
|
||||
"@types/jest": "^25.2.1",
|
||||
"@types/jest": "^27.0.1",
|
||||
"@types/lingui__core": "^2.7.1",
|
||||
"@types/lingui__macro": "^2.7.4",
|
||||
"@types/lingui__react": "^2.8.3",
|
||||
"@types/ms.macro": "^2.0.0",
|
||||
"@types/ms": "^0.7.31",
|
||||
"@types/multicodec": "^1.0.0",
|
||||
"@types/node": "^13.13.5",
|
||||
"@types/qs": "^6.9.2",
|
||||
@@ -106,12 +117,11 @@
|
||||
"@types/wcag-contrast": "^3.0.0",
|
||||
"@uniswap/default-token-list": "^11.2.0",
|
||||
"@uniswap/eslint-config": "^1.2.0",
|
||||
"@vanilla-extract/babel-plugin": "^1.1.7",
|
||||
"@vanilla-extract/jest-transform": "^1.1.1",
|
||||
"@vanilla-extract/webpack-plugin": "^2.1.11",
|
||||
"@vanilla-extract/webpack-plugin": "^2.2.0",
|
||||
"@vercel/og": "0.5.8",
|
||||
"@walletconnect/types": "^2.8.6",
|
||||
"babel-jest": "^29.6.1",
|
||||
"babel-plugin-istanbul": "^6.1.1",
|
||||
"browser-cache-mock": "^0.1.7",
|
||||
"buffer": "^6.0.3",
|
||||
"concurrently": "^8.0.1",
|
||||
@@ -122,58 +132,66 @@
|
||||
"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",
|
||||
"ms.macro": "^2.0.0",
|
||||
"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",
|
||||
"png-ts": "^0.0.3",
|
||||
"postinstall-postinstall": "^2.1.0",
|
||||
"prettier": "^2.8.8",
|
||||
"process": "^0.11.10",
|
||||
"react-scripts": "^5.0.1",
|
||||
"resize-observer-polyfill": "^1.5.1",
|
||||
"serve": "^11.3.2",
|
||||
"source-map-explorer": "^2.5.3",
|
||||
"swc-loader": "^0.2.3",
|
||||
"terser-webpack-plugin": "^5.3.9",
|
||||
"ts-jest": "^29.1.1",
|
||||
"ts-transform-graphql-tag": "^0.2.1",
|
||||
"tsafe": "^1.6.4",
|
||||
"typechain": "^5.0.0",
|
||||
"typescript": "^4.4.3",
|
||||
"typescript": "^4.9.4",
|
||||
"webpack": "^5.88.2",
|
||||
"webpack-retry-chunk-load-plugin": "^3.1.1",
|
||||
"wrangler": "https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/4925945367/npm-package-wrangler-3048",
|
||||
"wrangler": "^3.5.0",
|
||||
"yarn-deduplicate": "^6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.7.2",
|
||||
"@coinbase/wallet-sdk": "^3.6.4",
|
||||
"@cypress/code-coverage": "^3.10.0",
|
||||
"@fontsource/ibm-plex-mono": "^4.5.1",
|
||||
"@fontsource/inter": "^4.5.1",
|
||||
"@graphql-codegen/cli": "^2.15.0",
|
||||
"@graphql-codegen/client-preset": "^1.2.1",
|
||||
"@graphql-codegen/typescript": "^2.8.3",
|
||||
"@graphql-codegen/typescript-operations": "^2.5.8",
|
||||
"@graphql-codegen/cli": "^3.3.1",
|
||||
"@graphql-codegen/client-preset": "^3.0.1",
|
||||
"@graphql-codegen/typescript": "^3.0.4",
|
||||
"@graphql-codegen/typescript-operations": "^3.0.2",
|
||||
"@graphql-codegen/typescript-react-apollo": "^3.3.7",
|
||||
"@graphql-codegen/typescript-resolvers": "^2.7.8",
|
||||
"@graphql-codegen/typescript-resolvers": "^3.2.1",
|
||||
"@juggle/resize-observer": "^3.4.0",
|
||||
"@lingui/core": "^3.14.0",
|
||||
"@lingui/macro": "^3.14.0",
|
||||
"@lingui/react": "^3.14.0",
|
||||
"@lingui/core": "^4.3.0",
|
||||
"@lingui/macro": "^4.3.0",
|
||||
"@lingui/react": "^4.3.0",
|
||||
"@looksrare/sdk": "^0.10.2",
|
||||
"@metamask/jazzicon": "^2.0.0",
|
||||
"@opensea/seaport-js": "^1.2.0",
|
||||
"@popperjs/core": "^2.4.4",
|
||||
"@reach/dialog": "^0.10.3",
|
||||
"@reach/portal": "^0.10.3",
|
||||
"@reduxjs/toolkit": "^1.6.1",
|
||||
"@reduxjs/toolkit": "^1.9.3",
|
||||
"@sentry/react": "^7.45.0",
|
||||
"@sentry/tracing": "^7.45.0",
|
||||
"@sentry/types": "^7.45.0",
|
||||
"@types/react-window-infinite-loader": "^1.0.6",
|
||||
"@uniswap/analytics": "^1.4.0",
|
||||
"@uniswap/analytics-events": "^2.14.0",
|
||||
"@uniswap/conedison": "^1.8.0",
|
||||
"@uniswap/analytics-events": "^2.18.0",
|
||||
"@uniswap/governance": "^1.0.2",
|
||||
"@uniswap/liquidity-staker": "^1.0.2",
|
||||
"@uniswap/merkle-distributor": "^1.0.1",
|
||||
@@ -183,7 +201,7 @@
|
||||
"@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.1.0",
|
||||
"@uniswap/uniswapx-sdk": "^1.3.0",
|
||||
"@uniswap/universal-router-sdk": "^1.5.6",
|
||||
"@uniswap/v2-core": "^1.0.1",
|
||||
"@uniswap/v2-periphery": "^1.1.0-beta.0",
|
||||
@@ -191,10 +209,10 @@
|
||||
"@uniswap/v3-core": "^1.0.1",
|
||||
"@uniswap/v3-periphery": "^1.1.1",
|
||||
"@uniswap/v3-sdk": "^3.10.0",
|
||||
"@vanilla-extract/css": "^1.7.2",
|
||||
"@vanilla-extract/css-utils": "^0.1.2",
|
||||
"@vanilla-extract/dynamic": "^2.0.2",
|
||||
"@vanilla-extract/sprinkles": "^1.4.1",
|
||||
"@vanilla-extract/css": "^1.12.0",
|
||||
"@vanilla-extract/css-utils": "^0.1.3",
|
||||
"@vanilla-extract/dynamic": "^2.0.3",
|
||||
"@vanilla-extract/sprinkles": "^1.6.1",
|
||||
"@visx/axis": "^2.12.2",
|
||||
"@visx/event": "^2.6.0",
|
||||
"@visx/glyph": "^2.10.0",
|
||||
@@ -202,16 +220,16 @@
|
||||
"@visx/react-spring": "^2.12.2",
|
||||
"@visx/responsive": "^2.10.0",
|
||||
"@visx/shape": "^2.11.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",
|
||||
"@web3-react/coinbase-wallet": "^8.2.2",
|
||||
"@web3-react/core": "^8.2.2",
|
||||
"@web3-react/eip1193": "^8.2.2",
|
||||
"@web3-react/empty": "^8.2.2",
|
||||
"@web3-react/gnosis-safe": "^8.2.3",
|
||||
"@web3-react/metamask": "^8.2.3",
|
||||
"@web3-react/network": "^8.2.2",
|
||||
"@web3-react/types": "^8.2.2",
|
||||
"@web3-react/url": "^8.2.2",
|
||||
"@web3-react/walletconnect-v2": "^8.5.0",
|
||||
"ajv": "^8.11.0",
|
||||
"ajv-formats": "^2.1.1",
|
||||
"array.prototype.flat": "^1.2.4",
|
||||
@@ -221,6 +239,7 @@
|
||||
"copy-to-clipboard": "^3.2.0",
|
||||
"d3": "^7.6.1",
|
||||
"ethers": "^5.7.2",
|
||||
"ext-name": "^5.0.0",
|
||||
"focus-visible": "^5.2.0",
|
||||
"get-graphql-schema": "^2.1.2",
|
||||
"graphql": "^16.5.0",
|
||||
@@ -229,7 +248,9 @@
|
||||
"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",
|
||||
"node-vibrant": "^3.2.1-alpha.1",
|
||||
@@ -258,7 +279,7 @@
|
||||
"react-window-infinite-loader": "^1.0.8",
|
||||
"rebass": "^4.0.7",
|
||||
"redux": "^4.1.2",
|
||||
"redux-localstorage-simple": "^2.3.1",
|
||||
"redux-persist": "^6.0.0",
|
||||
"statsig-react": "^1.22.0",
|
||||
"styled-components": "^5.3.5",
|
||||
"tiny-invariant": "^1.2.0",
|
||||
|
||||
50
patches/@vercel+og+0.5.8.patch
Normal file
@@ -0,0 +1,50 @@
|
||||
diff --git a/node_modules/@vercel/og/dist/index.edge.js b/node_modules/@vercel/og/dist/index.edge.js
|
||||
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 {
|
||||
};
|
||||
|
||||
// src/index.edge.ts
|
||||
-import resvg_wasm from "./resvg.wasm?module";
|
||||
-import yoga_wasm from "./yoga.wasm?module";
|
||||
+import resvg_wasm from "./resvg.wasm";
|
||||
+import yoga_wasm from "./yoga.wasm";
|
||||
|
||||
// src/emoji/index.ts
|
||||
var U200D = String.fromCharCode(8205);
|
||||
@@ -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({
|
||||
async start(controller) {
|
||||
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..eb59ff4 100644
|
||||
--- a/node_modules/@vercel/og/dist/types.d.ts
|
||||
+++ b/node_modules/@vercel/og/dist/types.d.ts
|
||||
@@ -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.
|
||||
*/
|
||||
- fonts?: SatoriOptions['fonts'];
|
||||
+ fonts: SatoriOptions['fonts'];
|
||||
/**
|
||||
* Using a specific Emoji style. Defaults to `twemoji`.
|
||||
*
|
||||
@@ -5,29 +5,25 @@
|
||||
"namespace": "android_app",
|
||||
"package_name": "com.uniswap",
|
||||
"sha256_cert_fingerprints":
|
||||
["97:A5:81:51:DA:AF:8F:6E:65:3A:90:1E:82:12:6C:FB:61:2D:36:C7:CF:20:61:6B:A3:4C:52:CA:BC:58:43:8E"]
|
||||
["97:A5:81:51:DA:AF:8F:6E:65:3A:90:1E:82:12:6C:FB:61:2D:36:C7:CF:20:61:6B:A3:4C:52:CA:BC:58:43:8E", "F9:E9:E3:F0:04:28:66:62:81:44:50:7E:D6:A9:5F:B9:65:39:02:70:1D:13:74:15:D3:E1:A3:1B:D4:38:3A:1F"]
|
||||
}
|
||||
},
|
||||
[
|
||||
{
|
||||
"relation": ["delegate_permission/common.handle_all_urls"],
|
||||
"target": {
|
||||
"namespace": "android_app",
|
||||
"package_name": "com.uniswap.beta",
|
||||
"sha256_cert_fingerprints":
|
||||
["E5:39:87:DC:4D:FD:4C:1B:A6:74:36:7D:3A:3B:6B:ED:9E:B3:66:89:92:8A:1B:B8:FC:1B:22:56:56:B4:46:A3"]
|
||||
}
|
||||
{
|
||||
"relation": ["delegate_permission/common.handle_all_urls"],
|
||||
"target": {
|
||||
"namespace": "android_app",
|
||||
"package_name": "com.uniswap.beta",
|
||||
"sha256_cert_fingerprints":
|
||||
["E5:39:87:DC:4D:FD:4C:1B:A6:74:36:7D:3A:3B:6B:ED:9E:B3:66:89:92:8A:1B:B8:FC:1B:22:56:56:B4:46:A3", "54:4B:62:33:17:9B:5F:A8:E6:5D:D3:A6:E5:9D:80:5F:A5:02:7F:E2:14:B8:C1:7A:AC:4B:8D:E0:65:49:87:41"]
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"relation": ["delegate_permission/common.handle_all_urls"],
|
||||
"target": {
|
||||
"namespace": "android_app",
|
||||
"package_name": "com.uniswap.dev",
|
||||
"sha256_cert_fingerprints":
|
||||
["A8:A7:D4:DE:46:8E:BE:F6:DE:3B:62:2B:A7:26:60:F2:9A:4C:CD:AF:A6:96:C9:E5:7C:91:68:A1:29:2A:48:D3"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"relation": ["delegate_permission/common.handle_all_urls"],
|
||||
"target": {
|
||||
"namespace": "android_app",
|
||||
"package_name": "com.uniswap.dev",
|
||||
"sha256_cert_fingerprints":
|
||||
["5A:6D:23:50:2F:1E:0D:01:DC:96:65:F3:3A:18:4C:4C:8C:67:E0:09:99:9B:B1:9B:BF:44:99:D0:D1:D0:FC:5E", "02:E6:1C:76:8C:75:C3:78:C8:8C:FE:7B:2E:8F:4B:E1:FA:47:F2:F6:1A:DB:57:69:4A:41:99:C6:71:2C:AB:E3", "FA:C6:17:45:DC:09:03:78:6F:B9:ED:E6:2A:96:2B:39:9F:73:48:F0:BB:6F:89:9B:83:32:66:75:91:03:3B:9C"]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -22,6 +22,22 @@
|
||||
{
|
||||
"#": "/address/*",
|
||||
"comment": "Wallet address"
|
||||
},
|
||||
{
|
||||
"/": "/nfts/asset/*",
|
||||
"comment": "NFT Item"
|
||||
},
|
||||
{
|
||||
"/": "/nfts/collection/*",
|
||||
"comment": "NFT Collection"
|
||||
},
|
||||
{
|
||||
"/": "/tokens/*",
|
||||
"comment": "Token address"
|
||||
},
|
||||
{
|
||||
"/": "/address/*",
|
||||
"comment": "Wallet address"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
BIN
public/fonts/Basel-Book.woff
Normal file
BIN
public/fonts/Basel-Medium.woff
Normal file
BIN
public/fonts/Inter-normal.var.ttf
Normal file
BIN
public/images/1200x630_Rich_Link_Preview_Image.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
public/images/logos/Arbitrum_Logo.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
public/images/logos/Celo_Logo.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
public/images/logos/Optimism_Logo.png
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
BIN
public/images/logos/Polygon_Logo.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
@@ -4,7 +4,6 @@
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<title>Uniswap Interface</title>
|
||||
<meta name="description" content="Swap or provide liquidity on the Uniswap Protocol" />
|
||||
|
||||
<!--
|
||||
%PUBLIC_URL% will be replaced with the URL of the `public` folder during build.
|
||||
@@ -37,31 +36,43 @@
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
|
||||
<link rel="preload" href="%PUBLIC_URL%/fonts/Inter-roman.var.woff2" as="font" type="font/woff2" crossorigin />
|
||||
<link rel="preload" href="%PUBLIC_URL%/fonts/Basel-Book.woff" as="font" type="font/woff" crossorigin />
|
||||
<link rel="preload" href="%PUBLIC_URL%/fonts/Basel-Medium.woff" as="font" type="font/woff" crossorigin />
|
||||
|
||||
|
||||
<style>
|
||||
* {
|
||||
font-family: 'Inter', sans-serif;
|
||||
font-family: 'Basel', sans-serif;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/**
|
||||
Explicitly load Inter var from public/ so it does not block LCP's critical path.
|
||||
Explicitly load Basel var from public/ so it does not block LCP's critical path.
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Inter custom';
|
||||
font-weight: 100 900;
|
||||
font-family: 'Basel';
|
||||
font-weight: 535;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Regular';
|
||||
src: url(%PUBLIC_URL%/fonts/Inter-roman.var.woff2) format('woff2 supports variations(gvar)'),
|
||||
url(%PUBLIC_URL%/fonts/Inter-roman.var.woff2) format('woff2-variations'),
|
||||
url(%PUBLIC_URL%/fonts/Inter-roman.var.woff2) format('woff2');
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(%PUBLIC_URL%/fonts/Basel-Medium.woff) format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Basel';
|
||||
font-weight: 485;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
font-named-instance: 'Book';
|
||||
src:
|
||||
url(%PUBLIC_URL%/fonts/Basel-Book.woff) format('woff');
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
* {
|
||||
font-family: 'Inter custom', sans-serif;
|
||||
font-family: 'Basel', sans-serif;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,9 +88,11 @@
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
font-weight: 485;
|
||||
font-variant: none;
|
||||
font-smooth: always;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility !important;
|
||||
-webkit-font-smoothing: antialiased !important;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
@@ -105,13 +118,13 @@
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html {
|
||||
background: linear-gradient(180deg, #202738 0%, #070816 100%);
|
||||
background: linear-gradient(rgb(19, 19, 19) 0%, rgb(19, 19, 19) 100%);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
html {
|
||||
background: radial-gradient(100% 100% at 50% 0%, rgba(255, 184, 226, 0.51) 0%, rgba(255, 255, 255, 0) 100%), #FFFFFF
|
||||
background: radial-gradient(100% 100% at 50% 0%, rgba(255, 184, 226, 0) 0%, rgba(255, 255, 255, 0) 100%), rgb(255, 255, 255);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.64864 2L1 7.65256L10.5 17.1487L20 7.65256L14.3514 2H6.64864ZM6.13513 5.59458C8.5352 3.18398 12.4648 3.18396 14.8649 5.59456L16.9189 7.64866L14.8649 9.70272C12.4648 12.1133 8.5352 12.1133 6.13513 9.70274L4.08109 7.64866L6.13513 5.59458ZM7.54702 7.64848C7.54702 9.27987 8.86966 10.6012 10.4997 10.6012C12.1298 10.6012 13.4524 9.27987 13.4524 7.64848C13.4524 6.01708 12.1298 4.69576 10.4997 4.69576C8.86966 4.69576 7.54702 6.01708 7.54702 7.64848ZM10.4997 8.93225C9.791 8.93225 9.21593 8.35778 9.21593 7.64848C9.21593 6.93917 9.791 6.3647 10.4997 6.3647C11.2084 6.3647 11.7835 6.93917 11.7835 7.64848C11.7835 8.35778 11.2084 8.93225 10.4997 8.93225Z" fill="#5D6785"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.64864 2L1 7.65256L10.5 17.1487L20 7.65256L14.3514 2H6.64864ZM6.13513 5.59458C8.5352 3.18398 12.4648 3.18396 14.8649 5.59456L16.9189 7.64866L14.8649 9.70272C12.4648 12.1133 8.5352 12.1133 6.13513 9.70274L4.08109 7.64866L6.13513 5.59458ZM7.54702 7.64848C7.54702 9.27987 8.86966 10.6012 10.4997 10.6012C12.1298 10.6012 13.4524 9.27987 13.4524 7.64848C13.4524 6.01708 12.1298 4.69576 10.4997 4.69576C8.86966 4.69576 7.54702 6.01708 7.54702 7.64848ZM10.4997 8.93225C9.791 8.93225 9.21593 8.35778 9.21593 7.64848C9.21593 6.93917 9.791 6.3647 10.4997 6.3647C11.2084 6.3647 11.7835 6.93917 11.7835 7.64848C11.7835 8.35778 11.2084 8.93225 10.4997 8.93225Z" fill="#9B9B9B"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 820 B After Width: | Height: | Size: 820 B |
@@ -1,3 +1,3 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 1C5.0302 1 1 5.0302 1 10C1 14.9698 5.0302 19 10 19C14.9698 19 19 14.9698 19 10C19 5.0302 14.9716 1 10 1ZM5.4406 10.3024L5.4784 10.2412L7.8202 6.5782C7.8544 6.526 7.9354 6.5314 7.9606 6.589C8.3512 7.4656 8.6896 8.5564 8.5312 9.235C8.4646 9.514 8.2792 9.892 8.0704 10.2412C8.0434 10.2916 8.0146 10.342 7.9822 10.3906C7.9678 10.4122 7.9426 10.4248 7.9156 10.4248H5.509C5.4442 10.4248 5.4064 10.3546 5.4406 10.3024ZM15.8752 11.5624C15.8752 11.5966 15.8554 11.6254 15.8266 11.638C15.6448 11.7154 15.0238 12.0016 14.7664 12.3598C14.1076 13.276 13.6054 14.5864 12.4804 14.5864H7.7896C6.1264 14.5864 4.78 13.2346 4.78 11.566V11.512C4.78 11.4688 4.816 11.4328 4.861 11.4328H7.4746C7.5268 11.4328 7.5646 11.4796 7.561 11.5318C7.5412 11.701 7.5736 11.8756 7.6546 12.034C7.8094 12.349 8.1316 12.5452 8.479 12.5452H9.7732V11.5354H8.4934C8.4286 11.5354 8.389 11.4598 8.4268 11.4058C8.4412 11.3842 8.4556 11.3626 8.4736 11.3374C8.5942 11.1646 8.767 10.8982 8.9398 10.594C9.0568 10.3888 9.1702 10.1692 9.262 9.9496C9.28 9.91 9.2944 9.8686 9.3106 9.829C9.3358 9.7588 9.361 9.6922 9.379 9.6274C9.397 9.5716 9.4132 9.514 9.4276 9.46C9.4708 9.2728 9.4888 9.0748 9.4888 8.8696C9.4888 8.7886 9.4852 8.704 9.478 8.6248C9.4744 8.5366 9.4636 8.4484 9.4528 8.3602C9.4456 8.2828 9.4312 8.2054 9.4168 8.1262C9.397 8.0092 9.3718 7.8922 9.343 7.7752L9.3322 7.7302C9.3106 7.6492 9.2908 7.5736 9.2656 7.4926C9.1918 7.2406 9.109 6.994 9.019 6.7636C8.9866 6.6718 8.9506 6.5836 8.9128 6.4972C8.8588 6.364 8.803 6.2434 8.7526 6.13C8.7256 6.0778 8.704 6.031 8.6824 5.9824C8.6572 5.9284 8.632 5.8744 8.605 5.8222C8.587 5.7826 8.5654 5.7448 8.551 5.7088L8.3926 5.4172C8.371 5.3776 8.407 5.329 8.4502 5.3416L9.4402 5.6098H9.4438C9.4456 5.6098 9.4456 5.6098 9.4474 5.6098L9.577 5.6476L9.721 5.6872L9.7732 5.7016V5.1148C9.7732 4.8304 10 4.6 10.2826 4.6C10.423 4.6 10.5508 4.6576 10.6408 4.7512C10.7326 4.8448 10.7902 4.9726 10.7902 5.1148V5.9878L10.8964 6.0166C10.9036 6.0202 10.9126 6.0238 10.9198 6.0292C10.945 6.0472 10.9828 6.076 11.0296 6.112C11.0674 6.1408 11.107 6.1768 11.1538 6.2146C11.2492 6.292 11.3644 6.391 11.4886 6.5044C11.521 6.5332 11.5534 6.562 11.584 6.5926C11.7442 6.742 11.9242 6.9166 12.097 7.111C12.1456 7.1668 12.1924 7.2208 12.241 7.2802C12.2878 7.3396 12.34 7.3972 12.3832 7.4548C12.4426 7.5322 12.5038 7.6132 12.5596 7.6978C12.5848 7.7374 12.6154 7.7788 12.6388 7.8184C12.7108 7.9246 12.772 8.0344 12.8314 8.1442C12.8566 8.1946 12.8818 8.2504 12.9034 8.3044C12.97 8.452 13.0222 8.6014 13.0546 8.7526C13.0654 8.785 13.0726 8.8192 13.0762 8.8516V8.8588C13.087 8.902 13.0906 8.9488 13.0942 8.9974C13.1086 9.1504 13.1014 9.3052 13.069 9.46C13.0546 9.5248 13.0366 9.586 13.015 9.6526C12.9916 9.7156 12.97 9.7804 12.9412 9.8434C12.8854 9.9712 12.8206 10.1008 12.7432 10.2196C12.718 10.2646 12.6874 10.3114 12.6586 10.3564C12.6262 10.4032 12.592 10.4482 12.5632 10.4914C12.5218 10.5472 12.4786 10.6048 12.4336 10.657C12.394 10.711 12.3544 10.765 12.3094 10.8136C12.2482 10.8874 12.1888 10.9558 12.1258 11.0224C12.0898 11.0656 12.0502 11.1106 12.0088 11.1502C11.9692 11.1952 11.9278 11.2348 11.8918 11.2708C11.8288 11.3338 11.7784 11.3806 11.7352 11.422L11.6326 11.5138C11.6182 11.5282 11.5984 11.5354 11.5786 11.5354H10.7902V12.5452H11.782C12.0034 12.5452 12.214 12.4678 12.385 12.322C12.4426 12.2716 12.6964 12.052 12.997 11.7208C13.0078 11.7082 13.0204 11.701 13.0348 11.6974L15.7726 10.9054C15.8248 10.891 15.8752 10.9288 15.8752 10.9828V11.5624Z" fill="#5D6785"/>
|
||||
<path d="M10 1C5.0302 1 1 5.0302 1 10C1 14.9698 5.0302 19 10 19C14.9698 19 19 14.9698 19 10C19 5.0302 14.9716 1 10 1ZM5.4406 10.3024L5.4784 10.2412L7.8202 6.5782C7.8544 6.526 7.9354 6.5314 7.9606 6.589C8.3512 7.4656 8.6896 8.5564 8.5312 9.235C8.4646 9.514 8.2792 9.892 8.0704 10.2412C8.0434 10.2916 8.0146 10.342 7.9822 10.3906C7.9678 10.4122 7.9426 10.4248 7.9156 10.4248H5.509C5.4442 10.4248 5.4064 10.3546 5.4406 10.3024ZM15.8752 11.5624C15.8752 11.5966 15.8554 11.6254 15.8266 11.638C15.6448 11.7154 15.0238 12.0016 14.7664 12.3598C14.1076 13.276 13.6054 14.5864 12.4804 14.5864H7.7896C6.1264 14.5864 4.78 13.2346 4.78 11.566V11.512C4.78 11.4688 4.816 11.4328 4.861 11.4328H7.4746C7.5268 11.4328 7.5646 11.4796 7.561 11.5318C7.5412 11.701 7.5736 11.8756 7.6546 12.034C7.8094 12.349 8.1316 12.5452 8.479 12.5452H9.7732V11.5354H8.4934C8.4286 11.5354 8.389 11.4598 8.4268 11.4058C8.4412 11.3842 8.4556 11.3626 8.4736 11.3374C8.5942 11.1646 8.767 10.8982 8.9398 10.594C9.0568 10.3888 9.1702 10.1692 9.262 9.9496C9.28 9.91 9.2944 9.8686 9.3106 9.829C9.3358 9.7588 9.361 9.6922 9.379 9.6274C9.397 9.5716 9.4132 9.514 9.4276 9.46C9.4708 9.2728 9.4888 9.0748 9.4888 8.8696C9.4888 8.7886 9.4852 8.704 9.478 8.6248C9.4744 8.5366 9.4636 8.4484 9.4528 8.3602C9.4456 8.2828 9.4312 8.2054 9.4168 8.1262C9.397 8.0092 9.3718 7.8922 9.343 7.7752L9.3322 7.7302C9.3106 7.6492 9.2908 7.5736 9.2656 7.4926C9.1918 7.2406 9.109 6.994 9.019 6.7636C8.9866 6.6718 8.9506 6.5836 8.9128 6.4972C8.8588 6.364 8.803 6.2434 8.7526 6.13C8.7256 6.0778 8.704 6.031 8.6824 5.9824C8.6572 5.9284 8.632 5.8744 8.605 5.8222C8.587 5.7826 8.5654 5.7448 8.551 5.7088L8.3926 5.4172C8.371 5.3776 8.407 5.329 8.4502 5.3416L9.4402 5.6098H9.4438C9.4456 5.6098 9.4456 5.6098 9.4474 5.6098L9.577 5.6476L9.721 5.6872L9.7732 5.7016V5.1148C9.7732 4.8304 10 4.6 10.2826 4.6C10.423 4.6 10.5508 4.6576 10.6408 4.7512C10.7326 4.8448 10.7902 4.9726 10.7902 5.1148V5.9878L10.8964 6.0166C10.9036 6.0202 10.9126 6.0238 10.9198 6.0292C10.945 6.0472 10.9828 6.076 11.0296 6.112C11.0674 6.1408 11.107 6.1768 11.1538 6.2146C11.2492 6.292 11.3644 6.391 11.4886 6.5044C11.521 6.5332 11.5534 6.562 11.584 6.5926C11.7442 6.742 11.9242 6.9166 12.097 7.111C12.1456 7.1668 12.1924 7.2208 12.241 7.2802C12.2878 7.3396 12.34 7.3972 12.3832 7.4548C12.4426 7.5322 12.5038 7.6132 12.5596 7.6978C12.5848 7.7374 12.6154 7.7788 12.6388 7.8184C12.7108 7.9246 12.772 8.0344 12.8314 8.1442C12.8566 8.1946 12.8818 8.2504 12.9034 8.3044C12.97 8.452 13.0222 8.6014 13.0546 8.7526C13.0654 8.785 13.0726 8.8192 13.0762 8.8516V8.8588C13.087 8.902 13.0906 8.9488 13.0942 8.9974C13.1086 9.1504 13.1014 9.3052 13.069 9.46C13.0546 9.5248 13.0366 9.586 13.015 9.6526C12.9916 9.7156 12.97 9.7804 12.9412 9.8434C12.8854 9.9712 12.8206 10.1008 12.7432 10.2196C12.718 10.2646 12.6874 10.3114 12.6586 10.3564C12.6262 10.4032 12.592 10.4482 12.5632 10.4914C12.5218 10.5472 12.4786 10.6048 12.4336 10.657C12.394 10.711 12.3544 10.765 12.3094 10.8136C12.2482 10.8874 12.1888 10.9558 12.1258 11.0224C12.0898 11.0656 12.0502 11.1106 12.0088 11.1502C11.9692 11.1952 11.9278 11.2348 11.8918 11.2708C11.8288 11.3338 11.7784 11.3806 11.7352 11.422L11.6326 11.5138C11.6182 11.5282 11.5984 11.5354 11.5786 11.5354H10.7902V12.5452H11.782C12.0034 12.5452 12.214 12.4678 12.385 12.322C12.4426 12.2716 12.6964 12.052 12.997 11.7208C13.0078 11.7082 13.0204 11.701 13.0348 11.6974L15.7726 10.9054C15.8248 10.891 15.8752 10.9288 15.8752 10.9828V11.5624Z" fill="#9B9B9B"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
@@ -1,5 +1,5 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M17.146 4.52803C15.767 3.18049 13.8805 2.35 11.8 2.35C7.57502 2.35 4.15 5.77502 4.15 10C4.15 14.225 7.57502 17.65 11.8 17.65C13.8805 17.65 15.767 16.8195 17.146 15.472C15.501 17.617 12.912 19 10 19C5.02944 19 1 14.9706 1 10C1 5.02944 5.02944 1 10 1C12.912 1 15.501 2.38301 17.146 4.52803Z" fill="#5D6785"/>
|
||||
<path d="M6.08317 14.3776C7.18644 15.4556 8.69563 16.12 10.36 16.12C13.74 16.12 16.48 13.38 16.48 10C16.48 6.62002 13.74 3.88 10.36 3.88C8.69563 3.88 7.18644 4.54439 6.08317 5.62243C7.39916 3.90641 9.47037 2.8 11.8 2.8C15.7765 2.8 19 6.02355 19 10C19 13.9764 15.7764 17.2 11.8 17.2C9.47037 17.2 7.39916 16.0936 6.08317 14.3776Z" fill="#5D6785"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.4 10C15.4 12.9823 12.9823 15.4 10 15.4C7.01766 15.4 4.6 12.9823 4.6 10C4.6 7.01766 7.01766 4.6 10 4.6C12.9823 4.6 15.4 7.01766 15.4 10ZM13.6 10C13.6 11.9882 11.9882 13.6 10 13.6C8.01177 13.6 6.4 11.9882 6.4 10C6.4 8.01178 8.01177 6.4 10 6.4C11.9882 6.4 13.6 8.01178 13.6 10Z" fill="#5D6785"/>
|
||||
<path d="M17.146 4.52803C15.767 3.18049 13.8805 2.35 11.8 2.35C7.57502 2.35 4.15 5.77502 4.15 10C4.15 14.225 7.57502 17.65 11.8 17.65C13.8805 17.65 15.767 16.8195 17.146 15.472C15.501 17.617 12.912 19 10 19C5.02944 19 1 14.9706 1 10C1 5.02944 5.02944 1 10 1C12.912 1 15.501 2.38301 17.146 4.52803Z" fill="#9B9B9B"/>
|
||||
<path d="M6.08317 14.3776C7.18644 15.4556 8.69563 16.12 10.36 16.12C13.74 16.12 16.48 13.38 16.48 10C16.48 6.62002 13.74 3.88 10.36 3.88C8.69563 3.88 7.18644 4.54439 6.08317 5.62243C7.39916 3.90641 9.47037 2.8 11.8 2.8C15.7765 2.8 19 6.02355 19 10C19 13.9764 15.7764 17.2 11.8 17.2C9.47037 17.2 7.39916 16.0936 6.08317 14.3776Z" fill="#9B9B9B"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.4 10C15.4 12.9823 12.9823 15.4 10 15.4C7.01766 15.4 4.6 12.9823 4.6 10C4.6 7.01766 7.01766 4.6 10 4.6C12.9823 4.6 15.4 7.01766 15.4 10ZM13.6 10C13.6 11.9882 11.9882 13.6 10 13.6C8.01177 13.6 6.4 11.9882 6.4 10C6.4 8.01178 8.01177 6.4 10 6.4C11.9882 6.4 13.6 8.01178 13.6 10Z" fill="#9B9B9B"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
133
src/abis/fee-on-transfer-detector.json
Normal file
@@ -0,0 +1,133 @@
|
||||
[
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_factoryV2",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "constructor"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "PairLookupFailed",
|
||||
"type": "error"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "SameToken",
|
||||
"type": "error"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address[]",
|
||||
"name": "tokens",
|
||||
"type": "address[]"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "baseToken",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amountToBorrow",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "batchValidate",
|
||||
"outputs": [
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "buyFeeBps",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "sellFeeBps",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"internalType": "struct TokenFees[]",
|
||||
"name": "fotResults",
|
||||
"type": "tuple[]"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount0",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "data",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"name": "uniswapV2Call",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "token",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "baseToken",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amountToBorrow",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "validate",
|
||||
"outputs": [
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "buyFeeBps",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "sellFeeBps",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"internalType": "struct TokenFees",
|
||||
"name": "fotResult",
|
||||
"type": "tuple"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
}
|
||||
]
|
||||
@@ -6,7 +6,14 @@ import {
|
||||
import { atomWithStorage, useAtomValue } from 'jotai/utils'
|
||||
import { memo } from 'react'
|
||||
|
||||
export { getDeviceId, initializeAnalytics, OriginApplication, user, useTrace } from '@uniswap/analytics'
|
||||
export {
|
||||
type ITraceContext,
|
||||
getDeviceId,
|
||||
initializeAnalytics,
|
||||
OriginApplication,
|
||||
user,
|
||||
useTrace,
|
||||
} from '@uniswap/analytics'
|
||||
|
||||
const allowAnalyticsAtomKey = 'allow_analytics'
|
||||
export const allowAnalyticsAtom = atomWithStorage<boolean>(allowAnalyticsAtomKey, true)
|
||||
|
||||
3
src/assets/images/buy.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="19" height="14" viewBox="0 0 19 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M18.7501 2.99994V4.24994H0.750122V2.99994C0.750122 0.999939 1.75012 -6.10352e-05 3.75012 -6.10352e-05H15.7501C17.7501 -6.10352e-05 18.7501 0.999939 18.7501 2.99994ZM18.7501 5.74994V10.9999C18.7501 12.9999 17.7501 13.9999 15.7501 13.9999H3.75012C1.75012 13.9999 0.750122 12.9999 0.750122 10.9999V5.74994H18.7501ZM8.50012 9.99994C8.50012 9.58594 8.16412 9.24994 7.75012 9.24994H4.75012C4.33612 9.24994 4.00012 9.58594 4.00012 9.99994C4.00012 10.4139 4.33612 10.7499 4.75012 10.7499H7.75012C8.16412 10.7499 8.50012 10.4139 8.50012 9.99994Z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 672 B |
@@ -1,6 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.0047 9.26921H10.2714C11.0078 9.26921 11.6047 9.86617 11.6047 10.6025V12.1359C11.6047 12.7987 12.142 13.3359 12.8047 13.3359C13.4675 13.3359 14.0047 12.7995 14.0047 12.1367V5.22059C14.0047 4.86697 13.7758 4.56227 13.5258 4.31223L10.6714 1.33594M4.00472 2.00254H8.00472C8.7411 2.00254 9.33805 2.59949 9.33805 3.33587V14.0015H2.67139V3.33587C2.67139 2.59949 3.26834 2.00254 4.00472 2.00254ZM14.0047 5.33587C14.0047 6.07225 13.4078 6.66921 12.6714 6.66921C11.935 6.66921 11.3381 6.07225 11.3381 5.33587C11.3381 4.59949 11.935 4.00254 12.6714 4.00254C13.4078 4.00254 14.0047 4.59949 14.0047 5.33587Z" stroke="white"/>
|
||||
<line x1="4" y1="9.99414" x2="8" y2="9.99414" stroke="white"/>
|
||||
<line x1="4" y1="11.9941" x2="8" y2="11.9941" stroke="white"/>
|
||||
<path d="M4 8.16113H8" stroke="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 895 B |