Compare commits
71 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa3325b7e4 | ||
|
|
19aa7173ab | ||
|
|
a3238c701a | ||
|
|
82a763f905 | ||
|
|
61e0ce096b | ||
|
|
9e1a775c13 | ||
|
|
642a4177d8 | ||
|
|
37e085763c | ||
|
|
e2baa051c5 | ||
|
|
a5b152da06 | ||
|
|
38cf4f46d7 | ||
|
|
744c313ecf | ||
|
|
b967b1b236 | ||
|
|
596ea03043 | ||
|
|
e81e8a8f71 | ||
|
|
7d343dcfbd | ||
|
|
bf7a40be7a | ||
|
|
097b8361d4 | ||
|
|
82843ff16a | ||
|
|
890471f590 | ||
|
|
478ee7ba14 | ||
|
|
745be977ef | ||
|
|
0e25c055fb | ||
|
|
82a079935e | ||
|
|
876c1539d4 | ||
|
|
f43fd89884 | ||
|
|
efdfdc9083 | ||
|
|
709f0299e2 | ||
|
|
6b57ffe311 | ||
|
|
f7ecdc4332 | ||
|
|
b1009b0e03 | ||
|
|
5a4c7890c6 | ||
|
|
5a3c91f19f | ||
|
|
d5c4ee0342 | ||
|
|
262d984f92 | ||
|
|
7781f5112e | ||
|
|
204e44ac40 | ||
|
|
7c9d9bdb03 | ||
|
|
cb0ea3f14d | ||
|
|
e54ffcc483 | ||
|
|
8a72b374a8 | ||
|
|
3f64415906 | ||
|
|
41a4500f41 | ||
|
|
093dc66cfe | ||
|
|
b10729d217 | ||
|
|
9b0fa8a2c4 | ||
|
|
82c026872f | ||
|
|
222a6d53bc | ||
|
|
0f35f6ee93 | ||
|
|
7b83e3968f | ||
|
|
7938273c0c | ||
|
|
51a4504c75 | ||
|
|
b2697f0077 | ||
|
|
34a58851f7 | ||
|
|
5a20dc82cd | ||
|
|
d1627a6c36 | ||
|
|
55c971892c | ||
|
|
68f8576499 | ||
|
|
d0be3bf222 | ||
|
|
b79fe4b833 | ||
|
|
408c907870 | ||
|
|
8a99bad736 | ||
|
|
5ba3d2f679 | ||
|
|
ec4cd57dc0 | ||
|
|
ccad45d24e | ||
|
|
1903a16097 | ||
|
|
0ea029db4f | ||
|
|
cb41df4cd5 | ||
|
|
659a564db8 | ||
|
|
74c61c0213 | ||
|
|
dc55a21285 |
@@ -8,21 +8,42 @@
|
||||
"jsx": true
|
||||
}
|
||||
},
|
||||
"ignorePatterns": ["node_modules/**/*"],
|
||||
"settings": {
|
||||
"react": {
|
||||
"version": "detect"
|
||||
}
|
||||
},
|
||||
"ignorePatterns": [
|
||||
"src/types/v3",
|
||||
"src/abis/types",
|
||||
"src/locales/**/*.js",
|
||||
"src/locales/**/en-US.po",
|
||||
"src/state/data/generated.ts",
|
||||
"node_modules",
|
||||
"coverage",
|
||||
"build",
|
||||
"dist",
|
||||
".DS_Store",
|
||||
".env.local",
|
||||
".env.development.local",
|
||||
".env.test.local",
|
||||
".env.production.local",
|
||||
".idea/",
|
||||
".vscode/",
|
||||
"package-lock.json",
|
||||
"yarn.lock"
|
||||
],
|
||||
"extends": [
|
||||
"react-app",
|
||||
"plugin:react/recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:react-hooks/recommended",
|
||||
"prettier/@typescript-eslint",
|
||||
"plugin:prettier/recommended"
|
||||
],
|
||||
"plugins": ["simple-import-sort"],
|
||||
"plugins": ["simple-import-sort", "unused-imports"],
|
||||
"rules": {
|
||||
"unused-imports/no-unused-imports": "error",
|
||||
"simple-import-sort/imports": "error",
|
||||
"simple-import-sort/exports": "error",
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
|
||||
10
.github/workflows/lint.yml
vendored
10
.github/workflows/lint.yml
vendored
@@ -11,7 +11,6 @@ on:
|
||||
jobs:
|
||||
run-linters:
|
||||
name: Run linters
|
||||
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.owner.login == github.repository_owner }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
@@ -39,10 +38,15 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Run linters
|
||||
- name: Run eslint w/ autofix
|
||||
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.owner.login == github.repository_owner }}
|
||||
uses: wearerequired/lint-action@36c7e6689e80d785d27a22f71d970f3a3b4fcb70
|
||||
with:
|
||||
github_token: ${{ secrets.github_token }}
|
||||
eslint: true
|
||||
eslint_extensions: js,jsx,ts,tsx,json
|
||||
eslint_args: "-c .eslintrc.json"
|
||||
auto_fix: true
|
||||
|
||||
- name: Run eslint
|
||||
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.owner.login != github.repository_owner }}
|
||||
run: yarn eslint .
|
||||
|
||||
@@ -27,7 +27,7 @@ makes large architectural changes, consider following all the standards.
|
||||
- If something breaks, add automated tests so it doesn't break again
|
||||
- Add integration tests for new pages or flows
|
||||
- Verify that all CI checks pass before merging
|
||||
- Have at least one product manager or designer approve of significant UX changes
|
||||
- Have at least one product manager or designer approve of any significant UX changes
|
||||
|
||||
## Guidelines
|
||||
|
||||
@@ -42,7 +42,7 @@ The following points should help guide your development:
|
||||
- An Ethereum node should be the only critical dependency
|
||||
- All other external dependencies should only enhance the UX ([graceful degradation](https://developer.mozilla.org/en-US/docs/Glossary/Graceful_degradation))
|
||||
- Accessibility: anyone can use the interface
|
||||
- The interface should be responsive, small and run well on low performance devices (majority of swaps on mobile!)
|
||||
- The interface should be responsive, small and also run well on low performance devices (majority of swaps on mobile!)
|
||||
|
||||
## Release process
|
||||
|
||||
@@ -73,4 +73,4 @@ We sync to the repository on a schedule, rather than download translations at bu
|
||||
|
||||
You can contribute by joining Crowdin to proofread existing translations [here](https://crowdin.com/project/uniswap-interface/invite?d=93i5n413q403t4g473p443o4c3t2g3s21343u2c3n403l4b3v2735353i4g4k4l4g453j4g4o4j4e4k4b323l4a3h463s4g453q443m4e3t2b303s2a35353l403o443v293e303k4g4n4r4g483i4g4r4j4e4o473i5n4a3t463t4o4)
|
||||
|
||||
Or, ask to join us as a translator in the Discord!
|
||||
Or, ask to join us as a translator in the Discord!!
|
||||
|
||||
@@ -10,7 +10,7 @@ An open source interface for Uniswap -- a protocol for decentralized exchange of
|
||||
|
||||
- Website: [uniswap.org](https://uniswap.org/)
|
||||
- Interface: [app.uniswap.org](https://app.uniswap.org)
|
||||
- Docs: [uniswap.org/docs/](https://uniswap.org/docs/)
|
||||
- Docs: [uniswap.org/docs/](https://docs.uniswap.org/)
|
||||
- Twitter: [@Uniswap](https://twitter.com/Uniswap)
|
||||
- Reddit: [/r/Uniswap](https://www.reddit.com/r/Uniswap/)
|
||||
- Email: [contact@uniswap.org](mailto:contact@uniswap.org)
|
||||
|
||||
@@ -5,6 +5,11 @@
|
||||
}
|
||||
},
|
||||
"asToken0": [
|
||||
{
|
||||
"feeTier": "100",
|
||||
"totalValueLockedToken0": "0",
|
||||
"totalValueLockedToken1": "3"
|
||||
},
|
||||
{
|
||||
"feeTier": "500",
|
||||
"totalValueLockedToken0": "0",
|
||||
@@ -13,7 +18,7 @@
|
||||
{
|
||||
"feeTier": "3000",
|
||||
"totalValueLockedToken0": "0",
|
||||
"totalValueLockedToken1": "7"
|
||||
"totalValueLockedToken1": "4"
|
||||
},
|
||||
{
|
||||
"feeTier": "10000",
|
||||
|
||||
@@ -58,7 +58,7 @@ describe('Add Liquidity', () => {
|
||||
cy.wait('@feeTierDistributionQuery')
|
||||
|
||||
cy.get('#add-liquidity-selected-fee .selected-fee-label').should('contain.text', '0.3% fee tier')
|
||||
cy.get('#add-liquidity-selected-fee .selected-fee-percentage').should('contain.text', '70%')
|
||||
cy.get('#add-liquidity-selected-fee .selected-fee-percentage').should('contain.text', '40%')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -74,6 +74,7 @@ class CustomizedBridge extends Eip1193Bridge {
|
||||
}
|
||||
|
||||
// sets up the injected provider to be a mock ethereum provider with the given mnemonic/index
|
||||
// eslint-disable-next-line no-undef
|
||||
Cypress.Commands.overwrite('visit', (original, url, options) => {
|
||||
return original(url.startsWith('/') && url.length > 2 && !url.startsWith('/#') ? `/#${url}` : url, {
|
||||
...options,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export default {
|
||||
const linguiConfig = {
|
||||
catalogs: [
|
||||
{
|
||||
path: '<rootDir>/src/locales/{locale}',
|
||||
@@ -52,3 +52,5 @@ export default {
|
||||
runtimeConfigModule: ['@lingui/core', 'i18n'],
|
||||
sourceLocale: 'en-US',
|
||||
}
|
||||
|
||||
export default linguiConfig
|
||||
|
||||
24
package.json
24
package.json
@@ -11,7 +11,6 @@
|
||||
],
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@davatar/react": "1.8.1",
|
||||
"@ethersproject/experimental": "^5.4.0",
|
||||
"@gnosis.pm/safe-apps-web3-react": "^0.6.0",
|
||||
"@graphql-codegen/cli": "1.21.5",
|
||||
@@ -21,6 +20,7 @@
|
||||
"@lingui/cli": "^3.9.0",
|
||||
"@lingui/macro": "^3.9.0",
|
||||
"@lingui/react": "^3.9.0",
|
||||
"@metamask/jazzicon": "^2.0.0",
|
||||
"@popperjs/core": "^2.4.4",
|
||||
"@reach/dialog": "^0.10.3",
|
||||
"@reach/portal": "^0.10.3",
|
||||
@@ -37,7 +37,6 @@
|
||||
"@types/lingui__core": "^2.7.1",
|
||||
"@types/lingui__macro": "^2.7.4",
|
||||
"@types/lingui__react": "^2.8.3",
|
||||
"@types/luxon": "^1.24.4",
|
||||
"@types/ms.macro": "^2.0.0",
|
||||
"@types/multicodec": "^1.0.0",
|
||||
"@types/node": "^13.13.5",
|
||||
@@ -55,18 +54,20 @@
|
||||
"@types/wcag-contrast": "^3.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.1.0",
|
||||
"@typescript-eslint/parser": "^4.1.0",
|
||||
"@uniswap/default-token-list": "^2.1.0",
|
||||
"@uniswap/governance": "^1.0.2",
|
||||
"@uniswap/liquidity-staker": "^1.0.2",
|
||||
"@uniswap/merkle-distributor": "1.0.1",
|
||||
"@uniswap/redux-multicall": "^1.0.0",
|
||||
"@uniswap/router-sdk": "^1.0.1",
|
||||
"@uniswap/sdk-core": "^3.0.1",
|
||||
"@uniswap/smart-order-router": "^2.5.4",
|
||||
"@uniswap/token-lists": "^1.0.0-beta.27",
|
||||
"@uniswap/v2-core": "1.0.0",
|
||||
"@uniswap/v2-periphery": "^1.1.0-beta.0",
|
||||
"@uniswap/v2-sdk": "^3.0.0-alpha.2",
|
||||
"@uniswap/v2-sdk": "^3.0.1",
|
||||
"@uniswap/v3-core": "1.0.0",
|
||||
"@uniswap/v3-periphery": "^1.1.1",
|
||||
"@uniswap/v3-sdk": "^3.4.1",
|
||||
"@uniswap/v3-sdk": "^3.7.1",
|
||||
"@web3-react/core": "^6.0.9",
|
||||
"@web3-react/fortmatic-connector": "^6.0.9",
|
||||
"@web3-react/injected-connector": "^6.0.7",
|
||||
@@ -87,13 +88,13 @@
|
||||
"eslint-plugin-react": "^7.19.0",
|
||||
"eslint-plugin-react-hooks": "^4.0.0",
|
||||
"eslint-plugin-simple-import-sort": "^7.0.0",
|
||||
"eslint-plugin-unused-imports": "^2.0.0",
|
||||
"ethers": "^5.4.6",
|
||||
"firebase": "^9.1.3",
|
||||
"graphql": "^15.5.0",
|
||||
"graphql-request": "^3.4.0",
|
||||
"inter-ui": "^3.13.1",
|
||||
"jest-styled-components": "^7.0.5",
|
||||
"luxon": "^1.25.0",
|
||||
"microbundle": "^0.13.3",
|
||||
"ms.macro": "^2.0.0",
|
||||
"multicodec": "^3.0.1",
|
||||
@@ -128,6 +129,7 @@
|
||||
"typescript": "^4.2.3",
|
||||
"ua-parser-js": "^0.7.28",
|
||||
"use-count-up": "^2.2.5",
|
||||
"use-resize-observer": "^8.0.0",
|
||||
"wcag-contrast": "^3.0.0",
|
||||
"web-vitals": "^2.1.0",
|
||||
"workbox-core": "^6.1.0",
|
||||
@@ -138,8 +140,8 @@
|
||||
"@walletconnect/ethereum-provider": "1.6.5"
|
||||
},
|
||||
"scripts": {
|
||||
"contracts:compile:abi": "typechain --target ethers-v5 --out-dir src/abis/types './src/abis/**/*.json'",
|
||||
"contracts:compile:v3": "typechain --target ethers-v5 --out-dir src/types/v3 './node_modules/@uniswap/?(v3-core|v3-periphery)/artifacts/contracts/**/*.json'",
|
||||
"contracts:compile:abi": "typechain --target ethers-v5 --out-dir src/abis/types \"./src/abis/**/*.json\"",
|
||||
"contracts:compile:v3": "typechain --target ethers-v5 --out-dir src/types/v3 \"./node_modules/@uniswap/**/artifacts/contracts/**/*.json\"",
|
||||
"contracts:compile": "yarn contracts:compile:abi && yarn contracts:compile:v3",
|
||||
"graphql:generate": "graphql-codegen --config codegen.yml",
|
||||
"prei18n:extract": "touch src/locales/en-US.po",
|
||||
@@ -153,12 +155,6 @@
|
||||
"bundle": "microbundle --tsconfig tsconfig.lib.json src/lib/index.tsx --format esm,cjs",
|
||||
"cosmos": "open http://localhost:5000 && cross-env FAST_REFRESH=false cosmos"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "react-app",
|
||||
"ignorePatterns": [
|
||||
"node_modules"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
|
||||
@@ -67,6 +67,7 @@
|
||||
html {
|
||||
font-size: 16px;
|
||||
font-variant: none;
|
||||
font-smooth: always;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
|
||||
49
src/abis/erc1155.json
Normal file
49
src/abis/erc1155.json
Normal file
@@ -0,0 +1,49 @@
|
||||
[
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_owner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_id",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "balanceOf",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_id",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "uri",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "string",
|
||||
"name": "",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
}
|
||||
]
|
||||
40
src/abis/erc721.json
Normal file
40
src/abis/erc721.json
Normal file
@@ -0,0 +1,40 @@
|
||||
[
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "tokenId",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "ownerOf",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "tokenId",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "tokenURI",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "string",
|
||||
"name": "",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
}
|
||||
]
|
||||
6
src/assets/images/gas-icon.svg
Normal file
6
src/assets/images/gas-icon.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<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>
|
||||
|
After Width: | Height: | Size: 895 B |
12
src/assets/images/router-icon-grey.svg
Normal file
12
src/assets/images/router-icon-grey.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_988_5781)">
|
||||
<path d="M11.3333 12.5C7.33329 12.5 6.66663 8.5 3.99996 8.5M3.99996 8.5C6.66663 8.5 7.33329 4.5 11.3333 4.5M3.99996 8.5H1.66663" stroke="#888D9B" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="13.3334" cy="4.5" r="2" stroke="#888D9B" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="13.3334" cy="12.5" r="2" stroke="#888D9B" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_988_5781">
|
||||
<rect width="16" height="16" fill="white" transform="translate(0 0.5)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 733 B |
@@ -80,7 +80,7 @@ function ClaimSummary({ info: { recipient, uniAmountRaw } }: { info: ClaimTransa
|
||||
)
|
||||
}
|
||||
|
||||
function SubmitProposalTransactionSummary({}: { info: SubmitProposalTransactionInfo }) {
|
||||
function SubmitProposalTransactionSummary(_: { info: SubmitProposalTransactionInfo }) {
|
||||
return <Trans>Submit new proposal</Trans>
|
||||
}
|
||||
|
||||
@@ -147,13 +147,13 @@ function WrapSummary({ info: { currencyAmountRaw, unwrapped } }: { info: WrapTra
|
||||
}
|
||||
}
|
||||
|
||||
function DepositLiquidityStakingSummary({}: { info: DepositLiquidityStakingTransactionInfo }) {
|
||||
function DepositLiquidityStakingSummary(_: { info: DepositLiquidityStakingTransactionInfo }) {
|
||||
// not worth rendering the tokens since you can should no longer deposit liquidity in the staking contracts
|
||||
// todo: deprecate and delete the code paths that allow this, show user more information
|
||||
return <Trans>Deposit liquidity</Trans>
|
||||
}
|
||||
|
||||
function WithdrawLiquidityStakingSummary({}: { info: WithdrawLiquidityStakingTransactionInfo }) {
|
||||
function WithdrawLiquidityStakingSummary(_: { info: WithdrawLiquidityStakingTransactionInfo }) {
|
||||
return <Trans>Withdraw deposited liquidity</Trans>
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +1,20 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { AbstractConnector } from '@web3-react/abstract-connector'
|
||||
import { useCallback, useContext } from 'react'
|
||||
import { ExternalLink as LinkIcon } from 'react-feather'
|
||||
import { useAppDispatch } from 'state/hooks'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
|
||||
import CoinbaseWalletIcon from '../../assets/images/coinbaseWalletIcon.svg'
|
||||
import FortmaticIcon from '../../assets/images/fortmaticIcon.png'
|
||||
import PortisIcon from '../../assets/images/portisIcon.png'
|
||||
import WalletConnectIcon from '../../assets/images/walletConnectIcon.svg'
|
||||
import { ReactComponent as Close } from '../../assets/images/x.svg'
|
||||
import { fortmatic, injected, portis, walletconnect, walletlink } from '../../connectors'
|
||||
import { injected, portis, walletlink } from '../../connectors'
|
||||
import { SUPPORTED_WALLETS } from '../../constants/wallet'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { clearAllTransactions } from '../../state/transactions/actions'
|
||||
import { ExternalLink, LinkStyledButton, TYPE } from '../../theme'
|
||||
import { ExternalLink, LinkStyledButton, ThemedText } from '../../theme'
|
||||
import { shortenAddress } from '../../utils'
|
||||
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
|
||||
import { ButtonSecondary } from '../Button'
|
||||
import Identicon from '../Identicon'
|
||||
import StatusIcon from '../Identicon/StatusIcon'
|
||||
import { AutoRow } from '../Row'
|
||||
import Copy from './Copy'
|
||||
import Transaction from './Transaction'
|
||||
@@ -179,6 +176,23 @@ const IconWrapper = styled.div<{ size?: number }>`
|
||||
`};
|
||||
`
|
||||
|
||||
function WrappedStatusIcon({ connector }: { connector: AbstractConnector }) {
|
||||
return (
|
||||
<IconWrapper size={16}>
|
||||
<StatusIcon connector={connector} />
|
||||
{connector === portis && (
|
||||
<MainWalletAction
|
||||
onClick={() => {
|
||||
portis.portis.showPortis()
|
||||
}}
|
||||
>
|
||||
<Trans>Show Portis</Trans>
|
||||
</MainWalletAction>
|
||||
)}
|
||||
</IconWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
const TransactionListWrapper = styled.div`
|
||||
${({ theme }) => theme.flexColumnNoWrap};
|
||||
`
|
||||
@@ -244,50 +258,6 @@ export default function AccountDetails({
|
||||
)
|
||||
}
|
||||
|
||||
function getStatusIcon() {
|
||||
if (connector === injected) {
|
||||
return (
|
||||
<IconWrapper size={16}>
|
||||
<Identicon />
|
||||
</IconWrapper>
|
||||
)
|
||||
} else if (connector === walletconnect) {
|
||||
return (
|
||||
<IconWrapper size={16}>
|
||||
<img src={WalletConnectIcon} alt={'WalletConnect logo'} />
|
||||
</IconWrapper>
|
||||
)
|
||||
} else if (connector === walletlink) {
|
||||
return (
|
||||
<IconWrapper size={16}>
|
||||
<img src={CoinbaseWalletIcon} alt={'Coinbase Wallet logo'} />
|
||||
</IconWrapper>
|
||||
)
|
||||
} else if (connector === fortmatic) {
|
||||
return (
|
||||
<IconWrapper size={16}>
|
||||
<img src={FortmaticIcon} alt={'Fortmatic logo'} />
|
||||
</IconWrapper>
|
||||
)
|
||||
} else if (connector === portis) {
|
||||
return (
|
||||
<>
|
||||
<IconWrapper size={16}>
|
||||
<img src={PortisIcon} alt={'Portis logo'} />
|
||||
<MainWalletAction
|
||||
onClick={() => {
|
||||
portis.portis.showPortis()
|
||||
}}
|
||||
>
|
||||
<Trans>Show Portis</Trans>
|
||||
</MainWalletAction>
|
||||
</IconWrapper>
|
||||
</>
|
||||
)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const clearAllTransactionsCallback = useCallback(() => {
|
||||
if (chainId) dispatch(clearAllTransactions({ chainId }))
|
||||
}, [dispatch, chainId])
|
||||
@@ -332,14 +302,14 @@ export default function AccountDetails({
|
||||
{ENSName ? (
|
||||
<>
|
||||
<div>
|
||||
{getStatusIcon()}
|
||||
{connector && <WrappedStatusIcon connector={connector} />}
|
||||
<p> {ENSName}</p>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div>
|
||||
{getStatusIcon()}
|
||||
{connector && <WrappedStatusIcon connector={connector} />}
|
||||
<p> {account && shortenAddress(account)}</p>
|
||||
</div>
|
||||
</>
|
||||
@@ -408,9 +378,9 @@ export default function AccountDetails({
|
||||
{!!pendingTransactions.length || !!confirmedTransactions.length ? (
|
||||
<LowerSection>
|
||||
<AutoRow mb={'1rem'} style={{ justifyContent: 'space-between' }}>
|
||||
<TYPE.body>
|
||||
<ThemedText.Body>
|
||||
<Trans>Recent Transactions</Trans>
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
<LinkStyledButton onClick={clearAllTransactionsCallback}>
|
||||
<Trans>(clear all)</Trans>
|
||||
</LinkStyledButton>
|
||||
@@ -420,9 +390,9 @@ export default function AccountDetails({
|
||||
</LowerSection>
|
||||
) : (
|
||||
<LowerSection>
|
||||
<TYPE.body color={theme.text1}>
|
||||
<ThemedText.Body color={theme.text1}>
|
||||
<Trans>Your transactions will appear here...</Trans>
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
</LowerSection>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { t, Trans } from '@lingui/macro'
|
||||
import { t } from '@lingui/macro'
|
||||
import { ReactNode, useCallback, useContext } from 'react'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
|
||||
import useENS from '../../hooks/useENS'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { ExternalLink, TYPE } from '../../theme'
|
||||
import { ExternalLink, ThemedText } from '../../theme'
|
||||
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
|
||||
import { AutoColumn } from '../Column'
|
||||
import { RowBetween } from '../Row'
|
||||
@@ -107,9 +108,9 @@ export default function AddressInputPanel({
|
||||
<InputContainer>
|
||||
<AutoColumn gap="md">
|
||||
<RowBetween>
|
||||
<TYPE.black color={theme.text2} fontWeight={500} fontSize={14}>
|
||||
<ThemedText.Black color={theme.text2} fontWeight={500} fontSize={14}>
|
||||
{label ?? <Trans>Recipient</Trans>}
|
||||
</TYPE.black>
|
||||
</ThemedText.Black>
|
||||
{address && chainId && (
|
||||
<ExternalLink
|
||||
href={getExplorerLink(chainId, name ?? address, ExplorerDataType.ADDRESS)}
|
||||
|
||||
34
src/components/AnimatedDropdown/index.tsx
Normal file
34
src/components/AnimatedDropdown/index.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import { animated, useSpring } from 'react-spring'
|
||||
import useResizeObserver from 'use-resize-observer'
|
||||
|
||||
/**
|
||||
* @param open conditional to show content or hide
|
||||
* @returns Wrapper to smoothly hide and expand content
|
||||
*/
|
||||
export default function AnimatedDropdown({ open, children }: React.PropsWithChildren<{ open: boolean }>) {
|
||||
const { ref, height } = useResizeObserver()
|
||||
|
||||
const props = useSpring({
|
||||
height: open ? height ?? 0 : 0,
|
||||
config: {
|
||||
mass: 1.2,
|
||||
tension: 300,
|
||||
friction: 20,
|
||||
clamp: true,
|
||||
velocity: 0.01,
|
||||
},
|
||||
})
|
||||
|
||||
return (
|
||||
<animated.div
|
||||
style={{
|
||||
...props,
|
||||
overflow: 'hidden',
|
||||
width: '100%',
|
||||
willChange: 'height',
|
||||
}}
|
||||
>
|
||||
<div ref={ref}>{children}</div>
|
||||
</animated.div>
|
||||
)
|
||||
}
|
||||
@@ -33,6 +33,7 @@ export const BaseButton = styled(RebassButton)<
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
&:disabled {
|
||||
opacity: 50%;
|
||||
cursor: auto;
|
||||
pointer-events: none;
|
||||
}
|
||||
@@ -236,7 +237,7 @@ const ButtonConfirmedStyle = styled(BaseButton)`
|
||||
/* border: 1px solid ${({ theme }) => theme.green1}; */
|
||||
|
||||
&:disabled {
|
||||
/* opacity: 50%; */
|
||||
opacity: 50%;
|
||||
background-color: ${({ theme }) => theme.bg2};
|
||||
color: ${({ theme }) => theme.text2};
|
||||
cursor: auto;
|
||||
@@ -315,8 +316,8 @@ const ActiveOutlined = styled(ButtonOutlined)`
|
||||
`
|
||||
|
||||
const Circle = styled.div`
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
height: 17px;
|
||||
width: 17px;
|
||||
border-radius: 50%;
|
||||
background-color: ${({ theme }) => theme.primary1};
|
||||
display: flex;
|
||||
@@ -325,11 +326,11 @@ const Circle = styled.div`
|
||||
`
|
||||
|
||||
const CheckboxWrapper = styled.div`
|
||||
width: 30px;
|
||||
width: 20px;
|
||||
padding: 0 10px;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
top: 11px;
|
||||
right: 15px;
|
||||
`
|
||||
|
||||
const ResponsiveCheck = styled(Check)`
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { t } from '@lingui/macro'
|
||||
import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core'
|
||||
import HoverInlineText from 'components/HoverInlineText'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import useTheme from '../../hooks/useTheme'
|
||||
import { TYPE } from '../../theme'
|
||||
import { ThemedText } from '../../theme'
|
||||
import { warningSeverity } from '../../utils/prices'
|
||||
import { MouseoverTooltip } from '../Tooltip'
|
||||
|
||||
export function FiatValue({
|
||||
fiatValue,
|
||||
@@ -25,10 +28,14 @@ export function FiatValue({
|
||||
}, [priceImpact, theme.green1, theme.red1, theme.text3, theme.yellow1])
|
||||
|
||||
return (
|
||||
<TYPE.body fontSize={14} color={fiatValue ? theme.text2 : theme.text4}>
|
||||
<ThemedText.Body fontSize={14} color={fiatValue ? theme.text3 : theme.text4}>
|
||||
{fiatValue ? (
|
||||
<Trans>
|
||||
~$ <HoverInlineText text={fiatValue?.toSignificant(6, { groupSeparator: ',' })} />
|
||||
$
|
||||
<HoverInlineText
|
||||
text={fiatValue?.toSignificant(6, { groupSeparator: ',' })}
|
||||
textColor={fiatValue ? theme.text3 : theme.text4}
|
||||
/>
|
||||
</Trans>
|
||||
) : (
|
||||
''
|
||||
@@ -36,9 +43,11 @@ export function FiatValue({
|
||||
{priceImpact ? (
|
||||
<span style={{ color: priceImpactColor }}>
|
||||
{' '}
|
||||
(<Trans>{priceImpact.multiply(-1).toSignificant(3)}%</Trans>)
|
||||
<MouseoverTooltip text={t`The estimated difference between the USD values of input and output amounts.`}>
|
||||
(<Trans>{priceImpact.multiply(-1).toSignificant(3)}%</Trans>)
|
||||
</MouseoverTooltip>
|
||||
</span>
|
||||
) : null}
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import { ReactComponent as DropDown } from '../../assets/images/dropdown.svg'
|
||||
import useTheme from '../../hooks/useTheme'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { useCurrencyBalance } from '../../state/wallet/hooks'
|
||||
import { TYPE } from '../../theme'
|
||||
import { ThemedText } from '../../theme'
|
||||
import { ButtonGray } from '../Button'
|
||||
import CurrencyLogo from '../CurrencyLogo'
|
||||
import DoubleCurrencyLogo from '../DoubleLogo'
|
||||
@@ -29,6 +29,8 @@ const InputPanel = styled.div<{ hideInput?: boolean }>`
|
||||
background-color: ${({ theme, hideInput }) => (hideInput ? 'transparent' : theme.bg2)};
|
||||
z-index: 1;
|
||||
width: ${({ hideInput }) => (hideInput ? '100%' : 'initial')};
|
||||
transition: height 1s ease;
|
||||
will-change: height;
|
||||
`
|
||||
|
||||
const FixedContainer = styled.div`
|
||||
@@ -36,8 +38,7 @@ const FixedContainer = styled.div`
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
border-radius: 20px;
|
||||
background-color: ${({ theme }) => theme.bg1};
|
||||
opacity: 0.95;
|
||||
background-color: ${({ theme }) => theme.bg2};
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -46,7 +47,7 @@ const FixedContainer = styled.div`
|
||||
|
||||
const Container = styled.div<{ hideInput: boolean }>`
|
||||
border-radius: ${({ hideInput }) => (hideInput ? '16px' : '20px')};
|
||||
border: 1px solid ${({ theme, hideInput }) => (hideInput ? ' transparent' : theme.bg2)};
|
||||
border: 1px solid ${({ theme }) => theme.bg0};
|
||||
background-color: ${({ theme }) => theme.bg1};
|
||||
width: ${({ hideInput }) => (hideInput ? '100%' : 'initial')};
|
||||
:focus,
|
||||
@@ -56,35 +57,35 @@ const Container = styled.div<{ hideInput: boolean }>`
|
||||
`
|
||||
|
||||
const CurrencySelect = styled(ButtonGray)<{ visible: boolean; selected: boolean; hideInput?: boolean }>`
|
||||
visibility: ${({ visible }) => (visible ? 'visible' : 'hidden')};
|
||||
align-items: center;
|
||||
font-size: 24px;
|
||||
font-weight: 500;
|
||||
background-color: ${({ selected, theme }) => (selected ? theme.bg0 : theme.primary1)};
|
||||
color: ${({ selected, theme }) => (selected ? theme.text1 : theme.white)};
|
||||
border-radius: 16px;
|
||||
background-color: ${({ selected, theme }) => (selected ? theme.bg2 : theme.primary1)};
|
||||
box-shadow: ${({ selected }) => (selected ? 'none' : '0px 6px 10px rgba(0, 0, 0, 0.075)')};
|
||||
box-shadow: 0px 6px 10px rgba(0, 0, 0, 0.075);
|
||||
outline: none;
|
||||
color: ${({ selected, theme }) => (selected ? theme.text1 : theme.white)};
|
||||
cursor: pointer;
|
||||
border-radius: 16px;
|
||||
outline: none;
|
||||
user-select: none;
|
||||
border: none;
|
||||
font-size: 24px;
|
||||
font-weight: 500;
|
||||
height: ${({ hideInput }) => (hideInput ? '2.8rem' : '2.4rem')};
|
||||
width: ${({ hideInput }) => (hideInput ? '100%' : 'initial')};
|
||||
padding: 0 8px;
|
||||
justify-content: space-between;
|
||||
margin-right: ${({ hideInput }) => (hideInput ? '0' : '12px')};
|
||||
margin-left: ${({ hideInput }) => (hideInput ? '0' : '12px')};
|
||||
:focus,
|
||||
:hover {
|
||||
background-color: ${({ selected, theme }) => (selected ? theme.bg2 : darken(0.05, theme.primary1))};
|
||||
background-color: ${({ selected, theme }) => (selected ? theme.bg3 : darken(0.05, theme.primary1))};
|
||||
}
|
||||
visibility: ${({ visible }) => (visible ? 'visible' : 'hidden')};
|
||||
`
|
||||
|
||||
const InputRow = styled.div<{ selected: boolean }>`
|
||||
${({ theme }) => theme.flexRowNoWrap}
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: ${({ selected }) => (selected ? ' 1rem 1rem 0.75rem 1rem' : '1rem 1rem 0.75rem 1rem')};
|
||||
padding: ${({ selected }) => (selected ? ' 1rem 1rem 0.75rem 1rem' : '1rem 1rem 1rem 1rem')};
|
||||
`
|
||||
|
||||
const LabelRow = styled.div`
|
||||
@@ -128,28 +129,30 @@ const StyledTokenName = styled.span<{ active?: boolean }>`
|
||||
|
||||
const StyledBalanceMax = styled.button<{ disabled?: boolean }>`
|
||||
background-color: transparent;
|
||||
background-color: ${({ theme }) => theme.primary5};
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: ${({ theme }) => theme.primary1};
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
color: ${({ theme }) => theme.primaryText1};
|
||||
opacity: ${({ disabled }) => (!disabled ? 1 : 0.4)};
|
||||
pointer-events: ${({ disabled }) => (!disabled ? 'initial' : 'none')};
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
margin-left: 0.25rem;
|
||||
opacity: ${({ disabled }) => (!disabled ? 1 : 0.4)};
|
||||
padding: 4px 6px;
|
||||
pointer-events: ${({ disabled }) => (!disabled ? 'initial' : 'none')};
|
||||
|
||||
:hover {
|
||||
opacity: ${({ disabled }) => (!disabled ? 0.8 : 0.4)};
|
||||
}
|
||||
|
||||
:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
${({ theme }) => theme.mediaWidth.upToExtraSmall`
|
||||
margin-right: 0.5rem;
|
||||
`};
|
||||
`
|
||||
|
||||
const StyledNumericalInput = styled(NumericalInput)<{ $loading: boolean }>`
|
||||
${loadingOpacityMixin}
|
||||
${loadingOpacityMixin};
|
||||
text-align: left;
|
||||
`
|
||||
|
||||
interface CurrencyInputPanelProps {
|
||||
@@ -212,14 +215,23 @@ export default function CurrencyInputPanel({
|
||||
<FixedContainer>
|
||||
<AutoColumn gap="sm" justify="center">
|
||||
<Lock />
|
||||
<TYPE.label fontSize="12px" textAlign="center" padding="0 12px">
|
||||
<ThemedText.Label fontSize="12px" textAlign="center" padding="0 12px">
|
||||
<Trans>The market price is outside your specified price range. Single-asset deposit only.</Trans>
|
||||
</TYPE.label>
|
||||
</ThemedText.Label>
|
||||
</AutoColumn>
|
||||
</FixedContainer>
|
||||
)}
|
||||
<Container hideInput={hideInput}>
|
||||
<InputRow style={hideInput ? { padding: '0', borderRadius: '8px' } : {}} selected={!onCurrencySelect}>
|
||||
{!hideInput && (
|
||||
<StyledNumericalInput
|
||||
className="token-amount-input"
|
||||
value={value}
|
||||
onUserInput={onUserInput}
|
||||
$loading={loading}
|
||||
/>
|
||||
)}
|
||||
|
||||
<CurrencySelect
|
||||
visible={currency !== undefined}
|
||||
selected={!!currency}
|
||||
@@ -257,24 +269,19 @@ export default function CurrencyInputPanel({
|
||||
{onCurrencySelect && <StyledDropDown selected={!!currency} />}
|
||||
</Aligner>
|
||||
</CurrencySelect>
|
||||
{!hideInput && (
|
||||
<StyledNumericalInput
|
||||
className="token-amount-input"
|
||||
value={value}
|
||||
onUserInput={onUserInput}
|
||||
$loading={loading}
|
||||
/>
|
||||
)}
|
||||
</InputRow>
|
||||
{!hideInput && !hideBalance && (
|
||||
{!hideInput && !hideBalance && currency && (
|
||||
<FiatRow>
|
||||
<RowBetween>
|
||||
<LoadingOpacityContainer $loading={loading}>
|
||||
<FiatValue fiatValue={fiatValue} priceImpact={priceImpact} />
|
||||
</LoadingOpacityContainer>
|
||||
{account ? (
|
||||
<RowFixed style={{ height: '17px' }}>
|
||||
<TYPE.body
|
||||
<ThemedText.Body
|
||||
onClick={onMax}
|
||||
color={theme.text2}
|
||||
fontWeight={400}
|
||||
color={theme.text3}
|
||||
fontWeight={500}
|
||||
fontSize={14}
|
||||
style={{ display: 'inline', cursor: 'pointer' }}
|
||||
>
|
||||
@@ -282,24 +289,19 @@ export default function CurrencyInputPanel({
|
||||
renderBalance ? (
|
||||
renderBalance(selectedCurrencyBalance)
|
||||
) : (
|
||||
<Trans>
|
||||
Balance: {formatCurrencyAmount(selectedCurrencyBalance, 4)} {currency.symbol}
|
||||
</Trans>
|
||||
<Trans>Balance: {formatCurrencyAmount(selectedCurrencyBalance, 4)}</Trans>
|
||||
)
|
||||
) : null}
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
{showMaxButton && selectedCurrencyBalance ? (
|
||||
<StyledBalanceMax onClick={onMax}>
|
||||
<Trans>(Max)</Trans>
|
||||
<Trans>MAX</Trans>
|
||||
</StyledBalanceMax>
|
||||
) : null}
|
||||
</RowFixed>
|
||||
) : (
|
||||
<span />
|
||||
)}
|
||||
<LoadingOpacityContainer $loading={loading}>
|
||||
<FiatValue fiatValue={fiatValue} priceImpact={priceImpact} />
|
||||
</LoadingOpacityContainer>
|
||||
</RowBetween>
|
||||
</FiatRow>
|
||||
)}
|
||||
|
||||
@@ -37,16 +37,24 @@ export const getTokenLogoURL = (
|
||||
const StyledEthereumLogo = styled.img<{ size: string }>`
|
||||
width: ${({ size }) => size};
|
||||
height: ${({ size }) => size};
|
||||
box-shadow: 0px 6px 10px rgba(0, 0, 0, 0.075);
|
||||
border-radius: 24px;
|
||||
background: radial-gradient(white 50%, #ffffff00 calc(75% + 1px), #ffffff00 100%);
|
||||
|
||||
border-radius: 50%;
|
||||
-mox-box-shadow: 0 0 1px white;
|
||||
-webkit-box-shadow: 0 0 1px white;
|
||||
box-shadow: 0 0 1px white;
|
||||
border: 0px solid rgba(255, 255, 255, 0);
|
||||
`
|
||||
|
||||
const StyledLogo = styled(Logo)<{ size: string }>`
|
||||
width: ${({ size }) => size};
|
||||
height: ${({ size }) => size};
|
||||
border-radius: ${({ size }) => size};
|
||||
box-shadow: 0px 6px 10px rgba(0, 0, 0, 0.075);
|
||||
background-color: ${({ theme }) => theme.white};
|
||||
background: radial-gradient(white 50%, #ffffff00 calc(75% + 1px), #ffffff00 100%);
|
||||
border-radius: 50%;
|
||||
-mox-box-shadow: 0 0 1px black;
|
||||
-webkit-box-shadow: 0 0 1px black;
|
||||
box-shadow: 0 0 1px black;
|
||||
border: 0px solid rgba(255, 255, 255, 0);
|
||||
`
|
||||
|
||||
export default function CurrencyLogo({
|
||||
|
||||
@@ -4,7 +4,7 @@ import ReactGA from 'react-ga'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import store, { AppState } from '../../state'
|
||||
import { ExternalLink, TYPE } from '../../theme'
|
||||
import { ExternalLink, ThemedText } from '../../theme'
|
||||
import { userAgent } from '../../utils/userAgent'
|
||||
import { AutoColumn } from '../Column'
|
||||
import { AutoRow } from '../Row'
|
||||
@@ -47,6 +47,8 @@ type ErrorBoundaryState = {
|
||||
error: Error | null
|
||||
}
|
||||
|
||||
const IS_UNISWAP = window.location.hostname === 'app.uniswap.org'
|
||||
|
||||
export default class ErrorBoundary extends React.Component<unknown, ErrorBoundaryState> {
|
||||
constructor(props: unknown) {
|
||||
super(props)
|
||||
@@ -67,6 +69,7 @@ export default class ErrorBoundary extends React.Component<unknown, ErrorBoundar
|
||||
|
||||
render() {
|
||||
const { error } = this.state
|
||||
|
||||
if (error !== null) {
|
||||
const encodedBody = encodeURIComponent(issueBody(error))
|
||||
return (
|
||||
@@ -74,39 +77,41 @@ export default class ErrorBoundary extends React.Component<unknown, ErrorBoundar
|
||||
<BodyWrapper>
|
||||
<AutoColumn gap={'md'}>
|
||||
<SomethingWentWrongWrapper>
|
||||
<TYPE.label fontSize={24} fontWeight={600}>
|
||||
<ThemedText.Label fontSize={24} fontWeight={600}>
|
||||
<Trans>Something went wrong</Trans>
|
||||
</TYPE.label>
|
||||
</ThemedText.Label>
|
||||
</SomethingWentWrongWrapper>
|
||||
<CodeBlockWrapper>
|
||||
<code>
|
||||
<TYPE.main fontSize={10}>{error.stack}</TYPE.main>
|
||||
<ThemedText.Main fontSize={10}>{error.stack}</ThemedText.Main>
|
||||
</code>
|
||||
</CodeBlockWrapper>
|
||||
<AutoRow>
|
||||
<LinkWrapper>
|
||||
<ExternalLink
|
||||
id="create-github-issue-link"
|
||||
href={`https://github.com/Uniswap/uniswap-interface/issues/new?assignees=&labels=bug&body=${encodedBody}&title=${encodeURIComponent(
|
||||
`Crash report: \`${error.name}${error.message && `: ${error.message}`}\``
|
||||
)}`}
|
||||
target="_blank"
|
||||
>
|
||||
<TYPE.link fontSize={16}>
|
||||
<Trans>Create an issue on GitHub</Trans>
|
||||
<span>↗</span>
|
||||
</TYPE.link>
|
||||
</ExternalLink>
|
||||
</LinkWrapper>
|
||||
<LinkWrapper>
|
||||
<ExternalLink id="get-support-on-discord" href="https://discord.gg/FCfyBSbCU5" target="_blank">
|
||||
<TYPE.link fontSize={16}>
|
||||
<Trans>Get support on Discord</Trans>
|
||||
<span>↗</span>
|
||||
</TYPE.link>
|
||||
</ExternalLink>
|
||||
</LinkWrapper>
|
||||
</AutoRow>
|
||||
{IS_UNISWAP ? (
|
||||
<AutoRow>
|
||||
<LinkWrapper>
|
||||
<ExternalLink
|
||||
id="create-github-issue-link"
|
||||
href={`https://github.com/Uniswap/uniswap-interface/issues/new?assignees=&labels=bug&body=${encodedBody}&title=${encodeURIComponent(
|
||||
`Crash report: \`${error.name}${error.message && `: ${error.message}`}\``
|
||||
)}`}
|
||||
target="_blank"
|
||||
>
|
||||
<ThemedText.Link fontSize={16}>
|
||||
<Trans>Create an issue on GitHub</Trans>
|
||||
<span>↗</span>
|
||||
</ThemedText.Link>
|
||||
</ExternalLink>
|
||||
</LinkWrapper>
|
||||
<LinkWrapper>
|
||||
<ExternalLink id="get-support-on-discord" href="https://discord.gg/FCfyBSbCU5" target="_blank">
|
||||
<ThemedText.Link fontSize={16}>
|
||||
<Trans>Get support on Discord</Trans>
|
||||
<span>↗</span>
|
||||
</ThemedText.Link>
|
||||
</ExternalLink>
|
||||
</LinkWrapper>
|
||||
</AutoRow>
|
||||
) : null}
|
||||
</AutoColumn>
|
||||
</BodyWrapper>
|
||||
</FallbackWrapper>
|
||||
@@ -121,7 +126,7 @@ function getRelevantState(): null | keyof AppState {
|
||||
if (!path.startsWith('#/')) {
|
||||
return null
|
||||
}
|
||||
const pieces = path.substring(2).split(/[\/\\?]/)
|
||||
const pieces = path.substring(2).split(/[/\\?]/)
|
||||
switch (pieces[0]) {
|
||||
case 'swap':
|
||||
return 'swap'
|
||||
|
||||
51
src/components/FeeSelector/FeeOption.tsx
Normal file
51
src/components/FeeSelector/FeeOption.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { FeeAmount } from '@uniswap/v3-sdk'
|
||||
import { ButtonRadioChecked } from 'components/Button'
|
||||
import { AutoColumn } from 'components/Column'
|
||||
import { useFeeTierDistribution } from 'hooks/useFeeTierDistribution'
|
||||
import { PoolState } from 'hooks/usePools'
|
||||
import React from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ThemedText } from 'theme'
|
||||
|
||||
import { FeeTierPercentageBadge } from './FeeTierPercentageBadge'
|
||||
import { FEE_AMOUNT_DETAIL } from './shared'
|
||||
|
||||
const ResponsiveText = styled(ThemedText.Label)`
|
||||
line-height: 16px;
|
||||
font-size: 14px;
|
||||
|
||||
${({ theme }) => theme.mediaWidth.upToSmall`
|
||||
font-size: 12px;
|
||||
line-height: 12px;
|
||||
`};
|
||||
`
|
||||
|
||||
interface FeeOptionProps {
|
||||
feeAmount: FeeAmount
|
||||
active: boolean
|
||||
distributions: ReturnType<typeof useFeeTierDistribution>['distributions']
|
||||
poolState: PoolState
|
||||
onClick: () => void
|
||||
}
|
||||
|
||||
export function FeeOption({ feeAmount, active, poolState, distributions, onClick }: FeeOptionProps) {
|
||||
return (
|
||||
<ButtonRadioChecked active={active} onClick={onClick}>
|
||||
<AutoColumn gap="sm" justify="flex-start">
|
||||
<AutoColumn justify="flex-start" gap="6px">
|
||||
<ResponsiveText>
|
||||
<Trans>{FEE_AMOUNT_DETAIL[feeAmount].label}%</Trans>
|
||||
</ResponsiveText>
|
||||
<ThemedText.Main fontWeight={400} fontSize="12px" textAlign="left">
|
||||
{FEE_AMOUNT_DETAIL[feeAmount].description}
|
||||
</ThemedText.Main>
|
||||
</AutoColumn>
|
||||
|
||||
{distributions && (
|
||||
<FeeTierPercentageBadge distributions={distributions} feeAmount={feeAmount} poolState={poolState} />
|
||||
)}
|
||||
</AutoColumn>
|
||||
</ButtonRadioChecked>
|
||||
)
|
||||
}
|
||||
31
src/components/FeeSelector/FeeTierPercentageBadge.tsx
Normal file
31
src/components/FeeSelector/FeeTierPercentageBadge.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { FeeAmount } from '@uniswap/v3-sdk'
|
||||
import Badge from 'components/Badge'
|
||||
import { useFeeTierDistribution } from 'hooks/useFeeTierDistribution'
|
||||
import { PoolState } from 'hooks/usePools'
|
||||
import React from 'react'
|
||||
import { ThemedText } from 'theme'
|
||||
|
||||
export function FeeTierPercentageBadge({
|
||||
feeAmount,
|
||||
distributions,
|
||||
poolState,
|
||||
}: {
|
||||
feeAmount: FeeAmount
|
||||
distributions: ReturnType<typeof useFeeTierDistribution>['distributions']
|
||||
poolState: PoolState
|
||||
}) {
|
||||
return (
|
||||
<Badge>
|
||||
<ThemedText.Label fontSize={10}>
|
||||
{!distributions || poolState === PoolState.NOT_EXISTS || poolState === PoolState.INVALID ? (
|
||||
<Trans>Not created</Trans>
|
||||
) : distributions[feeAmount] !== undefined ? (
|
||||
<Trans>{distributions[feeAmount]?.toFixed(0)}% select</Trans>
|
||||
) : (
|
||||
<Trans>No data</Trans>
|
||||
)}
|
||||
</ThemedText.Label>
|
||||
</Badge>
|
||||
)
|
||||
}
|
||||
@@ -1,20 +1,24 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Currency } from '@uniswap/sdk-core'
|
||||
import { FeeAmount } from '@uniswap/v3-sdk'
|
||||
import Badge from 'components/Badge'
|
||||
import { ButtonGray, ButtonRadioChecked } from 'components/Button'
|
||||
import { ButtonGray } from 'components/Button'
|
||||
import Card from 'components/Card'
|
||||
import { AutoColumn } from 'components/Column'
|
||||
import { RowBetween } from 'components/Row'
|
||||
import { useFeeTierDistribution } from 'hooks/useFeeTierDistribution'
|
||||
import { PoolState, usePools } from 'hooks/usePools'
|
||||
import usePrevious from 'hooks/usePrevious'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import { DynamicSection } from 'pages/AddLiquidity/styled'
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import ReactGA from 'react-ga'
|
||||
import { Box } from 'rebass'
|
||||
import styled, { keyframes } from 'styled-components/macro'
|
||||
import { TYPE } from 'theme'
|
||||
import { ThemedText } from 'theme'
|
||||
|
||||
import { FeeOption } from './FeeOption'
|
||||
import { FeeTierPercentageBadge } from './FeeTierPercentageBadge'
|
||||
import { FEE_AMOUNT_DETAIL } from './shared'
|
||||
|
||||
const pulse = (color: string) => keyframes`
|
||||
0% {
|
||||
@@ -29,60 +33,18 @@ const pulse = (color: string) => keyframes`
|
||||
box-shadow: 0 0 0 0 ${color};
|
||||
}
|
||||
`
|
||||
|
||||
const ResponsiveText = styled(TYPE.label)`
|
||||
line-height: 16px;
|
||||
|
||||
${({ theme }) => theme.mediaWidth.upToSmall`
|
||||
font-size: 12px;
|
||||
line-height: 12px;
|
||||
`};
|
||||
`
|
||||
|
||||
const FocusedOutlineCard = styled(Card)<{ pulsing: boolean }>`
|
||||
border: 1px solid ${({ theme }) => theme.bg2};
|
||||
animation: ${({ pulsing, theme }) => pulsing && pulse(theme.primary1)} 0.6s linear;
|
||||
align-self: center;
|
||||
`
|
||||
|
||||
const FeeAmountLabel = {
|
||||
[FeeAmount.LOW]: {
|
||||
label: '0.05',
|
||||
description: <Trans>Best for stable pairs.</Trans>,
|
||||
},
|
||||
[FeeAmount.MEDIUM]: {
|
||||
label: '0.3',
|
||||
description: <Trans>Best for most pairs.</Trans>,
|
||||
},
|
||||
[FeeAmount.HIGH]: {
|
||||
label: '1',
|
||||
description: <Trans>Best for exotic pairs.</Trans>,
|
||||
},
|
||||
}
|
||||
|
||||
function FeeTierPercentageBadge({
|
||||
feeAmount,
|
||||
distributions,
|
||||
poolState,
|
||||
}: {
|
||||
feeAmount: FeeAmount
|
||||
distributions: ReturnType<typeof useFeeTierDistribution>['distributions']
|
||||
poolState: PoolState
|
||||
}) {
|
||||
return (
|
||||
<Badge>
|
||||
<TYPE.label fontSize={12}>
|
||||
{!distributions || poolState === PoolState.NOT_EXISTS || poolState === PoolState.INVALID ? (
|
||||
<Trans>Not created</Trans>
|
||||
) : distributions[feeAmount] !== undefined ? (
|
||||
<Trans>{distributions[feeAmount]?.toFixed(0)}% select</Trans>
|
||||
) : (
|
||||
<Trans>No data</Trans>
|
||||
)}
|
||||
</TYPE.label>
|
||||
</Badge>
|
||||
)
|
||||
}
|
||||
const Select = styled.div`
|
||||
align-items: flex-start;
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
grid-gap: 8px;
|
||||
`
|
||||
|
||||
export default function FeeSelector({
|
||||
disabled = false,
|
||||
@@ -97,16 +59,19 @@ export default function FeeSelector({
|
||||
currencyA?: Currency | undefined
|
||||
currencyB?: Currency | undefined
|
||||
}) {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
|
||||
const { isLoading, isError, largestUsageFeeTier, distributions } = useFeeTierDistribution(currencyA, currencyB)
|
||||
|
||||
// get pool data on-chain for latest states
|
||||
const pools = usePools([
|
||||
[currencyA, currencyB, FeeAmount.LOWEST],
|
||||
[currencyA, currencyB, FeeAmount.LOW],
|
||||
[currencyA, currencyB, FeeAmount.MEDIUM],
|
||||
[currencyA, currencyB, FeeAmount.HIGH],
|
||||
])
|
||||
|
||||
const poolsByFeeTier = useMemo(
|
||||
const poolsByFeeTier: Record<FeeAmount, PoolState> = useMemo(
|
||||
() =>
|
||||
pools.reduce(
|
||||
(acc, [curPoolState, curPool]) => {
|
||||
@@ -118,6 +83,7 @@ export default function FeeSelector({
|
||||
},
|
||||
{
|
||||
// default all states to NOT_EXISTS
|
||||
[FeeAmount.LOWEST]: PoolState.NOT_EXISTS,
|
||||
[FeeAmount.LOW]: PoolState.NOT_EXISTS,
|
||||
[FeeAmount.MEDIUM]: PoolState.NOT_EXISTS,
|
||||
[FeeAmount.HIGH]: PoolState.NOT_EXISTS,
|
||||
@@ -134,7 +100,7 @@ export default function FeeSelector({
|
||||
const recommended = useRef(false)
|
||||
|
||||
const handleFeePoolSelectWithEvent = useCallback(
|
||||
(fee) => {
|
||||
(fee: FeeAmount) => {
|
||||
ReactGA.event({
|
||||
category: 'FeePoolSelect',
|
||||
action: 'Manual',
|
||||
@@ -183,18 +149,18 @@ export default function FeeSelector({
|
||||
<AutoColumn id="add-liquidity-selected-fee">
|
||||
{!feeAmount ? (
|
||||
<>
|
||||
<TYPE.label>
|
||||
<ThemedText.Label>
|
||||
<Trans>Fee tier</Trans>
|
||||
</TYPE.label>
|
||||
<TYPE.main fontWeight={400} fontSize="12px" textAlign="left">
|
||||
</ThemedText.Label>
|
||||
<ThemedText.Main fontWeight={400} fontSize="12px" textAlign="left">
|
||||
<Trans>The % you will earn in fees.</Trans>
|
||||
</TYPE.main>
|
||||
</ThemedText.Main>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<TYPE.label className="selected-fee-label">
|
||||
<Trans>{FeeAmountLabel[feeAmount].label}% fee tier</Trans>
|
||||
</TYPE.label>
|
||||
<ThemedText.Label className="selected-fee-label">
|
||||
<Trans>{FEE_AMOUNT_DETAIL[feeAmount].label}% fee tier</Trans>
|
||||
</ThemedText.Label>
|
||||
<Box style={{ width: 'fit-content', marginTop: '8px' }} className="selected-fee-percentage">
|
||||
{distributions && (
|
||||
<FeeTierPercentageBadge
|
||||
@@ -214,81 +180,25 @@ export default function FeeSelector({
|
||||
</RowBetween>
|
||||
</FocusedOutlineCard>
|
||||
|
||||
{showOptions && (
|
||||
<RowBetween>
|
||||
<ButtonRadioChecked
|
||||
width="32%"
|
||||
active={feeAmount === FeeAmount.LOW}
|
||||
onClick={() => handleFeePoolSelectWithEvent(FeeAmount.LOW)}
|
||||
>
|
||||
<AutoColumn gap="sm" justify="flex-start">
|
||||
<AutoColumn justify="flex-start" gap="6px">
|
||||
<ResponsiveText>
|
||||
<Trans>0.05% fee</Trans>
|
||||
</ResponsiveText>
|
||||
<TYPE.main fontWeight={400} fontSize="12px" textAlign="left">
|
||||
<Trans>Best for stable pairs.</Trans>
|
||||
</TYPE.main>
|
||||
</AutoColumn>
|
||||
|
||||
{distributions && (
|
||||
<FeeTierPercentageBadge
|
||||
{chainId && showOptions && (
|
||||
<Select>
|
||||
{[FeeAmount.LOWEST, FeeAmount.LOW, FeeAmount.MEDIUM, FeeAmount.HIGH].map((_feeAmount, i) => {
|
||||
const { supportedChains } = FEE_AMOUNT_DETAIL[_feeAmount]
|
||||
if (supportedChains.includes(chainId)) {
|
||||
return (
|
||||
<FeeOption
|
||||
feeAmount={_feeAmount}
|
||||
active={feeAmount === _feeAmount}
|
||||
onClick={() => handleFeePoolSelectWithEvent(_feeAmount)}
|
||||
distributions={distributions}
|
||||
feeAmount={FeeAmount.LOW}
|
||||
poolState={poolsByFeeTier[FeeAmount.LOW]}
|
||||
poolState={poolsByFeeTier[_feeAmount]}
|
||||
key={i}
|
||||
/>
|
||||
)}
|
||||
</AutoColumn>
|
||||
</ButtonRadioChecked>
|
||||
<ButtonRadioChecked
|
||||
width="32%"
|
||||
active={feeAmount === FeeAmount.MEDIUM}
|
||||
onClick={() => handleFeePoolSelectWithEvent(FeeAmount.MEDIUM)}
|
||||
>
|
||||
<AutoColumn gap="sm" justify="flex-start">
|
||||
<AutoColumn justify="flex-start" gap="4px">
|
||||
<ResponsiveText>
|
||||
<Trans>0.3% fee</Trans>
|
||||
</ResponsiveText>
|
||||
<TYPE.main fontWeight={400} fontSize="12px" textAlign="left">
|
||||
<Trans>Best for most pairs.</Trans>
|
||||
</TYPE.main>
|
||||
</AutoColumn>
|
||||
|
||||
{distributions && (
|
||||
<FeeTierPercentageBadge
|
||||
distributions={distributions}
|
||||
feeAmount={FeeAmount.MEDIUM}
|
||||
poolState={poolsByFeeTier[FeeAmount.MEDIUM]}
|
||||
/>
|
||||
)}
|
||||
</AutoColumn>
|
||||
</ButtonRadioChecked>
|
||||
<ButtonRadioChecked
|
||||
width="32%"
|
||||
active={feeAmount === FeeAmount.HIGH}
|
||||
onClick={() => handleFeePoolSelectWithEvent(FeeAmount.HIGH)}
|
||||
>
|
||||
<AutoColumn gap="sm" justify="flex-start">
|
||||
<AutoColumn justify="flex-start" gap="4px">
|
||||
<ResponsiveText>
|
||||
<Trans>1% fee</Trans>
|
||||
</ResponsiveText>
|
||||
<TYPE.main fontWeight={400} fontSize="12px" textAlign="left">
|
||||
<Trans>Best for exotic pairs.</Trans>
|
||||
</TYPE.main>
|
||||
</AutoColumn>
|
||||
|
||||
{distributions && (
|
||||
<FeeTierPercentageBadge
|
||||
distributions={distributions}
|
||||
feeAmount={FeeAmount.HIGH}
|
||||
poolState={poolsByFeeTier[FeeAmount.HIGH]}
|
||||
/>
|
||||
)}
|
||||
</AutoColumn>
|
||||
</ButtonRadioChecked>
|
||||
</RowBetween>
|
||||
)
|
||||
}
|
||||
return null
|
||||
})}
|
||||
</Select>
|
||||
)}
|
||||
</DynamicSection>
|
||||
</AutoColumn>
|
||||
|
||||
30
src/components/FeeSelector/shared.tsx
Normal file
30
src/components/FeeSelector/shared.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { FeeAmount } from '@uniswap/v3-sdk'
|
||||
import { ALL_SUPPORTED_CHAIN_IDS, SupportedChainId } from 'constants/chains'
|
||||
import { ReactNode } from 'react'
|
||||
|
||||
export const FEE_AMOUNT_DETAIL: Record<
|
||||
FeeAmount,
|
||||
{ label: string; description: ReactNode; supportedChains: SupportedChainId[] }
|
||||
> = {
|
||||
[FeeAmount.LOWEST]: {
|
||||
label: '0.01',
|
||||
description: <Trans>Best for very stable pairs.</Trans>,
|
||||
supportedChains: [SupportedChainId.MAINNET],
|
||||
},
|
||||
[FeeAmount.LOW]: {
|
||||
label: '0.05',
|
||||
description: <Trans>Best for stable pairs.</Trans>,
|
||||
supportedChains: ALL_SUPPORTED_CHAIN_IDS,
|
||||
},
|
||||
[FeeAmount.MEDIUM]: {
|
||||
label: '0.3',
|
||||
description: <Trans>Best for most pairs.</Trans>,
|
||||
supportedChains: ALL_SUPPORTED_CHAIN_IDS,
|
||||
},
|
||||
[FeeAmount.HIGH]: {
|
||||
label: '1',
|
||||
description: <Trans>Best for exotic pairs.</Trans>,
|
||||
supportedChains: ALL_SUPPORTED_CHAIN_IDS,
|
||||
},
|
||||
}
|
||||
@@ -34,17 +34,16 @@ const ActiveRowLinkList = styled.div`
|
||||
text-decoration: none;
|
||||
}
|
||||
& > a:first-child {
|
||||
border-top: 1px solid ${({ theme }) => theme.text2};
|
||||
margin: 0;
|
||||
margin-top: 6px;
|
||||
margin-top: 0px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
`
|
||||
const ActiveRowWrapper = styled.div`
|
||||
background-color: ${({ theme }) => theme.bg2};
|
||||
background-color: ${({ theme }) => theme.bg1};
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
padding: 8px 0 8px 0;
|
||||
padding: 8px;
|
||||
width: 100%;
|
||||
`
|
||||
const FlyoutHeader = styled.div`
|
||||
@@ -53,7 +52,7 @@ const FlyoutHeader = styled.div`
|
||||
`
|
||||
const FlyoutMenu = styled.div`
|
||||
align-items: flex-start;
|
||||
background-color: ${({ theme }) => theme.bg1};
|
||||
background-color: ${({ theme }) => theme.bg0};
|
||||
box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.01), 0px 4px 8px rgba(0, 0, 0, 0.04), 0px 16px 24px rgba(0, 0, 0, 0.04),
|
||||
0px 24px 32px rgba(0, 0, 0, 0.01);
|
||||
border-radius: 20px;
|
||||
@@ -75,7 +74,7 @@ const FlyoutMenu = styled.div`
|
||||
`
|
||||
const FlyoutRow = styled.div<{ active: boolean }>`
|
||||
align-items: center;
|
||||
background-color: ${({ active, theme }) => (active ? theme.bg2 : 'transparent')};
|
||||
background-color: ${({ active, theme }) => (active ? theme.bg1 : 'transparent')};
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
@@ -113,8 +112,8 @@ const SelectorLabel = styled(NetworkLabel)`
|
||||
`
|
||||
const SelectorControls = styled.div<{ interactive: boolean }>`
|
||||
align-items: center;
|
||||
background-color: ${({ theme }) => theme.bg1};
|
||||
border: 2px solid ${({ theme }) => theme.bg1};
|
||||
background-color: ${({ theme }) => theme.bg0};
|
||||
border: 2px solid ${({ theme }) => theme.bg0};
|
||||
border-radius: 12px;
|
||||
color: ${({ theme }) => theme.text1};
|
||||
cursor: ${({ interactive }) => (interactive ? 'pointer' : 'auto')};
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { RowFixed } from 'components/Row'
|
||||
import { CHAIN_INFO } from 'constants/chains'
|
||||
import useCurrentBlockTimestamp from 'hooks/useCurrentBlockTimestamp'
|
||||
import useGasPrice from 'hooks/useGasPrice'
|
||||
import useMachineTimeMs from 'hooks/useMachineTime'
|
||||
import useTheme from 'hooks/useTheme'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import JSBI from 'jsbi'
|
||||
import ms from 'ms.macro'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useAppSelector } from 'state/hooks'
|
||||
import { useBlockNumber } from 'state/application/hooks'
|
||||
import styled, { keyframes } from 'styled-components/macro'
|
||||
import { ExternalLink, ThemedText } from 'theme'
|
||||
import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink'
|
||||
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { useBlockNumber } from '../../state/application/hooks'
|
||||
import { ExternalLink, TYPE } from '../../theme'
|
||||
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
|
||||
import { MouseoverTooltip } from '../Tooltip'
|
||||
import { ChainConnectivityWarning } from './ChainConnectivityWarning'
|
||||
|
||||
const StyledPolling = styled.div<{ warning: boolean }>`
|
||||
@@ -22,12 +31,20 @@ const StyledPolling = styled.div<{ warning: boolean }>`
|
||||
display: none;
|
||||
`}
|
||||
`
|
||||
const StyledPollingNumber = styled(TYPE.small)<{ breathe: boolean; hovering: boolean }>`
|
||||
const StyledPollingNumber = styled(ThemedText.Small)<{ breathe: boolean; hovering: boolean }>`
|
||||
transition: opacity 0.25s ease;
|
||||
opacity: ${({ breathe, hovering }) => (hovering ? 0.7 : breathe ? 1 : 0.5)};
|
||||
:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
a {
|
||||
color: unset;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: none;
|
||||
color: unset;
|
||||
}
|
||||
`
|
||||
const StyledPollingDot = styled.div<{ warning: boolean }>`
|
||||
width: 8px;
|
||||
@@ -40,6 +57,17 @@ const StyledPollingDot = styled.div<{ warning: boolean }>`
|
||||
transition: 250ms ease background-color;
|
||||
`
|
||||
|
||||
const StyledGasDot = styled.div`
|
||||
background-color: ${({ theme }) => theme.text3};
|
||||
border-radius: 50%;
|
||||
height: 4px;
|
||||
min-height: 4px;
|
||||
min-width: 4px;
|
||||
position: relative;
|
||||
transition: 250ms ease background-color;
|
||||
width: 4px;
|
||||
`
|
||||
|
||||
const rotate360 = keyframes`
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
@@ -68,12 +96,25 @@ const Spinner = styled.div<{ warning: boolean }>`
|
||||
top: -3px;
|
||||
`
|
||||
|
||||
const DEFAULT_MS_BEFORE_WARNING = ms`10m`
|
||||
const NETWORK_HEALTH_CHECK_MS = ms`10s`
|
||||
|
||||
export default function Polling() {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
const blockNumber = useBlockNumber()
|
||||
const [isMounting, setIsMounting] = useState(false)
|
||||
const [isHover, setIsHover] = useState(false)
|
||||
const chainConnectivityWarning = useAppSelector((state) => state.application.chainConnectivityWarning)
|
||||
const machineTime = useMachineTimeMs(NETWORK_HEALTH_CHECK_MS)
|
||||
const blockTime = useCurrentBlockTimestamp()
|
||||
const theme = useTheme()
|
||||
|
||||
const ethGasPrice = useGasPrice()
|
||||
const priceGwei = ethGasPrice ? JSBI.divide(ethGasPrice, JSBI.BigInt(1000000000)) : undefined
|
||||
|
||||
const waitMsBeforeWarning =
|
||||
(chainId ? CHAIN_INFO[chainId]?.blockWaitMsBeforeWarning : DEFAULT_MS_BEFORE_WARNING) ?? DEFAULT_MS_BEFORE_WARNING
|
||||
|
||||
const warning = Boolean(!!blockTime && machineTime - blockTime.mul(1000).toNumber() > waitMsBeforeWarning)
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
@@ -93,25 +134,48 @@ export default function Polling() {
|
||||
//if you pass a value to array, like this [data] than clearTimeout will run every time this value changes (useEffect re-run)
|
||||
)
|
||||
|
||||
//TODO - chainlink gas oracle is really slow. Can we get a better data source?
|
||||
|
||||
return (
|
||||
<>
|
||||
<ExternalLink
|
||||
href={chainId && blockNumber ? getExplorerLink(chainId, blockNumber.toString(), ExplorerDataType.BLOCK) : ''}
|
||||
>
|
||||
<StyledPolling
|
||||
onMouseEnter={() => setIsHover(true)}
|
||||
onMouseLeave={() => setIsHover(false)}
|
||||
warning={chainConnectivityWarning}
|
||||
>
|
||||
<RowFixed>
|
||||
<StyledPolling onMouseEnter={() => setIsHover(true)} onMouseLeave={() => setIsHover(false)} warning={warning}>
|
||||
<ExternalLink href={'https://etherscan.io/gastracker'}>
|
||||
{priceGwei ? (
|
||||
<RowFixed style={{ marginRight: '8px' }}>
|
||||
<ThemedText.Main fontSize="11px" mr="8px" color={theme.text3}>
|
||||
<MouseoverTooltip
|
||||
text={
|
||||
<Trans>
|
||||
{`The current fast gas amount for sending a transaction on L1.
|
||||
Gas fees are paid in Ethereum's native currency Ether (ETH) and denominated in gwei. `}
|
||||
</Trans>
|
||||
}
|
||||
>
|
||||
{priceGwei.toString()} <Trans>gwei</Trans>
|
||||
</MouseoverTooltip>
|
||||
</ThemedText.Main>
|
||||
<StyledGasDot />
|
||||
</RowFixed>
|
||||
) : null}
|
||||
</ExternalLink>
|
||||
<StyledPollingNumber breathe={isMounting} hovering={isHover}>
|
||||
{blockNumber} 
|
||||
<ExternalLink
|
||||
href={
|
||||
chainId && blockNumber ? getExplorerLink(chainId, blockNumber.toString(), ExplorerDataType.BLOCK) : ''
|
||||
}
|
||||
>
|
||||
<MouseoverTooltip
|
||||
text={<Trans>{`The most recent block number on this network. Prices update on every block.`}</Trans>}
|
||||
>
|
||||
{blockNumber} 
|
||||
</MouseoverTooltip>
|
||||
</ExternalLink>
|
||||
</StyledPollingNumber>
|
||||
<StyledPollingDot warning={chainConnectivityWarning}>
|
||||
{isMounting && <Spinner warning={chainConnectivityWarning} />}
|
||||
</StyledPollingDot>{' '}
|
||||
<StyledPollingDot warning={warning}>{isMounting && <Spinner warning={warning} />}</StyledPollingDot>{' '}
|
||||
</StyledPolling>
|
||||
</ExternalLink>
|
||||
{chainConnectivityWarning && <ChainConnectivityWarning />}
|
||||
{warning && <ChainConnectivityWarning />}
|
||||
</RowFixed>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import useUSDCPrice from '../../hooks/useUSDCPrice'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { useTotalUniEarned } from '../../state/stake/hooks'
|
||||
import { useAggregateUniBalance, useTokenBalance } from '../../state/wallet/hooks'
|
||||
import { ExternalLink, StyledInternalLink, TYPE, UniTokenAnimated } from '../../theme'
|
||||
import { ExternalLink, StyledInternalLink, ThemedText, UniTokenAnimated } from '../../theme'
|
||||
import { computeUniCirculation } from '../../utils/computeUniCirculation'
|
||||
import { AutoColumn } from '../Column'
|
||||
import { Break, CardBGImage, CardNoise, CardSection, DataCard } from '../earn/styled'
|
||||
@@ -70,9 +70,9 @@ export default function UniBalanceContent({ setShowUniBalanceModal }: { setShowU
|
||||
<CardNoise />
|
||||
<CardSection gap="md">
|
||||
<RowBetween>
|
||||
<TYPE.white color="white">
|
||||
<ThemedText.White color="white">
|
||||
<Trans>Your UNI Breakdown</Trans>
|
||||
</TYPE.white>
|
||||
</ThemedText.White>
|
||||
<StyledClose stroke="white" onClick={() => setShowUniBalanceModal(false)} />
|
||||
</RowBetween>
|
||||
</CardSection>
|
||||
@@ -82,29 +82,29 @@ export default function UniBalanceContent({ setShowUniBalanceModal }: { setShowU
|
||||
<CardSection gap="sm">
|
||||
<AutoColumn gap="md" justify="center">
|
||||
<UniTokenAnimated width="48px" src={tokenLogo} />{' '}
|
||||
<TYPE.white fontSize={48} fontWeight={600} color="white">
|
||||
<ThemedText.White fontSize={48} fontWeight={600} color="white">
|
||||
{total?.toFixed(2, { groupSeparator: ',' })}
|
||||
</TYPE.white>
|
||||
</ThemedText.White>
|
||||
</AutoColumn>
|
||||
<AutoColumn gap="md">
|
||||
<RowBetween>
|
||||
<TYPE.white color="white">
|
||||
<ThemedText.White color="white">
|
||||
<Trans>Balance:</Trans>
|
||||
</TYPE.white>
|
||||
<TYPE.white color="white">{uniBalance?.toFixed(2, { groupSeparator: ',' })}</TYPE.white>
|
||||
</ThemedText.White>
|
||||
<ThemedText.White color="white">{uniBalance?.toFixed(2, { groupSeparator: ',' })}</ThemedText.White>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<TYPE.white color="white">
|
||||
<ThemedText.White color="white">
|
||||
<Trans>Unclaimed:</Trans>
|
||||
</TYPE.white>
|
||||
<TYPE.white color="white">
|
||||
</ThemedText.White>
|
||||
<ThemedText.White color="white">
|
||||
{uniToClaim?.toFixed(4, { groupSeparator: ',' })}{' '}
|
||||
{uniToClaim && uniToClaim.greaterThan('0') && (
|
||||
<StyledInternalLink onClick={() => setShowUniBalanceModal(false)} to="/uni">
|
||||
<Trans>(claim)</Trans>
|
||||
</StyledInternalLink>
|
||||
)}
|
||||
</TYPE.white>
|
||||
</ThemedText.White>
|
||||
</RowBetween>
|
||||
</AutoColumn>
|
||||
</CardSection>
|
||||
@@ -114,22 +114,22 @@ export default function UniBalanceContent({ setShowUniBalanceModal }: { setShowU
|
||||
<CardSection gap="sm">
|
||||
<AutoColumn gap="md">
|
||||
<RowBetween>
|
||||
<TYPE.white color="white">
|
||||
<ThemedText.White color="white">
|
||||
<Trans>UNI price:</Trans>
|
||||
</TYPE.white>
|
||||
<TYPE.white color="white">${uniPrice?.toFixed(2) ?? '-'}</TYPE.white>
|
||||
</ThemedText.White>
|
||||
<ThemedText.White color="white">${uniPrice?.toFixed(2) ?? '-'}</ThemedText.White>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<TYPE.white color="white">
|
||||
<ThemedText.White color="white">
|
||||
<Trans>UNI in circulation:</Trans>
|
||||
</TYPE.white>
|
||||
<TYPE.white color="white">{circulation?.toFixed(0, { groupSeparator: ',' })}</TYPE.white>
|
||||
</ThemedText.White>
|
||||
<ThemedText.White color="white">{circulation?.toFixed(0, { groupSeparator: ',' })}</ThemedText.White>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<TYPE.white color="white">
|
||||
<ThemedText.White color="white">
|
||||
<Trans>Total Supply</Trans>
|
||||
</TYPE.white>
|
||||
<TYPE.white color="white">{totalSupply?.toFixed(0, { groupSeparator: ',' })}</TYPE.white>
|
||||
</ThemedText.White>
|
||||
<ThemedText.White color="white">{totalSupply?.toFixed(0, { groupSeparator: ',' })}</ThemedText.White>
|
||||
</RowBetween>
|
||||
{uni && uni.chainId === 1 ? (
|
||||
<ExternalLink href={`${infoLink}/token/${uni.address}`}>
|
||||
|
||||
@@ -15,7 +15,7 @@ import styled from 'styled-components/macro'
|
||||
|
||||
import { ReactComponent as Logo } from '../../assets/svg/logo.svg'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { ExternalLink, TYPE } from '../../theme'
|
||||
import { ExternalLink, ThemedText } from '../../theme'
|
||||
import ClaimModal from '../claim/ClaimModal'
|
||||
import { CardNoise } from '../earn/styled'
|
||||
import Menu from '../Menu'
|
||||
@@ -309,7 +309,7 @@ export default function Header() {
|
||||
{availableClaim && !showClaimPopup && (
|
||||
<UNIWrapper onClick={toggleClaimModal}>
|
||||
<UNIAmount active={!!account && !availableClaim} style={{ pointerEvents: 'auto' }}>
|
||||
<TYPE.white padding="0 2px">
|
||||
<ThemedText.White padding="0 2px">
|
||||
{claimTxn && !claimTxn?.receipt ? (
|
||||
<Dots>
|
||||
<Trans>Claiming UNI</Trans>
|
||||
@@ -317,7 +317,7 @@ export default function Header() {
|
||||
) : (
|
||||
<Trans>Claim UNI</Trans>
|
||||
)}
|
||||
</TYPE.white>
|
||||
</ThemedText.White>
|
||||
</UNIAmount>
|
||||
<CardNoise />
|
||||
</UNIWrapper>
|
||||
|
||||
@@ -2,9 +2,15 @@ import Tooltip from 'components/Tooltip'
|
||||
import { useState } from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
const TextWrapper = styled.span<{ margin: boolean; link?: boolean; fontSize?: string; adjustSize?: boolean }>`
|
||||
const TextWrapper = styled.span<{
|
||||
margin: boolean
|
||||
link?: boolean
|
||||
fontSize?: string
|
||||
adjustSize?: boolean
|
||||
textColor?: string
|
||||
}>`
|
||||
margin-left: ${({ margin }) => margin && '4px'};
|
||||
color: ${({ theme, link }) => (link ? theme.blue1 : theme.text1)};
|
||||
color: ${({ theme, link, textColor }) => (link ? theme.blue1 : textColor ?? theme.text1)};
|
||||
font-size: ${({ fontSize }) => fontSize ?? 'inherit'};
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
@@ -18,6 +24,7 @@ const HoverInlineText = ({
|
||||
margin = false,
|
||||
adjustSize = false,
|
||||
fontSize,
|
||||
textColor,
|
||||
link,
|
||||
...rest
|
||||
}: {
|
||||
@@ -26,6 +33,7 @@ const HoverInlineText = ({
|
||||
margin?: boolean
|
||||
adjustSize?: boolean
|
||||
fontSize?: string
|
||||
textColor?: string
|
||||
link?: boolean
|
||||
}) => {
|
||||
const [showHover, setShowHover] = useState(false)
|
||||
@@ -42,6 +50,7 @@ const HoverInlineText = ({
|
||||
onMouseLeave={() => setShowHover(false)}
|
||||
margin={margin}
|
||||
adjustSize={adjustSize}
|
||||
textColor={textColor}
|
||||
link={link}
|
||||
fontSize={fontSize}
|
||||
{...rest}
|
||||
@@ -53,7 +62,14 @@ const HoverInlineText = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<TextWrapper margin={margin} adjustSize={adjustSize} link={link} fontSize={fontSize} {...rest}>
|
||||
<TextWrapper
|
||||
margin={margin}
|
||||
adjustSize={adjustSize}
|
||||
link={link}
|
||||
fontSize={fontSize}
|
||||
textColor={textColor}
|
||||
{...rest}
|
||||
>
|
||||
{text}
|
||||
</TextWrapper>
|
||||
)
|
||||
|
||||
25
src/components/Identicon/StatusIcon.tsx
Normal file
25
src/components/Identicon/StatusIcon.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import { AbstractConnector } from '@web3-react/abstract-connector'
|
||||
|
||||
import CoinbaseWalletIcon from '../../assets/images/coinbaseWalletIcon.svg'
|
||||
import FortmaticIcon from '../../assets/images/fortmaticIcon.png'
|
||||
import PortisIcon from '../../assets/images/portisIcon.png'
|
||||
import WalletConnectIcon from '../../assets/images/walletConnectIcon.svg'
|
||||
import { fortmatic, injected, portis, walletconnect, walletlink } from '../../connectors'
|
||||
import Identicon from '../Identicon'
|
||||
|
||||
export default function StatusIcon({ connector }: { connector: AbstractConnector }) {
|
||||
switch (connector) {
|
||||
case injected:
|
||||
return <Identicon />
|
||||
case walletconnect:
|
||||
return <img src={WalletConnectIcon} alt={'WalletConnect'} />
|
||||
case walletlink:
|
||||
return <img src={CoinbaseWalletIcon} alt={'Coinbase Wallet'} />
|
||||
case fortmatic:
|
||||
return <img src={FortmaticIcon} alt={'Fortmatic'} />
|
||||
case portis:
|
||||
return <img src={PortisIcon} alt={'Portis'} />
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -1,32 +1,53 @@
|
||||
import Davatar, { Image } from '@davatar/react'
|
||||
import { useMemo } from 'react'
|
||||
import jazzicon from '@metamask/jazzicon'
|
||||
import useENSAvatar from 'hooks/useENSAvatar'
|
||||
import { useLayoutEffect, useMemo, useRef, useState } from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
|
||||
const StyledIdenticonContainer = styled.div`
|
||||
const StyledIdenticon = styled.div`
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
border-radius: 1.125rem;
|
||||
background-color: ${({ theme }) => theme.bg4};
|
||||
font-size: initial;
|
||||
`
|
||||
|
||||
const StyledAvatar = styled.img`
|
||||
height: inherit;
|
||||
width: inherit;
|
||||
border-radius: inherit;
|
||||
`
|
||||
|
||||
export default function Identicon() {
|
||||
const { account, library } = useActiveWeb3React()
|
||||
const { account } = useActiveWeb3React()
|
||||
const { avatar } = useENSAvatar(account ?? undefined)
|
||||
const [fetchable, setFetchable] = useState(true)
|
||||
|
||||
// restrict usage of Davatar until it stops sending 3p requests
|
||||
// see https://github.com/metaphor-xyz/davatar-helpers/issues/18
|
||||
const supportsENS = useMemo(() => {
|
||||
return ([1, 3, 4, 5] as Array<number | undefined>).includes(library?.network?.chainId)
|
||||
}, [library])
|
||||
const icon = useMemo(() => account && jazzicon(16, parseInt(account.slice(2, 10), 16)), [account])
|
||||
const iconRef = useRef<HTMLDivElement>(null)
|
||||
useLayoutEffect(() => {
|
||||
const current = iconRef.current
|
||||
if (icon) {
|
||||
current?.appendChild(icon)
|
||||
return () => {
|
||||
try {
|
||||
current?.removeChild(icon)
|
||||
} catch (e) {
|
||||
console.error('Avatar icon not found')
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}, [icon, iconRef])
|
||||
|
||||
return (
|
||||
<StyledIdenticonContainer>
|
||||
{account && supportsENS ? (
|
||||
<Davatar address={account} size={16} provider={library} />
|
||||
<StyledIdenticon>
|
||||
{avatar && fetchable ? (
|
||||
<StyledAvatar alt="avatar" src={avatar} onError={() => setFetchable(false)}></StyledAvatar>
|
||||
) : (
|
||||
<Image address={account} size={16} />
|
||||
<span ref={iconRef} />
|
||||
)}
|
||||
</StyledIdenticonContainer>
|
||||
</StyledIdenticon>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { AutoColumn } from 'components/Column'
|
||||
import { ReactNode, useCallback, useEffect, useState } from 'react'
|
||||
import { Minus, Plus } from 'react-feather'
|
||||
import styled, { keyframes } from 'styled-components/macro'
|
||||
import { TYPE } from 'theme'
|
||||
import { ThemedText } from 'theme'
|
||||
|
||||
import { Input as NumericalInput } from '../NumericalInput'
|
||||
|
||||
@@ -57,13 +57,13 @@ const StyledInput = styled(NumericalInput)<{ usePercent?: boolean }>`
|
||||
`};
|
||||
`
|
||||
|
||||
const InputTitle = styled(TYPE.small)`
|
||||
const InputTitle = styled(ThemedText.Small)`
|
||||
color: ${({ theme }) => theme.text2};
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
`
|
||||
|
||||
const ButtonLabel = styled(TYPE.white)<{ disabled: boolean }>`
|
||||
const ButtonLabel = styled(ThemedText.White)<{ disabled: boolean }>`
|
||||
color: ${({ theme, disabled }) => (disabled ? theme.text2 : theme.text1)} !important;
|
||||
`
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ export const Area = ({
|
||||
.y0(yScale(0))(
|
||||
series.filter((d) => {
|
||||
const value = xScale(xValue(d))
|
||||
return value > 0 && value <= innerWidth
|
||||
return value > 0 && value <= window.innerWidth
|
||||
}) as Iterable<[number, number]>
|
||||
) ?? undefined
|
||||
}
|
||||
|
||||
@@ -14,12 +14,18 @@ import { batch } from 'react-redux'
|
||||
import { Bound } from 'state/mint/v3/actions'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import { TYPE } from '../../theme'
|
||||
import { ThemedText } from '../../theme'
|
||||
import { Chart } from './Chart'
|
||||
import { useDensityChartData } from './hooks'
|
||||
import { ZoomLevels } from './types'
|
||||
|
||||
const ZOOM_LEVELS: Record<FeeAmount, ZoomLevels> = {
|
||||
[FeeAmount.LOWEST]: {
|
||||
initialMin: 0.999,
|
||||
initialMax: 1.001,
|
||||
min: 0.00001,
|
||||
max: 1.5,
|
||||
},
|
||||
[FeeAmount.LOW]: {
|
||||
initialMin: 0.999,
|
||||
initialMax: 1.001,
|
||||
@@ -52,9 +58,9 @@ function InfoBox({ message, icon }: { message?: ReactNode; icon: ReactNode }) {
|
||||
<ColumnCenter style={{ height: '100%', justifyContent: 'center' }}>
|
||||
{icon}
|
||||
{message && (
|
||||
<TYPE.mediumHeader padding={10} marginTop="20px" textAlign="center">
|
||||
<ThemedText.MediumHeader padding={10} marginTop="20px" textAlign="center">
|
||||
{message}
|
||||
</TYPE.mediumHeader>
|
||||
</ThemedText.MediumHeader>
|
||||
)}
|
||||
</ColumnCenter>
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { t, Trans } from '@lingui/macro'
|
||||
import { PrivacyPolicyModal } from 'components/PrivacyPolicy'
|
||||
import { CHAIN_INFO, L2_CHAIN_IDS, SupportedChainId } from 'constants/chains'
|
||||
import { L2_CHAIN_IDS } from 'constants/chains'
|
||||
import { LOCALE_LABEL, SUPPORTED_LOCALES, SupportedLocale } from 'constants/locales'
|
||||
import { useActiveLocale } from 'hooks/useActiveLocale'
|
||||
import { useLocationLinkProps } from 'hooks/useLocationLinkProps'
|
||||
@@ -10,13 +10,13 @@ import {
|
||||
BookOpen,
|
||||
Check,
|
||||
ChevronLeft,
|
||||
Code,
|
||||
Coffee,
|
||||
FileText,
|
||||
Globe,
|
||||
HelpCircle,
|
||||
Info,
|
||||
MessageCircle,
|
||||
Moon,
|
||||
PieChart,
|
||||
Sun,
|
||||
} from 'react-feather'
|
||||
import { Link } from 'react-router-dom'
|
||||
@@ -179,8 +179,6 @@ const ToggleMenuItem = styled.button`
|
||||
}
|
||||
`
|
||||
|
||||
const CODE_LINK = 'https://github.com/Uniswap/uniswap-interface'
|
||||
|
||||
function LanguageMenuItem({ locale, active, key }: { locale: SupportedLocale; active: boolean; key: string }) {
|
||||
const { to, onClick } = useLocationLinkProps(locale)
|
||||
|
||||
@@ -219,7 +217,6 @@ export default function Menu() {
|
||||
const togglePrivacyPolicy = useToggleModal(ApplicationModal.PRIVACY_POLICY)
|
||||
const openClaimModal = useToggleModal(ApplicationModal.ADDRESS_CLAIM)
|
||||
const showUNIClaimOption = Boolean(!!account && !!chainId && !L2_CHAIN_IDS.includes(chainId))
|
||||
const { infoLink } = CHAIN_INFO[chainId ? chainId : SupportedChainId.MAINNET]
|
||||
|
||||
const [darkMode, toggleDarkMode] = useDarkModeManager()
|
||||
|
||||
@@ -252,17 +249,17 @@ export default function Menu() {
|
||||
</div>
|
||||
<Info opacity={0.6} size={16} />
|
||||
</MenuItem>
|
||||
<MenuItem href="https://docs.uniswap.org/">
|
||||
<MenuItem href="https://help.uniswap.org/">
|
||||
<div>
|
||||
<Trans>Docs</Trans>
|
||||
<Trans>Help Center</Trans>
|
||||
</div>
|
||||
<BookOpen opacity={0.6} size={16} />
|
||||
<HelpCircle opacity={0.6} size={16} />
|
||||
</MenuItem>
|
||||
<MenuItem href={CODE_LINK}>
|
||||
<MenuItem href="https://uniswap.canny.io/feature-requests">
|
||||
<div>
|
||||
<Trans>Code</Trans>
|
||||
<Trans>Request Features</Trans>
|
||||
</div>
|
||||
<Code opacity={0.6} size={16} />
|
||||
<Coffee opacity={0.6} size={16} />
|
||||
</MenuItem>
|
||||
<MenuItem href="https://discord.gg/FCfyBSbCU5">
|
||||
<div>
|
||||
@@ -270,12 +267,6 @@ export default function Menu() {
|
||||
</div>
|
||||
<MessageCircle opacity={0.6} size={16} />
|
||||
</MenuItem>
|
||||
<MenuItem href={infoLink}>
|
||||
<div>
|
||||
<Trans>Analytics</Trans>
|
||||
</div>
|
||||
<PieChart opacity={0.6} size={16} />
|
||||
</MenuItem>
|
||||
<ToggleMenuItem onClick={() => setMenu('lang')}>
|
||||
<div>
|
||||
<Trans>Language</Trans>
|
||||
@@ -286,6 +277,12 @@ export default function Menu() {
|
||||
<div>{darkMode ? <Trans>Light Theme</Trans> : <Trans>Dark Theme</Trans>}</div>
|
||||
{darkMode ? <Moon opacity={0.6} size={16} /> : <Sun opacity={0.6} size={16} />}
|
||||
</ToggleMenuItem>
|
||||
<MenuItem href="https://docs.uniswap.org/">
|
||||
<div>
|
||||
<Trans>Docs</Trans>
|
||||
</div>
|
||||
<BookOpen opacity={0.6} size={16} />
|
||||
</MenuItem>
|
||||
<ToggleMenuItem onClick={() => togglePrivacyPolicy()}>
|
||||
<div>
|
||||
<Trans>Legal & Privacy</Trans>
|
||||
|
||||
@@ -5,7 +5,7 @@ import styled, { ThemeContext } from 'styled-components/macro'
|
||||
|
||||
import Circle from '../../assets/images/blue-loader.svg'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { CloseIcon, CustomLightSpinner, TYPE } from '../../theme'
|
||||
import { CloseIcon, CustomLightSpinner, ThemedText } from '../../theme'
|
||||
import { ExternalLink } from '../../theme/components'
|
||||
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
|
||||
import { AutoColumn, ColumnCenter } from '../Column'
|
||||
@@ -32,9 +32,9 @@ export function LoadingView({ children, onDismiss }: { children: any; onDismiss:
|
||||
</ConfirmedIcon>
|
||||
<AutoColumn gap="100px" justify={'center'}>
|
||||
{children}
|
||||
<TYPE.subHeader>
|
||||
<ThemedText.SubHeader>
|
||||
<Trans>Confirm this transaction in your wallet</Trans>
|
||||
</TYPE.subHeader>
|
||||
</ThemedText.SubHeader>
|
||||
</AutoColumn>
|
||||
</ConfirmOrLoadingWrapper>
|
||||
)
|
||||
@@ -68,9 +68,9 @@ export function SubmittedView({
|
||||
href={getExplorerLink(chainId, hash, ExplorerDataType.TRANSACTION)}
|
||||
style={{ marginLeft: '4px' }}
|
||||
>
|
||||
<TYPE.subHeader>
|
||||
<ThemedText.SubHeader>
|
||||
<Trans>View transaction on Explorer</Trans>
|
||||
</TYPE.subHeader>
|
||||
</ThemedText.SubHeader>
|
||||
</ExternalLink>
|
||||
)}
|
||||
</AutoColumn>
|
||||
|
||||
@@ -10,7 +10,7 @@ import { useAppDispatch } from 'state/hooks'
|
||||
import { resetMintState } from 'state/mint/actions'
|
||||
import { resetMintState as resetMintV3State } from 'state/mint/v3/actions'
|
||||
import styled from 'styled-components/macro'
|
||||
import { TYPE } from 'theme'
|
||||
import { ThemedText } from 'theme'
|
||||
|
||||
import Row, { RowBetween } from '../Row'
|
||||
import SettingsTab from '../Settings'
|
||||
@@ -136,7 +136,7 @@ export function AddRemoveTabs({
|
||||
>
|
||||
<StyledArrowLeft stroke={theme.text2} />
|
||||
</StyledHistoryLink>
|
||||
<TYPE.mediumHeader
|
||||
<ThemedText.MediumHeader
|
||||
fontWeight={500}
|
||||
fontSize={20}
|
||||
style={{ flex: '1', margin: 'auto', textAlign: children ? 'start' : 'center' }}
|
||||
@@ -148,7 +148,7 @@ export function AddRemoveTabs({
|
||||
) : (
|
||||
<Trans>Remove Liquidity</Trans>
|
||||
)}
|
||||
</TYPE.mediumHeader>
|
||||
</ThemedText.MediumHeader>
|
||||
<Box style={{ marginRight: '.5rem' }}>{children}</Box>
|
||||
<SettingsTab placeholderSlippage={defaultSlippage} />
|
||||
</RowBetween>
|
||||
|
||||
@@ -260,7 +260,7 @@ export function NetworkAlert(props: NetworkAlertProps) {
|
||||
</Header>
|
||||
<Body>
|
||||
<Trans>
|
||||
To starting trading on {info.label}, first bridge your assets from L1 to L2. Please treat this as a beta
|
||||
To start trading on {info.label}, first bridge your assets from L1 to L2. Please treat this as a beta
|
||||
release and learn about the risks before using {info.label}.
|
||||
</Trans>
|
||||
</Body>
|
||||
|
||||
@@ -12,7 +12,7 @@ const StyledInput = styled.input<{ error?: boolean; fontSize?: string; align?: s
|
||||
border: none;
|
||||
flex: 1 1 auto;
|
||||
background-color: ${({ theme }) => theme.bg1};
|
||||
font-size: ${({ fontSize }) => fontSize ?? '24px'};
|
||||
font-size: ${({ fontSize }) => fontSize ?? '28px'};
|
||||
text-align: ${({ align }) => align && align};
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
|
||||
@@ -6,7 +6,6 @@ import ReactGA from 'react-ga'
|
||||
import styled, { keyframes } from 'styled-components/macro'
|
||||
|
||||
import tokenLogo from '../../assets/images/token-logo.png'
|
||||
import { ButtonPrimary } from '../../components/Button'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import {
|
||||
useModalOpen,
|
||||
@@ -16,7 +15,8 @@ import {
|
||||
} from '../../state/application/hooks'
|
||||
import { ApplicationModal } from '../../state/application/reducer'
|
||||
import { useUserHasAvailableClaim, useUserUnclaimedAmount } from '../../state/claim/hooks'
|
||||
import { TYPE } from '../../theme'
|
||||
import { ThemedText } from '../../theme'
|
||||
import { ButtonPrimary } from '../Button'
|
||||
import { AutoColumn } from '../Column'
|
||||
import { CardBGImage, CardNoise } from '../earn/styled'
|
||||
|
||||
@@ -98,10 +98,10 @@ export default function ClaimPopup() {
|
||||
<StyledClose stroke="white" onClick={toggleShowClaimPopup} />
|
||||
<AutoColumn style={{ padding: '2rem 0', zIndex: 10 }} justify="center">
|
||||
<UniToken width="48px" src={tokenLogo} />{' '}
|
||||
<TYPE.white style={{ marginTop: '1rem' }} fontSize={36} fontWeight={600}>
|
||||
<ThemedText.White style={{ marginTop: '1rem' }} fontSize={36} fontWeight={600}>
|
||||
{unclaimedAmount?.toFixed(0, { groupSeparator: ',' } ?? '-')} UNI
|
||||
</TYPE.white>
|
||||
<TYPE.white style={{ paddingTop: '1.25rem', textAlign: 'center' }} fontWeight={600} color="white">
|
||||
</ThemedText.White>
|
||||
<ThemedText.White style={{ paddingTop: '1.25rem', textAlign: 'center' }} fontWeight={600} color="white">
|
||||
<span role="img" aria-label="party">
|
||||
🎉
|
||||
</span>{' '}
|
||||
@@ -109,12 +109,12 @@ export default function ClaimPopup() {
|
||||
<span role="img" aria-label="party">
|
||||
🎉
|
||||
</span>
|
||||
</TYPE.white>
|
||||
<TYPE.subHeader style={{ paddingTop: '0.5rem', textAlign: 'center' }} color="white">
|
||||
</ThemedText.White>
|
||||
<ThemedText.SubHeader style={{ paddingTop: '0.5rem', textAlign: 'center' }} color="white">
|
||||
<Trans>
|
||||
Thanks for being part of the Uniswap community <Heart size={12} />
|
||||
</Trans>
|
||||
</TYPE.subHeader>
|
||||
</ThemedText.SubHeader>
|
||||
</AutoColumn>
|
||||
<AutoColumn style={{ zIndex: 10 }} justify="center">
|
||||
<ButtonPrimary padding="8px" $borderRadius="8px" width={'fit-content'} onClick={handleToggleSelfClaimModal}>
|
||||
|
||||
@@ -4,8 +4,8 @@ import styled, { ThemeContext } from 'styled-components/macro'
|
||||
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { useTransaction } from '../../state/transactions/hooks'
|
||||
import { TYPE } from '../../theme'
|
||||
import { ExternalLink } from '../../theme/components'
|
||||
import { ThemedText } from '../../theme'
|
||||
import { ExternalLink } from '../../theme'
|
||||
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
|
||||
import { TransactionSummary } from '../AccountDetails/TransactionSummary'
|
||||
import { AutoColumn } from '../Column'
|
||||
@@ -30,9 +30,9 @@ export default function TransactionPopup({ hash }: { hash: string }) {
|
||||
{success ? <CheckCircle color={theme.green1} size={24} /> : <AlertCircle color={theme.red1} size={24} />}
|
||||
</div>
|
||||
<AutoColumn gap="8px">
|
||||
<TYPE.body fontWeight={500}>
|
||||
<ThemedText.Body fontWeight={500}>
|
||||
<TransactionSummary info={tx.info} />
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
{chainId && (
|
||||
<ExternalLink href={getExplorerLink(chainId, hash, ExplorerDataType.TRANSACTION)}>
|
||||
View on Explorer
|
||||
|
||||
@@ -14,7 +14,7 @@ import { useColor } from '../../hooks/useColor'
|
||||
import { useTotalSupply } from '../../hooks/useTotalSupply'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { useTokenBalance } from '../../state/wallet/hooks'
|
||||
import { ExternalLink, TYPE } from '../../theme'
|
||||
import { ExternalLink, ThemedText } from '../../theme'
|
||||
import { currencyId } from '../../utils/currencyId'
|
||||
import { unwrappedToken } from '../../utils/unwrappedToken'
|
||||
import { ButtonEmpty, ButtonPrimary, ButtonSecondary } from '../Button'
|
||||
@@ -142,7 +142,7 @@ export function MinimalPositionCard({ pair, showUnwrapped = false, border }: Pos
|
||||
</GreyCard>
|
||||
) : (
|
||||
<LightCard>
|
||||
<TYPE.subHeader style={{ textAlign: 'center' }}>
|
||||
<ThemedText.SubHeader style={{ textAlign: 'center' }}>
|
||||
<span role="img" aria-label="wizard-icon">
|
||||
⭐️
|
||||
</span>{' '}
|
||||
@@ -150,7 +150,7 @@ export function MinimalPositionCard({ pair, showUnwrapped = false, border }: Pos
|
||||
By adding liquidity you'll earn 0.3% of all trades on this pair proportional to your share of the
|
||||
pool. Fees are added to the pool, accrue in real time and can be claimed by withdrawing your liquidity.
|
||||
</Trans>{' '}
|
||||
</TYPE.subHeader>
|
||||
</ThemedText.SubHeader>
|
||||
</LightCard>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -13,7 +13,7 @@ import JSBI from 'jsbi'
|
||||
import { ReactNode, useCallback, useContext, useState } from 'react'
|
||||
import { Bound } from 'state/mint/v3/actions'
|
||||
import { ThemeContext } from 'styled-components/macro'
|
||||
import { TYPE } from 'theme'
|
||||
import { ThemedText } from 'theme'
|
||||
import { formatTickPrice } from 'utils/formatTickPrice'
|
||||
import { unwrappedToken } from 'utils/unwrappedToken'
|
||||
|
||||
@@ -70,9 +70,9 @@ export const PositionPreview = ({
|
||||
size={24}
|
||||
margin={true}
|
||||
/>
|
||||
<TYPE.label ml="10px" fontSize="24px">
|
||||
<ThemedText.Label ml="10px" fontSize="24px">
|
||||
{currency0?.symbol} / {currency1?.symbol}
|
||||
</TYPE.label>
|
||||
</ThemedText.Label>
|
||||
</RowFixed>
|
||||
<RangeBadge removed={removed} inRange={inRange} />
|
||||
</RowBetween>
|
||||
@@ -82,36 +82,36 @@ export const PositionPreview = ({
|
||||
<RowBetween>
|
||||
<RowFixed>
|
||||
<CurrencyLogo currency={currency0} />
|
||||
<TYPE.label ml="8px">{currency0?.symbol}</TYPE.label>
|
||||
<ThemedText.Label ml="8px">{currency0?.symbol}</ThemedText.Label>
|
||||
</RowFixed>
|
||||
<RowFixed>
|
||||
<TYPE.label mr="8px">{position.amount0.toSignificant(4)}</TYPE.label>
|
||||
<ThemedText.Label mr="8px">{position.amount0.toSignificant(4)}</ThemedText.Label>
|
||||
</RowFixed>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<RowFixed>
|
||||
<CurrencyLogo currency={currency1} />
|
||||
<TYPE.label ml="8px">{currency1?.symbol}</TYPE.label>
|
||||
<ThemedText.Label ml="8px">{currency1?.symbol}</ThemedText.Label>
|
||||
</RowFixed>
|
||||
<RowFixed>
|
||||
<TYPE.label mr="8px">{position.amount1.toSignificant(4)}</TYPE.label>
|
||||
<ThemedText.Label mr="8px">{position.amount1.toSignificant(4)}</ThemedText.Label>
|
||||
</RowFixed>
|
||||
</RowBetween>
|
||||
<Break />
|
||||
<RowBetween>
|
||||
<TYPE.label>
|
||||
<ThemedText.Label>
|
||||
<Trans>Fee Tier</Trans>
|
||||
</TYPE.label>
|
||||
<TYPE.label>
|
||||
</ThemedText.Label>
|
||||
<ThemedText.Label>
|
||||
<Trans>{position?.pool?.fee / 10000}%</Trans>
|
||||
</TYPE.label>
|
||||
</ThemedText.Label>
|
||||
</RowBetween>
|
||||
</AutoColumn>
|
||||
</LightCard>
|
||||
|
||||
<AutoColumn gap="md">
|
||||
<RowBetween>
|
||||
{title ? <TYPE.main>{title}</TYPE.main> : <div />}
|
||||
{title ? <ThemedText.Main>{title}</ThemedText.Main> : <div />}
|
||||
<RateToggle
|
||||
currencyA={sorted ? currency0 : currency1}
|
||||
currencyB={sorted ? currency1 : currency0}
|
||||
@@ -122,57 +122,57 @@ export const PositionPreview = ({
|
||||
<RowBetween>
|
||||
<LightCard width="48%" padding="8px">
|
||||
<AutoColumn gap="4px" justify="center">
|
||||
<TYPE.main fontSize="12px">
|
||||
<ThemedText.Main fontSize="12px">
|
||||
<Trans>Min Price</Trans>
|
||||
</TYPE.main>
|
||||
<TYPE.mediumHeader textAlign="center">{`${formatTickPrice(
|
||||
</ThemedText.Main>
|
||||
<ThemedText.MediumHeader textAlign="center">{`${formatTickPrice(
|
||||
priceLower,
|
||||
ticksAtLimit,
|
||||
Bound.LOWER
|
||||
)}`}</TYPE.mediumHeader>
|
||||
<TYPE.main textAlign="center" fontSize="12px">
|
||||
)}`}</ThemedText.MediumHeader>
|
||||
<ThemedText.Main textAlign="center" fontSize="12px">
|
||||
<Trans>
|
||||
{quoteCurrency.symbol} per {baseCurrency.symbol}
|
||||
</Trans>
|
||||
</TYPE.main>
|
||||
<TYPE.small textAlign="center" color={theme.text3} style={{ marginTop: '4px' }}>
|
||||
</ThemedText.Main>
|
||||
<ThemedText.Small textAlign="center" color={theme.text3} style={{ marginTop: '4px' }}>
|
||||
<Trans>Your position will be 100% composed of {baseCurrency?.symbol} at this price</Trans>
|
||||
</TYPE.small>
|
||||
</ThemedText.Small>
|
||||
</AutoColumn>
|
||||
</LightCard>
|
||||
|
||||
<LightCard width="48%" padding="8px">
|
||||
<AutoColumn gap="4px" justify="center">
|
||||
<TYPE.main fontSize="12px">
|
||||
<ThemedText.Main fontSize="12px">
|
||||
<Trans>Max Price</Trans>
|
||||
</TYPE.main>
|
||||
<TYPE.mediumHeader textAlign="center">{`${formatTickPrice(
|
||||
</ThemedText.Main>
|
||||
<ThemedText.MediumHeader textAlign="center">{`${formatTickPrice(
|
||||
priceUpper,
|
||||
ticksAtLimit,
|
||||
Bound.UPPER
|
||||
)}`}</TYPE.mediumHeader>
|
||||
<TYPE.main textAlign="center" fontSize="12px">
|
||||
)}`}</ThemedText.MediumHeader>
|
||||
<ThemedText.Main textAlign="center" fontSize="12px">
|
||||
<Trans>
|
||||
{quoteCurrency.symbol} per {baseCurrency.symbol}
|
||||
</Trans>
|
||||
</TYPE.main>
|
||||
<TYPE.small textAlign="center" color={theme.text3} style={{ marginTop: '4px' }}>
|
||||
</ThemedText.Main>
|
||||
<ThemedText.Small textAlign="center" color={theme.text3} style={{ marginTop: '4px' }}>
|
||||
<Trans>Your position will be 100% composed of {quoteCurrency?.symbol} at this price</Trans>
|
||||
</TYPE.small>
|
||||
</ThemedText.Small>
|
||||
</AutoColumn>
|
||||
</LightCard>
|
||||
</RowBetween>
|
||||
<LightCard padding="12px ">
|
||||
<AutoColumn gap="4px" justify="center">
|
||||
<TYPE.main fontSize="12px">
|
||||
<ThemedText.Main fontSize="12px">
|
||||
<Trans>Current price</Trans>
|
||||
</TYPE.main>
|
||||
<TYPE.mediumHeader>{`${price.toSignificant(5)} `}</TYPE.mediumHeader>
|
||||
<TYPE.main textAlign="center" fontSize="12px">
|
||||
</ThemedText.Main>
|
||||
<ThemedText.MediumHeader>{`${price.toSignificant(5)} `}</ThemedText.MediumHeader>
|
||||
<ThemedText.Main textAlign="center" fontSize="12px">
|
||||
<Trans>
|
||||
{quoteCurrency.symbol} per {baseCurrency.symbol}
|
||||
</Trans>
|
||||
</TYPE.main>
|
||||
</ThemedText.Main>
|
||||
</AutoColumn>
|
||||
</LightCard>
|
||||
</AutoColumn>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useEffect, useRef } from 'react'
|
||||
import { ArrowDown, Info, X } from 'react-feather'
|
||||
import ReactGA from 'react-ga'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ExternalLink, TYPE } from 'theme'
|
||||
import { ExternalLink, ThemedText } from 'theme'
|
||||
import { isMobile } from 'utils/userAgent'
|
||||
|
||||
import { useModalOpen, useTogglePrivacyPolicy } from '../../state/application/hooks'
|
||||
@@ -58,9 +58,15 @@ const EXTERNAL_APIS = [
|
||||
{
|
||||
name: 'TRM Labs',
|
||||
description: (
|
||||
<Trans>
|
||||
The app securely collects your wallet address and shares it with TRM Labs Inc. for risk and compliance reasons.
|
||||
</Trans>
|
||||
<>
|
||||
<Trans>
|
||||
The app securely collects your wallet address and shares it with TRM Labs Inc. for risk and compliance
|
||||
reasons.
|
||||
</Trans>{' '}
|
||||
<ExternalLink href="https://help.uniswap.org/en/articles/5675203-terms-of-service-faq">
|
||||
<Trans>Learn more</Trans>
|
||||
</ExternalLink>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
@@ -91,9 +97,9 @@ export function PrivacyPolicyModal() {
|
||||
<Modal isOpen={open} onDismiss={() => toggle()}>
|
||||
<AutoColumn gap="12px" ref={node as any}>
|
||||
<RowBetween padding="1rem 1rem 0.5rem 1rem">
|
||||
<TYPE.mediumHeader>
|
||||
<ThemedText.MediumHeader>
|
||||
<Trans>Legal & Privacy</Trans>
|
||||
</TYPE.mediumHeader>
|
||||
</ThemedText.MediumHeader>
|
||||
<HoverText onClick={() => toggle()}>
|
||||
<X size={24} />
|
||||
</HoverText>
|
||||
@@ -122,9 +128,9 @@ export function PrivacyPolicy() {
|
||||
<RowBetween>
|
||||
<AutoRow gap="4px">
|
||||
<Info size={20} />
|
||||
<TYPE.main fontSize={14} color={'primaryText1'}>
|
||||
<ThemedText.Main fontSize={14} color={'primaryText1'}>
|
||||
<Trans>Uniswap Labs' Terms of Service</Trans>
|
||||
</TYPE.main>
|
||||
</ThemedText.Main>
|
||||
</AutoRow>
|
||||
<StyledLinkOut size={20} />
|
||||
</RowBetween>
|
||||
@@ -135,29 +141,29 @@ export function PrivacyPolicy() {
|
||||
<RowBetween>
|
||||
<AutoRow gap="4px">
|
||||
<Info size={20} />
|
||||
<TYPE.main fontSize={14} color={'primaryText1'}>
|
||||
<ThemedText.Main fontSize={14} color={'primaryText1'}>
|
||||
<Trans>Protocol Disclaimer</Trans>
|
||||
</TYPE.main>
|
||||
</ThemedText.Main>
|
||||
</AutoRow>
|
||||
<StyledLinkOut size={20} />
|
||||
</RowBetween>
|
||||
</ExternalLink>
|
||||
</StyledExternalCard>
|
||||
</AutoColumn>
|
||||
<TYPE.main fontSize={14}>
|
||||
<ThemedText.Main fontSize={14}>
|
||||
<Trans>This app uses the following third-party APIs:</Trans>
|
||||
</TYPE.main>
|
||||
</ThemedText.Main>
|
||||
<AutoColumn gap="12px">
|
||||
{EXTERNAL_APIS.map(({ name, description }, i) => (
|
||||
<DarkGreyCard key={i}>
|
||||
<AutoColumn gap="8px">
|
||||
<AutoRow gap="4px">
|
||||
<Info size={18} />
|
||||
<TYPE.main fontSize={14} color={'text1'}>
|
||||
<ThemedText.Main fontSize={14} color={'text1'}>
|
||||
{name}
|
||||
</TYPE.main>
|
||||
</ThemedText.Main>
|
||||
</AutoRow>
|
||||
<TYPE.main fontSize={14}>{description}</TYPE.main>
|
||||
<ThemedText.Main fontSize={14}>{description}</ThemedText.Main>
|
||||
</AutoColumn>
|
||||
</DarkGreyCard>
|
||||
))}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useContext } from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ThemeContext } from 'styled-components/macro'
|
||||
|
||||
import { TYPE } from '../../theme'
|
||||
import { ThemedText } from '../../theme'
|
||||
import { AutoColumn } from '../Column'
|
||||
|
||||
const Wrapper = styled(AutoColumn)`
|
||||
@@ -65,7 +65,7 @@ export default function ProgressCircles({ steps, disabled = false, ...rest }: Pr
|
||||
<Circle confirmed={step} disabled={disabled || (!steps[i - 1] && i !== 0)}>
|
||||
{step ? '✓' : i + 1 + '.'}
|
||||
</Circle>
|
||||
<TYPE.main color={theme.text4}>|</TYPE.main>
|
||||
<ThemedText.Main color={theme.text4}>|</ThemedText.Main>
|
||||
</CircleRow>
|
||||
)
|
||||
})}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { AutoRow } from 'components/Row'
|
||||
import React from 'react'
|
||||
import ReactGA from 'react-ga'
|
||||
import styled from 'styled-components/macro'
|
||||
import { TYPE } from 'theme'
|
||||
import { ThemedText } from 'theme'
|
||||
|
||||
const Button = styled(ButtonOutlined).attrs(() => ({
|
||||
padding: '8px',
|
||||
@@ -26,9 +26,9 @@ export default function PresetsButtons({ setFullRange }: { setFullRange: () => v
|
||||
})
|
||||
}}
|
||||
>
|
||||
<TYPE.body fontSize={12}>
|
||||
<ThemedText.Body fontSize={12}>
|
||||
<Trans>Full Range</Trans>
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
</Button>
|
||||
</AutoRow>
|
||||
)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Protocol } from '@uniswap/router-sdk'
|
||||
import { Currency, Percent } from '@uniswap/sdk-core'
|
||||
import { FeeAmount } from '@uniswap/v3-sdk'
|
||||
import { DAI, USDC, WBTC } from 'constants/tokens'
|
||||
@@ -7,16 +8,21 @@ import RoutingDiagram, { RoutingDiagramEntry } from './RoutingDiagram'
|
||||
|
||||
const percent = (strings: TemplateStringsArray) => new Percent(parseInt(strings[0]), 100)
|
||||
|
||||
const singleRoute: RoutingDiagramEntry = { percent: percent`100`, path: [[USDC, DAI, FeeAmount.LOW]] }
|
||||
const singleRoute: RoutingDiagramEntry = {
|
||||
percent: percent`100`,
|
||||
path: [[USDC, DAI, FeeAmount.LOW]],
|
||||
protocol: Protocol.V3,
|
||||
}
|
||||
|
||||
const multiRoute: RoutingDiagramEntry[] = [
|
||||
{ percent: percent`75`, path: [[USDC, DAI, FeeAmount.LOW]] },
|
||||
{ percent: percent`75`, path: [[USDC, DAI, FeeAmount.LOWEST]], protocol: Protocol.V2 },
|
||||
{
|
||||
percent: percent`25`,
|
||||
path: [
|
||||
[USDC, WBTC, FeeAmount.MEDIUM],
|
||||
[WBTC, DAI, FeeAmount.HIGH],
|
||||
],
|
||||
protocol: Protocol.V3,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Protocol } from '@uniswap/router-sdk'
|
||||
import { Currency, Percent } from '@uniswap/sdk-core'
|
||||
import { FeeAmount } from '@uniswap/v3-sdk'
|
||||
import Badge from 'components/Badge'
|
||||
@@ -7,24 +9,24 @@ import Row, { AutoRow } from 'components/Row'
|
||||
import { useTokenInfoFromActiveList } from 'hooks/useTokenInfoFromActiveList'
|
||||
import { Box } from 'rebass'
|
||||
import styled from 'styled-components/macro'
|
||||
import { TYPE } from 'theme'
|
||||
import { ThemedText, Z_INDEX } from 'theme'
|
||||
|
||||
import { ReactComponent as DotLine } from '../../assets/svg/dot_line.svg'
|
||||
import { MouseoverTooltip } from '../Tooltip'
|
||||
|
||||
export interface RoutingDiagramEntry {
|
||||
percent: Percent
|
||||
path: [Currency, Currency, FeeAmount][]
|
||||
protocol: Protocol
|
||||
}
|
||||
|
||||
const Wrapper = styled(Box)`
|
||||
align-items: center;
|
||||
background-color: ${({ theme }) => theme.bg0};
|
||||
width: 400px;
|
||||
width: 100%;
|
||||
`
|
||||
|
||||
const RouteContainerRow = styled(Row)`
|
||||
display: grid;
|
||||
grid-gap: 8px;
|
||||
grid-template-columns: 24px 1fr 24px;
|
||||
`
|
||||
|
||||
@@ -38,7 +40,7 @@ const RouteRow = styled(Row)`
|
||||
|
||||
const PoolBadge = styled(Badge)`
|
||||
display: flex;
|
||||
padding: 0.25rem 0.5rem;
|
||||
padding: 4px 4px;
|
||||
`
|
||||
|
||||
const DottedLine = styled.div`
|
||||
@@ -58,7 +60,27 @@ const DotColor = styled(DotLine)`
|
||||
|
||||
const OpaqueBadge = styled(Badge)`
|
||||
background-color: ${({ theme }) => theme.bg2};
|
||||
z-index: 2;
|
||||
border-radius: 8px;
|
||||
display: grid;
|
||||
font-size: 12px;
|
||||
grid-gap: 4px;
|
||||
grid-auto-flow: column;
|
||||
justify-content: start;
|
||||
padding: 4px 6px 4px 4px;
|
||||
z-index: ${Z_INDEX.sticky};
|
||||
`
|
||||
|
||||
const ProtocolBadge = styled(Badge)`
|
||||
background-color: ${({ theme }) => theme.bg3};
|
||||
border-radius: 4px;
|
||||
color: ${({ theme }) => theme.text2};
|
||||
font-size: 10px;
|
||||
padding: 2px 4px;
|
||||
z-index: ${Z_INDEX.sticky + 1};
|
||||
`
|
||||
|
||||
const BadgeText = styled(ThemedText.Small)`
|
||||
word-break: normal;
|
||||
`
|
||||
|
||||
export default function RoutingDiagram({
|
||||
@@ -75,29 +97,31 @@ export default function RoutingDiagram({
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
{routes.map(({ percent, path }, index) => (
|
||||
{routes.map((entry, index) => (
|
||||
<RouteContainerRow key={index}>
|
||||
<CurrencyLogo currency={tokenIn} />
|
||||
<Route percent={percent} path={path} />
|
||||
<CurrencyLogo currency={tokenOut} />
|
||||
<CurrencyLogo currency={tokenIn} size={'20px'} />
|
||||
<Route entry={entry} />
|
||||
<CurrencyLogo currency={tokenOut} size={'20px'} />
|
||||
</RouteContainerRow>
|
||||
))}
|
||||
</Wrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function Route({ percent, path }: { percent: RoutingDiagramEntry['percent']; path: RoutingDiagramEntry['path'] }) {
|
||||
function Route({ entry: { percent, path, protocol } }: { entry: RoutingDiagramEntry }) {
|
||||
return (
|
||||
<RouteRow>
|
||||
<DottedLine>
|
||||
<DotColor />
|
||||
</DottedLine>
|
||||
<OpaqueBadge>
|
||||
<TYPE.small fontSize={12} style={{ wordBreak: 'normal' }}>
|
||||
<ProtocolBadge>
|
||||
<BadgeText fontSize={12}>{protocol.toUpperCase()}</BadgeText>
|
||||
</ProtocolBadge>
|
||||
<BadgeText fontSize={14} style={{ minWidth: 'auto' }}>
|
||||
{percent.toSignificant(2)}%
|
||||
</TYPE.small>
|
||||
</BadgeText>
|
||||
</OpaqueBadge>
|
||||
|
||||
<AutoRow gap="1px" width="100%" style={{ justifyContent: 'space-evenly', zIndex: 2 }}>
|
||||
{path.map(([currency0, currency1, feeAmount], index) => (
|
||||
<Pool key={index} currency0={currency0} currency1={currency1} feeAmount={feeAmount} />
|
||||
@@ -111,12 +135,17 @@ function Pool({ currency0, currency1, feeAmount }: { currency0: Currency; curren
|
||||
const tokenInfo0 = useTokenInfoFromActiveList(currency0)
|
||||
const tokenInfo1 = useTokenInfoFromActiveList(currency1)
|
||||
|
||||
// TODO - link pool icon to info.uniswap.org via query params
|
||||
return (
|
||||
<PoolBadge>
|
||||
<Box margin="0 5px 0 10px">
|
||||
<DoubleCurrencyLogo currency0={tokenInfo1} currency1={tokenInfo0} size={20} />
|
||||
</Box>
|
||||
<TYPE.small fontSize={12}>{feeAmount / 10000}%</TYPE.small>
|
||||
</PoolBadge>
|
||||
<MouseoverTooltip
|
||||
text={<Trans>{tokenInfo0?.symbol + '/' + tokenInfo1?.symbol + ' ' + feeAmount / 10000}% pool</Trans>}
|
||||
>
|
||||
<PoolBadge>
|
||||
<Box margin="0 4px 0 12px">
|
||||
<DoubleCurrencyLogo currency0={tokenInfo1} currency1={tokenInfo0} size={20} />
|
||||
</Box>
|
||||
<ThemedText.Small fontSize={14}>{feeAmount / 10000}%</ThemedText.Small>
|
||||
</PoolBadge>
|
||||
</MouseoverTooltip>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
exports[`renders multi route 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="RoutingDiagram__Wrapper-sc-o1ook0-0 fUoVYh css-vurnku"
|
||||
class="RoutingDiagram__Wrapper-sc-o1ook0-0 ePDWDk css-vurnku"
|
||||
>
|
||||
<div
|
||||
class="sc-bdnxRM Row-sc-nrd8cx-0 RoutingDiagram__RouteContainerRow-sc-o1ook0-1 lmTMKd itvFNV iiQQUx"
|
||||
class="sc-bdnxRM Row-sc-nrd8cx-0 RoutingDiagram__RouteContainerRow-sc-o1ook0-1 lmTMKd itvFNV ibRCpr"
|
||||
>
|
||||
CurrencyLogo currency=USDC
|
||||
<div
|
||||
@@ -22,11 +22,20 @@ exports[`renders multi route 1`] = `
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="Badge-sc-1mhw5si-0 RoutingDiagram__OpaqueBadge-sc-o1ook0-6 gayll khxosM"
|
||||
class="Badge-sc-1mhw5si-0 RoutingDiagram__OpaqueBadge-sc-o1ook0-6 gayll OurGh"
|
||||
>
|
||||
<div
|
||||
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab css-15li2d9"
|
||||
style="word-break: normal;"
|
||||
class="Badge-sc-1mhw5si-0 RoutingDiagram__ProtocolBadge-sc-o1ook0-7 gayll bNVqMw"
|
||||
>
|
||||
<div
|
||||
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab RoutingDiagram__BadgeText-sc-o1ook0-8 dYpdfO css-15li2d9"
|
||||
>
|
||||
V2
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab RoutingDiagram__BadgeText-sc-o1ook0-8 dYpdfO css-1aekuku"
|
||||
style="min-width: auto;"
|
||||
>
|
||||
75%
|
||||
</div>
|
||||
@@ -36,26 +45,13 @@ exports[`renders multi route 1`] = `
|
||||
style="justify-content: space-evenly; z-index: 2;"
|
||||
width="100%"
|
||||
>
|
||||
<div
|
||||
class="Badge-sc-1mhw5si-0 RoutingDiagram__PoolBadge-sc-o1ook0-3 gayll bRJvWg"
|
||||
>
|
||||
<div
|
||||
class="css-1t7xebc"
|
||||
>
|
||||
DoubleCurrencyLogo currency0=DAI currency1=USDC
|
||||
</div>
|
||||
<div
|
||||
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab css-15li2d9"
|
||||
>
|
||||
0.05%
|
||||
</div>
|
||||
</div>
|
||||
Popover
|
||||
</div>
|
||||
</div>
|
||||
CurrencyLogo currency=DAI
|
||||
</div>
|
||||
<div
|
||||
class="sc-bdnxRM Row-sc-nrd8cx-0 RoutingDiagram__RouteContainerRow-sc-o1ook0-1 lmTMKd itvFNV iiQQUx"
|
||||
class="sc-bdnxRM Row-sc-nrd8cx-0 RoutingDiagram__RouteContainerRow-sc-o1ook0-1 lmTMKd itvFNV ibRCpr"
|
||||
>
|
||||
CurrencyLogo currency=USDC
|
||||
<div
|
||||
@@ -71,11 +67,20 @@ exports[`renders multi route 1`] = `
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="Badge-sc-1mhw5si-0 RoutingDiagram__OpaqueBadge-sc-o1ook0-6 gayll khxosM"
|
||||
class="Badge-sc-1mhw5si-0 RoutingDiagram__OpaqueBadge-sc-o1ook0-6 gayll OurGh"
|
||||
>
|
||||
<div
|
||||
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab css-15li2d9"
|
||||
style="word-break: normal;"
|
||||
class="Badge-sc-1mhw5si-0 RoutingDiagram__ProtocolBadge-sc-o1ook0-7 gayll bNVqMw"
|
||||
>
|
||||
<div
|
||||
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab RoutingDiagram__BadgeText-sc-o1ook0-8 dYpdfO css-15li2d9"
|
||||
>
|
||||
V3
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab RoutingDiagram__BadgeText-sc-o1ook0-8 dYpdfO css-1aekuku"
|
||||
style="min-width: auto;"
|
||||
>
|
||||
25%
|
||||
</div>
|
||||
@@ -85,34 +90,7 @@ exports[`renders multi route 1`] = `
|
||||
style="justify-content: space-evenly; z-index: 2;"
|
||||
width="100%"
|
||||
>
|
||||
<div
|
||||
class="Badge-sc-1mhw5si-0 RoutingDiagram__PoolBadge-sc-o1ook0-3 gayll bRJvWg"
|
||||
>
|
||||
<div
|
||||
class="css-1t7xebc"
|
||||
>
|
||||
DoubleCurrencyLogo currency0=WBTC currency1=USDC
|
||||
</div>
|
||||
<div
|
||||
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab css-15li2d9"
|
||||
>
|
||||
0.3%
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Badge-sc-1mhw5si-0 RoutingDiagram__PoolBadge-sc-o1ook0-3 gayll bRJvWg"
|
||||
>
|
||||
<div
|
||||
class="css-1t7xebc"
|
||||
>
|
||||
DoubleCurrencyLogo currency0=DAI currency1=WBTC
|
||||
</div>
|
||||
<div
|
||||
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab css-15li2d9"
|
||||
>
|
||||
1%
|
||||
</div>
|
||||
</div>
|
||||
PopoverPopover
|
||||
</div>
|
||||
</div>
|
||||
CurrencyLogo currency=DAI
|
||||
@@ -124,10 +102,10 @@ exports[`renders multi route 1`] = `
|
||||
exports[`renders single route 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="RoutingDiagram__Wrapper-sc-o1ook0-0 fUoVYh css-vurnku"
|
||||
class="RoutingDiagram__Wrapper-sc-o1ook0-0 ePDWDk css-vurnku"
|
||||
>
|
||||
<div
|
||||
class="sc-bdnxRM Row-sc-nrd8cx-0 RoutingDiagram__RouteContainerRow-sc-o1ook0-1 lmTMKd itvFNV iiQQUx"
|
||||
class="sc-bdnxRM Row-sc-nrd8cx-0 RoutingDiagram__RouteContainerRow-sc-o1ook0-1 lmTMKd itvFNV ibRCpr"
|
||||
>
|
||||
CurrencyLogo currency=USDC
|
||||
<div
|
||||
@@ -143,11 +121,20 @@ exports[`renders single route 1`] = `
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="Badge-sc-1mhw5si-0 RoutingDiagram__OpaqueBadge-sc-o1ook0-6 gayll khxosM"
|
||||
class="Badge-sc-1mhw5si-0 RoutingDiagram__OpaqueBadge-sc-o1ook0-6 gayll OurGh"
|
||||
>
|
||||
<div
|
||||
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab css-15li2d9"
|
||||
style="word-break: normal;"
|
||||
class="Badge-sc-1mhw5si-0 RoutingDiagram__ProtocolBadge-sc-o1ook0-7 gayll bNVqMw"
|
||||
>
|
||||
<div
|
||||
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab RoutingDiagram__BadgeText-sc-o1ook0-8 dYpdfO css-15li2d9"
|
||||
>
|
||||
V3
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab RoutingDiagram__BadgeText-sc-o1ook0-8 dYpdfO css-1aekuku"
|
||||
style="min-width: auto;"
|
||||
>
|
||||
100%
|
||||
</div>
|
||||
@@ -157,20 +144,7 @@ exports[`renders single route 1`] = `
|
||||
style="justify-content: space-evenly; z-index: 2;"
|
||||
width="100%"
|
||||
>
|
||||
<div
|
||||
class="Badge-sc-1mhw5si-0 RoutingDiagram__PoolBadge-sc-o1ook0-3 gayll bRJvWg"
|
||||
>
|
||||
<div
|
||||
class="css-1t7xebc"
|
||||
>
|
||||
DoubleCurrencyLogo currency0=DAI currency1=USDC
|
||||
</div>
|
||||
<div
|
||||
class="theme__TextWrapper-sc-18nh1jk-0 cWOfab css-15li2d9"
|
||||
>
|
||||
0.05%
|
||||
</div>
|
||||
</div>
|
||||
Popover
|
||||
</div>
|
||||
</div>
|
||||
CurrencyLogo currency=DAI
|
||||
@@ -182,7 +156,7 @@ exports[`renders single route 1`] = `
|
||||
exports[`renders when no routes are provided 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="RoutingDiagram__Wrapper-sc-o1ook0-0 fUoVYh css-vurnku"
|
||||
class="RoutingDiagram__Wrapper-sc-o1ook0-0 ePDWDk css-vurnku"
|
||||
/>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Token } from '@uniswap/sdk-core'
|
||||
import { ButtonPrimary } from 'components/Button'
|
||||
import { AlertCircle, ArrowLeft } from 'react-feather'
|
||||
import styled from 'styled-components/macro'
|
||||
import { CloseIcon, TYPE } from 'theme'
|
||||
import { CloseIcon, ThemedText } from 'theme'
|
||||
|
||||
import TokenImportCard from './TokenImportCard'
|
||||
|
||||
@@ -22,7 +22,7 @@ const Button = styled(ButtonPrimary)`
|
||||
const Content = styled.div`
|
||||
padding: 1em;
|
||||
`
|
||||
const Copy = styled(TYPE.body)`
|
||||
const Copy = styled(ThemedText.Body)`
|
||||
text-align: center;
|
||||
margin: 0 2em 1em !important;
|
||||
font-weight: 400;
|
||||
@@ -51,9 +51,9 @@ const BlockedToken = ({ onBack, onDismiss, blockedTokens }: BlockedTokenProps) =
|
||||
<Wrapper>
|
||||
<Header>
|
||||
{onBack ? <ArrowLeft style={{ cursor: 'pointer' }} onClick={onBack} /> : <div />}
|
||||
<TYPE.mediumHeader>
|
||||
<ThemedText.MediumHeader>
|
||||
<Trans>Token not supported</Trans>
|
||||
</TYPE.mediumHeader>
|
||||
</ThemedText.MediumHeader>
|
||||
{onDismiss ? <CloseIcon onClick={onDismiss} /> : <div />}
|
||||
</Header>
|
||||
<Icon />
|
||||
|
||||
@@ -14,7 +14,7 @@ import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { useCombinedActiveList } from '../../state/lists/hooks'
|
||||
import { WrappedTokenInfo } from '../../state/lists/wrappedTokenInfo'
|
||||
import { useCurrencyBalance } from '../../state/wallet/hooks'
|
||||
import { TYPE } from '../../theme'
|
||||
import { ThemedText } from '../../theme'
|
||||
import { isTokenOnList } from '../../utils'
|
||||
import Column from '../Column'
|
||||
import CurrencyLogo from '../CurrencyLogo'
|
||||
@@ -135,13 +135,13 @@ function CurrencyRow({
|
||||
<Text title={currency.name} fontWeight={500}>
|
||||
{currency.symbol}
|
||||
</Text>
|
||||
<TYPE.darkGray ml="0px" fontSize={'12px'} fontWeight={300}>
|
||||
<ThemedText.DarkGray ml="0px" fontSize={'12px'} fontWeight={300}>
|
||||
{!currency.isNative && !isOnSelectedList && customAdded ? (
|
||||
<Trans>{currency.name} • Added by user</Trans>
|
||||
) : (
|
||||
currency.name
|
||||
)}
|
||||
</TYPE.darkGray>
|
||||
</ThemedText.DarkGray>
|
||||
</Column>
|
||||
<TokenTags currency={currency} />
|
||||
{showCurrencyAmount && (
|
||||
@@ -167,9 +167,9 @@ function BreakLineComponent({ style }: { style: CSSProperties }) {
|
||||
<RowBetween>
|
||||
<RowFixed>
|
||||
<TokenListLogoWrapper src={TokenListLogo} />
|
||||
<TYPE.main ml="6px" fontSize="12px" color={theme.text1}>
|
||||
<ThemedText.Main ml="6px" fontSize="12px" color={theme.text1}>
|
||||
<Trans>Expanded results from inactive Token Lists</Trans>
|
||||
</TYPE.main>
|
||||
</ThemedText.Main>
|
||||
</RowFixed>
|
||||
<QuestionHelper
|
||||
text={
|
||||
|
||||
@@ -16,7 +16,7 @@ import styled from 'styled-components/macro'
|
||||
import { ExtendedEther } from '../../constants/tokens'
|
||||
import { useAllTokens, useIsUserAddedToken, useSearchInactiveTokenLists, useToken } from '../../hooks/Tokens'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { ButtonText, CloseIcon, IconWrapper, TYPE } from '../../theme'
|
||||
import { ButtonText, CloseIcon, IconWrapper, ThemedText } from '../../theme'
|
||||
import { isAddress } from '../../utils'
|
||||
import Column from '../Column'
|
||||
import Row, { RowBetween, RowFixed } from '../Row'
|
||||
@@ -224,9 +224,9 @@ export function CurrencySearch({
|
||||
</div>
|
||||
) : (
|
||||
<Column style={{ padding: '20px', height: '100%' }}>
|
||||
<TYPE.main color={theme.text3} textAlign="center" mb="20px">
|
||||
<ThemedText.Main color={theme.text3} textAlign="center" mb="20px">
|
||||
<Trans>No results found.</Trans>
|
||||
</TYPE.main>
|
||||
</ThemedText.Main>
|
||||
</Column>
|
||||
)}
|
||||
<Footer>
|
||||
@@ -236,9 +236,9 @@ export function CurrencySearch({
|
||||
<IconWrapper size="16px" marginRight="6px" stroke={theme.primaryText1}>
|
||||
<Edit />
|
||||
</IconWrapper>
|
||||
<TYPE.main color={theme.primaryText1}>
|
||||
<ThemedText.Main color={theme.primaryText1}>
|
||||
<Trans>Manage Token Lists</Trans>
|
||||
</TYPE.main>
|
||||
</ThemedText.Main>
|
||||
</RowFixed>
|
||||
</ButtonText>
|
||||
</Row>
|
||||
|
||||
@@ -16,9 +16,9 @@ import { useAppDispatch } from 'state/hooks'
|
||||
import { enableList, removeList } from 'state/lists/actions'
|
||||
import { useAllLists } from 'state/lists/hooks'
|
||||
import styled from 'styled-components/macro'
|
||||
import { CloseIcon, TYPE } from 'theme'
|
||||
import { CloseIcon, ThemedText } from 'theme'
|
||||
|
||||
import { ExternalLink } from '../../theme/components'
|
||||
import { ExternalLink } from '../../theme'
|
||||
import { CurrencyModalView } from './CurrencySearchModal'
|
||||
import { Checkbox, PaddedColumn, TextDot } from './styleds'
|
||||
|
||||
@@ -81,9 +81,9 @@ export function ImportList({ listURL, list, setModalView, onDismiss }: ImportPro
|
||||
<PaddedColumn gap="14px" style={{ width: '100%', flex: '1 1' }}>
|
||||
<RowBetween>
|
||||
<ArrowLeft style={{ cursor: 'pointer' }} onClick={() => setModalView(CurrencyModalView.manage)} />
|
||||
<TYPE.mediumHeader>
|
||||
<ThemedText.MediumHeader>
|
||||
<Trans>Import List</Trans>
|
||||
</TYPE.mediumHeader>
|
||||
</ThemedText.MediumHeader>
|
||||
<CloseIcon onClick={onDismiss} />
|
||||
</RowBetween>
|
||||
</PaddedColumn>
|
||||
@@ -96,18 +96,18 @@ export function ImportList({ listURL, list, setModalView, onDismiss }: ImportPro
|
||||
{list.logoURI && <ListLogo logoURI={list.logoURI} size="40px" />}
|
||||
<AutoColumn gap="sm" style={{ marginLeft: '20px' }}>
|
||||
<RowFixed>
|
||||
<TYPE.body fontWeight={600} mr="6px">
|
||||
<ThemedText.Body fontWeight={600} mr="6px">
|
||||
{list.name}
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
<TextDot />
|
||||
<TYPE.main fontSize={'16px'} ml="6px">
|
||||
<ThemedText.Main fontSize={'16px'} ml="6px">
|
||||
<Trans>{list.tokens.length} tokens</Trans>
|
||||
</TYPE.main>
|
||||
</ThemedText.Main>
|
||||
</RowFixed>
|
||||
<ExternalLink href={`https://tokenlists.org/token-list?url=${listURL}`}>
|
||||
<TYPE.main fontSize={'12px'} color={theme.blue1}>
|
||||
<ThemedText.Main fontSize={'12px'} color={theme.blue1}>
|
||||
{listURL}
|
||||
</TYPE.main>
|
||||
</ThemedText.Main>
|
||||
</ExternalLink>
|
||||
</AutoColumn>
|
||||
</RowFixed>
|
||||
@@ -116,22 +116,22 @@ export function ImportList({ listURL, list, setModalView, onDismiss }: ImportPro
|
||||
<Card style={{ backgroundColor: transparentize(0.8, theme.red1) }}>
|
||||
<AutoColumn justify="center" style={{ textAlign: 'center', gap: '16px', marginBottom: '12px' }}>
|
||||
<AlertTriangle stroke={theme.red1} size={32} />
|
||||
<TYPE.body fontWeight={500} fontSize={20} color={theme.red1}>
|
||||
<ThemedText.Body fontWeight={500} fontSize={20} color={theme.red1}>
|
||||
<Trans>Import at your own risk</Trans>
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
</AutoColumn>
|
||||
|
||||
<AutoColumn style={{ textAlign: 'center', gap: '16px', marginBottom: '12px' }}>
|
||||
<TYPE.body fontWeight={500} color={theme.red1}>
|
||||
<ThemedText.Body fontWeight={500} color={theme.red1}>
|
||||
<Trans>
|
||||
By adding this list you are implicitly trusting that the data is correct. Anyone can create a list,
|
||||
including creating fake versions of existing lists and lists that claim to represent projects that do
|
||||
not have one.
|
||||
</Trans>
|
||||
</TYPE.body>
|
||||
<TYPE.body fontWeight={600} color={theme.red1}>
|
||||
</ThemedText.Body>
|
||||
<ThemedText.Body fontWeight={600} color={theme.red1}>
|
||||
<Trans>If you purchase a token from this list, you may not be able to sell it back.</Trans>
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
</AutoColumn>
|
||||
<AutoRow justify="center" style={{ cursor: 'pointer' }} onClick={() => setConfirmed(!confirmed)}>
|
||||
<Checkbox
|
||||
@@ -140,9 +140,9 @@ export function ImportList({ listURL, list, setModalView, onDismiss }: ImportPro
|
||||
checked={confirmed}
|
||||
onChange={() => setConfirmed(!confirmed)}
|
||||
/>
|
||||
<TYPE.body ml="10px" fontSize="16px" color={theme.red1} fontWeight={500}>
|
||||
<ThemedText.Body ml="10px" fontSize="16px" color={theme.red1} fontWeight={500}>
|
||||
<Trans>I understand</Trans>
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
</AutoRow>
|
||||
</Card>
|
||||
|
||||
@@ -156,9 +156,9 @@ export function ImportList({ listURL, list, setModalView, onDismiss }: ImportPro
|
||||
<Trans>Import</Trans>
|
||||
</ButtonPrimary>
|
||||
{addError ? (
|
||||
<TYPE.error title={addError} style={{ textOverflow: 'ellipsis', overflow: 'hidden' }} error>
|
||||
<ThemedText.Error title={addError} style={{ textOverflow: 'ellipsis', overflow: 'hidden' }} error>
|
||||
{addError}
|
||||
</TYPE.error>
|
||||
</ThemedText.Error>
|
||||
) : null}
|
||||
</AutoColumn>
|
||||
{/* </Card> */}
|
||||
|
||||
@@ -10,7 +10,7 @@ import useTheme from 'hooks/useTheme'
|
||||
import { CSSProperties } from 'react'
|
||||
import { CheckCircle } from 'react-feather'
|
||||
import styled from 'styled-components/macro'
|
||||
import { TYPE } from 'theme'
|
||||
import { ThemedText } from 'theme'
|
||||
|
||||
import { WrappedTokenInfo } from '../../state/lists/wrappedTokenInfo'
|
||||
|
||||
@@ -67,16 +67,16 @@ export default function ImportRow({
|
||||
<CurrencyLogo currency={token} size={'24px'} style={{ opacity: dim ? '0.6' : '1' }} />
|
||||
<AutoColumn gap="4px" style={{ opacity: dim ? '0.6' : '1' }}>
|
||||
<AutoRow>
|
||||
<TYPE.body fontWeight={500}>{token.symbol}</TYPE.body>
|
||||
<TYPE.darkGray ml="8px" fontWeight={300}>
|
||||
<ThemedText.Body fontWeight={500}>{token.symbol}</ThemedText.Body>
|
||||
<ThemedText.DarkGray ml="8px" fontWeight={300}>
|
||||
<NameOverflow title={token.name}>{token.name}</NameOverflow>
|
||||
</TYPE.darkGray>
|
||||
</ThemedText.DarkGray>
|
||||
</AutoRow>
|
||||
{list && list.logoURI && (
|
||||
<RowFixed>
|
||||
<TYPE.small mr="4px" color={theme.text3}>
|
||||
<ThemedText.Small mr="4px" color={theme.text3}>
|
||||
<Trans>via {list.name} </Trans>
|
||||
</TYPE.small>
|
||||
</ThemedText.Small>
|
||||
<ListLogo logoURI={list.logoURI} size="12px" />
|
||||
</RowFixed>
|
||||
)}
|
||||
@@ -97,9 +97,9 @@ export default function ImportRow({
|
||||
) : (
|
||||
<RowFixed style={{ minWidth: 'fit-content' }}>
|
||||
<CheckIcon />
|
||||
<TYPE.main color={theme.green1}>
|
||||
<ThemedText.Main color={theme.green1}>
|
||||
<Trans>Active</Trans>
|
||||
</TYPE.main>
|
||||
</ThemedText.Main>
|
||||
</RowFixed>
|
||||
)}
|
||||
</TokenSection>
|
||||
|
||||
@@ -10,7 +10,7 @@ import useTheme from 'hooks/useTheme'
|
||||
import { AlertCircle, ArrowLeft } from 'react-feather'
|
||||
import { useAddUserToken } from 'state/user/hooks'
|
||||
import styled from 'styled-components/macro'
|
||||
import { CloseIcon, TYPE } from 'theme'
|
||||
import { CloseIcon, ThemedText } from 'theme'
|
||||
|
||||
import BlockedToken from './BlockedToken'
|
||||
import { PaddedColumn } from './styleds'
|
||||
@@ -47,9 +47,9 @@ export function ImportToken(props: ImportProps) {
|
||||
<PaddedColumn gap="14px" style={{ width: '100%', flex: '1 1' }}>
|
||||
<RowBetween>
|
||||
{onBack ? <ArrowLeft style={{ cursor: 'pointer' }} onClick={onBack} /> : <div />}
|
||||
<TYPE.mediumHeader>
|
||||
<ThemedText.MediumHeader>
|
||||
<Plural value={tokens.length} one="Import token" other="Import tokens" />
|
||||
</TYPE.mediumHeader>
|
||||
</ThemedText.MediumHeader>
|
||||
{onDismiss ? <CloseIcon onClick={onDismiss} /> : <div />}
|
||||
</RowBetween>
|
||||
</PaddedColumn>
|
||||
@@ -57,12 +57,12 @@ export function ImportToken(props: ImportProps) {
|
||||
<AutoColumn gap="md" style={{ marginBottom: '32px', padding: '1rem' }}>
|
||||
<AutoColumn justify="center" style={{ textAlign: 'center', gap: '16px', padding: '1rem' }}>
|
||||
<AlertCircle size={48} stroke={theme.text2} strokeWidth={1} />
|
||||
<TYPE.body fontWeight={400} fontSize={16}>
|
||||
<ThemedText.Body fontWeight={400} fontSize={16}>
|
||||
<Trans>
|
||||
This token doesn't appear on the active token list(s). Make sure this is the token that you want to
|
||||
trade.
|
||||
</Trans>
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
</AutoColumn>
|
||||
{tokens.map((token) => (
|
||||
<TokenImportCard token={token} list={list} key={'import' + token.address} />
|
||||
|
||||
@@ -18,7 +18,7 @@ import useTheme from '../../hooks/useTheme'
|
||||
import useToggle from '../../hooks/useToggle'
|
||||
import { acceptListUpdate, disableList, enableList, removeList } from '../../state/lists/actions'
|
||||
import { useActiveListUrls, useAllLists, useIsListActive } from '../../state/lists/hooks'
|
||||
import { ExternalLink, IconWrapper, LinkStyledButton, TYPE } from '../../theme'
|
||||
import { ExternalLink, IconWrapper, LinkStyledButton, ThemedText } from '../../theme'
|
||||
import listVersionLabel from '../../utils/listVersionLabel'
|
||||
import { parseENSAddress } from '../../utils/parseENSAddress'
|
||||
import uriToHttp from '../../utils/uriToHttp'
|
||||
@@ -75,7 +75,7 @@ const StyledTitleText = styled.div<{ active: boolean }>`
|
||||
color: ${({ theme, active }) => (active ? theme.white : theme.text2)};
|
||||
`
|
||||
|
||||
const StyledListUrlText = styled(TYPE.main)<{ active: boolean }>`
|
||||
const StyledListUrlText = styled(ThemedText.Main)<{ active: boolean }>`
|
||||
font-size: 12px;
|
||||
color: ${({ theme, active }) => (active ? theme.white : theme.text2)};
|
||||
`
|
||||
@@ -361,9 +361,9 @@ export function ManageLists({
|
||||
/>
|
||||
</Row>
|
||||
{addError ? (
|
||||
<TYPE.error title={addError} style={{ textOverflow: 'ellipsis', overflow: 'hidden' }} error>
|
||||
<ThemedText.Error title={addError} style={{ textOverflow: 'ellipsis', overflow: 'hidden' }} error>
|
||||
{addError}
|
||||
</TYPE.error>
|
||||
</ThemedText.Error>
|
||||
) : null}
|
||||
</PaddedColumn>
|
||||
{tempList && (
|
||||
@@ -373,10 +373,10 @@ export function ManageLists({
|
||||
<RowFixed>
|
||||
{tempList.logoURI && <ListLogo logoURI={tempList.logoURI} size="40px" />}
|
||||
<AutoColumn gap="4px" style={{ marginLeft: '20px' }}>
|
||||
<TYPE.body fontWeight={600}>{tempList.name}</TYPE.body>
|
||||
<TYPE.main fontSize={'12px'}>
|
||||
<ThemedText.Body fontWeight={600}>{tempList.name}</ThemedText.Body>
|
||||
<ThemedText.Main fontSize={'12px'}>
|
||||
<Trans>{tempList.tokens.length} tokens</Trans>
|
||||
</TYPE.main>
|
||||
</ThemedText.Main>
|
||||
</AutoColumn>
|
||||
</RowFixed>
|
||||
{isImported ? (
|
||||
@@ -384,9 +384,9 @@ export function ManageLists({
|
||||
<IconWrapper stroke={theme.text2} size="16px" marginRight={'10px'}>
|
||||
<CheckCircle />
|
||||
</IconWrapper>
|
||||
<TYPE.body color={theme.text2}>
|
||||
<ThemedText.Body color={theme.text2}>
|
||||
<Trans>Loaded</Trans>
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
</RowFixed>
|
||||
) : (
|
||||
<ButtonPrimary
|
||||
|
||||
@@ -9,7 +9,7 @@ import { useActiveWeb3React } from 'hooks/web3'
|
||||
import { RefObject, useCallback, useMemo, useRef, useState } from 'react'
|
||||
import { useRemoveUserAddedToken, useUserAddedTokens } from 'state/user/hooks'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ButtonText, ExternalLink, ExternalLinkIcon, TrashIcon, TYPE } from 'theme'
|
||||
import { ButtonText, ExternalLink, ExternalLinkIcon, ThemedText, TrashIcon } from 'theme'
|
||||
import { isAddress } from 'utils'
|
||||
|
||||
import useTheme from '../../hooks/useTheme'
|
||||
@@ -81,9 +81,9 @@ export default function ManageTokens({
|
||||
<RowFixed>
|
||||
<CurrencyLogo currency={token} size={'20px'} />
|
||||
<ExternalLink href={getExplorerLink(chainId, token.address, ExplorerDataType.ADDRESS)}>
|
||||
<TYPE.main ml={'10px'} fontWeight={600}>
|
||||
<ThemedText.Main ml={'10px'} fontWeight={600}>
|
||||
{token.symbol}
|
||||
</TYPE.main>
|
||||
</ThemedText.Main>
|
||||
</ExternalLink>
|
||||
</RowFixed>
|
||||
<RowFixed>
|
||||
@@ -111,9 +111,9 @@ export default function ManageTokens({
|
||||
/>
|
||||
</Row>
|
||||
{searchQuery !== '' && !isAddressSearch && (
|
||||
<TYPE.error error={true}>
|
||||
<ThemedText.Error error={true}>
|
||||
<Trans>Enter valid token address</Trans>
|
||||
</TYPE.error>
|
||||
</ThemedText.Error>
|
||||
)}
|
||||
{searchToken && (
|
||||
<Card backgroundColor={theme.bg2} padding="10px 0">
|
||||
@@ -129,14 +129,14 @@ export default function ManageTokens({
|
||||
<Separator />
|
||||
<PaddedColumn gap="lg" style={{ overflow: 'auto', marginBottom: '10px' }}>
|
||||
<RowBetween>
|
||||
<TYPE.main fontWeight={600}>
|
||||
<ThemedText.Main fontWeight={600}>
|
||||
<Trans>{userAddedTokens?.length} Custom Tokens</Trans>
|
||||
</TYPE.main>
|
||||
</ThemedText.Main>
|
||||
{userAddedTokens.length > 0 && (
|
||||
<ButtonText onClick={handleRemoveAll}>
|
||||
<TYPE.blue>
|
||||
<ThemedText.Blue>
|
||||
<Trans>Clear all</Trans>
|
||||
</TYPE.blue>
|
||||
</ThemedText.Blue>
|
||||
</ButtonText>
|
||||
)}
|
||||
</RowBetween>
|
||||
@@ -144,9 +144,9 @@ export default function ManageTokens({
|
||||
</PaddedColumn>
|
||||
</Column>
|
||||
<Footer>
|
||||
<TYPE.darkGray>
|
||||
<ThemedText.DarkGray>
|
||||
<Trans>Tip: Custom tokens are stored locally in your browser</Trans>
|
||||
</TYPE.darkGray>
|
||||
</ThemedText.DarkGray>
|
||||
</Footer>
|
||||
</Wrapper>
|
||||
)
|
||||
|
||||
@@ -10,7 +10,7 @@ import { useActiveWeb3React } from 'hooks/web3'
|
||||
import { transparentize } from 'polished'
|
||||
import { AlertCircle } from 'react-feather'
|
||||
import styled, { useTheme } from 'styled-components/macro'
|
||||
import { ExternalLink, TYPE } from 'theme'
|
||||
import { ExternalLink, ThemedText } from 'theme'
|
||||
import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink'
|
||||
|
||||
const WarningWrapper = styled(Card)<{ highWarning: boolean }>`
|
||||
@@ -19,7 +19,7 @@ const WarningWrapper = styled(Card)<{ highWarning: boolean }>`
|
||||
width: fit-content;
|
||||
`
|
||||
|
||||
const AddressText = styled(TYPE.blue)`
|
||||
const AddressText = styled(ThemedText.Blue)`
|
||||
font-size: 12px;
|
||||
word-break: break-all;
|
||||
|
||||
@@ -39,12 +39,12 @@ const TokenImportCard = ({ list, token }: TokenImportCardProps) => {
|
||||
<AutoColumn gap="10px" justify="center">
|
||||
<CurrencyLogo currency={token} size={'32px'} />
|
||||
<AutoColumn gap="4px" justify="center">
|
||||
<TYPE.body ml="8px" mr="8px" fontWeight={500} fontSize={20}>
|
||||
<ThemedText.Body ml="8px" mr="8px" fontWeight={500} fontSize={20}>
|
||||
{token.symbol}
|
||||
</TYPE.body>
|
||||
<TYPE.darkGray fontWeight={400} fontSize={14}>
|
||||
</ThemedText.Body>
|
||||
<ThemedText.DarkGray fontWeight={400} fontSize={14}>
|
||||
{token.name}
|
||||
</TYPE.darkGray>
|
||||
</ThemedText.DarkGray>
|
||||
</AutoColumn>
|
||||
{chainId && (
|
||||
<ExternalLink href={getExplorerLink(chainId, token.address, ExplorerDataType.ADDRESS)}>
|
||||
@@ -54,17 +54,17 @@ const TokenImportCard = ({ list, token }: TokenImportCardProps) => {
|
||||
{list !== undefined ? (
|
||||
<RowFixed>
|
||||
{list.logoURI && <ListLogo logoURI={list.logoURI} size="16px" />}
|
||||
<TYPE.small ml="6px" fontSize={14} color={theme.text3}>
|
||||
<ThemedText.Small ml="6px" fontSize={14} color={theme.text3}>
|
||||
<Trans>via {list.name} token list</Trans>
|
||||
</TYPE.small>
|
||||
</ThemedText.Small>
|
||||
</RowFixed>
|
||||
) : (
|
||||
<WarningWrapper $borderRadius="4px" padding="4px" highWarning={true}>
|
||||
<RowFixed>
|
||||
<AlertCircle stroke={theme.red1} size="10px" />
|
||||
<TYPE.body color={theme.red1} ml="4px" fontSize="10px" fontWeight={500}>
|
||||
<ThemedText.Body color={theme.red1} ml="4px" fontSize="10px" fontWeight={500}>
|
||||
<Trans>Unknown Source</Trans>
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
</RowFixed>
|
||||
</WarningWrapper>
|
||||
)}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { t, Trans } from '@lingui/macro'
|
||||
import { Percent } from '@uniswap/sdk-core'
|
||||
import { SupportedChainId } from 'constants/chains'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import { useContext, useRef, useState } from 'react'
|
||||
import { Settings, X } from 'react-feather'
|
||||
import ReactGA from 'react-ga'
|
||||
import { Text } from 'rebass'
|
||||
import { AUTO_ROUTER_SUPPORTED_CHAINS } from 'state/routing/clientSideSmartOrderRouter/constants'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
|
||||
import { useOnClickOutside } from '../../hooks/useOnClickOutside'
|
||||
import { useModalOpen, useToggleSettingsMenu } from '../../state/application/hooks'
|
||||
import { ApplicationModal } from '../../state/application/reducer'
|
||||
import { useClientSideRouter, useExpertModeManager } from '../../state/user/hooks'
|
||||
import { TYPE } from '../../theme'
|
||||
import { ThemedText } from '../../theme'
|
||||
import { ButtonError } from '../Button'
|
||||
import { AutoColumn } from '../Column'
|
||||
import Modal from '../Modal'
|
||||
@@ -27,7 +27,7 @@ const StyledMenuIcon = styled(Settings)`
|
||||
width: 20px;
|
||||
|
||||
> * {
|
||||
stroke: ${({ theme }) => theme.text2};
|
||||
stroke: ${({ theme }) => theme.text1};
|
||||
}
|
||||
|
||||
:hover {
|
||||
@@ -199,16 +199,13 @@ export default function SettingsTab({ placeholderSlippage }: { placeholderSlippa
|
||||
<Text fontWeight={600} fontSize={14}>
|
||||
<Trans>Interface Settings</Trans>
|
||||
</Text>
|
||||
|
||||
{chainId === SupportedChainId.MAINNET && (
|
||||
{chainId && AUTO_ROUTER_SUPPORTED_CHAINS.includes(chainId) && (
|
||||
<RowBetween>
|
||||
<RowFixed>
|
||||
<TYPE.black fontWeight={400} fontSize={14} color={theme.text2}>
|
||||
<Trans>Auto Router</Trans>
|
||||
</TYPE.black>
|
||||
<QuestionHelper
|
||||
text={<Trans>Use the Uniswap Labs API to get better pricing through a more efficient route.</Trans>}
|
||||
/>
|
||||
<ThemedText.Black fontWeight={400} fontSize={14} color={theme.text2}>
|
||||
<Trans>Auto Router API</Trans>
|
||||
</ThemedText.Black>
|
||||
<QuestionHelper text={<Trans>Use the Uniswap Labs API to get faster quotes.</Trans>} />
|
||||
</RowFixed>
|
||||
<Toggle
|
||||
id="toggle-optimized-router-button"
|
||||
@@ -223,12 +220,11 @@ export default function SettingsTab({ placeholderSlippage }: { placeholderSlippa
|
||||
/>
|
||||
</RowBetween>
|
||||
)}
|
||||
|
||||
<RowBetween>
|
||||
<RowFixed>
|
||||
<TYPE.black fontWeight={400} fontSize={14} color={theme.text2}>
|
||||
<ThemedText.Black fontWeight={400} fontSize={14} color={theme.text2}>
|
||||
<Trans>Expert Mode</Trans>
|
||||
</TYPE.black>
|
||||
</ThemedText.Black>
|
||||
<QuestionHelper
|
||||
text={
|
||||
<Trans>Allow high price impact trades and skip the confirm screen. Use at your own risk.</Trans>
|
||||
|
||||
@@ -5,9 +5,9 @@ import styled from 'styled-components/macro'
|
||||
|
||||
import { DEFAULT_LOCALE, LOCALE_LABEL, SupportedLocale } from '../../constants/locales'
|
||||
import { navigatorLocale, useActiveLocale } from '../../hooks/useActiveLocale'
|
||||
import { StyledInternalLink, TYPE } from '../../theme'
|
||||
import { StyledInternalLink, ThemedText } from '../../theme'
|
||||
|
||||
const Container = styled(TYPE.small)`
|
||||
const Container = styled(ThemedText.Small)`
|
||||
opacity: 0.6;
|
||||
:hover {
|
||||
opacity: 1;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import { TYPE } from '../../theme'
|
||||
import { ThemedText } from '../../theme'
|
||||
|
||||
const Wrapper = styled.button<{ isActive?: boolean; activeElement?: boolean }>`
|
||||
border-radius: 20px;
|
||||
@@ -25,7 +25,7 @@ const ToggleElement = styled.span<{ isActive?: boolean; bgColor?: string }>`
|
||||
}
|
||||
`
|
||||
|
||||
const StatusText = styled(TYPE.main)<{ isActive?: boolean }>`
|
||||
const StatusText = styled(ThemedText.Main)<{ isActive?: boolean }>`
|
||||
margin: 0 10px;
|
||||
width: 24px;
|
||||
color: ${({ theme, isActive }) => (isActive ? theme.text1 : theme.text3)};
|
||||
|
||||
@@ -5,7 +5,7 @@ import styled from 'styled-components/macro'
|
||||
import Popover, { PopoverProps } from '../Popover'
|
||||
|
||||
export const TooltipContainer = styled.div`
|
||||
width: 256px;
|
||||
max-width: 256px;
|
||||
padding: 0.6rem 1rem;
|
||||
font-weight: 400;
|
||||
word-break: break-word;
|
||||
@@ -25,6 +25,7 @@ interface TooltipContentProps extends Omit<PopoverProps, 'content'> {
|
||||
onOpen?: () => void
|
||||
// whether to wrap the content in a `TooltipContainer`
|
||||
wrap?: boolean
|
||||
disableHover?: boolean // disable the hover and content display
|
||||
}
|
||||
|
||||
export default function Tooltip({ text, ...rest }: TooltipProps) {
|
||||
@@ -52,6 +53,7 @@ export function MouseoverTooltipContent({
|
||||
content,
|
||||
children,
|
||||
onOpen: openCallback = undefined,
|
||||
disableHover,
|
||||
...rest
|
||||
}: Omit<TooltipContentProps, 'show'>) {
|
||||
const [show, setShow] = useState(false)
|
||||
@@ -61,7 +63,7 @@ export function MouseoverTooltipContent({
|
||||
}, [openCallback])
|
||||
const close = useCallback(() => setShow(false), [setShow])
|
||||
return (
|
||||
<TooltipContent {...rest} show={show} content={content}>
|
||||
<TooltipContent {...rest} show={show} content={disableHover ? null : content}>
|
||||
<div
|
||||
style={{ display: 'inline-block', lineHeight: 0, padding: '0.25rem' }}
|
||||
onMouseEnter={open}
|
||||
|
||||
@@ -13,7 +13,7 @@ import Circle from '../../assets/images/blue-loader.svg'
|
||||
import MetaMaskLogo from '../../assets/images/metamask.png'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { ExternalLink } from '../../theme'
|
||||
import { CloseIcon, CustomLightSpinner } from '../../theme/components'
|
||||
import { CloseIcon, CustomLightSpinner } from '../../theme'
|
||||
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
|
||||
import { TransactionSummary } from '../AccountDetails/TransactionSummary'
|
||||
import { ButtonLight, ButtonPrimary } from '../Button'
|
||||
@@ -284,11 +284,11 @@ function L2Content({
|
||||
</Text>
|
||||
</ExternalLink>
|
||||
) : (
|
||||
<div style={{ height: '17px' }}></div>
|
||||
<div style={{ height: '17px' }} />
|
||||
)}
|
||||
<Text color={theme.text3} style={{ margin: '20px 0 0 0' }} fontSize={'14px'}>
|
||||
{!secondsToConfirm ? (
|
||||
<div style={{ height: '24px' }}></div>
|
||||
<div style={{ height: '24px' }} />
|
||||
) : (
|
||||
<div>
|
||||
<Trans>Transaction completed in </Trans>
|
||||
|
||||
@@ -3,12 +3,13 @@ import { Percent } from '@uniswap/sdk-core'
|
||||
import { L2_CHAIN_IDS } from 'constants/chains'
|
||||
import { DEFAULT_DEADLINE_FROM_NOW } from 'constants/misc'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import ms from 'ms.macro'
|
||||
import { darken } from 'polished'
|
||||
import { useContext, useState } from 'react'
|
||||
import { useSetUserSlippageTolerance, useUserSlippageTolerance, useUserTransactionTTL } from 'state/user/hooks'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
|
||||
import { TYPE } from '../../theme'
|
||||
import { ThemedText } from '../../theme'
|
||||
import { AutoColumn } from '../Column'
|
||||
import QuestionHelper from '../QuestionHelper'
|
||||
import { RowBetween, RowFixed } from '../Row'
|
||||
@@ -85,7 +86,7 @@ const OptionCustom = styled(FancyButton)<{ active?: boolean; warning?: boolean }
|
||||
const SlippageEmojiContainer = styled.span`
|
||||
color: #f3841e;
|
||||
${({ theme }) => theme.mediaWidth.upToSmall`
|
||||
display: none;
|
||||
display: none;
|
||||
`}
|
||||
`
|
||||
|
||||
@@ -93,6 +94,8 @@ interface TransactionSettingsProps {
|
||||
placeholderSlippage: Percent // varies according to the context in which the settings dialog is placed
|
||||
}
|
||||
|
||||
const THREE_DAYS_IN_SECONDS = ms`3 days` / 1000
|
||||
|
||||
export default function TransactionSettings({ placeholderSlippage }: TransactionSettingsProps) {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
const theme = useContext(ThemeContext)
|
||||
@@ -142,7 +145,7 @@ export default function TransactionSettings({ placeholderSlippage }: Transaction
|
||||
} else {
|
||||
try {
|
||||
const parsed: number = Math.floor(Number.parseFloat(value) * 60)
|
||||
if (!Number.isInteger(parsed) || parsed < 60 || parsed > 180 * 60) {
|
||||
if (!Number.isInteger(parsed) || parsed < 60 || parsed > THREE_DAYS_IN_SECONDS) {
|
||||
setDeadlineError(DeadlineError.InvalidInput)
|
||||
} else {
|
||||
setDeadline(parsed)
|
||||
@@ -160,9 +163,9 @@ export default function TransactionSettings({ placeholderSlippage }: Transaction
|
||||
<AutoColumn gap="md">
|
||||
<AutoColumn gap="sm">
|
||||
<RowFixed>
|
||||
<TYPE.black fontWeight={400} fontSize={14} color={theme.text2}>
|
||||
<ThemedText.Black fontWeight={400} fontSize={14} color={theme.text2}>
|
||||
<Trans>Slippage tolerance</Trans>
|
||||
</TYPE.black>
|
||||
</ThemedText.Black>
|
||||
<QuestionHelper
|
||||
text={
|
||||
<Trans>Your transaction will revert if the price changes unfavorably by more than this percentage.</Trans>
|
||||
@@ -229,9 +232,9 @@ export default function TransactionSettings({ placeholderSlippage }: Transaction
|
||||
{showCustomDeadlineRow && (
|
||||
<AutoColumn gap="sm">
|
||||
<RowFixed>
|
||||
<TYPE.black fontSize={14} fontWeight={400} color={theme.text2}>
|
||||
<ThemedText.Black fontSize={14} fontWeight={400} color={theme.text2}>
|
||||
<Trans>Transaction deadline</Trans>
|
||||
</TYPE.black>
|
||||
</ThemedText.Black>
|
||||
<QuestionHelper
|
||||
text={<Trans>Your transaction will revert if it is pending for more than this period of time.</Trans>}
|
||||
/>
|
||||
@@ -255,9 +258,9 @@ export default function TransactionSettings({ placeholderSlippage }: Transaction
|
||||
color={deadlineError ? 'red' : ''}
|
||||
/>
|
||||
</OptionCustom>
|
||||
<TYPE.body style={{ paddingLeft: '8px' }} fontSize={14}>
|
||||
<ThemedText.Body style={{ paddingLeft: '8px' }} fontSize={14}>
|
||||
<Trans>minutes</Trans>
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
</RowFixed>
|
||||
</AutoColumn>
|
||||
)}
|
||||
|
||||
@@ -19,7 +19,7 @@ import { SUPPORTED_WALLETS } from '../../constants/wallet'
|
||||
import usePrevious from '../../hooks/usePrevious'
|
||||
import { useModalOpen, useWalletModalToggle } from '../../state/application/hooks'
|
||||
import { ApplicationModal } from '../../state/application/reducer'
|
||||
import { ExternalLink, TYPE } from '../../theme'
|
||||
import { ExternalLink, ThemedText } from '../../theme'
|
||||
import { isMobile } from '../../utils/userAgent'
|
||||
import AccountDetails from '../AccountDetails'
|
||||
import Card, { LightCard } from '../Card'
|
||||
@@ -110,7 +110,7 @@ const HoverText = styled.div`
|
||||
`
|
||||
|
||||
const LinkCard = styled(Card)`
|
||||
background-color: ${({ theme }) => theme.primary1};
|
||||
background-color: ${({ theme }) => theme.bg1};
|
||||
color: ${({ theme }) => theme.white};
|
||||
|
||||
:hover {
|
||||
@@ -344,9 +344,9 @@ export default function WalletModal({
|
||||
<ArrowLeft />
|
||||
</HoverText>
|
||||
<Row justify="center">
|
||||
<TYPE.mediumHeader>
|
||||
<ThemedText.MediumHeader>
|
||||
<Trans>Legal & Privacy</Trans>
|
||||
</TYPE.mediumHeader>
|
||||
</ThemedText.MediumHeader>
|
||||
</Row>
|
||||
</HeaderRow>
|
||||
<PrivacyPolicy />
|
||||
@@ -392,27 +392,16 @@ export default function WalletModal({
|
||||
<AutoColumn gap="16px">
|
||||
<LightCard>
|
||||
<AutoRow style={{ flexWrap: 'nowrap' }}>
|
||||
<TYPE.black fontSize={14}>
|
||||
<ThemedText.Black fontSize={14}>
|
||||
<Trans>
|
||||
By connecting a wallet, you agree to Uniswap Labs’{' '}
|
||||
<ExternalLink href="https://uniswap.org/terms-of-service/">Terms of Service</ExternalLink> and
|
||||
acknowledge that you have read and understand the Uniswap{' '}
|
||||
<ExternalLink href="https://uniswap.org/disclaimer/">Protocol Disclaimer</ExternalLink>.
|
||||
</Trans>
|
||||
</TYPE.black>
|
||||
</ThemedText.Black>
|
||||
</AutoRow>
|
||||
</LightCard>
|
||||
<LinkCard padding=".5rem" $borderRadius=".75rem" onClick={() => setWalletView(WALLET_VIEWS.LEGAL)}>
|
||||
<RowBetween>
|
||||
<AutoRow gap="4px">
|
||||
<Info size={20} />
|
||||
<TYPE.white fontSize={14}>
|
||||
<Trans>How this app uses APIs</Trans>
|
||||
</TYPE.white>
|
||||
</AutoRow>
|
||||
<ArrowRight size={16} />
|
||||
</RowBetween>
|
||||
</LinkCard>
|
||||
{walletView === WALLET_VIEWS.PENDING ? (
|
||||
<PendingView
|
||||
connector={pendingWallet}
|
||||
@@ -423,6 +412,17 @@ export default function WalletModal({
|
||||
) : (
|
||||
<OptionGrid>{getOptions()}</OptionGrid>
|
||||
)}
|
||||
<LinkCard padding=".5rem" $borderRadius=".75rem" onClick={() => setWalletView(WALLET_VIEWS.LEGAL)}>
|
||||
<RowBetween>
|
||||
<AutoRow gap="4px">
|
||||
<Info size={20} />
|
||||
<ThemedText.White fontSize={14}>
|
||||
<Trans>How this app uses APIs</Trans>
|
||||
</ThemedText.White>
|
||||
</AutoRow>
|
||||
<ArrowRight size={16} />
|
||||
</RowBetween>
|
||||
</LinkCard>
|
||||
</AutoColumn>
|
||||
</ContentWrapper>
|
||||
</UpperSection>
|
||||
|
||||
@@ -7,11 +7,6 @@ import { useMemo } from 'react'
|
||||
import { Activity } from 'react-feather'
|
||||
import styled, { css } from 'styled-components/macro'
|
||||
|
||||
import CoinbaseWalletIcon from '../../assets/images/coinbaseWalletIcon.svg'
|
||||
import FortmaticIcon from '../../assets/images/fortmaticIcon.png'
|
||||
import PortisIcon from '../../assets/images/portisIcon.png'
|
||||
import WalletConnectIcon from '../../assets/images/walletConnectIcon.svg'
|
||||
import { fortmatic, injected, portis, walletconnect, walletlink } from '../../connectors'
|
||||
import { NetworkContextName } from '../../constants/misc'
|
||||
import useENSName from '../../hooks/useENSName'
|
||||
import { useHasSocks } from '../../hooks/useSocksBalance'
|
||||
@@ -20,7 +15,7 @@ import { isTransactionRecent, useAllTransactions } from '../../state/transaction
|
||||
import { TransactionDetails } from '../../state/transactions/reducer'
|
||||
import { shortenAddress } from '../../utils'
|
||||
import { ButtonSecondary } from '../Button'
|
||||
import Identicon from '../Identicon'
|
||||
import StatusIcon from '../Identicon/StatusIcon'
|
||||
import Loader from '../Loader'
|
||||
import { RowBetween } from '../Row'
|
||||
import WalletModal from '../WalletModal'
|
||||
@@ -132,36 +127,12 @@ function Sock() {
|
||||
)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react/prop-types
|
||||
function StatusIcon({ connector }: { connector: AbstractConnector }) {
|
||||
if (connector === injected) {
|
||||
return <Identicon />
|
||||
} else if (connector === walletconnect) {
|
||||
return (
|
||||
<IconWrapper size={16}>
|
||||
<img src={WalletConnectIcon} alt={'WalletConnect'} />
|
||||
</IconWrapper>
|
||||
)
|
||||
} else if (connector === walletlink) {
|
||||
return (
|
||||
<IconWrapper size={16}>
|
||||
<img src={CoinbaseWalletIcon} alt={'CoinbaseWallet'} />
|
||||
</IconWrapper>
|
||||
)
|
||||
} else if (connector === fortmatic) {
|
||||
return (
|
||||
<IconWrapper size={16}>
|
||||
<img src={FortmaticIcon} alt={'Fortmatic'} />
|
||||
</IconWrapper>
|
||||
)
|
||||
} else if (connector === portis) {
|
||||
return (
|
||||
<IconWrapper size={16}>
|
||||
<img src={PortisIcon} alt={'Portis'} />
|
||||
</IconWrapper>
|
||||
)
|
||||
}
|
||||
return null
|
||||
function WrappedStatusIcon({ connector }: { connector: AbstractConnector }) {
|
||||
return (
|
||||
<IconWrapper size={16}>
|
||||
<StatusIcon connector={connector} />
|
||||
</IconWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function Web3StatusInner() {
|
||||
@@ -198,7 +169,7 @@ function Web3StatusInner() {
|
||||
<Text>{ENSName || shortenAddress(account)}</Text>
|
||||
</>
|
||||
)}
|
||||
{!hasPendingTransactions && connector && <StatusIcon connector={connector} />}
|
||||
{!hasPendingTransactions && connector && <WrappedStatusIcon connector={connector} />}
|
||||
</Web3StatusConnected>
|
||||
)
|
||||
} else if (error) {
|
||||
|
||||
@@ -11,7 +11,7 @@ import useENS from '../../hooks/useENS'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { useClaimCallback, useUserHasAvailableClaim, useUserUnclaimedAmount } from '../../state/claim/hooks'
|
||||
import { useIsTransactionPending } from '../../state/transactions/hooks'
|
||||
import { CloseIcon, CustomLightSpinner, ExternalLink, TYPE, UniTokenAnimated } from '../../theme'
|
||||
import { CloseIcon, CustomLightSpinner, ExternalLink, ThemedText, UniTokenAnimated } from '../../theme'
|
||||
import { shortenAddress } from '../../utils'
|
||||
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
|
||||
import AddressInputPanel from '../AddressInputPanel'
|
||||
@@ -105,29 +105,29 @@ export default function AddressClaimModal({ isOpen, onDismiss }: { isOpen: boole
|
||||
<CardNoise />
|
||||
<CardSection gap="md">
|
||||
<RowBetween>
|
||||
<TYPE.white fontWeight={500}>
|
||||
<ThemedText.White fontWeight={500}>
|
||||
<Trans>Claim UNI Token</Trans>
|
||||
</TYPE.white>
|
||||
</ThemedText.White>
|
||||
<CloseIcon onClick={wrappedOnDismiss} style={{ zIndex: 99 }} stroke="white" />
|
||||
</RowBetween>
|
||||
<TYPE.white fontWeight={700} fontSize={36}>
|
||||
<ThemedText.White fontWeight={700} fontSize={36}>
|
||||
<Trans>{unclaimedAmount?.toFixed(0, { groupSeparator: ',' } ?? '-')} UNI</Trans>
|
||||
</TYPE.white>
|
||||
</ThemedText.White>
|
||||
</CardSection>
|
||||
<Break />
|
||||
</ModalUpper>
|
||||
<AutoColumn gap="md" style={{ padding: '1rem', paddingTop: '0' }} justify="center">
|
||||
<TYPE.subHeader fontWeight={500}>
|
||||
<ThemedText.SubHeader fontWeight={500}>
|
||||
<Trans>
|
||||
Enter an address to trigger a UNI claim. If the address has any claimable UNI it will be sent to them on
|
||||
submission.
|
||||
</Trans>
|
||||
</TYPE.subHeader>
|
||||
</ThemedText.SubHeader>
|
||||
<AddressInputPanel value={typed} onChange={handleRecipientType} />
|
||||
{parsedAddress && !hasAvailableClaim && (
|
||||
<TYPE.error error={true}>
|
||||
<ThemedText.Error error={true}>
|
||||
<Trans>Address has no available claim</Trans>
|
||||
</TYPE.error>
|
||||
</ThemedText.Error>
|
||||
)}
|
||||
<ButtonPrimary
|
||||
disabled={!isAddress(parsedAddress ?? '') || !hasAvailableClaim}
|
||||
@@ -159,23 +159,23 @@ export default function AddressClaimModal({ isOpen, onDismiss }: { isOpen: boole
|
||||
</ConfirmedIcon>
|
||||
<AutoColumn gap="100px" justify={'center'}>
|
||||
<AutoColumn gap="12px" justify={'center'}>
|
||||
<TYPE.largeHeader fontWeight={600} color="black">
|
||||
<ThemedText.LargeHeader fontWeight={600} color="black">
|
||||
{claimConfirmed ? <Trans>Claimed</Trans> : <Trans>Claiming</Trans>}
|
||||
</TYPE.largeHeader>
|
||||
</ThemedText.LargeHeader>
|
||||
{!claimConfirmed && (
|
||||
<Text fontSize={36} color={'#ff007a'} fontWeight={800}>
|
||||
<Trans>{unclaimedAmount?.toFixed(0, { groupSeparator: ',' } ?? '-')} UNI</Trans>
|
||||
</Text>
|
||||
)}
|
||||
{parsedAddress && (
|
||||
<TYPE.largeHeader fontWeight={600} color="black">
|
||||
<ThemedText.LargeHeader fontWeight={600} color="black">
|
||||
<Trans>for {shortenAddress(parsedAddress)}</Trans>
|
||||
</TYPE.largeHeader>
|
||||
</ThemedText.LargeHeader>
|
||||
)}
|
||||
</AutoColumn>
|
||||
{claimConfirmed && (
|
||||
<>
|
||||
<TYPE.subHeader fontWeight={500} color="black">
|
||||
<ThemedText.SubHeader fontWeight={500} color="black">
|
||||
<span role="img" aria-label="party-hat">
|
||||
🎉{' '}
|
||||
</span>
|
||||
@@ -183,13 +183,13 @@ export default function AddressClaimModal({ isOpen, onDismiss }: { isOpen: boole
|
||||
<span role="img" aria-label="party-hat">
|
||||
🎉
|
||||
</span>
|
||||
</TYPE.subHeader>
|
||||
</ThemedText.SubHeader>
|
||||
</>
|
||||
)}
|
||||
{attempting && !hash && (
|
||||
<TYPE.subHeader color="black">
|
||||
<ThemedText.SubHeader color="black">
|
||||
<Trans>Confirm this transaction in your wallet</Trans>
|
||||
</TYPE.subHeader>
|
||||
</ThemedText.SubHeader>
|
||||
)}
|
||||
{attempting && hash && !claimConfirmed && chainId && hash && (
|
||||
<ExternalLink href={getExplorerLink(chainId, hash, ExplorerDataType.TRANSACTION)} style={{ zIndex: 99 }}>
|
||||
|
||||
@@ -13,7 +13,7 @@ import { useModalOpen, useToggleSelfClaimModal } from '../../state/application/h
|
||||
import { ApplicationModal } from '../../state/application/reducer'
|
||||
import { useClaimCallback, useUserClaimData, useUserUnclaimedAmount } from '../../state/claim/hooks'
|
||||
import { useUserHasSubmittedClaim } from '../../state/transactions/hooks'
|
||||
import { CloseIcon, CustomLightSpinner, ExternalLink, TYPE, UniTokenAnimated } from '../../theme'
|
||||
import { CloseIcon, CustomLightSpinner, ExternalLink, ThemedText, UniTokenAnimated } from '../../theme'
|
||||
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
|
||||
import { ButtonPrimary } from '../Button'
|
||||
import { AutoColumn, ColumnCenter } from '../Column'
|
||||
@@ -100,63 +100,63 @@ export default function ClaimModal() {
|
||||
<CardNoise />
|
||||
<CardSection gap="md">
|
||||
<RowBetween>
|
||||
<TYPE.white fontWeight={500}>
|
||||
<ThemedText.White fontWeight={500}>
|
||||
<Trans>Claim UNI</Trans>
|
||||
</TYPE.white>
|
||||
</ThemedText.White>
|
||||
<CloseIcon onClick={toggleClaimModal} style={{ zIndex: 99 }} color="white" />
|
||||
</RowBetween>
|
||||
<TYPE.white fontWeight={700} fontSize={36}>
|
||||
<ThemedText.White fontWeight={700} fontSize={36}>
|
||||
<Trans>{unclaimedAmount?.toFixed(0, { groupSeparator: ',' } ?? '-')} UNI</Trans>
|
||||
</TYPE.white>
|
||||
</ThemedText.White>
|
||||
</CardSection>
|
||||
<Break />
|
||||
<CardSection gap="sm">
|
||||
{userClaimData?.flags?.isSOCKS && (
|
||||
<RowBetween>
|
||||
<TYPE.subHeader color="white">SOCKS</TYPE.subHeader>
|
||||
<TYPE.subHeader color="white">
|
||||
<ThemedText.SubHeader color="white">SOCKS</ThemedText.SubHeader>
|
||||
<ThemedText.SubHeader color="white">
|
||||
<Trans>{SOCKS_AMOUNT} UNI</Trans>
|
||||
</TYPE.subHeader>
|
||||
</ThemedText.SubHeader>
|
||||
</RowBetween>
|
||||
)}
|
||||
{userClaimData?.flags?.isLP &&
|
||||
unclaimedAmount &&
|
||||
JSBI.greaterThanOrEqual(unclaimedAmount.quotient, nonLPAmount) && (
|
||||
<RowBetween>
|
||||
<TYPE.subHeader color="white">
|
||||
<ThemedText.SubHeader color="white">
|
||||
<Trans>Liquidity</Trans>
|
||||
</TYPE.subHeader>
|
||||
<TYPE.subHeader color="white">
|
||||
</ThemedText.SubHeader>
|
||||
<ThemedText.SubHeader color="white">
|
||||
<Trans>
|
||||
{unclaimedAmount
|
||||
.subtract(CurrencyAmount.fromRawAmount(unclaimedAmount.currency, nonLPAmount))
|
||||
.toFixed(0, { groupSeparator: ',' })}{' '}
|
||||
UNI
|
||||
</Trans>
|
||||
</TYPE.subHeader>
|
||||
</ThemedText.SubHeader>
|
||||
</RowBetween>
|
||||
)}
|
||||
{userClaimData?.flags?.isUser && (
|
||||
<RowBetween>
|
||||
<TYPE.subHeader color="white">
|
||||
<ThemedText.SubHeader color="white">
|
||||
<Trans>User</Trans>
|
||||
</TYPE.subHeader>
|
||||
<TYPE.subHeader color="white">
|
||||
</ThemedText.SubHeader>
|
||||
<ThemedText.SubHeader color="white">
|
||||
<Trans>{USER_AMOUNT} UNI</Trans>
|
||||
</TYPE.subHeader>
|
||||
</ThemedText.SubHeader>
|
||||
</RowBetween>
|
||||
)}
|
||||
</CardSection>
|
||||
</ModalUpper>
|
||||
<AutoColumn gap="md" style={{ padding: '1rem', paddingTop: '0' }} justify="center">
|
||||
<TYPE.subHeader fontWeight={500}>
|
||||
<ThemedText.SubHeader fontWeight={500}>
|
||||
<Trans>
|
||||
As a member of the Uniswap community you may claim UNI to be used for voting and governance.
|
||||
<br />
|
||||
<br />
|
||||
<ExternalLink href="https://uniswap.org/blog/uni">Read more about UNI</ExternalLink>
|
||||
</Trans>
|
||||
</TYPE.subHeader>
|
||||
</ThemedText.SubHeader>
|
||||
<ButtonPrimary
|
||||
disabled={!isAddress(account ?? '')}
|
||||
padding="16px 16px"
|
||||
@@ -187,9 +187,9 @@ export default function ClaimModal() {
|
||||
</ConfirmedIcon>
|
||||
<AutoColumn gap="100px" justify={'center'}>
|
||||
<AutoColumn gap="12px" justify={'center'}>
|
||||
<TYPE.largeHeader fontWeight={600} color="black">
|
||||
<ThemedText.LargeHeader fontWeight={600} color="black">
|
||||
{claimConfirmed ? <Trans>Claimed!</Trans> : <Trans>Claiming</Trans>}
|
||||
</TYPE.largeHeader>
|
||||
</ThemedText.LargeHeader>
|
||||
{!claimConfirmed && (
|
||||
<Text fontSize={36} color={'#ff007a'} fontWeight={800}>
|
||||
<Trans>{unclaimedAmount?.toFixed(0, { groupSeparator: ',' } ?? '-')} UNI</Trans>
|
||||
@@ -198,7 +198,7 @@ export default function ClaimModal() {
|
||||
</AutoColumn>
|
||||
{claimConfirmed && (
|
||||
<>
|
||||
<TYPE.subHeader fontWeight={500} color="black">
|
||||
<ThemedText.SubHeader fontWeight={500} color="black">
|
||||
<Trans>
|
||||
<span role="img" aria-label="party-hat">
|
||||
🎉{' '}
|
||||
@@ -208,13 +208,13 @@ export default function ClaimModal() {
|
||||
🎉
|
||||
</span>
|
||||
</Trans>
|
||||
</TYPE.subHeader>
|
||||
</ThemedText.SubHeader>
|
||||
</>
|
||||
)}
|
||||
{attempting && !claimSubmitted && (
|
||||
<TYPE.subHeader color="black">
|
||||
<ThemedText.SubHeader color="black">
|
||||
<Trans>Confirm this transaction in your wallet</Trans>
|
||||
</TYPE.subHeader>
|
||||
</ThemedText.SubHeader>
|
||||
)}
|
||||
{attempting && claimSubmitted && !claimConfirmed && chainId && claimTxn?.hash && (
|
||||
<ExternalLink
|
||||
|
||||
@@ -8,7 +8,7 @@ import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { StakingInfo } from '../../state/stake/hooks'
|
||||
import { TransactionType } from '../../state/transactions/actions'
|
||||
import { useTransactionAdder } from '../../state/transactions/hooks'
|
||||
import { CloseIcon, TYPE } from '../../theme'
|
||||
import { CloseIcon, ThemedText } from '../../theme'
|
||||
import { ButtonError } from '../Button'
|
||||
import { AutoColumn } from '../Column'
|
||||
import Modal from '../Modal'
|
||||
@@ -74,24 +74,24 @@ export default function ClaimRewardModal({ isOpen, onDismiss, stakingInfo }: Sta
|
||||
{!attempting && !hash && (
|
||||
<ContentWrapper gap="lg">
|
||||
<RowBetween>
|
||||
<TYPE.mediumHeader>
|
||||
<ThemedText.MediumHeader>
|
||||
<Trans>Claim</Trans>
|
||||
</TYPE.mediumHeader>
|
||||
</ThemedText.MediumHeader>
|
||||
<CloseIcon onClick={wrappedOnDismiss} />
|
||||
</RowBetween>
|
||||
{stakingInfo?.earnedAmount && (
|
||||
<AutoColumn justify="center" gap="md">
|
||||
<TYPE.body fontWeight={600} fontSize={36}>
|
||||
<ThemedText.Body fontWeight={600} fontSize={36}>
|
||||
{stakingInfo?.earnedAmount?.toSignificant(6)}
|
||||
</TYPE.body>
|
||||
<TYPE.body>
|
||||
</ThemedText.Body>
|
||||
<ThemedText.Body>
|
||||
<Trans>Unclaimed UNI</Trans>
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
</AutoColumn>
|
||||
)}
|
||||
<TYPE.subHeader style={{ textAlign: 'center' }}>
|
||||
<ThemedText.SubHeader style={{ textAlign: 'center' }}>
|
||||
<Trans>When you claim without withdrawing your liquidity remains in the mining pool.</Trans>
|
||||
</TYPE.subHeader>
|
||||
</ThemedText.SubHeader>
|
||||
<ButtonError disabled={!!error} error={!!error && !!stakingInfo?.stakedAmount} onClick={onClaimReward}>
|
||||
{error ?? <Trans>Claim</Trans>}
|
||||
</ButtonError>
|
||||
@@ -100,21 +100,21 @@ export default function ClaimRewardModal({ isOpen, onDismiss, stakingInfo }: Sta
|
||||
{attempting && !hash && (
|
||||
<LoadingView onDismiss={wrappedOnDismiss}>
|
||||
<AutoColumn gap="12px" justify={'center'}>
|
||||
<TYPE.body fontSize={20}>
|
||||
<ThemedText.Body fontSize={20}>
|
||||
<Trans>Claiming {stakingInfo?.earnedAmount?.toSignificant(6)} UNI</Trans>
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
</AutoColumn>
|
||||
</LoadingView>
|
||||
)}
|
||||
{hash && (
|
||||
<SubmittedView onDismiss={wrappedOnDismiss} hash={hash}>
|
||||
<AutoColumn gap="12px" justify={'center'}>
|
||||
<TYPE.largeHeader>
|
||||
<ThemedText.LargeHeader>
|
||||
<Trans>Transaction Submitted</Trans>
|
||||
</TYPE.largeHeader>
|
||||
<TYPE.body fontSize={20}>
|
||||
</ThemedText.LargeHeader>
|
||||
<ThemedText.Body fontSize={20}>
|
||||
<Trans>Claimed UNI!</Trans>
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
</AutoColumn>
|
||||
</SubmittedView>
|
||||
)}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { useTotalSupply } from '../../hooks/useTotalSupply'
|
||||
import useUSDCPrice from '../../hooks/useUSDCPrice'
|
||||
import { useV2Pair } from '../../hooks/useV2Pairs'
|
||||
import { StakingInfo } from '../../state/stake/hooks'
|
||||
import { StyledInternalLink, TYPE } from '../../theme'
|
||||
import { StyledInternalLink, ThemedText } from '../../theme'
|
||||
import { currencyId } from '../../utils/currencyId'
|
||||
import { unwrappedToken } from '../../utils/unwrappedToken'
|
||||
import { ButtonPrimary } from '../Button'
|
||||
@@ -115,9 +115,9 @@ export default function PoolCard({ stakingInfo }: { stakingInfo: StakingInfo })
|
||||
|
||||
<TopSection>
|
||||
<DoubleCurrencyLogo currency0={currency0} currency1={currency1} size={24} />
|
||||
<TYPE.white fontWeight={600} fontSize={24} style={{ marginLeft: '8px' }}>
|
||||
<ThemedText.White fontWeight={600} fontSize={24} style={{ marginLeft: '8px' }}>
|
||||
{currency0.symbol}-{currency1.symbol}
|
||||
</TYPE.white>
|
||||
</ThemedText.White>
|
||||
|
||||
<StyledInternalLink to={`/uni/${currencyId(currency0)}/${currencyId(currency1)}`} style={{ width: '100%' }}>
|
||||
<ButtonPrimary padding="8px" $borderRadius="8px">
|
||||
@@ -128,22 +128,22 @@ export default function PoolCard({ stakingInfo }: { stakingInfo: StakingInfo })
|
||||
|
||||
<StatContainer>
|
||||
<RowBetween>
|
||||
<TYPE.white>
|
||||
<ThemedText.White>
|
||||
<Trans>Total deposited</Trans>
|
||||
</TYPE.white>
|
||||
<TYPE.white>
|
||||
</ThemedText.White>
|
||||
<ThemedText.White>
|
||||
{valueOfTotalStakedAmountInUSDC ? (
|
||||
<Trans>${valueOfTotalStakedAmountInUSDC.toFixed(0, { groupSeparator: ',' })}</Trans>
|
||||
) : (
|
||||
<Trans>{valueOfTotalStakedAmountInWETH?.toSignificant(4, { groupSeparator: ',' }) ?? '-'} ETH</Trans>
|
||||
)}
|
||||
</TYPE.white>
|
||||
</ThemedText.White>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<TYPE.white>
|
||||
<ThemedText.White>
|
||||
<Trans>Pool rate</Trans>
|
||||
</TYPE.white>
|
||||
<TYPE.white>
|
||||
</ThemedText.White>
|
||||
<ThemedText.White>
|
||||
{stakingInfo ? (
|
||||
stakingInfo.active ? (
|
||||
<Trans>
|
||||
@@ -156,7 +156,7 @@ export default function PoolCard({ stakingInfo }: { stakingInfo: StakingInfo })
|
||||
) : (
|
||||
'-'
|
||||
)}
|
||||
</TYPE.white>
|
||||
</ThemedText.White>
|
||||
</RowBetween>
|
||||
</StatContainer>
|
||||
|
||||
@@ -164,13 +164,13 @@ export default function PoolCard({ stakingInfo }: { stakingInfo: StakingInfo })
|
||||
<>
|
||||
<Break />
|
||||
<BottomSection showBackground={true}>
|
||||
<TYPE.black color={'white'} fontWeight={500}>
|
||||
<ThemedText.Black color={'white'} fontWeight={500}>
|
||||
<span>
|
||||
<Trans>Your rate</Trans>
|
||||
</span>
|
||||
</TYPE.black>
|
||||
</ThemedText.Black>
|
||||
|
||||
<TYPE.black style={{ textAlign: 'right' }} color={'white'} fontWeight={500}>
|
||||
<ThemedText.Black style={{ textAlign: 'right' }} color={'white'} fontWeight={500}>
|
||||
<span role="img" aria-label="wizard-icon" style={{ marginRight: '0.5rem' }}>
|
||||
⚡
|
||||
</span>
|
||||
@@ -188,7 +188,7 @@ export default function PoolCard({ stakingInfo }: { stakingInfo: StakingInfo })
|
||||
) : (
|
||||
'-'
|
||||
)}
|
||||
</TYPE.black>
|
||||
</ThemedText.Black>
|
||||
</BottomSection>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -13,7 +13,7 @@ import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { StakingInfo, useDerivedStakeInfo } from '../../state/stake/hooks'
|
||||
import { TransactionType } from '../../state/transactions/actions'
|
||||
import { useTransactionAdder } from '../../state/transactions/hooks'
|
||||
import { CloseIcon, TYPE } from '../../theme'
|
||||
import { CloseIcon, ThemedText } from '../../theme'
|
||||
import { formatCurrencyAmount } from '../../utils/formatCurrencyAmount'
|
||||
import { maxAmountSpend } from '../../utils/maxAmountSpend'
|
||||
import { ButtonConfirmed, ButtonError } from '../Button'
|
||||
@@ -159,9 +159,9 @@ export default function StakingModal({ isOpen, onDismiss, stakingInfo, userLiqui
|
||||
{!attempting && !hash && (
|
||||
<ContentWrapper gap="lg">
|
||||
<RowBetween>
|
||||
<TYPE.mediumHeader>
|
||||
<ThemedText.MediumHeader>
|
||||
<Trans>Deposit</Trans>
|
||||
</TYPE.mediumHeader>
|
||||
</ThemedText.MediumHeader>
|
||||
<CloseIcon onClick={wrappedOnDismiss} />
|
||||
</RowBetween>
|
||||
<CurrencyInputPanel
|
||||
@@ -178,19 +178,19 @@ export default function StakingModal({ isOpen, onDismiss, stakingInfo, userLiqui
|
||||
|
||||
<HypotheticalRewardRate dim={!hypotheticalRewardRate.greaterThan('0')}>
|
||||
<div>
|
||||
<TYPE.black fontWeight={600}>
|
||||
<ThemedText.Black fontWeight={600}>
|
||||
<Trans>Weekly Rewards</Trans>
|
||||
</TYPE.black>
|
||||
</ThemedText.Black>
|
||||
</div>
|
||||
|
||||
<TYPE.black>
|
||||
<ThemedText.Black>
|
||||
<Trans>
|
||||
{hypotheticalRewardRate
|
||||
.multiply((60 * 60 * 24 * 7).toString())
|
||||
.toSignificant(4, { groupSeparator: ',' })}{' '}
|
||||
UNI / week
|
||||
</Trans>
|
||||
</TYPE.black>
|
||||
</ThemedText.Black>
|
||||
</HypotheticalRewardRate>
|
||||
|
||||
<RowBetween>
|
||||
@@ -216,24 +216,24 @@ export default function StakingModal({ isOpen, onDismiss, stakingInfo, userLiqui
|
||||
{attempting && !hash && (
|
||||
<LoadingView onDismiss={wrappedOnDismiss}>
|
||||
<AutoColumn gap="12px" justify={'center'}>
|
||||
<TYPE.largeHeader>
|
||||
<ThemedText.LargeHeader>
|
||||
<Trans>Depositing Liquidity</Trans>
|
||||
</TYPE.largeHeader>
|
||||
<TYPE.body fontSize={20}>
|
||||
</ThemedText.LargeHeader>
|
||||
<ThemedText.Body fontSize={20}>
|
||||
<Trans>{parsedAmount?.toSignificant(4)} UNI-V2</Trans>
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
</AutoColumn>
|
||||
</LoadingView>
|
||||
)}
|
||||
{attempting && hash && (
|
||||
<SubmittedView onDismiss={wrappedOnDismiss} hash={hash}>
|
||||
<AutoColumn gap="12px" justify={'center'}>
|
||||
<TYPE.largeHeader>
|
||||
<ThemedText.LargeHeader>
|
||||
<Trans>Transaction Submitted</Trans>
|
||||
</TYPE.largeHeader>
|
||||
<TYPE.body fontSize={20}>
|
||||
</ThemedText.LargeHeader>
|
||||
<ThemedText.Body fontSize={20}>
|
||||
<Trans>Deposited {parsedAmount?.toSignificant(4)} UNI-V2</Trans>
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
</AutoColumn>
|
||||
</SubmittedView>
|
||||
)}
|
||||
|
||||
@@ -8,7 +8,7 @@ import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { StakingInfo } from '../../state/stake/hooks'
|
||||
import { TransactionType } from '../../state/transactions/actions'
|
||||
import { useTransactionAdder } from '../../state/transactions/hooks'
|
||||
import { CloseIcon, TYPE } from '../../theme'
|
||||
import { CloseIcon, ThemedText } from '../../theme'
|
||||
import { ButtonError } from '../Button'
|
||||
import { AutoColumn } from '../Column'
|
||||
import FormattedCurrencyAmount from '../FormattedCurrencyAmount'
|
||||
@@ -76,34 +76,34 @@ export default function UnstakingModal({ isOpen, onDismiss, stakingInfo }: Staki
|
||||
{!attempting && !hash && (
|
||||
<ContentWrapper gap="lg">
|
||||
<RowBetween>
|
||||
<TYPE.mediumHeader>
|
||||
<ThemedText.MediumHeader>
|
||||
<Trans>Withdraw</Trans>
|
||||
</TYPE.mediumHeader>
|
||||
</ThemedText.MediumHeader>
|
||||
<CloseIcon onClick={wrappedOndismiss} />
|
||||
</RowBetween>
|
||||
{stakingInfo?.stakedAmount && (
|
||||
<AutoColumn justify="center" gap="md">
|
||||
<TYPE.body fontWeight={600} fontSize={36}>
|
||||
<ThemedText.Body fontWeight={600} fontSize={36}>
|
||||
{<FormattedCurrencyAmount currencyAmount={stakingInfo.stakedAmount} />}
|
||||
</TYPE.body>
|
||||
<TYPE.body>
|
||||
</ThemedText.Body>
|
||||
<ThemedText.Body>
|
||||
<Trans>Deposited liquidity:</Trans>
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
</AutoColumn>
|
||||
)}
|
||||
{stakingInfo?.earnedAmount && (
|
||||
<AutoColumn justify="center" gap="md">
|
||||
<TYPE.body fontWeight={600} fontSize={36}>
|
||||
<ThemedText.Body fontWeight={600} fontSize={36}>
|
||||
{<FormattedCurrencyAmount currencyAmount={stakingInfo?.earnedAmount} />}
|
||||
</TYPE.body>
|
||||
<TYPE.body>
|
||||
</ThemedText.Body>
|
||||
<ThemedText.Body>
|
||||
<Trans>Unclaimed UNI</Trans>
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
</AutoColumn>
|
||||
)}
|
||||
<TYPE.subHeader style={{ textAlign: 'center' }}>
|
||||
<ThemedText.SubHeader style={{ textAlign: 'center' }}>
|
||||
<Trans>When you withdraw, your UNI is claimed and your liquidity is removed from the mining pool.</Trans>
|
||||
</TYPE.subHeader>
|
||||
</ThemedText.SubHeader>
|
||||
<ButtonError disabled={!!error} error={!!error && !!stakingInfo?.stakedAmount} onClick={onWithdraw}>
|
||||
{error ?? <Trans>Withdraw & Claim</Trans>}
|
||||
</ButtonError>
|
||||
@@ -112,27 +112,27 @@ export default function UnstakingModal({ isOpen, onDismiss, stakingInfo }: Staki
|
||||
{attempting && !hash && (
|
||||
<LoadingView onDismiss={wrappedOndismiss}>
|
||||
<AutoColumn gap="12px" justify={'center'}>
|
||||
<TYPE.body fontSize={20}>
|
||||
<ThemedText.Body fontSize={20}>
|
||||
<Trans>Withdrawing {stakingInfo?.stakedAmount?.toSignificant(4)} UNI-V2</Trans>
|
||||
</TYPE.body>
|
||||
<TYPE.body fontSize={20}>
|
||||
</ThemedText.Body>
|
||||
<ThemedText.Body fontSize={20}>
|
||||
<Trans>Claiming {stakingInfo?.earnedAmount?.toSignificant(4)} UNI</Trans>
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
</AutoColumn>
|
||||
</LoadingView>
|
||||
)}
|
||||
{hash && (
|
||||
<SubmittedView onDismiss={wrappedOndismiss} hash={hash}>
|
||||
<AutoColumn gap="12px" justify={'center'}>
|
||||
<TYPE.largeHeader>
|
||||
<ThemedText.LargeHeader>
|
||||
<Trans>Transaction Submitted</Trans>
|
||||
</TYPE.largeHeader>
|
||||
<TYPE.body fontSize={20}>
|
||||
</ThemedText.LargeHeader>
|
||||
<ThemedText.Body fontSize={20}>
|
||||
<Trans>Withdrew UNI-V2!</Trans>
|
||||
</TYPE.body>
|
||||
<TYPE.body fontSize={20}>
|
||||
</ThemedText.Body>
|
||||
<ThemedText.Body fontSize={20}>
|
||||
<Trans>Claimed UNI!</Trans>
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
</AutoColumn>
|
||||
</SubmittedView>
|
||||
)}
|
||||
|
||||
@@ -1,22 +1,28 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Currency, Percent, TradeType } from '@uniswap/sdk-core'
|
||||
import { Trade as V2Trade } from '@uniswap/v2-sdk'
|
||||
import { Trade as V3Trade } from '@uniswap/v3-sdk'
|
||||
import Card from 'components/Card'
|
||||
import { LoadingRows } from 'components/Loader/styled'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import { useContext, useMemo } from 'react'
|
||||
import { ThemeContext } from 'styled-components/macro'
|
||||
import { InterfaceTrade } from 'state/routing/types'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
|
||||
import { TYPE } from '../../theme'
|
||||
import { Separator, ThemedText } from '../../theme'
|
||||
import { computeRealizedLPFeePercent } from '../../utils/prices'
|
||||
import { AutoColumn } from '../Column'
|
||||
import { RowBetween, RowFixed } from '../Row'
|
||||
import FormattedPriceImpact from './FormattedPriceImpact'
|
||||
import { TransactionDetailsLabel } from './styleds'
|
||||
import { SUPPORTED_GAS_ESTIMATE_CHAIN_IDS } from './GasEstimateBadge'
|
||||
|
||||
const StyledCard = styled(Card)`
|
||||
padding: 0;
|
||||
`
|
||||
|
||||
interface AdvancedSwapDetailsProps {
|
||||
trade?: V2Trade<Currency, Currency, TradeType> | V3Trade<Currency, Currency, TradeType>
|
||||
trade?: InterfaceTrade<Currency, Currency, TradeType>
|
||||
allowedSlippage: Percent
|
||||
syncing?: boolean
|
||||
hideRouteDiagram?: boolean
|
||||
}
|
||||
|
||||
function TextWithLoadingPlaceholder({
|
||||
@@ -39,74 +45,78 @@ function TextWithLoadingPlaceholder({
|
||||
|
||||
export function AdvancedSwapDetails({ trade, allowedSlippage, syncing = false }: AdvancedSwapDetailsProps) {
|
||||
const theme = useContext(ThemeContext)
|
||||
const { chainId } = useActiveWeb3React()
|
||||
|
||||
const { realizedLPFee, priceImpact } = useMemo(() => {
|
||||
if (!trade) return { realizedLPFee: undefined, priceImpact: undefined }
|
||||
|
||||
const { expectedOutputAmount, priceImpact } = useMemo(() => {
|
||||
if (!trade) return { expectedOutputAmount: undefined, priceImpact: undefined }
|
||||
const expectedOutputAmount = trade.outputAmount
|
||||
const realizedLpFeePercent = computeRealizedLPFeePercent(trade)
|
||||
const realizedLPFee = trade.inputAmount.multiply(realizedLpFeePercent)
|
||||
const priceImpact = trade.priceImpact.subtract(realizedLpFeePercent)
|
||||
return { priceImpact, realizedLPFee }
|
||||
return { expectedOutputAmount, priceImpact }
|
||||
}, [trade])
|
||||
|
||||
return !trade ? null : (
|
||||
<AutoColumn gap="8px">
|
||||
<TransactionDetailsLabel fontWeight={500} fontSize={14}>
|
||||
<Trans>Transaction Details</Trans>
|
||||
</TransactionDetailsLabel>
|
||||
<RowBetween>
|
||||
<RowFixed>
|
||||
<TYPE.subHeader color={theme.text1}>
|
||||
<Trans>Liquidity Provider Fee</Trans>
|
||||
</TYPE.subHeader>
|
||||
</RowFixed>
|
||||
<TextWithLoadingPlaceholder syncing={syncing} width={65}>
|
||||
<TYPE.black textAlign="right" fontSize={14}>
|
||||
{realizedLPFee ? `${realizedLPFee.toSignificant(4)} ${realizedLPFee.currency.symbol}` : '-'}
|
||||
</TYPE.black>
|
||||
</TextWithLoadingPlaceholder>
|
||||
</RowBetween>
|
||||
|
||||
<RowBetween>
|
||||
<RowFixed>
|
||||
<TYPE.subHeader color={theme.text1}>
|
||||
<Trans>Price Impact</Trans>
|
||||
</TYPE.subHeader>
|
||||
</RowFixed>
|
||||
<TextWithLoadingPlaceholder syncing={syncing} width={50}>
|
||||
<TYPE.black textAlign="right" fontSize={14}>
|
||||
<FormattedPriceImpact priceImpact={priceImpact} />
|
||||
</TYPE.black>
|
||||
</TextWithLoadingPlaceholder>
|
||||
</RowBetween>
|
||||
|
||||
<RowBetween>
|
||||
<RowFixed>
|
||||
<TYPE.subHeader color={theme.text1}>
|
||||
<Trans>Allowed Slippage</Trans>
|
||||
</TYPE.subHeader>
|
||||
</RowFixed>
|
||||
<TextWithLoadingPlaceholder syncing={syncing} width={45}>
|
||||
<TYPE.black textAlign="right" fontSize={14}>
|
||||
{allowedSlippage.toFixed(2)}%
|
||||
</TYPE.black>
|
||||
</TextWithLoadingPlaceholder>
|
||||
</RowBetween>
|
||||
|
||||
<RowBetween>
|
||||
<RowFixed>
|
||||
<TYPE.subHeader color={theme.text1}>
|
||||
{trade.tradeType === TradeType.EXACT_INPUT ? <Trans>Minimum received</Trans> : <Trans>Maximum sent</Trans>}
|
||||
</TYPE.subHeader>
|
||||
</RowFixed>
|
||||
<TextWithLoadingPlaceholder syncing={syncing} width={70}>
|
||||
<TYPE.black textAlign="right" fontSize={14}>
|
||||
{trade.tradeType === TradeType.EXACT_INPUT
|
||||
? `${trade.minimumAmountOut(allowedSlippage).toSignificant(6)} ${trade.outputAmount.currency.symbol}`
|
||||
: `${trade.maximumAmountIn(allowedSlippage).toSignificant(6)} ${trade.inputAmount.currency.symbol}`}
|
||||
</TYPE.black>
|
||||
</TextWithLoadingPlaceholder>
|
||||
</RowBetween>
|
||||
</AutoColumn>
|
||||
<StyledCard>
|
||||
<AutoColumn gap="8px">
|
||||
<RowBetween>
|
||||
<RowFixed>
|
||||
<ThemedText.SubHeader color={theme.text1}>
|
||||
<Trans>Expected Output</Trans>
|
||||
</ThemedText.SubHeader>
|
||||
</RowFixed>
|
||||
<TextWithLoadingPlaceholder syncing={syncing} width={65}>
|
||||
<ThemedText.Black textAlign="right" fontSize={14}>
|
||||
{expectedOutputAmount
|
||||
? `${expectedOutputAmount.toSignificant(6)} ${expectedOutputAmount.currency.symbol}`
|
||||
: '-'}
|
||||
</ThemedText.Black>
|
||||
</TextWithLoadingPlaceholder>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<RowFixed>
|
||||
<ThemedText.SubHeader color={theme.text1}>
|
||||
<Trans>Price Impact</Trans>
|
||||
</ThemedText.SubHeader>
|
||||
</RowFixed>
|
||||
<TextWithLoadingPlaceholder syncing={syncing} width={50}>
|
||||
<ThemedText.Black textAlign="right" fontSize={14}>
|
||||
<FormattedPriceImpact priceImpact={priceImpact} />
|
||||
</ThemedText.Black>
|
||||
</TextWithLoadingPlaceholder>
|
||||
</RowBetween>
|
||||
<Separator />
|
||||
<RowBetween>
|
||||
<RowFixed style={{ marginRight: '20px' }}>
|
||||
<ThemedText.SubHeader color={theme.text3}>
|
||||
{trade.tradeType === TradeType.EXACT_INPUT ? (
|
||||
<Trans>Minimum received</Trans>
|
||||
) : (
|
||||
<Trans>Maximum sent</Trans>
|
||||
)}{' '}
|
||||
<Trans>after slippage</Trans> ({allowedSlippage.toFixed(2)}%)
|
||||
</ThemedText.SubHeader>
|
||||
</RowFixed>
|
||||
<TextWithLoadingPlaceholder syncing={syncing} width={70}>
|
||||
<ThemedText.Black textAlign="right" fontSize={14} color={theme.text3}>
|
||||
{trade.tradeType === TradeType.EXACT_INPUT
|
||||
? `${trade.minimumAmountOut(allowedSlippage).toSignificant(6)} ${trade.outputAmount.currency.symbol}`
|
||||
: `${trade.maximumAmountIn(allowedSlippage).toSignificant(6)} ${trade.inputAmount.currency.symbol}`}
|
||||
</ThemedText.Black>
|
||||
</TextWithLoadingPlaceholder>
|
||||
</RowBetween>
|
||||
{!trade?.gasUseEstimateUSD || !chainId || !SUPPORTED_GAS_ESTIMATE_CHAIN_IDS.includes(chainId) ? null : (
|
||||
<RowBetween>
|
||||
<ThemedText.SubHeader color={theme.text3}>
|
||||
<Trans>Network Fee</Trans>
|
||||
</ThemedText.SubHeader>
|
||||
<TextWithLoadingPlaceholder syncing={syncing} width={50}>
|
||||
<ThemedText.Black textAlign="right" fontSize={14} color={theme.text3}>
|
||||
~${trade.gasUseEstimateUSD.toFixed(2)}
|
||||
</ThemedText.Black>
|
||||
</TextWithLoadingPlaceholder>
|
||||
</RowBetween>
|
||||
)}
|
||||
</AutoColumn>
|
||||
</StyledCard>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Trade } from '@uniswap/router-sdk'
|
||||
import { Currency, Percent, TradeType } from '@uniswap/sdk-core'
|
||||
import { Trade as V2Trade } from '@uniswap/v2-sdk'
|
||||
import { Trade as V3Trade } from '@uniswap/v3-sdk'
|
||||
import { ReactNode, useCallback, useMemo } from 'react'
|
||||
import { InterfaceTrade } from 'state/routing/types'
|
||||
|
||||
import TransactionConfirmationModal, {
|
||||
ConfirmationModalContent,
|
||||
@@ -16,9 +16,7 @@ import SwapModalHeader from './SwapModalHeader'
|
||||
* @param args either a pair of V2 trades or a pair of V3 trades
|
||||
*/
|
||||
function tradeMeaningfullyDiffers(
|
||||
...args:
|
||||
| [V2Trade<Currency, Currency, TradeType>, V2Trade<Currency, Currency, TradeType>]
|
||||
| [V3Trade<Currency, Currency, TradeType>, V3Trade<Currency, Currency, TradeType>]
|
||||
...args: [Trade<Currency, Currency, TradeType>, Trade<Currency, Currency, TradeType>]
|
||||
): boolean {
|
||||
const [tradeA, tradeB] = args
|
||||
return (
|
||||
@@ -44,8 +42,8 @@ export default function ConfirmSwapModal({
|
||||
txHash,
|
||||
}: {
|
||||
isOpen: boolean
|
||||
trade: V2Trade<Currency, Currency, TradeType> | V3Trade<Currency, Currency, TradeType> | undefined
|
||||
originalTrade: V2Trade<Currency, Currency, TradeType> | V3Trade<Currency, Currency, TradeType> | undefined
|
||||
trade: InterfaceTrade<Currency, Currency, TradeType> | undefined
|
||||
originalTrade: Trade<Currency, Currency, TradeType> | undefined
|
||||
attemptingTxn: boolean
|
||||
txHash: string | undefined
|
||||
recipient: string | null
|
||||
@@ -56,15 +54,7 @@ export default function ConfirmSwapModal({
|
||||
onDismiss: () => void
|
||||
}) {
|
||||
const showAcceptChanges = useMemo(
|
||||
() =>
|
||||
Boolean(
|
||||
(trade instanceof V2Trade &&
|
||||
originalTrade instanceof V2Trade &&
|
||||
tradeMeaningfullyDiffers(trade, originalTrade)) ||
|
||||
(trade instanceof V3Trade &&
|
||||
originalTrade instanceof V3Trade &&
|
||||
tradeMeaningfullyDiffers(trade, originalTrade))
|
||||
),
|
||||
() => Boolean(trade && originalTrade && tradeMeaningfullyDiffers(trade, originalTrade)),
|
||||
[originalTrade, trade]
|
||||
)
|
||||
|
||||
|
||||
105
src/components/swap/GasEstimateBadge.tsx
Normal file
105
src/components/swap/GasEstimateBadge.tsx
Normal file
@@ -0,0 +1,105 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Currency, TradeType } from '@uniswap/sdk-core'
|
||||
import { ChainId } from '@uniswap/smart-order-router'
|
||||
import { AutoColumn } from 'components/Column'
|
||||
import { LoadingOpacityContainer } from 'components/Loader/styled'
|
||||
import { RowFixed } from 'components/Row'
|
||||
import { MouseoverTooltipContent } from 'components/Tooltip'
|
||||
import ReactGA from 'react-ga'
|
||||
import { InterfaceTrade } from 'state/routing/types'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ThemedText } from 'theme'
|
||||
|
||||
import { ReactComponent as GasIcon } from '../../assets/images/gas-icon.svg'
|
||||
import { ResponsiveTooltipContainer } from './styleds'
|
||||
import SwapRoute from './SwapRoute'
|
||||
|
||||
const GasWrapper = styled(RowFixed)`
|
||||
border-radius: 8px;
|
||||
padding: 4px 6px;
|
||||
height: 24px;
|
||||
color: ${({ theme }) => theme.text3};
|
||||
background-color: ${({ theme }) => theme.bg1};
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
user-select: none;
|
||||
`
|
||||
const StyledGasIcon = styled(GasIcon)`
|
||||
margin-right: 4px;
|
||||
height: 14px;
|
||||
& > * {
|
||||
stroke: ${({ theme }) => theme.text3};
|
||||
}
|
||||
`
|
||||
|
||||
export const SUPPORTED_GAS_ESTIMATE_CHAIN_IDS = [ChainId.MAINNET]
|
||||
|
||||
export default function GasEstimateBadge({
|
||||
trade,
|
||||
loading,
|
||||
showRoute,
|
||||
disableHover,
|
||||
}: {
|
||||
trade: InterfaceTrade<Currency, Currency, TradeType> | undefined | null // dollar amount in active chain's stablecoin
|
||||
loading: boolean
|
||||
showRoute?: boolean // show route instead of gas estimation summary
|
||||
disableHover?: boolean
|
||||
}) {
|
||||
const formattedGasPriceString = trade?.gasUseEstimateUSD
|
||||
? trade.gasUseEstimateUSD.toFixed(2) === '0.00'
|
||||
? '<$0.01'
|
||||
: '$' + trade.gasUseEstimateUSD.toFixed(2)
|
||||
: undefined
|
||||
|
||||
return (
|
||||
<MouseoverTooltipContent
|
||||
wrap={false}
|
||||
disableHover={disableHover}
|
||||
content={
|
||||
loading ? null : (
|
||||
<ResponsiveTooltipContainer
|
||||
origin="top right"
|
||||
style={{
|
||||
padding: showRoute ? '0' : '12px',
|
||||
border: 'none',
|
||||
borderRadius: showRoute ? '16px' : '12px',
|
||||
maxWidth: '400px',
|
||||
}}
|
||||
>
|
||||
{showRoute ? (
|
||||
trade ? (
|
||||
<SwapRoute trade={trade} syncing={loading} fixedOpen={showRoute} />
|
||||
) : null
|
||||
) : (
|
||||
<AutoColumn gap="4px" justify="center">
|
||||
<ThemedText.Main fontSize="12px" textAlign="center">
|
||||
<Trans>Estimated network fee</Trans>
|
||||
</ThemedText.Main>
|
||||
<ThemedText.Body textAlign="center" fontWeight={500} style={{ userSelect: 'none' }}>
|
||||
<Trans>${trade?.gasUseEstimateUSD?.toFixed(2)}</Trans>
|
||||
</ThemedText.Body>
|
||||
<ThemedText.Main fontSize="10px" textAlign="center" maxWidth="140px" color="text3">
|
||||
<Trans>Estimate may differ due to your wallet gas settings</Trans>
|
||||
</ThemedText.Main>
|
||||
</AutoColumn>
|
||||
)}
|
||||
</ResponsiveTooltipContainer>
|
||||
)
|
||||
}
|
||||
placement="bottom"
|
||||
onOpen={() =>
|
||||
ReactGA.event({
|
||||
category: 'Gas',
|
||||
action: 'Gas Details Tooltip Open',
|
||||
})
|
||||
}
|
||||
>
|
||||
<LoadingOpacityContainer $loading={loading}>
|
||||
<GasWrapper>
|
||||
<StyledGasIcon />
|
||||
{formattedGasPriceString ?? null}
|
||||
</GasWrapper>
|
||||
</LoadingOpacityContainer>
|
||||
</MouseoverTooltipContent>
|
||||
)
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { useRoutingAPIEnabled } from 'state/user/hooks'
|
||||
import useAutoRouterSupported from 'hooks/useAutoRouterSupported'
|
||||
import styled from 'styled-components/macro'
|
||||
import { TYPE } from 'theme'
|
||||
import { ThemedText } from 'theme'
|
||||
|
||||
import { ReactComponent as AutoRouterIcon } from '../../assets/svg/auto_router.svg'
|
||||
import { ReactComponent as StaticRouterIcon } from '../../assets/svg/static_route.svg'
|
||||
@@ -26,7 +26,7 @@ const StyledStaticRouterIcon = styled(StaticRouterIcon)`
|
||||
}
|
||||
`
|
||||
|
||||
const StyledAutoRouterLabel = styled(TYPE.black)`
|
||||
const StyledAutoRouterLabel = styled(ThemedText.Black)`
|
||||
line-height: 1rem;
|
||||
|
||||
/* fallback color */
|
||||
@@ -40,19 +40,19 @@ const StyledAutoRouterLabel = styled(TYPE.black)`
|
||||
`
|
||||
|
||||
export function AutoRouterLogo() {
|
||||
const routingAPIEnabled = useRoutingAPIEnabled()
|
||||
const autoRouterSupported = useAutoRouterSupported()
|
||||
|
||||
return routingAPIEnabled ? <StyledAutoRouterIcon /> : <StyledStaticRouterIcon />
|
||||
return autoRouterSupported ? <StyledAutoRouterIcon /> : <StyledStaticRouterIcon />
|
||||
}
|
||||
|
||||
export function AutoRouterLabel() {
|
||||
const routingAPIEnabled = useRoutingAPIEnabled()
|
||||
const autoRouterSupported = useAutoRouterSupported()
|
||||
|
||||
return routingAPIEnabled ? (
|
||||
return autoRouterSupported ? (
|
||||
<StyledAutoRouterLabel fontSize={14}>Auto Router</StyledAutoRouterLabel>
|
||||
) : (
|
||||
<TYPE.black fontSize={14}>
|
||||
<ThemedText.Black fontSize={14}>
|
||||
<Trans>Trade Route</Trans>
|
||||
</TYPE.black>
|
||||
</ThemedText.Black>
|
||||
)
|
||||
}
|
||||
|
||||
202
src/components/swap/SwapDetailsDropdown.tsx
Normal file
202
src/components/swap/SwapDetailsDropdown.tsx
Normal file
@@ -0,0 +1,202 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Currency, Percent, TradeType } from '@uniswap/sdk-core'
|
||||
import AnimatedDropdown from 'components/AnimatedDropdown'
|
||||
import Card, { OutlineCard } from 'components/Card'
|
||||
import { AutoColumn } from 'components/Column'
|
||||
import { LoadingOpacityContainer } from 'components/Loader/styled'
|
||||
import Row, { RowBetween, RowFixed } from 'components/Row'
|
||||
import { MouseoverTooltipContent } from 'components/Tooltip'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import { darken } from 'polished'
|
||||
import { useState } from 'react'
|
||||
import { ChevronDown, Info } from 'react-feather'
|
||||
import { InterfaceTrade } from 'state/routing/types'
|
||||
import styled, { keyframes, useTheme } from 'styled-components/macro'
|
||||
import { HideSmall, ThemedText } from 'theme'
|
||||
|
||||
import { AdvancedSwapDetails } from './AdvancedSwapDetails'
|
||||
import GasEstimateBadge, { SUPPORTED_GAS_ESTIMATE_CHAIN_IDS } from './GasEstimateBadge'
|
||||
import { ResponsiveTooltipContainer } from './styleds'
|
||||
import SwapRoute from './SwapRoute'
|
||||
import TradePrice from './TradePrice'
|
||||
|
||||
const Wrapper = styled(Row)`
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
`
|
||||
|
||||
const StyledInfoIcon = styled(Info)`
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
margin-right: 4px;
|
||||
color: ${({ theme }) => theme.text3};
|
||||
`
|
||||
|
||||
const StyledCard = styled(OutlineCard)`
|
||||
padding: 12px;
|
||||
border: 1px solid ${({ theme }) => theme.bg2};
|
||||
`
|
||||
|
||||
const StyledHeaderRow = styled(RowBetween)<{ disabled: boolean; open: boolean }>`
|
||||
padding: 4px 8px;
|
||||
border-radius: 12px;
|
||||
background-color: ${({ open, theme }) => (open ? theme.bg1 : 'transparent')};
|
||||
align-items: center;
|
||||
cursor: ${({ disabled }) => (disabled ? 'initial' : 'pointer')};
|
||||
min-height: 40px;
|
||||
|
||||
:hover {
|
||||
background-color: ${({ theme, disabled }) => (disabled ? theme.bg1 : darken(0.015, theme.bg1))};
|
||||
}
|
||||
`
|
||||
|
||||
const RotatingArrow = styled(ChevronDown)<{ open?: boolean }>`
|
||||
transform: ${({ open }) => (open ? 'rotate(180deg)' : 'none')};
|
||||
transition: transform 0.1s linear;
|
||||
`
|
||||
|
||||
const StyledPolling = styled.div`
|
||||
display: flex;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
margin-right: 2px;
|
||||
margin-left: 10px;
|
||||
align-items: center;
|
||||
color: ${({ theme }) => theme.text1};
|
||||
transition: 250ms ease color;
|
||||
|
||||
${({ theme }) => theme.mediaWidth.upToMedium`
|
||||
display: none;
|
||||
`}
|
||||
`
|
||||
|
||||
const StyledPollingDot = styled.div`
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
min-height: 8px;
|
||||
min-width: 8px;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
background-color: ${({ theme }) => theme.bg2};
|
||||
transition: 250ms ease background-color;
|
||||
`
|
||||
|
||||
const rotate360 = keyframes`
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
`
|
||||
|
||||
const Spinner = styled.div`
|
||||
animation: ${rotate360} 1s cubic-bezier(0.83, 0, 0.17, 1) infinite;
|
||||
transform: translateZ(0);
|
||||
border-top: 1px solid transparent;
|
||||
border-right: 1px solid transparent;
|
||||
border-bottom: 1px solid transparent;
|
||||
border-left: 2px solid ${({ theme }) => theme.text1};
|
||||
background: transparent;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
transition: 250ms ease border-color;
|
||||
left: -3px;
|
||||
top: -3px;
|
||||
`
|
||||
|
||||
interface SwapDetailsInlineProps {
|
||||
trade: InterfaceTrade<Currency, Currency, TradeType> | undefined
|
||||
syncing: boolean
|
||||
loading: boolean
|
||||
showInverted: boolean
|
||||
setShowInverted: React.Dispatch<React.SetStateAction<boolean>>
|
||||
allowedSlippage: Percent
|
||||
}
|
||||
|
||||
export default function SwapDetailsDropdown({
|
||||
trade,
|
||||
syncing,
|
||||
loading,
|
||||
showInverted,
|
||||
setShowInverted,
|
||||
allowedSlippage,
|
||||
}: SwapDetailsInlineProps) {
|
||||
const theme = useTheme()
|
||||
const { chainId } = useActiveWeb3React()
|
||||
const [showDetails, setShowDetails] = useState(false)
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<AutoColumn gap={'8px'} style={{ width: '100%', marginBottom: '-8px' }}>
|
||||
<StyledHeaderRow onClick={() => setShowDetails(!showDetails)} disabled={!trade} open={showDetails}>
|
||||
<RowFixed style={{ position: 'relative' }}>
|
||||
{loading || syncing ? (
|
||||
<StyledPolling>
|
||||
<StyledPollingDot>
|
||||
<Spinner />
|
||||
</StyledPollingDot>
|
||||
</StyledPolling>
|
||||
) : (
|
||||
<HideSmall>
|
||||
<MouseoverTooltipContent
|
||||
wrap={false}
|
||||
content={
|
||||
<ResponsiveTooltipContainer origin="top right" style={{ padding: '0' }}>
|
||||
<Card padding="12px">
|
||||
<AdvancedSwapDetails trade={trade} allowedSlippage={allowedSlippage} syncing={syncing} />
|
||||
</Card>
|
||||
</ResponsiveTooltipContainer>
|
||||
}
|
||||
placement="bottom"
|
||||
disableHover={showDetails}
|
||||
>
|
||||
<StyledInfoIcon color={trade ? theme.text3 : theme.bg3} />
|
||||
</MouseoverTooltipContent>
|
||||
</HideSmall>
|
||||
)}
|
||||
{trade ? (
|
||||
<LoadingOpacityContainer $loading={syncing}>
|
||||
<TradePrice
|
||||
price={trade.executionPrice}
|
||||
showInverted={showInverted}
|
||||
setShowInverted={setShowInverted}
|
||||
/>
|
||||
</LoadingOpacityContainer>
|
||||
) : loading || syncing ? (
|
||||
<ThemedText.Main fontSize={14}>
|
||||
<Trans>Fetching best price...</Trans>
|
||||
</ThemedText.Main>
|
||||
) : null}
|
||||
</RowFixed>
|
||||
<RowFixed>
|
||||
{!trade?.gasUseEstimateUSD ||
|
||||
showDetails ||
|
||||
!chainId ||
|
||||
!SUPPORTED_GAS_ESTIMATE_CHAIN_IDS.includes(chainId) ? null : (
|
||||
<GasEstimateBadge
|
||||
trade={trade}
|
||||
loading={syncing || loading}
|
||||
showRoute={!showDetails}
|
||||
disableHover={showDetails}
|
||||
/>
|
||||
)}
|
||||
<RotatingArrow stroke={trade ? theme.text3 : theme.bg3} open={Boolean(trade && showDetails)} />
|
||||
</RowFixed>
|
||||
</StyledHeaderRow>
|
||||
<AnimatedDropdown open={showDetails}>
|
||||
<AutoColumn gap={'8px'} style={{ padding: '0', paddingBottom: '8px' }}>
|
||||
{trade ? (
|
||||
<StyledCard>
|
||||
<AdvancedSwapDetails trade={trade} allowedSlippage={allowedSlippage} syncing={syncing} />
|
||||
</StyledCard>
|
||||
) : null}
|
||||
{trade ? <SwapRoute trade={trade} syncing={syncing} /> : null}
|
||||
</AutoColumn>
|
||||
</AnimatedDropdown>
|
||||
</AutoColumn>
|
||||
</Wrapper>
|
||||
)
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import { Trans } from '@lingui/macro'
|
||||
import { Percent } from '@uniswap/sdk-core'
|
||||
import styled from 'styled-components/macro'
|
||||
|
||||
import { TYPE } from '../../theme'
|
||||
import { ThemedText } from '../../theme'
|
||||
import { RowBetween, RowFixed } from '../Row'
|
||||
import SettingsTab from '../Settings'
|
||||
|
||||
@@ -17,9 +17,9 @@ export default function SwapHeader({ allowedSlippage }: { allowedSlippage: Perce
|
||||
<StyledSwapHeader>
|
||||
<RowBetween>
|
||||
<RowFixed>
|
||||
<TYPE.black fontWeight={500} fontSize={16} style={{ marginRight: '8px' }}>
|
||||
<ThemedText.Black fontWeight={500} fontSize={16} style={{ marginRight: '8px' }}>
|
||||
<Trans>Swap</Trans>
|
||||
</TYPE.black>
|
||||
</ThemedText.Black>
|
||||
</RowFixed>
|
||||
<RowFixed>
|
||||
<SettingsTab placeholderSlippage={allowedSlippage} />
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Trade } from '@uniswap/router-sdk'
|
||||
import { Currency, TradeType } from '@uniswap/sdk-core'
|
||||
import { Trade as V2Trade } from '@uniswap/v2-sdk'
|
||||
import { Trade as V3Trade } from '@uniswap/v3-sdk'
|
||||
import { ReactNode } from 'react'
|
||||
import { Text } from 'rebass'
|
||||
|
||||
@@ -14,7 +13,7 @@ export default function SwapModalFooter({
|
||||
swapErrorMessage,
|
||||
disabledConfirm,
|
||||
}: {
|
||||
trade: V2Trade<Currency, Currency, TradeType> | V3Trade<Currency, Currency, TradeType>
|
||||
trade: Trade<Currency, Currency, TradeType>
|
||||
onConfirm: () => void
|
||||
swapErrorMessage: ReactNode | undefined
|
||||
disabledConfirm: boolean
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Currency, Percent, TradeType } from '@uniswap/sdk-core'
|
||||
import { Trade as V2Trade } from '@uniswap/v2-sdk'
|
||||
import { Trade as V3Trade } from '@uniswap/v3-sdk'
|
||||
import { useContext, useState } from 'react'
|
||||
import { AlertTriangle, ArrowDown } from 'react-feather'
|
||||
import { Text } from 'rebass'
|
||||
import { InterfaceTrade } from 'state/routing/types'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
|
||||
import { useUSDCValue } from '../../hooks/useUSDCPrice'
|
||||
import { TYPE } from '../../theme'
|
||||
import { ThemedText } from '../../theme'
|
||||
import { isAddress, shortenAddress } from '../../utils'
|
||||
import { computeFiatValuePriceImpact } from '../../utils/computeFiatValuePriceImpact'
|
||||
import { ButtonPrimary } from '../Button'
|
||||
@@ -46,7 +45,7 @@ export default function SwapModalHeader({
|
||||
showAcceptChanges,
|
||||
onAcceptChanges,
|
||||
}: {
|
||||
trade: V2Trade<Currency, Currency, TradeType> | V3Trade<Currency, Currency, TradeType>
|
||||
trade: InterfaceTrade<Currency, Currency, TradeType>
|
||||
allowedSlippage: Percent
|
||||
recipient: string | null
|
||||
showAcceptChanges: boolean
|
||||
@@ -63,19 +62,7 @@ export default function SwapModalHeader({
|
||||
<AutoColumn gap={'4px'} style={{ marginTop: '1rem' }}>
|
||||
<LightCard padding="0.75rem 1rem">
|
||||
<AutoColumn gap={'8px'}>
|
||||
<RowBetween>
|
||||
<TYPE.body color={theme.text3} fontWeight={500} fontSize={14}>
|
||||
<Trans>From</Trans>
|
||||
</TYPE.body>
|
||||
<FiatValue fiatValue={fiatValueInput} />
|
||||
</RowBetween>
|
||||
<RowBetween align="center">
|
||||
<RowFixed gap={'0px'}>
|
||||
<CurrencyLogo currency={trade.inputAmount.currency} size={'20px'} style={{ marginRight: '12px' }} />
|
||||
<Text fontSize={20} fontWeight={500}>
|
||||
{trade.inputAmount.currency.symbol}
|
||||
</Text>
|
||||
</RowFixed>
|
||||
<RowFixed gap={'0px'}>
|
||||
<TruncatedText
|
||||
fontSize={24}
|
||||
@@ -85,6 +72,15 @@ export default function SwapModalHeader({
|
||||
{trade.inputAmount.toSignificant(6)}
|
||||
</TruncatedText>
|
||||
</RowFixed>
|
||||
<RowFixed gap={'0px'}>
|
||||
<CurrencyLogo currency={trade.inputAmount.currency} size={'20px'} style={{ marginRight: '12px' }} />
|
||||
<Text fontSize={20} fontWeight={500}>
|
||||
{trade.inputAmount.currency.symbol}
|
||||
</Text>
|
||||
</RowFixed>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<FiatValue fiatValue={fiatValueInput} />
|
||||
</RowBetween>
|
||||
</AutoColumn>
|
||||
</LightCard>
|
||||
@@ -93,51 +89,43 @@ export default function SwapModalHeader({
|
||||
</ArrowWrapper>
|
||||
<LightCard padding="0.75rem 1rem" style={{ marginBottom: '0.25rem' }}>
|
||||
<AutoColumn gap={'8px'}>
|
||||
<RowBetween>
|
||||
<TYPE.body color={theme.text3} fontWeight={500} fontSize={14}>
|
||||
<Trans>To</Trans>
|
||||
</TYPE.body>
|
||||
<TYPE.body fontSize={14} color={theme.text3}>
|
||||
<FiatValue
|
||||
fiatValue={fiatValueOutput}
|
||||
priceImpact={computeFiatValuePriceImpact(fiatValueInput, fiatValueOutput)}
|
||||
/>
|
||||
</TYPE.body>
|
||||
</RowBetween>
|
||||
<RowBetween align="flex-end">
|
||||
<RowFixed gap={'0px'}>
|
||||
<TruncatedText fontSize={24} fontWeight={500}>
|
||||
{trade.outputAmount.toSignificant(6)}
|
||||
</TruncatedText>
|
||||
</RowFixed>
|
||||
<RowFixed gap={'0px'}>
|
||||
<CurrencyLogo currency={trade.outputAmount.currency} size={'20px'} style={{ marginRight: '12px' }} />
|
||||
<Text fontSize={20} fontWeight={500}>
|
||||
{trade.outputAmount.currency.symbol}
|
||||
</Text>
|
||||
</RowFixed>
|
||||
<RowFixed gap={'0px'}>
|
||||
<TruncatedText fontSize={24} fontWeight={500}>
|
||||
{trade.outputAmount.toSignificant(6)}
|
||||
</TruncatedText>
|
||||
</RowFixed>
|
||||
</RowBetween>
|
||||
<RowBetween>
|
||||
<ThemedText.Body fontSize={14} color={theme.text3}>
|
||||
<FiatValue
|
||||
fiatValue={fiatValueOutput}
|
||||
priceImpact={computeFiatValuePriceImpact(fiatValueInput, fiatValueOutput)}
|
||||
/>
|
||||
</ThemedText.Body>
|
||||
</RowBetween>
|
||||
</AutoColumn>
|
||||
</LightCard>
|
||||
<RowBetween style={{ marginTop: '0.25rem', padding: '0 1rem' }}>
|
||||
<TYPE.body color={theme.text2} fontWeight={500} fontSize={14}>
|
||||
<Trans>Price</Trans>
|
||||
</TYPE.body>
|
||||
<TradePrice price={trade.executionPrice} showInverted={showInverted} setShowInverted={setShowInverted} />
|
||||
</RowBetween>
|
||||
|
||||
<LightCard style={{ padding: '.75rem', marginTop: '0.5rem' }}>
|
||||
<AdvancedSwapDetails trade={trade} allowedSlippage={allowedSlippage} />
|
||||
</LightCard>
|
||||
|
||||
{showAcceptChanges ? (
|
||||
<SwapShowAcceptChanges justify="flex-start" gap={'0px'}>
|
||||
<RowBetween>
|
||||
<RowFixed>
|
||||
<AlertTriangle size={20} style={{ marginRight: '8px', minWidth: 24 }} />
|
||||
<TYPE.main color={theme.primary1}>
|
||||
<ThemedText.Main color={theme.primary1}>
|
||||
<Trans>Price Updated</Trans>
|
||||
</TYPE.main>
|
||||
</ThemedText.Main>
|
||||
</RowFixed>
|
||||
<ButtonPrimary
|
||||
style={{ padding: '.5rem', width: 'fit-content', fontSize: '0.825rem', borderRadius: '12px' }}
|
||||
@@ -151,7 +139,7 @@ export default function SwapModalHeader({
|
||||
|
||||
<AutoColumn justify="flex-start" gap="sm" style={{ padding: '.75rem 1rem' }}>
|
||||
{trade.tradeType === TradeType.EXACT_INPUT ? (
|
||||
<TYPE.italic fontWeight={400} textAlign="left" style={{ width: '100%' }}>
|
||||
<ThemedText.Italic fontWeight={400} textAlign="left" style={{ width: '100%' }}>
|
||||
<Trans>
|
||||
Output is estimated. You will receive at least{' '}
|
||||
<b>
|
||||
@@ -159,9 +147,9 @@ export default function SwapModalHeader({
|
||||
</b>{' '}
|
||||
or the transaction will revert.
|
||||
</Trans>
|
||||
</TYPE.italic>
|
||||
</ThemedText.Italic>
|
||||
) : (
|
||||
<TYPE.italic fontWeight={400} textAlign="left" style={{ width: '100%' }}>
|
||||
<ThemedText.Italic fontWeight={400} textAlign="left" style={{ width: '100%' }}>
|
||||
<Trans>
|
||||
Input is estimated. You will sell at most{' '}
|
||||
<b>
|
||||
@@ -169,17 +157,17 @@ export default function SwapModalHeader({
|
||||
</b>{' '}
|
||||
or the transaction will revert.
|
||||
</Trans>
|
||||
</TYPE.italic>
|
||||
</ThemedText.Italic>
|
||||
)}
|
||||
</AutoColumn>
|
||||
{recipient !== null ? (
|
||||
<AutoColumn justify="flex-start" gap="sm" style={{ padding: '12px 0 0 0px' }}>
|
||||
<TYPE.main>
|
||||
<ThemedText.Main>
|
||||
<Trans>
|
||||
Output will be sent to{' '}
|
||||
<b title={recipient}>{isAddress(recipient) ? shortenAddress(recipient) : recipient}</b>
|
||||
</Trans>
|
||||
</TYPE.main>
|
||||
</ThemedText.Main>
|
||||
</AutoColumn>
|
||||
) : null}
|
||||
</AutoColumn>
|
||||
|
||||
@@ -1,92 +1,113 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Trade } from '@uniswap/router-sdk'
|
||||
import { Currency, Percent, TradeType } from '@uniswap/sdk-core'
|
||||
import { Trade as V2Trade } from '@uniswap/v2-sdk'
|
||||
import { FeeAmount, Trade as V3Trade } from '@uniswap/v3-sdk'
|
||||
import Badge from 'components/Badge'
|
||||
import { Pair } from '@uniswap/v2-sdk'
|
||||
import AnimatedDropdown from 'components/AnimatedDropdown'
|
||||
import { AutoColumn } from 'components/Column'
|
||||
import { LoadingRows } from 'components/Loader/styled'
|
||||
import RoutingDiagram, { RoutingDiagramEntry } from 'components/RoutingDiagram/RoutingDiagram'
|
||||
import { AutoRow, RowBetween } from 'components/Row'
|
||||
import { Version } from 'hooks/useToggledVersion'
|
||||
import { memo } from 'react'
|
||||
import { useRoutingAPIEnabled } from 'state/user/hooks'
|
||||
import useAutoRouterSupported from 'hooks/useAutoRouterSupported'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import { memo, useState } from 'react'
|
||||
import { Plus } from 'react-feather'
|
||||
import { InterfaceTrade } from 'state/routing/types'
|
||||
import { useDarkModeManager } from 'state/user/hooks'
|
||||
import styled from 'styled-components/macro'
|
||||
import { TYPE } from 'theme'
|
||||
import { getTradeVersion } from 'utils/getTradeVersion'
|
||||
import { Separator, ThemedText } from 'theme'
|
||||
|
||||
import { SUPPORTED_GAS_ESTIMATE_CHAIN_IDS } from './GasEstimateBadge'
|
||||
import { AutoRouterLabel, AutoRouterLogo } from './RouterLabel'
|
||||
|
||||
const Separator = styled.div`
|
||||
border-top: 1px solid ${({ theme }) => theme.bg2};
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
const Wrapper = styled(AutoColumn)<{ darkMode?: boolean; fixedOpen?: boolean }>`
|
||||
padding: ${({ fixedOpen }) => (fixedOpen ? '12px' : '12px 8px 12px 12px')};
|
||||
border-radius: 16px;
|
||||
border: 1px solid ${({ theme, fixedOpen }) => (fixedOpen ? 'transparent' : theme.bg2)};
|
||||
cursor: pointer;
|
||||
`
|
||||
|
||||
const OpenCloseIcon = styled(Plus)<{ open?: boolean }>`
|
||||
margin-left: 8px;
|
||||
height: 20px;
|
||||
stroke-width: 2px;
|
||||
transition: transform 0.1s;
|
||||
transform: ${({ open }) => (open ? 'rotate(45deg)' : 'none')};
|
||||
stroke: ${({ theme }) => theme.text3};
|
||||
cursor: pointer;
|
||||
:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
`
|
||||
|
||||
const V2_DEFAULT_FEE_TIER = 3000
|
||||
|
||||
export default memo(function SwapRoute({
|
||||
trade,
|
||||
syncing,
|
||||
}: {
|
||||
trade: V2Trade<Currency, Currency, TradeType> | V3Trade<Currency, Currency, TradeType>
|
||||
interface SwapRouteProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
trade: InterfaceTrade<Currency, Currency, TradeType>
|
||||
syncing: boolean
|
||||
}) {
|
||||
const routingAPIEnabled = useRoutingAPIEnabled()
|
||||
fixedOpen?: boolean // fixed in open state, hide open/close icon
|
||||
}
|
||||
|
||||
export default memo(function SwapRoute({ trade, syncing, fixedOpen = false, ...rest }: SwapRouteProps) {
|
||||
const autoRouterSupported = useAutoRouterSupported()
|
||||
const routes = getTokenPath(trade)
|
||||
const [open, setOpen] = useState(false)
|
||||
const { chainId } = useActiveWeb3React()
|
||||
|
||||
const [darkMode] = useDarkModeManager()
|
||||
|
||||
const formattedGasPriceString = trade?.gasUseEstimateUSD
|
||||
? trade.gasUseEstimateUSD.toFixed(2) === '0.00'
|
||||
? '<$0.01'
|
||||
: '$' + trade.gasUseEstimateUSD.toFixed(2)
|
||||
: undefined
|
||||
|
||||
return (
|
||||
<AutoColumn gap="12px">
|
||||
<RowBetween>
|
||||
<Wrapper {...rest} darkMode={darkMode} fixedOpen={fixedOpen}>
|
||||
<RowBetween onClick={() => setOpen(!open)}>
|
||||
<AutoRow gap="4px" width="auto">
|
||||
<AutoRouterLogo />
|
||||
<AutoRouterLabel />
|
||||
</AutoRow>
|
||||
{syncing ? (
|
||||
<LoadingRows>
|
||||
<div style={{ width: '30px', height: '24px' }} />
|
||||
</LoadingRows>
|
||||
) : (
|
||||
<Badge>
|
||||
<TYPE.black fontSize={12}>
|
||||
{getTradeVersion(trade) === Version.v2 ? <Trans>V2</Trans> : <Trans>V3</Trans>}
|
||||
</TYPE.black>
|
||||
</Badge>
|
||||
)}
|
||||
{fixedOpen ? null : <OpenCloseIcon open={open} />}
|
||||
</RowBetween>
|
||||
<Separator />
|
||||
{syncing ? (
|
||||
<LoadingRows>
|
||||
<div style={{ width: '400px', height: '30px' }} />
|
||||
</LoadingRows>
|
||||
) : (
|
||||
<RoutingDiagram
|
||||
currencyIn={trade.inputAmount.currency}
|
||||
currencyOut={trade.outputAmount.currency}
|
||||
routes={getTokenPath(trade)}
|
||||
/>
|
||||
)}
|
||||
{routingAPIEnabled && (
|
||||
<TYPE.main fontSize={12} width={400}>
|
||||
<Trans>This route optimizes your price by considering split routes, multiple hops, and gas costs.</Trans>
|
||||
</TYPE.main>
|
||||
)}
|
||||
</AutoColumn>
|
||||
<AnimatedDropdown open={open || fixedOpen}>
|
||||
<AutoRow gap="4px" width="auto" style={{ paddingTop: '12px', margin: 0 }}>
|
||||
{syncing ? (
|
||||
<LoadingRows>
|
||||
<div style={{ width: '400px', height: '30px' }} />
|
||||
</LoadingRows>
|
||||
) : (
|
||||
<RoutingDiagram
|
||||
currencyIn={trade.inputAmount.currency}
|
||||
currencyOut={trade.outputAmount.currency}
|
||||
routes={routes}
|
||||
/>
|
||||
)}
|
||||
<Separator />
|
||||
{autoRouterSupported &&
|
||||
(syncing ? (
|
||||
<LoadingRows>
|
||||
<div style={{ width: '250px', height: '15px' }} />
|
||||
</LoadingRows>
|
||||
) : (
|
||||
<ThemedText.Main fontSize={12} width={400} margin={0}>
|
||||
{trade?.gasUseEstimateUSD && chainId && SUPPORTED_GAS_ESTIMATE_CHAIN_IDS.includes(chainId) ? (
|
||||
<Trans>Best price route costs ~{formattedGasPriceString} in gas. </Trans>
|
||||
) : null}{' '}
|
||||
<Trans>
|
||||
This route optimizes your total output by considering split routes, multiple hops, and the gas cost of
|
||||
each step.
|
||||
</Trans>
|
||||
</ThemedText.Main>
|
||||
))}
|
||||
</AutoRow>
|
||||
</AnimatedDropdown>
|
||||
</Wrapper>
|
||||
)
|
||||
})
|
||||
|
||||
function getTokenPath(
|
||||
trade: V2Trade<Currency, Currency, TradeType> | V3Trade<Currency, Currency, TradeType>
|
||||
): RoutingDiagramEntry[] {
|
||||
// convert V2 path to a list of routes
|
||||
if (trade instanceof V2Trade) {
|
||||
const { path: tokenPath } = (trade as V2Trade<Currency, Currency, TradeType>).route
|
||||
const path = []
|
||||
for (let i = 1; i < tokenPath.length; i++) {
|
||||
path.push([tokenPath[i - 1], tokenPath[i], V2_DEFAULT_FEE_TIER] as RoutingDiagramEntry['path'][0])
|
||||
}
|
||||
return [{ percent: new Percent(100, 100), path }]
|
||||
}
|
||||
|
||||
return trade.swaps.map(({ route: { tokenPath, pools }, inputAmount, outputAmount }) => {
|
||||
function getTokenPath(trade: Trade<Currency, Currency, TradeType>): RoutingDiagramEntry[] {
|
||||
return trade.swaps.map(({ route: { path: tokenPath, pools, protocol }, inputAmount, outputAmount }) => {
|
||||
const portion =
|
||||
trade.tradeType === TradeType.EXACT_INPUT
|
||||
? inputAmount.divide(trade.inputAmount)
|
||||
@@ -94,18 +115,25 @@ function getTokenPath(
|
||||
|
||||
const percent = new Percent(portion.numerator, portion.denominator)
|
||||
|
||||
const path: [Currency, Currency, FeeAmount][] = []
|
||||
const path: RoutingDiagramEntry['path'] = []
|
||||
for (let i = 0; i < pools.length; i++) {
|
||||
const nextPool = pools[i]
|
||||
const tokenIn = tokenPath[i]
|
||||
const tokenOut = tokenPath[i + 1]
|
||||
|
||||
path.push([tokenIn, tokenOut, nextPool.fee])
|
||||
const entry: RoutingDiagramEntry['path'][0] = [
|
||||
tokenIn,
|
||||
tokenOut,
|
||||
nextPool instanceof Pair ? V2_DEFAULT_FEE_TIER : nextPool.fee,
|
||||
]
|
||||
|
||||
path.push(entry)
|
||||
}
|
||||
|
||||
return {
|
||||
percent,
|
||||
path,
|
||||
protocol,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
75
src/components/swap/SwapWarningDropdown.tsx
Normal file
75
src/components/swap/SwapWarningDropdown.tsx
Normal file
@@ -0,0 +1,75 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Currency, CurrencyAmount, Token, TradeType } from '@uniswap/sdk-core'
|
||||
import { RowBetween } from 'components/Row'
|
||||
import { MouseoverTooltipContent } from 'components/Tooltip'
|
||||
import { Info } from 'react-feather'
|
||||
import { InterfaceTrade } from 'state/routing/types'
|
||||
import styled from 'styled-components/macro'
|
||||
import { ThemedText } from 'theme'
|
||||
|
||||
import { ResponsiveTooltipContainer } from './styleds'
|
||||
|
||||
const Wrapper = styled.div`
|
||||
background-color: ${({ theme }) => theme.bg1};
|
||||
border-bottom-left-radius: 20px;
|
||||
border-bottom-right-radius: 20px;
|
||||
padding: 14px;
|
||||
margin-top: -20px;
|
||||
padding-top: 32px;
|
||||
`
|
||||
|
||||
const StyledInfoIcon = styled(Info)`
|
||||
stroke: ${({ theme }) => theme.text3};
|
||||
`
|
||||
|
||||
/**
|
||||
* @returns Dropdown card for showing edge case warnings outside of button
|
||||
*/
|
||||
export default function SwapWarningDropdown({
|
||||
fiatValueInput,
|
||||
trade,
|
||||
}: {
|
||||
fiatValueInput: CurrencyAmount<Token> | null
|
||||
trade: InterfaceTrade<Currency, Currency, TradeType> | undefined
|
||||
}) {
|
||||
// gas cost estimate is more than half of input value
|
||||
const showNetworkFeeWarning = Boolean(
|
||||
fiatValueInput &&
|
||||
trade?.gasUseEstimateUSD &&
|
||||
parseFloat(trade.gasUseEstimateUSD.toSignificant(6)) > parseFloat(fiatValueInput.toFixed(6)) / 2
|
||||
)
|
||||
|
||||
if (!showNetworkFeeWarning) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
{showNetworkFeeWarning ? (
|
||||
<RowBetween>
|
||||
<ThemedText.Main fontSize="14px" color="text3">
|
||||
<Trans>Network fees exceed 50% of the swap amount!</Trans>
|
||||
</ThemedText.Main>
|
||||
<MouseoverTooltipContent
|
||||
wrap={false}
|
||||
content={
|
||||
<ResponsiveTooltipContainer origin="top right" style={{ padding: '12px' }}>
|
||||
<ThemedText.Main fontSize="12px" color="text3" maxWidth="200px">
|
||||
<Trans>
|
||||
The cost of sending this transaction is more than half of the value of the input amount.
|
||||
</Trans>
|
||||
</ThemedText.Main>
|
||||
<ThemedText.Main fontSize="12px" color="text3" maxWidth="200px" mt="8px">
|
||||
<Trans>You might consider waiting until the network fees go down to complete this transaction.</Trans>
|
||||
</ThemedText.Main>
|
||||
</ResponsiveTooltipContainer>
|
||||
}
|
||||
placement="bottom"
|
||||
>
|
||||
<StyledInfoIcon size={16} />
|
||||
</MouseoverTooltipContent>
|
||||
</RowBetween>
|
||||
) : null}
|
||||
</Wrapper>
|
||||
)
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import useUSDCPrice from 'hooks/useUSDCPrice'
|
||||
import { useCallback, useContext } from 'react'
|
||||
import { Text } from 'rebass'
|
||||
import styled, { ThemeContext } from 'styled-components/macro'
|
||||
import { TYPE } from 'theme'
|
||||
import { ThemedText } from 'theme'
|
||||
|
||||
interface TradePriceProps {
|
||||
price: Price<Currency, Currency>
|
||||
@@ -13,16 +13,20 @@ interface TradePriceProps {
|
||||
}
|
||||
|
||||
const StyledPriceContainer = styled.button`
|
||||
align-items: center;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
display: grid;
|
||||
height: 24px;
|
||||
justify-content: center;
|
||||
align-items: center
|
||||
justify-content: flex-start;
|
||||
padding: 0;
|
||||
grid-template-columns: 1fr auto;
|
||||
grid-gap: 0.25rem;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
text-align: left;
|
||||
flex-wrap: wrap;
|
||||
padding: 8px 0;
|
||||
user-select: text;
|
||||
`
|
||||
|
||||
export default function TradePrice({ price, showInverted, setShowInverted }: TradePriceProps) {
|
||||
@@ -44,14 +48,20 @@ export default function TradePrice({ price, showInverted, setShowInverted }: Tra
|
||||
const text = `${'1 ' + labelInverted + ' = ' + formattedPrice ?? '-'} ${label}`
|
||||
|
||||
return (
|
||||
<StyledPriceContainer onClick={flipPrice} title={text}>
|
||||
<Text fontWeight={500} fontSize={14} color={theme.text1}>
|
||||
<StyledPriceContainer
|
||||
onClick={(e) => {
|
||||
e.stopPropagation() // dont want this click to affect dropdowns / hovers
|
||||
flipPrice()
|
||||
}}
|
||||
title={text}
|
||||
>
|
||||
<Text fontWeight={500} color={theme.text1}>
|
||||
{text}
|
||||
</Text>{' '}
|
||||
{usdcPrice && (
|
||||
<TYPE.darkGray>
|
||||
<ThemedText.DarkGray>
|
||||
<Trans>(${usdcPrice.toSignificant(6, { groupSeparator: ',' })})</Trans>
|
||||
</TYPE.darkGray>
|
||||
</ThemedText.DarkGray>
|
||||
)}
|
||||
</StyledPriceContainer>
|
||||
)
|
||||
|
||||
@@ -9,7 +9,7 @@ import { AutoRow, RowBetween } from 'components/Row'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import { useState } from 'react'
|
||||
import styled from 'styled-components/macro'
|
||||
import { CloseIcon, ExternalLink, TYPE, Z_INDEX } from 'theme'
|
||||
import { CloseIcon, ExternalLink, ThemedText, Z_INDEX } from 'theme'
|
||||
|
||||
import { useUnsupportedTokens } from '../../hooks/Tokens'
|
||||
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
|
||||
@@ -37,7 +37,7 @@ const StyledButtonEmpty = styled(ButtonEmpty)`
|
||||
text-decoration: none;
|
||||
`
|
||||
|
||||
const AddressText = styled(TYPE.blue)`
|
||||
const AddressText = styled(ThemedText.Blue)`
|
||||
font-size: 12px;
|
||||
|
||||
${({ theme }) => theme.mediaWidth.upToSmall`
|
||||
@@ -70,9 +70,9 @@ export default function UnsupportedCurrencyFooter({
|
||||
<Card padding="2rem">
|
||||
<AutoColumn gap="lg">
|
||||
<RowBetween>
|
||||
<TYPE.mediumHeader>
|
||||
<ThemedText.MediumHeader>
|
||||
<Trans>Unsupported Assets</Trans>
|
||||
</TYPE.mediumHeader>
|
||||
</ThemedText.MediumHeader>
|
||||
<CloseIcon onClick={() => setShowDetails(false)} />
|
||||
</RowBetween>
|
||||
{tokens.map((token) => {
|
||||
@@ -84,7 +84,7 @@ export default function UnsupportedCurrencyFooter({
|
||||
<AutoColumn gap="10px">
|
||||
<AutoRow gap="5px" align="center">
|
||||
<CurrencyLogo currency={token} size={'24px'} />
|
||||
<TYPE.body fontWeight={500}>{token.symbol}</TYPE.body>
|
||||
<ThemedText.Body fontWeight={500}>{token.symbol}</ThemedText.Body>
|
||||
</AutoRow>
|
||||
{chainId && (
|
||||
<ExternalLink href={getExplorerLink(chainId, token.address, ExplorerDataType.ADDRESS)}>
|
||||
@@ -97,20 +97,20 @@ export default function UnsupportedCurrencyFooter({
|
||||
)
|
||||
})}
|
||||
<AutoColumn gap="lg">
|
||||
<TYPE.body fontWeight={500}>
|
||||
<ThemedText.Body fontWeight={500}>
|
||||
<Trans>
|
||||
Some assets are not available through this interface because they may not work well with the smart
|
||||
contracts or we are unable to allow trading for legal reasons.
|
||||
</Trans>
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
</AutoColumn>
|
||||
</AutoColumn>
|
||||
</Card>
|
||||
</Modal>
|
||||
<StyledButtonEmpty padding={'0'} onClick={() => setShowDetails(true)}>
|
||||
<TYPE.blue>
|
||||
<ThemedText.Blue>
|
||||
<Trans>Read more about unsupported assets</Trans>
|
||||
</TYPE.blue>
|
||||
</ThemedText.Blue>
|
||||
</StyledButtonEmpty>
|
||||
</DetailsFooter>
|
||||
)
|
||||
|
||||
@@ -5,8 +5,8 @@ import { ReactNode } from 'react'
|
||||
import { AlertTriangle } from 'react-feather'
|
||||
import { Text } from 'rebass'
|
||||
import styled, { css } from 'styled-components/macro'
|
||||
import { TYPE } from 'theme'
|
||||
|
||||
import { ThemedText } from '../../theme'
|
||||
import { AutoColumn } from '../Column'
|
||||
import TradePrice from './TradePrice'
|
||||
|
||||
@@ -133,7 +133,7 @@ export const SwapShowAcceptChanges = styled(AutoColumn)`
|
||||
margin-top: 8px;
|
||||
`
|
||||
|
||||
export const TransactionDetailsLabel = styled(TYPE.black)`
|
||||
export const TransactionDetailsLabel = styled(ThemedText.Black)`
|
||||
border-bottom: 1px solid ${({ theme }) => theme.bg2};
|
||||
padding-bottom: 0.5rem;
|
||||
`
|
||||
|
||||
@@ -10,7 +10,7 @@ import useENS from '../../hooks/useENS'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { useDelegateCallback } from '../../state/governance/hooks'
|
||||
import { useTokenBalance } from '../../state/wallet/hooks'
|
||||
import { TYPE } from '../../theme'
|
||||
import { ThemedText } from '../../theme'
|
||||
import AddressInputPanel from '../AddressInputPanel'
|
||||
import { ButtonPrimary } from '../Button'
|
||||
import { AutoColumn } from '../Column'
|
||||
@@ -95,23 +95,25 @@ export default function DelegateModal({ isOpen, onDismiss, title }: VoteModalPro
|
||||
<ContentWrapper gap="lg">
|
||||
<AutoColumn gap="lg" justify="center">
|
||||
<RowBetween>
|
||||
<TYPE.mediumHeader fontWeight={500}>{title}</TYPE.mediumHeader>
|
||||
<ThemedText.MediumHeader fontWeight={500}>{title}</ThemedText.MediumHeader>
|
||||
<StyledClosed stroke="black" onClick={wrappedOndismiss} />
|
||||
</RowBetween>
|
||||
<TYPE.body>
|
||||
<ThemedText.Body>
|
||||
<Trans>Earned UNI tokens represent voting shares in Uniswap governance.</Trans>
|
||||
</TYPE.body>
|
||||
<TYPE.body>
|
||||
</ThemedText.Body>
|
||||
<ThemedText.Body>
|
||||
<Trans>You can either vote on each proposal yourself or delegate your votes to a third party.</Trans>
|
||||
</TYPE.body>
|
||||
</ThemedText.Body>
|
||||
{usingDelegate && <AddressInputPanel value={typed} onChange={handleRecipientType} />}
|
||||
<ButtonPrimary disabled={!isAddress(parsedAddress ?? '')} onClick={onDelegate}>
|
||||
<TYPE.mediumHeader color="white">
|
||||
<ThemedText.MediumHeader color="white">
|
||||
{usingDelegate ? <Trans>Delegate Votes</Trans> : <Trans>Self Delegate</Trans>}
|
||||
</TYPE.mediumHeader>
|
||||
</ThemedText.MediumHeader>
|
||||
</ButtonPrimary>
|
||||
<TextButton onClick={() => setUsingDelegate(!usingDelegate)}>
|
||||
<TYPE.blue>{usingDelegate ? <Trans>Remove Delegate</Trans> : <Trans>Add Delegate +</Trans>}</TYPE.blue>
|
||||
<ThemedText.Blue>
|
||||
{usingDelegate ? <Trans>Remove Delegate</Trans> : <Trans>Add Delegate +</Trans>}
|
||||
</ThemedText.Blue>
|
||||
</TextButton>
|
||||
</AutoColumn>
|
||||
</ContentWrapper>
|
||||
@@ -119,20 +121,20 @@ export default function DelegateModal({ isOpen, onDismiss, title }: VoteModalPro
|
||||
{attempting && !hash && (
|
||||
<LoadingView onDismiss={wrappedOndismiss}>
|
||||
<AutoColumn gap="12px" justify={'center'}>
|
||||
<TYPE.largeHeader>
|
||||
<ThemedText.LargeHeader>
|
||||
{usingDelegate ? <Trans>Delegating votes</Trans> : <Trans>Unlocking Votes</Trans>}
|
||||
</TYPE.largeHeader>
|
||||
<TYPE.main fontSize={36}> {formatCurrencyAmount(uniBalance, 4)}</TYPE.main>
|
||||
</ThemedText.LargeHeader>
|
||||
<ThemedText.Main fontSize={36}> {formatCurrencyAmount(uniBalance, 4)}</ThemedText.Main>
|
||||
</AutoColumn>
|
||||
</LoadingView>
|
||||
)}
|
||||
{hash && (
|
||||
<SubmittedView onDismiss={wrappedOndismiss} hash={hash}>
|
||||
<AutoColumn gap="12px" justify={'center'}>
|
||||
<TYPE.largeHeader>
|
||||
<ThemedText.LargeHeader>
|
||||
<Trans>Transaction Submitted</Trans>
|
||||
</TYPE.largeHeader>
|
||||
<TYPE.main fontSize={36}>{formatCurrencyAmount(uniBalance, 4)}</TYPE.main>
|
||||
</ThemedText.LargeHeader>
|
||||
<ThemedText.Main fontSize={36}>{formatCurrencyAmount(uniBalance, 4)}</ThemedText.Main>
|
||||
</AutoColumn>
|
||||
</SubmittedView>
|
||||
)}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Trans } from '@lingui/macro'
|
||||
import { L2_CHAIN_IDS } from 'constants/chains'
|
||||
import { useActiveWeb3React } from 'hooks/web3'
|
||||
import styled from 'styled-components/macro'
|
||||
import { TYPE } from 'theme'
|
||||
import { ThemedText } from 'theme'
|
||||
|
||||
const EmptyProposals = styled.div`
|
||||
border: 1px solid ${({ theme }) => theme.text4};
|
||||
@@ -25,14 +25,14 @@ interface EmptyStateProps {
|
||||
}
|
||||
const EmptyState = ({ HeaderContent, SubHeaderContent }: EmptyStateProps) => (
|
||||
<EmptyProposals>
|
||||
<TYPE.body style={{ marginBottom: '8px' }}>
|
||||
<ThemedText.Body style={{ marginBottom: '8px' }}>
|
||||
<HeaderContent />
|
||||
</TYPE.body>
|
||||
<TYPE.subHeader>
|
||||
</ThemedText.Body>
|
||||
<ThemedText.SubHeader>
|
||||
<Sub>
|
||||
<SubHeaderContent />
|
||||
</Sub>
|
||||
</TYPE.subHeader>
|
||||
</ThemedText.SubHeader>
|
||||
</EmptyProposals>
|
||||
)
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ import Circle from '../../assets/images/blue-loader.svg'
|
||||
import { useActiveWeb3React } from '../../hooks/web3'
|
||||
import { useUserVotes, useVoteCallback } from '../../state/governance/hooks'
|
||||
import { VoteOption } from '../../state/governance/types'
|
||||
import { CustomLightSpinner, TYPE } from '../../theme'
|
||||
import { ExternalLink } from '../../theme/components'
|
||||
import { CustomLightSpinner, ThemedText } from '../../theme'
|
||||
import { ExternalLink } from '../../theme'
|
||||
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
|
||||
import { ButtonPrimary } from '../Button'
|
||||
import { AutoColumn, ColumnCenter } from '../Column'
|
||||
@@ -85,7 +85,7 @@ export default function VoteModal({ isOpen, onDismiss, proposalId, voteOption }:
|
||||
<ContentWrapper gap="lg">
|
||||
<AutoColumn gap="lg" justify="center">
|
||||
<RowBetween>
|
||||
<TYPE.mediumHeader fontWeight={500}>
|
||||
<ThemedText.MediumHeader fontWeight={500}>
|
||||
{voteOption === VoteOption.Against ? (
|
||||
<Trans>Vote against proposal {proposalId}</Trans>
|
||||
) : voteOption === VoteOption.For ? (
|
||||
@@ -93,14 +93,14 @@ export default function VoteModal({ isOpen, onDismiss, proposalId, voteOption }:
|
||||
) : (
|
||||
<Trans>Vote to abstain on proposal {proposalId}</Trans>
|
||||
)}
|
||||
</TYPE.mediumHeader>
|
||||
</ThemedText.MediumHeader>
|
||||
<StyledClosed stroke="black" onClick={wrappedOndismiss} />
|
||||
</RowBetween>
|
||||
<TYPE.largeHeader>
|
||||
<ThemedText.LargeHeader>
|
||||
<Trans>{formatCurrencyAmount(availableVotes, 4)} Votes</Trans>
|
||||
</TYPE.largeHeader>
|
||||
</ThemedText.LargeHeader>
|
||||
<ButtonPrimary onClick={onVote}>
|
||||
<TYPE.mediumHeader color="white">
|
||||
<ThemedText.MediumHeader color="white">
|
||||
{voteOption === VoteOption.Against ? (
|
||||
<Trans>Vote against proposal {proposalId}</Trans>
|
||||
) : voteOption === VoteOption.For ? (
|
||||
@@ -108,7 +108,7 @@ export default function VoteModal({ isOpen, onDismiss, proposalId, voteOption }:
|
||||
) : (
|
||||
<Trans>Vote to abstain on proposal {proposalId}</Trans>
|
||||
)}
|
||||
</TYPE.mediumHeader>
|
||||
</ThemedText.MediumHeader>
|
||||
</ButtonPrimary>
|
||||
</AutoColumn>
|
||||
</ContentWrapper>
|
||||
@@ -124,13 +124,13 @@ export default function VoteModal({ isOpen, onDismiss, proposalId, voteOption }:
|
||||
</ConfirmedIcon>
|
||||
<AutoColumn gap="100px" justify={'center'}>
|
||||
<AutoColumn gap="12px" justify={'center'}>
|
||||
<TYPE.largeHeader>
|
||||
<ThemedText.LargeHeader>
|
||||
<Trans>Submitting Vote</Trans>
|
||||
</TYPE.largeHeader>
|
||||
</ThemedText.LargeHeader>
|
||||
</AutoColumn>
|
||||
<TYPE.subHeader>
|
||||
<ThemedText.SubHeader>
|
||||
<Trans>Confirm this transaction in your wallet</Trans>
|
||||
</TYPE.subHeader>
|
||||
</ThemedText.SubHeader>
|
||||
</AutoColumn>
|
||||
</ConfirmOrLoadingWrapper>
|
||||
)}
|
||||
@@ -145,18 +145,18 @@ export default function VoteModal({ isOpen, onDismiss, proposalId, voteOption }:
|
||||
</ConfirmedIcon>
|
||||
<AutoColumn gap="100px" justify={'center'}>
|
||||
<AutoColumn gap="12px" justify={'center'}>
|
||||
<TYPE.largeHeader>
|
||||
<ThemedText.LargeHeader>
|
||||
<Trans>Transaction Submitted</Trans>
|
||||
</TYPE.largeHeader>
|
||||
</ThemedText.LargeHeader>
|
||||
</AutoColumn>
|
||||
{chainId && (
|
||||
<ExternalLink
|
||||
href={getExplorerLink(chainId, hash, ExplorerDataType.TRANSACTION)}
|
||||
style={{ marginLeft: '4px' }}
|
||||
>
|
||||
<TYPE.subHeader>
|
||||
<ThemedText.SubHeader>
|
||||
<Trans>View transaction on Explorer</Trans>
|
||||
</TYPE.subHeader>
|
||||
</ThemedText.SubHeader>
|
||||
</ExternalLink>
|
||||
)}
|
||||
</AutoColumn>
|
||||
|
||||
@@ -5,10 +5,10 @@ export const OVERLAY_READY = 'OVERLAY_READY'
|
||||
type FormaticSupportedChains = 1 | 3 | 4 | 42
|
||||
|
||||
const CHAIN_ID_NETWORK_ARGUMENT: { readonly [chainId in FormaticSupportedChains]: string | undefined } = {
|
||||
[1]: undefined,
|
||||
[3]: 'ropsten',
|
||||
[4]: 'rinkeby',
|
||||
[42]: 'kovan',
|
||||
1: undefined,
|
||||
3: 'ropsten',
|
||||
4: 'rinkeby',
|
||||
42: 'kovan',
|
||||
}
|
||||
|
||||
export class FortmaticConnector extends FortmaticConnectorCore {
|
||||
|
||||
@@ -19,7 +19,7 @@ if (typeof INFURA_KEY === 'undefined') {
|
||||
throw new Error(`REACT_APP_INFURA_KEY must be a defined environment variable`)
|
||||
}
|
||||
|
||||
const NETWORK_URLS: { [key in SupportedChainId]: string } = {
|
||||
export const NETWORK_URLS: { [key in SupportedChainId]: string } = {
|
||||
[SupportedChainId.MAINNET]: `https://mainnet.infura.io/v3/${INFURA_KEY}`,
|
||||
[SupportedChainId.RINKEBY]: `https://rinkeby.infura.io/v3/${INFURA_KEY}`,
|
||||
[SupportedChainId.ROPSTEN]: `https://ropsten.infura.io/v3/${INFURA_KEY}`,
|
||||
|
||||
@@ -8,13 +8,28 @@ type AddressMap = { [chainId: number]: string }
|
||||
|
||||
export const UNI_ADDRESS: AddressMap = constructSameAddressMap('0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984')
|
||||
export const MULTICALL_ADDRESS: AddressMap = {
|
||||
...constructSameAddressMap('0x1F98415757620B543A52E61c46B32eB19261F984', [SupportedChainId.OPTIMISTIC_KOVAN]),
|
||||
[SupportedChainId.OPTIMISM]: '0x90f872b3d8f33f305e0250db6A2761B354f7710A',
|
||||
...constructSameAddressMap('0x1F98415757620B543A52E61c46B32eB19261F984', [
|
||||
SupportedChainId.OPTIMISTIC_KOVAN,
|
||||
SupportedChainId.OPTIMISM,
|
||||
]),
|
||||
[SupportedChainId.ARBITRUM_ONE]: '0xadF885960B47eA2CD9B55E6DAc6B42b7Cb2806dB',
|
||||
[SupportedChainId.ARBITRUM_RINKEBY]: '0xa501c031958F579dB7676fF1CE78AD305794d579',
|
||||
}
|
||||
export const V2_FACTORY_ADDRESSES: AddressMap = constructSameAddressMap(V2_FACTORY_ADDRESS)
|
||||
|
||||
export const V2_ROUTER_ADDRESS: AddressMap = constructSameAddressMap('0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D')
|
||||
export const V3_ROUTER_ADDRESS: AddressMap = constructSameAddressMap('0xE592427A0AEce92De3Edee1F18E0157C05861564', [
|
||||
SupportedChainId.OPTIMISM,
|
||||
SupportedChainId.OPTIMISTIC_KOVAN,
|
||||
SupportedChainId.ARBITRUM_ONE,
|
||||
SupportedChainId.ARBITRUM_RINKEBY,
|
||||
])
|
||||
export const SWAP_ROUTER_ADDRESSES: AddressMap = constructSameAddressMap('0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45', [
|
||||
SupportedChainId.OPTIMISM,
|
||||
SupportedChainId.OPTIMISTIC_KOVAN,
|
||||
SupportedChainId.ARBITRUM_ONE,
|
||||
SupportedChainId.ARBITRUM_RINKEBY,
|
||||
])
|
||||
|
||||
/**
|
||||
* The oldest V0 governance address
|
||||
@@ -73,12 +88,7 @@ export const ENS_REGISTRAR_ADDRESSES: AddressMap = {
|
||||
export const SOCKS_CONTROLLER_ADDRESSES: AddressMap = {
|
||||
[SupportedChainId.MAINNET]: '0x65770b5283117639760beA3F867b69b3697a91dd',
|
||||
}
|
||||
export const SWAP_ROUTER_ADDRESSES: AddressMap = constructSameAddressMap('0xE592427A0AEce92De3Edee1F18E0157C05861564', [
|
||||
SupportedChainId.OPTIMISM,
|
||||
SupportedChainId.OPTIMISTIC_KOVAN,
|
||||
SupportedChainId.ARBITRUM_ONE,
|
||||
SupportedChainId.ARBITRUM_RINKEBY,
|
||||
])
|
||||
|
||||
export const V3_MIGRATOR_ADDRESSES: AddressMap = constructSameAddressMap('0xA5644E29708357803b5A882D272c41cC0dF92B34', [
|
||||
SupportedChainId.ARBITRUM_ONE,
|
||||
SupportedChainId.ARBITRUM_RINKEBY,
|
||||
|
||||
@@ -3,6 +3,8 @@ import arbitrumLogoUrl from 'assets/svg/arbitrum_logo.svg'
|
||||
import optimismLogoUrl from 'assets/svg/optimistic_ethereum.svg'
|
||||
import ms from 'ms.macro'
|
||||
|
||||
import { ARBITRUM_LIST, OPTIMISM_LIST } from './lists'
|
||||
|
||||
export enum SupportedChainId {
|
||||
MAINNET = 1,
|
||||
ROPSTEN = 3,
|
||||
@@ -66,6 +68,7 @@ export interface L2ChainInfo extends L1ChainInfo {
|
||||
readonly bridge: string
|
||||
readonly logoUrl: string
|
||||
readonly statusPage?: string
|
||||
readonly defaultListUrl: string
|
||||
}
|
||||
|
||||
export type ChainInfo = { readonly [chainId: number]: L1ChainInfo | L2ChainInfo } & {
|
||||
@@ -77,9 +80,10 @@ export const CHAIN_INFO: ChainInfo = {
|
||||
[SupportedChainId.ARBITRUM_ONE]: {
|
||||
blockWaitMsBeforeWarning: ms`10m`,
|
||||
bridge: 'https://bridge.arbitrum.io/',
|
||||
defaultListUrl: ARBITRUM_LIST,
|
||||
docs: 'https://offchainlabs.com/',
|
||||
explorer: 'https://arbiscan.io/',
|
||||
infoLink: 'https://info.uniswap.org/#/arbitrum',
|
||||
infoLink: 'https://info.uniswap.org/#/arbitrum/',
|
||||
label: 'Arbitrum',
|
||||
logoUrl: arbitrumLogoUrl,
|
||||
nativeCurrency: { name: 'ETH', symbol: 'ETH', decimals: 18 },
|
||||
@@ -88,6 +92,7 @@ export const CHAIN_INFO: ChainInfo = {
|
||||
[SupportedChainId.ARBITRUM_RINKEBY]: {
|
||||
blockWaitMsBeforeWarning: ms`10m`,
|
||||
bridge: 'https://bridge.arbitrum.io/',
|
||||
defaultListUrl: ARBITRUM_LIST,
|
||||
docs: 'https://offchainlabs.com/',
|
||||
explorer: 'https://rinkeby-explorer.arbitrum.io/',
|
||||
infoLink: 'https://info.uniswap.org/#/arbitrum/',
|
||||
@@ -133,28 +138,28 @@ export const CHAIN_INFO: ChainInfo = {
|
||||
nativeCurrency: { name: 'Görli ETH', symbol: 'görETH', decimals: 18 },
|
||||
},
|
||||
[SupportedChainId.OPTIMISM]: {
|
||||
blockWaitMsBeforeWarning: ms`10m`,
|
||||
blockWaitMsBeforeWarning: ms`15m`,
|
||||
bridge: 'https://gateway.optimism.io/',
|
||||
defaultListUrl: OPTIMISM_LIST,
|
||||
docs: 'https://optimism.io/',
|
||||
explorer: 'https://optimistic.etherscan.io/',
|
||||
infoLink: 'https://info.uniswap.org/#/optimism',
|
||||
infoLink: 'https://info.uniswap.org/#/optimism/',
|
||||
label: 'OΞ',
|
||||
logoUrl: optimismLogoUrl,
|
||||
nativeCurrency: { name: 'Optimistic ETH', symbol: 'ETH', decimals: 18 },
|
||||
rpcUrls: ['https://mainnet.optimism.io'],
|
||||
statusPage: 'https://optimism.io/status',
|
||||
},
|
||||
[SupportedChainId.OPTIMISTIC_KOVAN]: {
|
||||
blockWaitMsBeforeWarning: ms`10m`,
|
||||
blockWaitMsBeforeWarning: ms`15m`,
|
||||
bridge: 'https://gateway.optimism.io/',
|
||||
defaultListUrl: OPTIMISM_LIST,
|
||||
docs: 'https://optimism.io/',
|
||||
explorer: 'https://optimistic.etherscan.io/',
|
||||
infoLink: 'https://info.uniswap.org/#/optimism',
|
||||
infoLink: 'https://info.uniswap.org/#/optimism/',
|
||||
label: 'Optimistic Kovan',
|
||||
rpcUrls: ['https://kovan.optimism.io'],
|
||||
logoUrl: optimismLogoUrl,
|
||||
nativeCurrency: { name: 'Optimistic kovETH', symbol: 'kovOpETH', decimals: 18 },
|
||||
statusPage: 'https://optimism.io/status',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -19,5 +19,5 @@ export const DEFAULT_AVERAGE_BLOCK_TIME_IN_SECS = 13
|
||||
|
||||
// Block time here is slightly higher (~1s) than average in order to avoid ongoing proposals past the displayed time
|
||||
export const AVERAGE_BLOCK_TIME_IN_SECS: { [chainId: number]: number } = {
|
||||
[1]: DEFAULT_AVERAGE_BLOCK_TIME_IN_SECS,
|
||||
1: DEFAULT_AVERAGE_BLOCK_TIME_IN_SECS,
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
const UNI_LIST = 'https://tokens.uniswap.org'
|
||||
const AAVE_LIST = 'tokenlist.aave.eth'
|
||||
const BA_LIST = 'https://raw.githubusercontent.com/The-Blockchain-Association/sec-notice-list/master/ba-sec-list.json'
|
||||
const CMC_ALL_LIST = 'https://api.coinmarketcap.com/data-api/v3/uniswap/all.json'
|
||||
@@ -16,6 +17,7 @@ export const UNSUPPORTED_LIST_URLS: string[] = [BA_LIST]
|
||||
// this is the default list of lists that are exposed to users
|
||||
// lower index == higher priority for token import
|
||||
const DEFAULT_LIST_OF_LISTS_TO_DISPLAY: string[] = [
|
||||
UNI_LIST,
|
||||
COMPOUND_LIST,
|
||||
AAVE_LIST,
|
||||
CMC_ALL_LIST,
|
||||
@@ -35,4 +37,4 @@ export const DEFAULT_LIST_OF_LISTS: string[] = [
|
||||
]
|
||||
|
||||
// default lists to be 'active' aka searched across
|
||||
export const DEFAULT_ACTIVE_LIST_URLS: string[] = [GEMINI_LIST]
|
||||
export const DEFAULT_ACTIVE_LIST_URLS: string[] = [UNI_LIST, GEMINI_LIST]
|
||||
|
||||
@@ -49,7 +49,7 @@ export const LOCALE_LABEL: { [locale in SupportedLocale]: string } = {
|
||||
'el-GR': 'ελληνικά',
|
||||
'en-US': 'English',
|
||||
'es-ES': 'Español',
|
||||
'fi-FI': 'Suomalainen',
|
||||
'fi-FI': 'suomi',
|
||||
'fr-FR': 'français',
|
||||
'he-IL': 'עִברִית',
|
||||
'hu-HU': 'Magyar',
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export const UNISWAP_GRANTS_START_BLOCK = 11473815
|
||||
export const BRAVO_START_BLOCK = 13059344
|
||||
export const ONE_BIP_START_BLOCK = 13551293
|
||||
export const POLYGON_START_BLOCK = 13786993
|
||||
|
||||
1
src/constants/proposals/polygon_proposal_title.ts
Normal file
1
src/constants/proposals/polygon_proposal_title.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const POLYGON_PROPOSAL_TITLE = 'Should Uniswap v3 be deployed to Polygon?'
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user