Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ffa601ab6 | ||
|
|
b887d0f607 | ||
|
|
6160c446ea | ||
|
|
f556f745fb | ||
|
|
7f597c0fab | ||
|
|
cfaf5d79c1 | ||
|
|
e9fbf61375 | ||
|
|
749c9b40ea | ||
|
|
b553a6fcd8 | ||
|
|
ad1e2c60a1 | ||
|
|
7001452f89 | ||
|
|
5fee3c6fdd | ||
|
|
40b1e40721 | ||
|
|
aee4df10a8 | ||
|
|
82a194987a | ||
|
|
1882b14690 | ||
|
|
d56030a920 | ||
|
|
b75438bc8b | ||
|
|
9f44e48cf1 | ||
|
|
48855f487f | ||
|
|
f09ded1a3f | ||
|
|
e16348e2e0 | ||
|
|
45c3e1dc78 | ||
|
|
24ddace1eb | ||
|
|
b38ce038e6 | ||
|
|
04bf075826 | ||
|
|
27ec2e018c | ||
|
|
3ffe7693cf | ||
|
|
2c7381ff47 | ||
|
|
6e4746a7fe | ||
|
|
48379c66ce | ||
|
|
1b7f0d11fd | ||
|
|
db1d264ad3 | ||
|
|
fd24cb890a | ||
|
|
932c4482d2 | ||
|
|
2d8dac5c15 | ||
|
|
0e3d188a9a | ||
|
|
1be62f0bec | ||
|
|
e6519a7dd1 | ||
|
|
3ced65b8a4 | ||
|
|
bab8506919 | ||
|
|
4a79280edc | ||
|
|
53f0ca9b7e | ||
|
|
0381200fec | ||
|
|
040ebb5475 | ||
|
|
0752314d87 | ||
|
|
9db5fd104a | ||
|
|
b9db195017 | ||
|
|
b6bdbcf587 | ||
|
|
cc325b2fbe | ||
|
|
2694379c97 | ||
|
|
82aaf0784a | ||
|
|
55a509cad8 | ||
|
|
463dd6fdfb | ||
|
|
3ad4fb6846 | ||
|
|
1c76277c46 | ||
|
|
f90f81b3d9 | ||
|
|
81accd1864 | ||
|
|
524ce49fcb | ||
|
|
cbec108172 |
1
.github/workflows/test.yml
vendored
@@ -11,6 +11,7 @@ on:
|
||||
- main
|
||||
- releases/staging
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
|
||||
@@ -9,6 +9,7 @@ ignore:
|
||||
- "**/styled.tsx"
|
||||
- "**/constants/**/*"
|
||||
- "constants/**/*"
|
||||
- "src/dev/*"
|
||||
|
||||
coverage:
|
||||
status:
|
||||
|
||||
@@ -39,4 +39,30 @@ describe('Landing Page', () => {
|
||||
cy.get(getTestSelector('pool-nav-link')).last().click()
|
||||
cy.url().should('include', '/pools')
|
||||
})
|
||||
|
||||
it('does not render uk compliance banner in US', () => {
|
||||
cy.visit('/swap')
|
||||
cy.contains('UK disclaimer').should('not.exist')
|
||||
})
|
||||
|
||||
it('renders uk compliance banner in uk', () => {
|
||||
cy.intercept('https://api.uniswap.org/v1/amplitude-proxy', (req) => {
|
||||
const requestBody = JSON.stringify(req.body)
|
||||
const byteSize = new Blob([requestBody]).size
|
||||
req.alias = 'amplitude'
|
||||
req.reply(
|
||||
JSON.stringify({
|
||||
code: 200,
|
||||
server_upload_time: Date.now(),
|
||||
payload_size_bytes: byteSize,
|
||||
events_ingested: req.body.events.length,
|
||||
}),
|
||||
{
|
||||
'origin-country': 'GB',
|
||||
}
|
||||
)
|
||||
})
|
||||
cy.visit('/swap')
|
||||
cy.contains('UK disclaimer')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -53,7 +53,7 @@ describe('Mini Portfolio account drawer', () => {
|
||||
|
||||
// Verify that wallet state loads correctly
|
||||
cy.get(getTestSelector('mini-portfolio-navbar')).contains('Tokens')
|
||||
cy.get(getTestSelector('mini-portfolio-page')).contains('Hidden (201)')
|
||||
cy.get(getTestSelector('mini-portfolio-page')).contains('Hidden (197)')
|
||||
|
||||
cy.intercept(/graphql/, { fixture: 'mini-portfolio/nfts.json' })
|
||||
cy.get(getTestSelector('mini-portfolio-navbar')).contains('NFTs').click()
|
||||
|
||||
149
cypress/e2e/swap/fees.test.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
import { CurrencyAmount } from '@uniswap/sdk-core'
|
||||
import { FeatureFlag } from 'featureFlags'
|
||||
|
||||
import { USDC_MAINNET } from '../../../src/constants/tokens'
|
||||
import { getBalance, getTestSelector } from '../../utils'
|
||||
|
||||
describe('Swap with fees', () => {
|
||||
describe('Classic swaps', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/swap', { featureFlags: [{ name: FeatureFlag.feesEnabled, value: true }] })
|
||||
|
||||
// Store trade quote into alias
|
||||
cy.intercept({ url: 'https://api.uniswap.org/v2/quote' }, (req) => {
|
||||
// Avoid tracking stablecoin pricing fetches
|
||||
if (JSON.parse(req.body).intent !== 'pricing') req.alias = 'quoteFetch'
|
||||
})
|
||||
})
|
||||
|
||||
it('displays $0 fee on swaps without fees', () => {
|
||||
// Set up a stablecoin <> stablecoin swap (no fees)
|
||||
cy.get('#swap-currency-input .open-currency-select-button').click()
|
||||
cy.contains('DAI').click()
|
||||
cy.get('#swap-currency-output .open-currency-select-button').click()
|
||||
cy.contains('USDC').click()
|
||||
cy.get('#swap-currency-output .token-amount-input').type('1')
|
||||
|
||||
// Verify 0 fee UI is displayed
|
||||
cy.get(getTestSelector('swap-details-header-row')).click()
|
||||
cy.contains('Fee')
|
||||
cy.contains('$0')
|
||||
})
|
||||
|
||||
it('swaps ETH for USDC exact-out with swap fee', () => {
|
||||
cy.hardhat().then((hardhat) => {
|
||||
getBalance(USDC_MAINNET).then((initialBalance) => {
|
||||
// Set up swap
|
||||
cy.get('#swap-currency-output .open-currency-select-button').click()
|
||||
cy.contains('USDC').click()
|
||||
cy.get('#swap-currency-output .token-amount-input').type('1')
|
||||
|
||||
cy.wait('@quoteFetch')
|
||||
.its('response.body')
|
||||
.then(({ quote: { portionBips, portionRecipient, portionAmount } }) => {
|
||||
// Fees are generally expected to always be enabled for ETH -> USDC swaps
|
||||
// If the routing api does not include a fee, end the test early rather than manually update routes and hardcode fee vars
|
||||
if (portionRecipient) return
|
||||
|
||||
cy.then(() => hardhat.getBalance(portionRecipient, USDC_MAINNET)).then((initialRecipientBalance) => {
|
||||
const feeCurrencyAmount = CurrencyAmount.fromRawAmount(USDC_MAINNET, portionAmount)
|
||||
|
||||
// Initiate transaction
|
||||
cy.get('#swap-button').click()
|
||||
cy.contains('Review swap')
|
||||
|
||||
// Verify fee percentage and amount is displayed
|
||||
cy.contains(`Fee (${portionBips / 100}%)`)
|
||||
|
||||
// Confirm transaction
|
||||
cy.contains('Confirm swap').click()
|
||||
|
||||
// Verify transaction
|
||||
cy.get(getTestSelector('web3-status-connected')).should('not.contain', 'Pending')
|
||||
cy.get(getTestSelector('popups')).contains('Swapped')
|
||||
|
||||
// Verify the post-fee output is the expected exact-out amount
|
||||
const finalBalance = initialBalance + 1
|
||||
cy.get('#swap-currency-output').contains(`Balance: ${finalBalance}`)
|
||||
getBalance(USDC_MAINNET).should('eq', finalBalance)
|
||||
|
||||
// Verify fee recipient received fee
|
||||
cy.then(() => hardhat.getBalance(portionRecipient, USDC_MAINNET)).then((finalRecipientBalance) => {
|
||||
const expectedFinalRecipientBalance = initialRecipientBalance.add(feeCurrencyAmount)
|
||||
cy.then(() => finalRecipientBalance.equalTo(expectedFinalRecipientBalance)).should('be.true')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('swaps ETH for USDC exact-in with swap fee', () => {
|
||||
cy.hardhat().then((hardhat) => {
|
||||
// Set up swap
|
||||
cy.get('#swap-currency-output .open-currency-select-button').click()
|
||||
cy.contains('USDC').click()
|
||||
cy.get('#swap-currency-input .token-amount-input').type('.01')
|
||||
|
||||
cy.wait('@quoteFetch')
|
||||
.its('response.body')
|
||||
.then(({ quote: { portionBips, portionRecipient } }) => {
|
||||
// Fees are generally expected to always be enabled for ETH -> USDC swaps
|
||||
// If the routing api does not include a fee, end the test early rather than manually update routes and hardcode fee vars
|
||||
if (portionRecipient) return
|
||||
|
||||
cy.then(() => hardhat.getBalance(portionRecipient, USDC_MAINNET)).then((initialRecipientBalance) => {
|
||||
// Initiate transaction
|
||||
cy.get('#swap-button').click()
|
||||
cy.contains('Review swap')
|
||||
|
||||
// Verify fee percentage and amount is displayed
|
||||
cy.contains(`Fee (${portionBips / 100}%)`)
|
||||
|
||||
// Confirm transaction
|
||||
cy.contains('Confirm swap').click()
|
||||
|
||||
// Verify transaction
|
||||
cy.get(getTestSelector('web3-status-connected')).should('not.contain', 'Pending')
|
||||
cy.get(getTestSelector('popups')).contains('Swapped')
|
||||
|
||||
// Verify fee recipient received fee
|
||||
cy.then(() => hardhat.getBalance(portionRecipient, USDC_MAINNET)).then((finalRecipientBalance) => {
|
||||
cy.then(() => finalRecipientBalance.greaterThan(initialRecipientBalance)).should('be.true')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('UniswapX swaps', () => {
|
||||
it('displays UniswapX fee in UI', () => {
|
||||
cy.visit('/swap', {
|
||||
featureFlags: [
|
||||
{ name: FeatureFlag.feesEnabled, value: true },
|
||||
{ name: FeatureFlag.uniswapXDefaultEnabled, value: true },
|
||||
],
|
||||
})
|
||||
|
||||
// Intercept the trade quote
|
||||
cy.intercept({ url: 'https://api.uniswap.org/v2/quote' }, (req) => {
|
||||
// Avoid intercepting stablecoin pricing fetches
|
||||
if (JSON.parse(req.body).intent !== 'pricing') {
|
||||
req.reply({ fixture: 'uniswapx/feeQuote.json' })
|
||||
}
|
||||
})
|
||||
|
||||
// Setup swap
|
||||
cy.get('#swap-currency-input .open-currency-select-button').click()
|
||||
cy.contains('USDC').click()
|
||||
cy.get('#swap-currency-output .open-currency-select-button').click()
|
||||
cy.contains('ETH').click()
|
||||
cy.get('#swap-currency-input .token-amount-input').type('200')
|
||||
|
||||
// Verify fee UI is displayed
|
||||
cy.get(getTestSelector('swap-details-header-row')).click()
|
||||
cy.contains('Fee (0.15%)')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -6,10 +6,9 @@ describe('Swap settings', () => {
|
||||
cy.contains('Settings').should('not.exist')
|
||||
cy.get(getTestSelector('open-settings-dialog-button')).click()
|
||||
cy.get(getTestSelector('mobile-settings-menu')).should('not.exist')
|
||||
cy.contains('Max slippage').should('exist')
|
||||
cy.contains('Max. slippage').should('exist')
|
||||
cy.contains('Transaction deadline').should('exist')
|
||||
cy.contains('UniswapX').should('exist')
|
||||
cy.contains('Local routing').should('exist')
|
||||
cy.get(getTestSelector('open-settings-dialog-button')).click()
|
||||
cy.contains('Settings').should('not.exist')
|
||||
})
|
||||
@@ -26,9 +25,8 @@ describe('Swap settings', () => {
|
||||
cy.get(getTestSelector('mobile-settings-menu'))
|
||||
.should('exist')
|
||||
.within(() => {
|
||||
cy.contains('Max slippage').should('exist')
|
||||
cy.contains('Max. slippage').should('exist')
|
||||
cy.contains('UniswapX').should('exist')
|
||||
cy.contains('Local routing').should('exist')
|
||||
cy.contains('Transaction deadline').should('exist')
|
||||
cy.get(getTestSelector('mobile-settings-close')).click()
|
||||
})
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ChainId, CurrencyAmount } from '@uniswap/sdk-core'
|
||||
import { FeatureFlag } from 'featureFlags'
|
||||
|
||||
import { DAI, nativeOnChain, USDC_MAINNET } from '../../../src/constants/tokens'
|
||||
import { getTestSelector } from '../../utils'
|
||||
@@ -26,7 +27,9 @@ function stubSwapTxReceipt() {
|
||||
describe('UniswapX Toggle', () => {
|
||||
beforeEach(() => {
|
||||
cy.intercept(QuoteEndpoint, { fixture: QuoteWhereUniswapXIsBetter })
|
||||
cy.visit(`/swap/?inputCurrency=${USDC_MAINNET.address}&outputCurrency=${DAI.address}`)
|
||||
cy.visit(`/swap/?inputCurrency=${USDC_MAINNET.address}&outputCurrency=${DAI.address}`, {
|
||||
featureFlags: [{ name: FeatureFlag.uniswapXDefaultEnabled, value: false }],
|
||||
})
|
||||
})
|
||||
|
||||
it('only displays uniswapx ui when setting is on', () => {
|
||||
@@ -76,7 +79,9 @@ describe('UniswapX Orders', () => {
|
||||
stubSwapTxReceipt()
|
||||
|
||||
cy.hardhat().then((hardhat) => hardhat.fund(hardhat.wallet, CurrencyAmount.fromRawAmount(USDC_MAINNET, 3e8)))
|
||||
cy.visit(`/swap/?inputCurrency=${USDC_MAINNET.address}&outputCurrency=${DAI.address}`)
|
||||
cy.visit(`/swap/?inputCurrency=${USDC_MAINNET.address}&outputCurrency=${DAI.address}`, {
|
||||
featureFlags: [{ name: FeatureFlag.uniswapXDefaultEnabled, value: false }],
|
||||
})
|
||||
})
|
||||
|
||||
it('can swap exact-in trades using uniswapX', () => {
|
||||
@@ -164,7 +169,9 @@ describe('UniswapX Eth Input', () => {
|
||||
|
||||
stubSwapTxReceipt()
|
||||
|
||||
cy.visit(`/swap/?inputCurrency=ETH&outputCurrency=${DAI.address}`)
|
||||
cy.visit(`/swap/?inputCurrency=ETH&outputCurrency=${DAI.address}`, {
|
||||
featureFlags: [{ name: FeatureFlag.uniswapXDefaultEnabled, value: false }],
|
||||
})
|
||||
})
|
||||
|
||||
it('can swap using uniswapX with ETH as input', () => {
|
||||
@@ -249,7 +256,9 @@ describe('UniswapX activity history', () => {
|
||||
cy.hardhat().then(async (hardhat) => {
|
||||
await hardhat.fund(hardhat.wallet, CurrencyAmount.fromRawAmount(USDC_MAINNET, 3e8))
|
||||
})
|
||||
cy.visit(`/swap/?inputCurrency=${USDC_MAINNET.address}&outputCurrency=${DAI.address}`)
|
||||
cy.visit(`/swap/?inputCurrency=${USDC_MAINNET.address}&outputCurrency=${DAI.address}`, {
|
||||
featureFlags: [{ name: FeatureFlag.uniswapXDefaultEnabled, value: false }],
|
||||
})
|
||||
})
|
||||
|
||||
it('can view UniswapX order status progress in activity', () => {
|
||||
|
||||
@@ -48,8 +48,8 @@ describe('Token details', () => {
|
||||
})
|
||||
|
||||
it('token with warning and low trading volume should have all information populated', () => {
|
||||
// Shiba predator token, low trading volume and also has warning modal
|
||||
cy.visit('/tokens/ethereum/0xa71d0588EAf47f12B13cF8eC750430d21DF04974')
|
||||
// Null token created for this test, 0 trading volume and has warning modal
|
||||
cy.visit('/tokens/ethereum/0x1eFBB78C8b917f67986BcE54cE575069c0143681')
|
||||
|
||||
// Should have missing price chart when price unavailable (expected for this token)
|
||||
if (cy.get('[data-cy="chart-header"]').contains('Price unavailable')) {
|
||||
@@ -61,22 +61,20 @@ describe('Token details', () => {
|
||||
|
||||
// About section should have description of token
|
||||
cy.get(getTestSelector('token-details-about-section')).should('exist')
|
||||
cy.contains('QOM is the Shiba Predator').should('exist')
|
||||
cy.contains('No token information available').should('exist')
|
||||
|
||||
// Links section should link out to Etherscan, More analytics, Website, Twitter
|
||||
// Links section should link out to Etherscan, More analytics
|
||||
cy.get('[data-cy="resources-container"]').within(() => {
|
||||
cy.contains('Etherscan')
|
||||
.should('have.attr', 'href')
|
||||
.and('include', 'etherscan.io/address/0xa71d0588EAf47f12B13cF8eC750430d21DF04974')
|
||||
.and('include', 'etherscan.io/address/0x1eFBB78C8b917f67986BcE54cE575069c0143681')
|
||||
cy.contains('More analytics')
|
||||
.should('have.attr', 'href')
|
||||
.and('include', 'info.uniswap.org/#/tokens/0xa71d0588EAf47f12B13cF8eC750430d21DF04974')
|
||||
cy.contains('Website').should('have.attr', 'href').and('include', 'qom')
|
||||
cy.contains('Twitter').should('have.attr', 'href').and('include', 'twitter.com/ShibaPredator1')
|
||||
.and('include', 'info.uniswap.org/#/tokens/0x1eFBB78C8b917f67986BcE54cE575069c0143681')
|
||||
})
|
||||
|
||||
// Contract address should be displayed
|
||||
cy.contains('0xa71d0588EAf47f12B13cF8eC750430d21DF04974').should('exist')
|
||||
cy.contains('0x1eFBB78C8b917f67986BcE54cE575069c0143681').should('exist')
|
||||
|
||||
// Warning label should show if relevant ([spec](https://www.notion.so/3f7fce6f93694be08a94a6984d50298e))
|
||||
cy.get('[data-cy="token-safety-message"]')
|
||||
|
||||
@@ -69,6 +69,6 @@ describe('Token explore', () => {
|
||||
cy.get(getTestSelector('tokens-network-filter-selected')).click()
|
||||
cy.get(getTestSelector('tokens-network-filter-option-optimism')).click()
|
||||
cy.get(getTestSelector('tokens-network-filter-selected')).should('contain', 'Optimism')
|
||||
cy.get(getTestSelector('chain-selector-logo')).invoke('attr', 'alt').should('eq', 'Ethereum')
|
||||
cy.get(getTestSelector('chain-selector-logo')).find('title').should('include.text', 'Ethereum logo')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -65,7 +65,7 @@ describe('Universal search bar', () => {
|
||||
cy.get(getTestSelector('searchbar-token-row-ETHEREUM-NATIVE'))
|
||||
|
||||
// Validate that we go to the searched/selected result.
|
||||
getSearchBar().type('{enter}')
|
||||
cy.get(getTestSelector('searchbar-token-row-ETHEREUM-NATIVE')).click()
|
||||
cy.url().should('contain', 'tokens/ethereum/NATIVE')
|
||||
}
|
||||
)
|
||||
|
||||
@@ -2,7 +2,7 @@ import { createDeferredPromise } from '../../../src/test-utils/promise'
|
||||
import { getTestSelector } from '../../utils'
|
||||
|
||||
function waitsForActiveChain(chain: string) {
|
||||
cy.get(getTestSelector('chain-selector-logo')).invoke('attr', 'alt').should('eq', chain)
|
||||
cy.get(getTestSelector('chain-selector-logo')).find('title').should('include.text', `${chain} logo`)
|
||||
}
|
||||
|
||||
function switchChain(chain: string) {
|
||||
|
||||
@@ -53,7 +53,7 @@ describe('Wallet Dropdown', () => {
|
||||
|
||||
describe('should change locale with feature flag', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/', { featureFlags: [FeatureFlag.currencyConversion] })
|
||||
cy.visit('/', { featureFlags: [{ name: FeatureFlag.currencyConversion, value: true }] })
|
||||
cy.get(getTestSelector('web3-status-connected')).click()
|
||||
cy.get(getTestSelector('wallet-settings')).click()
|
||||
})
|
||||
@@ -147,19 +147,19 @@ describe('Wallet Dropdown', () => {
|
||||
|
||||
describe('local currency', () => {
|
||||
it('loads local currency from the query param', () => {
|
||||
cy.visit('/', { featureFlags: [FeatureFlag.currencyConversion] })
|
||||
cy.visit('/', { featureFlags: [{ name: FeatureFlag.currencyConversion, value: true }] })
|
||||
cy.get(getTestSelector('web3-status-connected')).click()
|
||||
cy.get(getTestSelector('wallet-settings')).click()
|
||||
cy.contains('USD')
|
||||
|
||||
cy.visit('/?cur=AUD', { featureFlags: [FeatureFlag.currencyConversion] })
|
||||
cy.visit('/?cur=AUD', { featureFlags: [{ name: FeatureFlag.currencyConversion, value: true }] })
|
||||
cy.get(getTestSelector('web3-status-connected')).click()
|
||||
cy.get(getTestSelector('wallet-settings')).click()
|
||||
cy.contains('AUD')
|
||||
})
|
||||
|
||||
it('loads local currency from menu', () => {
|
||||
cy.visit('/', { featureFlags: [FeatureFlag.currencyConversion] })
|
||||
cy.visit('/', { featureFlags: [{ name: FeatureFlag.currencyConversion, value: true }] })
|
||||
cy.get(getTestSelector('web3-status-connected')).click()
|
||||
cy.get(getTestSelector('wallet-settings')).click()
|
||||
cy.contains('USD')
|
||||
|
||||
562
cypress/fixtures/uniswapx/feeQuote.json
Normal file
@@ -0,0 +1,562 @@
|
||||
{
|
||||
"routing": "DUTCH_LIMIT",
|
||||
"quote": {
|
||||
"orderInfo": {
|
||||
"chainId": 1,
|
||||
"permit2Address": "0x000000000022d473030f116ddee9f6b43ac78ba3",
|
||||
"reactor": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4",
|
||||
"swapper": "0x0938a82F93D5DAB110Dc6277FC236b5b082DC10F",
|
||||
"nonce": "1993353164669688581970088190602701610528397285201889446578254799128576197633",
|
||||
"deadline": 1697481666,
|
||||
"additionalValidationContract": "0x0000000000000000000000000000000000000000",
|
||||
"additionalValidationData": "0x",
|
||||
"decayStartTime": 1697481594,
|
||||
"decayEndTime": 1697481654,
|
||||
"exclusiveFiller": "0xaAFb85ad4a412dd8adC49611496a7695A22f4aeb",
|
||||
"exclusivityOverrideBps": "100",
|
||||
"input": {
|
||||
"token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
||||
"startAmount": "200000000",
|
||||
"endAmount": "200000000"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"token": "0x0000000000000000000000000000000000000000",
|
||||
"startAmount": "123803169993201727",
|
||||
"endAmount": "117908377342236273",
|
||||
"recipient": "0x0938a82F93D5DAB110Dc6277FC236b5b082DC10F"
|
||||
},
|
||||
{
|
||||
"token": "0x0000000000000000000000000000000000000000",
|
||||
"startAmount": "185983730585681",
|
||||
"endAmount": "177128258400955",
|
||||
"recipient": "0x37a8f295612602f2774d331e562be9e61B83a327"
|
||||
}
|
||||
]
|
||||
},
|
||||
"encodedOrder": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000652d837a00000000000000000000000000000000000000000000000000000000652d83b6000000000000000000000000aafb85ad4a412dd8adc49611496a7695a22f4aeb0000000000000000000000000000000000000000000000000000000000000064000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000000bebc200000000000000000000000000000000000000000000000000000000000bebc20000000000000000000000000000000000000000000000000000000000000002000000000000000000000000006000da47483062a0d734ba3dc7576ce6a0b645c40000000000000000000000000938a82f93d5dab110dc6277fc236b5b082dc10f046832aa305880d33daa871e5041a0cd4853599a9ead518917239e206765040100000000000000000000000000000000000000000000000000000000652d83c2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b7d653c183183f00000000000000000000000000000000000000000000000001a2e50b6386d6710000000000000000000000000938a82f93d5dab110dc6277fc236b5b082dc10f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a926b63210510000000000000000000000000000000000000000000000000000a118e2ebf2bb00000000000000000000000037a8f295612602f2774d331e562be9e61b83a327",
|
||||
"quoteId": "7b924043-f2d8-4f2e-abaa-9f65fbe5f890",
|
||||
"requestId": "a02ca0ca-7855-4dd0-9330-8b818aaeb59f",
|
||||
"orderHash": "0xb5b4e3be188f6eb9dbe7e1489595829184a9ebfb5389185ed7ba7c03142278c9",
|
||||
"startTimeBufferSecs": 45,
|
||||
"auctionPeriodSecs": 60,
|
||||
"deadlineBufferSecs": 12,
|
||||
"slippageTolerance": "0.5",
|
||||
"permitData": {
|
||||
"domain": {
|
||||
"name": "Permit2",
|
||||
"chainId": 1,
|
||||
"verifyingContract": "0x000000000022d473030f116ddee9f6b43ac78ba3"
|
||||
},
|
||||
"types": {
|
||||
"PermitWitnessTransferFrom": [
|
||||
{
|
||||
"name": "permitted",
|
||||
"type": "TokenPermissions"
|
||||
},
|
||||
{
|
||||
"name": "spender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "nonce",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "deadline",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "witness",
|
||||
"type": "ExclusiveDutchOrder"
|
||||
}
|
||||
],
|
||||
"TokenPermissions": [
|
||||
{
|
||||
"name": "token",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "amount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"ExclusiveDutchOrder": [
|
||||
{
|
||||
"name": "info",
|
||||
"type": "OrderInfo"
|
||||
},
|
||||
{
|
||||
"name": "decayStartTime",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "decayEndTime",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "exclusiveFiller",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "exclusivityOverrideBps",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "inputToken",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "inputStartAmount",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "inputEndAmount",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "outputs",
|
||||
"type": "DutchOutput[]"
|
||||
}
|
||||
],
|
||||
"OrderInfo": [
|
||||
{
|
||||
"name": "reactor",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "swapper",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "nonce",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "deadline",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "additionalValidationContract",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "additionalValidationData",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"DutchOutput": [
|
||||
{
|
||||
"name": "token",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "startAmount",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "endAmount",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
}
|
||||
]
|
||||
},
|
||||
"values": {
|
||||
"permitted": {
|
||||
"token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
||||
"amount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x0bebc200"
|
||||
}
|
||||
},
|
||||
"spender": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4",
|
||||
"nonce": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x046832aa305880d33daa871e5041a0cd4853599a9ead518917239e2067650401"
|
||||
},
|
||||
"deadline": 1697481666,
|
||||
"witness": {
|
||||
"info": {
|
||||
"reactor": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4",
|
||||
"swapper": "0x0938a82F93D5DAB110Dc6277FC236b5b082DC10F",
|
||||
"nonce": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x046832aa305880d33daa871e5041a0cd4853599a9ead518917239e2067650401"
|
||||
},
|
||||
"deadline": 1697481666,
|
||||
"additionalValidationContract": "0x0000000000000000000000000000000000000000",
|
||||
"additionalValidationData": "0x"
|
||||
},
|
||||
"decayStartTime": 1697481594,
|
||||
"decayEndTime": 1697481654,
|
||||
"exclusiveFiller": "0xaAFb85ad4a412dd8adC49611496a7695A22f4aeb",
|
||||
"exclusivityOverrideBps": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x64"
|
||||
},
|
||||
"inputToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
||||
"inputStartAmount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x0bebc200"
|
||||
},
|
||||
"inputEndAmount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x0bebc200"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"token": "0x0000000000000000000000000000000000000000",
|
||||
"startAmount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x01b7d653c183183f"
|
||||
},
|
||||
"endAmount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x01a2e50b6386d671"
|
||||
},
|
||||
"recipient": "0x0938a82F93D5DAB110Dc6277FC236b5b082DC10F"
|
||||
},
|
||||
{
|
||||
"token": "0x0000000000000000000000000000000000000000",
|
||||
"startAmount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0xa926b6321051"
|
||||
},
|
||||
"endAmount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0xa118e2ebf2bb"
|
||||
},
|
||||
"recipient": "0x37a8f295612602f2774d331e562be9e61B83a327"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"portionBips": 15,
|
||||
"portionAmount": "185983730585681",
|
||||
"portionRecipient": "0x37a8f295612602f2774d331e562be9e61B83a327"
|
||||
},
|
||||
"requestId": "a02ca0ca-7855-4dd0-9330-8b818aaeb59f",
|
||||
"allQuotes": [
|
||||
{
|
||||
"routing": "DUTCH_LIMIT",
|
||||
"quote": {
|
||||
"orderInfo": {
|
||||
"chainId": 1,
|
||||
"permit2Address": "0x000000000022d473030f116ddee9f6b43ac78ba3",
|
||||
"reactor": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4",
|
||||
"swapper": "0x0938a82F93D5DAB110Dc6277FC236b5b082DC10F",
|
||||
"nonce": "1993353164669688581970088190602701610528397285201889446578254799128576197633",
|
||||
"deadline": 1697481666,
|
||||
"additionalValidationContract": "0x0000000000000000000000000000000000000000",
|
||||
"additionalValidationData": "0x",
|
||||
"decayStartTime": 1697481594,
|
||||
"decayEndTime": 1697481654,
|
||||
"exclusiveFiller": "0xaAFb85ad4a412dd8adC49611496a7695A22f4aeb",
|
||||
"exclusivityOverrideBps": "100",
|
||||
"input": {
|
||||
"token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
||||
"startAmount": "200000000",
|
||||
"endAmount": "200000000"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"token": "0x0000000000000000000000000000000000000000",
|
||||
"startAmount": "123803169993201727",
|
||||
"endAmount": "117908377342236273",
|
||||
"recipient": "0x0938a82F93D5DAB110Dc6277FC236b5b082DC10F"
|
||||
},
|
||||
{
|
||||
"token": "0x0000000000000000000000000000000000000000",
|
||||
"startAmount": "185983730585681",
|
||||
"endAmount": "177128258400955",
|
||||
"recipient": "0x37a8f295612602f2774d331e562be9e61B83a327"
|
||||
}
|
||||
]
|
||||
},
|
||||
"encodedOrder": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000652d837a00000000000000000000000000000000000000000000000000000000652d83b6000000000000000000000000aafb85ad4a412dd8adc49611496a7695a22f4aeb0000000000000000000000000000000000000000000000000000000000000064000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000000bebc200000000000000000000000000000000000000000000000000000000000bebc20000000000000000000000000000000000000000000000000000000000000002000000000000000000000000006000da47483062a0d734ba3dc7576ce6a0b645c40000000000000000000000000938a82f93d5dab110dc6277fc236b5b082dc10f046832aa305880d33daa871e5041a0cd4853599a9ead518917239e206765040100000000000000000000000000000000000000000000000000000000652d83c2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b7d653c183183f00000000000000000000000000000000000000000000000001a2e50b6386d6710000000000000000000000000938a82f93d5dab110dc6277fc236b5b082dc10f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a926b63210510000000000000000000000000000000000000000000000000000a118e2ebf2bb00000000000000000000000037a8f295612602f2774d331e562be9e61b83a327",
|
||||
"quoteId": "7b924043-f2d8-4f2e-abaa-9f65fbe5f890",
|
||||
"requestId": "a02ca0ca-7855-4dd0-9330-8b818aaeb59f",
|
||||
"orderHash": "0xb5b4e3be188f6eb9dbe7e1489595829184a9ebfb5389185ed7ba7c03142278c9",
|
||||
"startTimeBufferSecs": 45,
|
||||
"auctionPeriodSecs": 60,
|
||||
"deadlineBufferSecs": 12,
|
||||
"slippageTolerance": "0.5",
|
||||
"permitData": {
|
||||
"domain": {
|
||||
"name": "Permit2",
|
||||
"chainId": 1,
|
||||
"verifyingContract": "0x000000000022d473030f116ddee9f6b43ac78ba3"
|
||||
},
|
||||
"types": {
|
||||
"PermitWitnessTransferFrom": [
|
||||
{
|
||||
"name": "permitted",
|
||||
"type": "TokenPermissions"
|
||||
},
|
||||
{
|
||||
"name": "spender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "nonce",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "deadline",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "witness",
|
||||
"type": "ExclusiveDutchOrder"
|
||||
}
|
||||
],
|
||||
"TokenPermissions": [
|
||||
{
|
||||
"name": "token",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "amount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"ExclusiveDutchOrder": [
|
||||
{
|
||||
"name": "info",
|
||||
"type": "OrderInfo"
|
||||
},
|
||||
{
|
||||
"name": "decayStartTime",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "decayEndTime",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "exclusiveFiller",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "exclusivityOverrideBps",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "inputToken",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "inputStartAmount",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "inputEndAmount",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "outputs",
|
||||
"type": "DutchOutput[]"
|
||||
}
|
||||
],
|
||||
"OrderInfo": [
|
||||
{
|
||||
"name": "reactor",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "swapper",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "nonce",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "deadline",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "additionalValidationContract",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "additionalValidationData",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"DutchOutput": [
|
||||
{
|
||||
"name": "token",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "startAmount",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "endAmount",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
}
|
||||
]
|
||||
},
|
||||
"values": {
|
||||
"permitted": {
|
||||
"token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
||||
"amount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x0bebc200"
|
||||
}
|
||||
},
|
||||
"spender": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4",
|
||||
"nonce": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x046832aa305880d33daa871e5041a0cd4853599a9ead518917239e2067650401"
|
||||
},
|
||||
"deadline": 1697481666,
|
||||
"witness": {
|
||||
"info": {
|
||||
"reactor": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4",
|
||||
"swapper": "0x0938a82F93D5DAB110Dc6277FC236b5b082DC10F",
|
||||
"nonce": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x046832aa305880d33daa871e5041a0cd4853599a9ead518917239e2067650401"
|
||||
},
|
||||
"deadline": 1697481666,
|
||||
"additionalValidationContract": "0x0000000000000000000000000000000000000000",
|
||||
"additionalValidationData": "0x"
|
||||
},
|
||||
"decayStartTime": 1697481594,
|
||||
"decayEndTime": 1697481654,
|
||||
"exclusiveFiller": "0xaAFb85ad4a412dd8adC49611496a7695A22f4aeb",
|
||||
"exclusivityOverrideBps": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x64"
|
||||
},
|
||||
"inputToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
||||
"inputStartAmount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x0bebc200"
|
||||
},
|
||||
"inputEndAmount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x0bebc200"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"token": "0x0000000000000000000000000000000000000000",
|
||||
"startAmount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x01b7d653c183183f"
|
||||
},
|
||||
"endAmount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0x01a2e50b6386d671"
|
||||
},
|
||||
"recipient": "0x0938a82F93D5DAB110Dc6277FC236b5b082DC10F"
|
||||
},
|
||||
{
|
||||
"token": "0x0000000000000000000000000000000000000000",
|
||||
"startAmount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0xa926b6321051"
|
||||
},
|
||||
"endAmount": {
|
||||
"type": "BigNumber",
|
||||
"hex": "0xa118e2ebf2bb"
|
||||
},
|
||||
"recipient": "0x37a8f295612602f2774d331e562be9e61B83a327"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"portionBips": 15,
|
||||
"portionAmount": "185983730585681",
|
||||
"portionRecipient": "0x37a8f295612602f2774d331e562be9e61B83a327"
|
||||
}
|
||||
},
|
||||
{
|
||||
"routing": "CLASSIC",
|
||||
"quote": {
|
||||
"methodParameters": {
|
||||
"calldata": "0x3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000652d85d0000000000000000000000000000000000000000000000000000000000000000308060c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000bebc20000000000000000000000000000000000000000000000000001bdf1285753b47400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000037a8f295612602f2774d331e562be9e61b83a327000000000000000000000000000000000000000000000000000000000000000f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000938a82f93d5dab110dc6277fc236b5b082dc10f00000000000000000000000000000000000000000000000001bd45ea74e458eb",
|
||||
"value": "0x00",
|
||||
"to": "0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD"
|
||||
},
|
||||
"blockNumber": "18364784",
|
||||
"amount": "200000000",
|
||||
"amountDecimals": "200",
|
||||
"quote": "126149127803342909",
|
||||
"quoteDecimals": "0.126149127803342909",
|
||||
"quoteGasAdjusted": "122888348391508943",
|
||||
"quoteGasAdjustedDecimals": "0.122888348391508943",
|
||||
"quoteGasAndPortionAdjusted": "122699124699803928",
|
||||
"quoteGasAndPortionAdjustedDecimals": "0.122699124699803928",
|
||||
"gasUseEstimateQuote": "3260779411833966",
|
||||
"gasUseEstimateQuoteDecimals": "0.003260779411833966",
|
||||
"gasUseEstimate": "240911",
|
||||
"gasUseEstimateUSD": "5.153332510477604328",
|
||||
"simulationStatus": "SUCCESS",
|
||||
"simulationError": false,
|
||||
"gasPriceWei": "13535203506",
|
||||
"route": [
|
||||
[
|
||||
{
|
||||
"type": "v2-pool",
|
||||
"address": "0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc",
|
||||
"tokenIn": {
|
||||
"chainId": 1,
|
||||
"decimals": "6",
|
||||
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
||||
"symbol": "USDC"
|
||||
},
|
||||
"tokenOut": {
|
||||
"chainId": 1,
|
||||
"decimals": "18",
|
||||
"address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
||||
"symbol": "WETH"
|
||||
},
|
||||
"reserve0": {
|
||||
"token": {
|
||||
"chainId": 1,
|
||||
"decimals": "6",
|
||||
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
||||
"symbol": "USDC"
|
||||
},
|
||||
"quotient": "27487668611269"
|
||||
},
|
||||
"reserve1": {
|
||||
"token": {
|
||||
"chainId": 1,
|
||||
"decimals": "18",
|
||||
"address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
||||
"symbol": "WETH"
|
||||
},
|
||||
"quotient": "17390022942803382004255"
|
||||
},
|
||||
"amountIn": "200000000",
|
||||
"amountOut": "125959904111637894"
|
||||
}
|
||||
]
|
||||
],
|
||||
"routeString": "[V2] 100.00% = USDC -- [0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc] --> WETH",
|
||||
"quoteId": "f46cf31c-251e-470c-bd57-13209015694e",
|
||||
"portionBips": 15,
|
||||
"portionRecipient": "0x37a8f295612602f2774d331e562be9e61B83a327",
|
||||
"portionAmount": "189223691705014",
|
||||
"portionAmountDecimals": "0.000189223691705014",
|
||||
"requestId": "a02ca0ca-7855-4dd0-9330-8b818aaeb59f",
|
||||
"tradeType": "EXACT_INPUT",
|
||||
"slippage": 0.5
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -24,7 +24,7 @@ declare global {
|
||||
}
|
||||
interface VisitOptions {
|
||||
serviceWorker?: true
|
||||
featureFlags?: Array<FeatureFlag>
|
||||
featureFlags?: Array<{ name: FeatureFlag; value: boolean }>
|
||||
/**
|
||||
* Initial user state.
|
||||
* @default {@type import('../utils/user-state').CONNECTED_WALLET_USER_STATE}
|
||||
@@ -59,7 +59,10 @@ Cypress.Commands.overwrite(
|
||||
|
||||
// Set feature flags, if configured.
|
||||
if (options?.featureFlags) {
|
||||
const featureFlags = options.featureFlags.reduce((flags, flag) => ({ ...flags, [flag]: 'enabled' }), {})
|
||||
const featureFlags = options.featureFlags.reduce(
|
||||
(flags, flag) => ({ ...flags, [flag.name]: flag.value ? 'enabled' : 'control' }),
|
||||
{}
|
||||
)
|
||||
win.localStorage.setItem('featureFlags', JSON.stringify(featureFlags))
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"incremental": true,
|
||||
"isolatedModules": false,
|
||||
"noImplicitAny": false,
|
||||
"target": "ES5",
|
||||
"target": "ES6",
|
||||
"tsBuildInfoFile": "../node_modules/.cache/tsbuildinfo/cypress", // avoid clobbering the build tsbuildinfo
|
||||
"types": ["cypress", "node"],
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@ export const onRequest: PagesFunction = async ({ request, next }) => {
|
||||
}
|
||||
const res = next()
|
||||
try {
|
||||
return new HTMLRewriter().on('head', new MetaTagInjector(data)).transform(await res)
|
||||
return new HTMLRewriter().on('head', new MetaTagInjector(data, request)).transform(await res)
|
||||
} catch (e) {
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -6,12 +6,15 @@ test('should append meta tag to element', () => {
|
||||
} as unknown as Element
|
||||
const property = 'property'
|
||||
const content = 'content'
|
||||
const injector = new MetaTagInjector({
|
||||
title: 'test',
|
||||
url: 'testUrl',
|
||||
image: 'testImage',
|
||||
description: 'testDescription',
|
||||
})
|
||||
const injector = new MetaTagInjector(
|
||||
{
|
||||
title: 'test',
|
||||
url: 'testUrl',
|
||||
image: 'testImage',
|
||||
description: 'testDescription',
|
||||
},
|
||||
new Request('http://localhost')
|
||||
)
|
||||
injector.append(element, property, content)
|
||||
expect(element.append).toHaveBeenCalledWith(`<meta property="${property}" content="${content}"/>`, { html: true })
|
||||
|
||||
@@ -36,3 +39,22 @@ test('should append meta tag to element', () => {
|
||||
|
||||
expect(element.append).toHaveBeenCalledTimes(13)
|
||||
})
|
||||
|
||||
test('should pass through header blocked paths', () => {
|
||||
const element = {
|
||||
append: jest.fn(),
|
||||
} as unknown as Element
|
||||
const request = new Request('http://localhost')
|
||||
request.headers.set('x-blocked-paths', '/')
|
||||
const injector = new MetaTagInjector(
|
||||
{
|
||||
title: 'test',
|
||||
url: 'testUrl',
|
||||
image: 'testImage',
|
||||
description: 'testDescription',
|
||||
},
|
||||
request
|
||||
)
|
||||
injector.element(element)
|
||||
expect(element.append).toHaveBeenCalledWith(`<meta property="x:blocked-paths" content="/"/>`, { html: true })
|
||||
})
|
||||
|
||||
@@ -10,7 +10,7 @@ type MetaTagInjectorInput = {
|
||||
* to inject meta tags into the <head> of an HTML document.
|
||||
*/
|
||||
export class MetaTagInjector implements HTMLRewriterElementContentHandlers {
|
||||
constructor(private input: MetaTagInjectorInput) {}
|
||||
constructor(private input: MetaTagInjectorInput, private request: Request) {}
|
||||
|
||||
append(element: Element, property: string, content: string) {
|
||||
element.append(`<meta property="${property}" content="${content}"/>`, { html: true })
|
||||
@@ -38,5 +38,10 @@ export class MetaTagInjector implements HTMLRewriterElementContentHandlers {
|
||||
this.append(element, 'twitter:image', this.input.image)
|
||||
this.append(element, 'twitter:image:alt', this.input.title)
|
||||
}
|
||||
|
||||
const blockedPaths = this.request.headers.get('x-blocked-paths')
|
||||
if (blockedPaths) {
|
||||
this.append(element, 'x:blocked-paths', blockedPaths)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ export const onRequest: PagesFunction = async ({ params, request, next }) => {
|
||||
const { index } = params
|
||||
const collectionAddress = index[0]?.toString()
|
||||
const tokenId = index[1]?.toString()
|
||||
return getMetadataRequest(res, request.url, () => getAsset(collectionAddress, tokenId, request.url))
|
||||
return getMetadataRequest(res, request, () => getAsset(collectionAddress, tokenId, request.url))
|
||||
} catch (e) {
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ export const onRequest: PagesFunction = async ({ params, request, next }) => {
|
||||
try {
|
||||
const { index } = params
|
||||
const collectionAddress = index?.toString()
|
||||
return getMetadataRequest(res, request.url, () => getCollection(collectionAddress, request.url))
|
||||
return getMetadataRequest(res, request, () => getCollection(collectionAddress, request.url))
|
||||
} catch (e) {
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ export const onRequest: PagesFunction = async ({ params, request, next }) => {
|
||||
if (!tokenAddress) {
|
||||
return res
|
||||
}
|
||||
return getMetadataRequest(res, request.url, () => getToken(networkName, tokenAddress, request.url))
|
||||
return getMetadataRequest(res, request, () => getToken(networkName, tokenAddress, request.url))
|
||||
} catch (e) {
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@ import { Data } from './cache'
|
||||
|
||||
export async function getMetadataRequest(
|
||||
res: Promise<Response>,
|
||||
url: string,
|
||||
request: Request,
|
||||
getData: () => Promise<Data | undefined>
|
||||
) {
|
||||
try {
|
||||
const cachedData = await getRequest(url, getData, (data): data is Data => true)
|
||||
const cachedData = await getRequest(request.url, getData, (data): data is Data => true)
|
||||
if (cachedData) {
|
||||
return new HTMLRewriter().on('head', new MetaTagInjector(cachedData)).transform(await res)
|
||||
return new HTMLRewriter().on('head', new MetaTagInjector(cachedData, request)).transform(await res)
|
||||
} else {
|
||||
return res
|
||||
}
|
||||
|
||||
31
package.json
@@ -13,6 +13,7 @@
|
||||
"graphql:generate:thegraph": "graphql-codegen --config graphql.thegraph.codegen.config.ts",
|
||||
"graphql:generate": "yarn graphql:generate:data && yarn graphql:generate:thegraph",
|
||||
"graphql": "yarn graphql:fetch && yarn graphql:generate",
|
||||
"sitemap:generate": "node scripts/generate-sitemap.js",
|
||||
"i18n:extract": "lingui extract --locale en-US",
|
||||
"i18n:compile": "lingui compile",
|
||||
"i18n": "yarn i18n:extract --clean && yarn i18n:compile",
|
||||
@@ -114,6 +115,7 @@
|
||||
"@types/ua-parser-js": "^0.7.36",
|
||||
"@types/uuid": "^8.3.4",
|
||||
"@types/wcag-contrast": "^3.0.0",
|
||||
"@types/xml2js": "^0.4.12",
|
||||
"@uniswap/default-token-list": "^11.2.0",
|
||||
"@uniswap/eslint-config": "^1.2.0",
|
||||
"@vanilla-extract/jest-transform": "^1.1.1",
|
||||
@@ -189,6 +191,7 @@
|
||||
"@sentry/react": "^7.45.0",
|
||||
"@sentry/tracing": "^7.45.0",
|
||||
"@sentry/types": "^7.45.0",
|
||||
"@types/react-helmet": "^6.1.7",
|
||||
"@types/react-window-infinite-loader": "^1.0.6",
|
||||
"@uniswap/analytics": "1.5.0",
|
||||
"@uniswap/analytics-events": "^2.24.0",
|
||||
@@ -201,8 +204,8 @@
|
||||
"@uniswap/sdk-core": "^4.0.3",
|
||||
"@uniswap/smart-order-router": "^3.15.0",
|
||||
"@uniswap/token-lists": "^1.0.0-beta.33",
|
||||
"@uniswap/uniswapx-sdk": "^1.3.0",
|
||||
"@uniswap/universal-router-sdk": "^1.5.6",
|
||||
"@uniswap/uniswapx-sdk": "^1.4.1",
|
||||
"@uniswap/universal-router-sdk": "^1.5.8",
|
||||
"@uniswap/v2-core": "^1.0.1",
|
||||
"@uniswap/v2-periphery": "^1.1.0-beta.0",
|
||||
"@uniswap/v2-sdk": "^3.2.0",
|
||||
@@ -220,16 +223,16 @@
|
||||
"@visx/react-spring": "^2.12.2",
|
||||
"@visx/responsive": "^2.10.0",
|
||||
"@visx/shape": "^2.11.1",
|
||||
"@web3-react/coinbase-wallet": "^8.2.2",
|
||||
"@web3-react/core": "^8.2.2",
|
||||
"@web3-react/eip1193": "^8.2.2",
|
||||
"@web3-react/empty": "^8.2.2",
|
||||
"@web3-react/gnosis-safe": "^8.2.3",
|
||||
"@web3-react/metamask": "^8.2.3",
|
||||
"@web3-react/network": "^8.2.2",
|
||||
"@web3-react/types": "^8.2.2",
|
||||
"@web3-react/url": "^8.2.2",
|
||||
"@web3-react/walletconnect-v2": "^8.5.0",
|
||||
"@web3-react/coinbase-wallet": "^8.2.3",
|
||||
"@web3-react/core": "^8.2.3",
|
||||
"@web3-react/eip1193": "^8.2.3",
|
||||
"@web3-react/empty": "^8.2.3",
|
||||
"@web3-react/gnosis-safe": "^8.2.4",
|
||||
"@web3-react/metamask": "^8.2.4",
|
||||
"@web3-react/network": "^8.2.3",
|
||||
"@web3-react/types": "^8.2.3",
|
||||
"@web3-react/url": "^8.2.3",
|
||||
"@web3-react/walletconnect-v2": "^8.5.1",
|
||||
"ajv": "^8.11.0",
|
||||
"ajv-formats": "^2.1.1",
|
||||
"array.prototype.flat": "^1.2.4",
|
||||
@@ -253,6 +256,8 @@
|
||||
"ms": "^2.1.3",
|
||||
"multicodec": "^3.0.1",
|
||||
"multihashes": "^4.0.2",
|
||||
"nock": "^13.3.3",
|
||||
"node-fetch": "^3.3.2",
|
||||
"node-vibrant": "^3.2.1-alpha.1",
|
||||
"numbro": "^2.3.6",
|
||||
"polished": "^3.3.2",
|
||||
@@ -263,6 +268,7 @@
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-feather": "^2.0.8",
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-infinite-scroll-component": "^6.1.0",
|
||||
"react-is": "^17.0.2",
|
||||
"react-markdown": "^4.3.1",
|
||||
@@ -292,6 +298,7 @@
|
||||
"workbox-navigation-preload": "^6.1.0",
|
||||
"workbox-precaching": "^6.1.0",
|
||||
"workbox-routing": "^6.1.0",
|
||||
"xml2js": "^0.6.2",
|
||||
"zustand": "^4.3.6"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -3,27 +3,27 @@
|
||||
"relation": ["delegate_permission/common.handle_all_urls"],
|
||||
"target": {
|
||||
"namespace": "android_app",
|
||||
"package_name": "com.uniswap",
|
||||
"package_name": "com.uniswap.mobile",
|
||||
"sha256_cert_fingerprints":
|
||||
["97:A5:81:51:DA:AF:8F:6E:65:3A:90:1E:82:12:6C:FB:61:2D:36:C7:CF:20:61:6B:A3:4C:52:CA:BC:58:43:8E", "F9:E9:E3:F0:04:28:66:62:81:44:50:7E:D6:A9:5F:B9:65:39:02:70:1D:13:74:15:D3:E1:A3:1B:D4:38:3A:1F"]
|
||||
["49:D9:3D:5D:FB:AA:64:A4:64:80:85:0F:39:A8:C1:D9:25:D3:D4:BC:8E:6B:1F:45:0C:EA:AF:B1:0C:27:DF:B8", "F9:E9:E3:F0:04:28:66:62:81:44:50:7E:D6:A9:5F:B9:65:39:02:70:1D:13:74:15:D3:E1:A3:1B:D4:38:3A:1F"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"relation": ["delegate_permission/common.handle_all_urls"],
|
||||
"target": {
|
||||
"namespace": "android_app",
|
||||
"package_name": "com.uniswap.beta",
|
||||
"package_name": "com.uniswap.mobile.beta",
|
||||
"sha256_cert_fingerprints":
|
||||
["E5:39:87:DC:4D:FD:4C:1B:A6:74:36:7D:3A:3B:6B:ED:9E:B3:66:89:92:8A:1B:B8:FC:1B:22:56:56:B4:46:A3", "54:4B:62:33:17:9B:5F:A8:E6:5D:D3:A6:E5:9D:80:5F:A5:02:7F:E2:14:B8:C1:7A:AC:4B:8D:E0:65:49:87:41"]
|
||||
["75:41:9C:2D:01:4A:88:4E:8D:C6:EF:E5:51:54:28:6B:99:05:31:43:AD:84:B4:EB:39:28:B8:C3:C4:CE:48:E3", "54:4B:62:33:17:9B:5F:A8:E6:5D:D3:A6:E5:9D:80:5F:A5:02:7F:E2:14:B8:C1:7A:AC:4B:8D:E0:65:49:87:41"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"relation": ["delegate_permission/common.handle_all_urls"],
|
||||
"target": {
|
||||
"namespace": "android_app",
|
||||
"package_name": "com.uniswap.dev",
|
||||
"package_name": "com.uniswap.mobile.dev",
|
||||
"sha256_cert_fingerprints":
|
||||
["5A:6D:23:50:2F:1E:0D:01:DC:96:65:F3:3A:18:4C:4C:8C:67:E0:09:99:9B:B1:9B:BF:44:99:D0:D1:D0:FC:5E", "02:E6:1C:76:8C:75:C3:78:C8:8C:FE:7B:2E:8F:4B:E1:FA:47:F2:F6:1A:DB:57:69:4A:41:99:C6:71:2C:AB:E3", "FA:C6:17:45:DC:09:03:78:6F:B9:ED:E6:2A:96:2B:39:9F:73:48:F0:BB:6F:89:9B:83:32:66:75:91:03:3B:9C"]
|
||||
["45:F8:15:02:C5:4F:AD:82:E7:51:F0:9C:D1:CA:77:C8:C9:BF:06:A6:D9:5A:55:4F:9E:B8:5F:81:33:2B:D0:DB", "02:E6:1C:76:8C:75:C3:78:C8:8C:FE:7B:2E:8F:4B:E1:FA:47:F2:F6:1A:DB:57:69:4A:41:99:C6:71:2C:AB:E3", "FA:C6:17:45:DC:09:03:78:6F:B9:ED:E6:2A:96:2B:39:9F:73:48:F0:BB:6F:89:9B:83:32:66:75:91:03:3B:9C"]
|
||||
}
|
||||
}
|
||||
]
|
||||
10
public/robots.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
# *
|
||||
User-agent: *
|
||||
Disallow: /static/js/
|
||||
Allow: /
|
||||
|
||||
# Host
|
||||
Host: https://app.uniswap.org
|
||||
|
||||
# Sitemaps
|
||||
Sitemap: https://app.uniswap.org/sitemap.xml
|
||||
1975
public/sitemap.xml
Normal file
108
scripts/generate-sitemap.js
Normal file
@@ -0,0 +1,108 @@
|
||||
/* eslint-env node */
|
||||
|
||||
const fs = require('fs')
|
||||
const { parseStringPromise, Builder } = require('xml2js')
|
||||
|
||||
const weekMs = 7 * 24 * 60 * 60 * 1000
|
||||
const nowISO = new Date().toISOString()
|
||||
|
||||
const getTopTokensQuery = (chain) => `
|
||||
query {
|
||||
topTokens(pageSize: 100, page: 1, chain: ${chain}, orderBy: VOLUME) {
|
||||
address
|
||||
}
|
||||
}
|
||||
`
|
||||
const chains = ['ETHEREUM', 'ARBITRUM', 'OPTIMISM', 'POLYGON', 'BASE', 'BNB', 'CELO']
|
||||
|
||||
const nftTopCollectionsQuery = `
|
||||
query {
|
||||
topCollections(first: 100, duration: MAX) {
|
||||
edges {
|
||||
node {
|
||||
nftContracts {
|
||||
address
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
fs.readFile('./public/sitemap.xml', 'utf8', async (err, data) => {
|
||||
const sitemapURLs = {}
|
||||
try {
|
||||
const sitemap = await parseStringPromise(data)
|
||||
if (sitemap.urlset.url) {
|
||||
sitemap.urlset.url.forEach((url) => {
|
||||
const lastMod = new Date(url.lastmod).getTime()
|
||||
if (lastMod < Date.now() - weekMs) {
|
||||
url.lastmod = nowISO
|
||||
}
|
||||
sitemapURLs[url.loc] = true
|
||||
})
|
||||
}
|
||||
|
||||
for (const chainName of chains) {
|
||||
const tokensResponse = await fetch('https://api.uniswap.org/v1/graphql', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Origin: 'https://app.uniswap.org',
|
||||
},
|
||||
body: JSON.stringify({ query: getTopTokensQuery(chainName) }),
|
||||
})
|
||||
const tokensJSON = await tokensResponse.json()
|
||||
const tokenAddresses = tokensJSON.data.topTokens.map((token) => token.address.toLowerCase())
|
||||
|
||||
tokenAddresses.forEach((address) => {
|
||||
const tokenURL = `https://app.uniswap.org/tokens/${chainName.toLowerCase()}/${address}`
|
||||
if (!(tokenURL in sitemapURLs)) {
|
||||
sitemap.urlset.url.push({
|
||||
loc: [tokenURL],
|
||||
lastmod: [nowISO],
|
||||
priority: [0.8],
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const nftResponse = await fetch('https://api.uniswap.org/v1/graphql', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Origin: 'https://app.uniswap.org',
|
||||
},
|
||||
body: JSON.stringify({ query: nftTopCollectionsQuery }),
|
||||
})
|
||||
const nftJSON = await nftResponse.json()
|
||||
const collectionAddresses = nftJSON.data.topCollections.edges.map((edge) => edge.node.nftContracts[0].address)
|
||||
collectionAddresses.forEach((address) => {
|
||||
const collectionURL = `https://app.uniswap.org/nfts/collection/${address}`
|
||||
if (!(collectionURL in sitemapURLs)) {
|
||||
sitemap.urlset.url.push({
|
||||
loc: [collectionURL],
|
||||
lastmod: [nowISO],
|
||||
priority: [0.7],
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const builder = new Builder()
|
||||
const xml = builder.buildObject(sitemap)
|
||||
const path = './public/sitemap.xml'
|
||||
fs.writeFile(path, xml, (error) => {
|
||||
if (error) throw error
|
||||
const stats = fs.statSync(path)
|
||||
const fileSizeBytes = stats.size
|
||||
const fileSizeMegabytes = fileSizeBytes / (1024 * 1024)
|
||||
|
||||
if (fileSizeMegabytes > 50) {
|
||||
throw new Error('Generated sitemap file size exceeds 50MB')
|
||||
}
|
||||
console.log('Sitemap updated')
|
||||
})
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
})
|
||||
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 2496 2496" style="enable-background:new 0 0 2496 2496;" xml:space="preserve">
|
||||
<g>
|
||||
<path style="fill-rule:evenodd;clip-rule:evenodd;fill:#F0B90B;" d="M1248,0c689.3,0,1248,558.7,1248,1248s-558.7,1248-1248,1248
|
||||
S0,1937.3,0,1248S558.7,0,1248,0L1248,0z"/>
|
||||
<path style="fill:#FFFFFF;" d="M685.9,1248l0.9,330l280.4,165v193.2l-444.5-260.7v-524L685.9,1248L685.9,1248z M685.9,918v192.3
|
||||
l-163.3-96.6V821.4l163.3-96.6l164.1,96.6L685.9,918L685.9,918z M1084.3,821.4l163.3-96.6l164.1,96.6L1247.6,918L1084.3,821.4
|
||||
L1084.3,821.4z"/>
|
||||
<path style="fill:#FFFFFF;" d="M803.9,1509.6v-193.2l163.3,96.6v192.3L803.9,1509.6L803.9,1509.6z M1084.3,1812.2l163.3,96.6
|
||||
l164.1-96.6v192.3l-164.1,96.6l-163.3-96.6V1812.2L1084.3,1812.2z M1645.9,821.4l163.3-96.6l164.1,96.6v192.3l-164.1,96.6V918
|
||||
L1645.9,821.4L1645.9,821.4L1645.9,821.4z M1809.2,1578l0.9-330l163.3-96.6v524l-444.5,260.7v-193.2L1809.2,1578L1809.2,1578
|
||||
L1809.2,1578z"/>
|
||||
<polygon style="fill:#FFFFFF;" points="1692.1,1509.6 1528.8,1605.3 1528.8,1413 1692.1,1316.4 1692.1,1509.6 "/>
|
||||
<path style="fill:#FFFFFF;" d="M1692.1,986.4l0.9,193.2l-281.2,165v330.8l-163.3,95.7l-163.3-95.7v-330.8l-281.2-165V986.4
|
||||
L968,889.8l279.5,165.8l281.2-165.8l164.1,96.6H1692.1L1692.1,986.4z M803.9,656.5l443.7-261.6l444.5,261.6l-163.3,96.6
|
||||
l-281.2-165.8L967.2,753.1L803.9,656.5L803.9,656.5z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 3.3 KiB |
@@ -1,9 +0,0 @@
|
||||
<svg width="14" height="16" viewBox="0 0 14 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0.53125 5.04465V10.9554C0.53125 11.3328 0.742546 11.6817 1.08477 11.8698L6.44755 14.8258C6.78977 15.0139 7.21107 15.0139 7.55329 14.8258L12.9161 11.8698C13.2583 11.6817 13.4696 11.3328 13.4696 10.9554V5.04465C13.4696 4.66726 13.2583 4.31833 12.9161 4.13026L7.55329 1.17426C7.21107 0.986184 6.78977 0.986184 6.44755 1.17426L1.08347 4.13026C0.74125 4.31833 0.53125 4.66726 0.53125 5.04465Z" fill="#213147"/>
|
||||
<path d="M8.17051 9.14643L7.40569 11.1484C7.38495 11.2041 7.38495 11.2648 7.40569 11.3204L8.72143 14.7652L10.2433 13.9263L8.4168 9.14643C8.37532 9.03631 8.21199 9.03631 8.17051 9.14643Z" fill="#12AAFF"/>
|
||||
<path d="M9.70391 5.77961C9.66243 5.66949 9.4991 5.66949 9.45762 5.77961L8.6928 7.78162C8.67206 7.83731 8.67206 7.89793 8.6928 7.95361L10.8485 13.5934L12.3704 12.7545L9.70391 5.77961Z" fill="#12AAFF"/>
|
||||
<path d="M7 1.39574C7.03759 1.39574 7.07519 1.40564 7.10889 1.42296L12.9124 4.62147C12.9798 4.65859 13.0213 4.72789 13.0213 4.80089V11.1967C13.0213 11.2709 12.9798 11.339 12.9124 11.3761L7.10889 14.5746C7.07648 14.5932 7.03759 14.6018 7 14.6018C6.96241 14.6018 6.92482 14.5919 6.89111 14.5746L1.08759 11.3786C1.02019 11.3415 0.978704 11.2722 0.978704 11.1992V4.80213C0.978704 4.72789 1.02019 4.65983 1.08759 4.62271L6.89111 1.4242C6.92482 1.40564 6.96241 1.39574 7 1.39574ZM7 0.461548C6.79389 0.461548 6.58648 0.512279 6.40111 0.614978L0.598889 3.81226C0.228148 4.01642 0 4.3938 0 4.80213V11.1979C0 11.6062 0.228148 11.9836 0.598889 12.1878L6.40241 15.3863C6.58778 15.4878 6.79389 15.5397 7.0013 15.5397C7.20741 15.5397 7.41482 15.489 7.60019 15.3863L13.4037 12.1878C13.7744 11.9836 14.0026 11.6062 14.0026 11.1979V4.80213C14.0026 4.3938 13.7744 4.01642 13.4037 3.81226L7.59889 0.614978C7.41352 0.512279 7.20611 0.461548 7 0.461548Z" fill="#9DCCED"/>
|
||||
<path d="M3.16162 13.6008L3.6957 12.2051L4.77033 13.0576L3.7657 13.9336L3.16162 13.6008Z" fill="#213147"/>
|
||||
<path d="M6.51113 4.3443H5.03983C4.92965 4.3443 4.83113 4.40988 4.79354 4.50887L1.63965 12.7619L3.1615 13.6008L6.63428 4.51258C6.66669 4.43091 6.60317 4.3443 6.51113 4.3443Z" fill="white"/>
|
||||
<path d="M9.08579 4.3443H7.6145C7.50431 4.3443 7.40579 4.40988 7.3682 4.50887L3.76709 13.9324L5.28894 14.7713L9.20894 4.51258C9.24005 4.43091 9.17653 4.3443 9.08579 4.3443Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.3 KiB |
@@ -1,11 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_298_130193)">
|
||||
<path d="M12.9346 2.74121H3.05566V11.7259H12.9346V2.74121Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.9998 0C15.9998 4.41538 15.9998 15.9947 15.9998 15.9947C11.5844 15.9947 0.00590861 15.9947 0.00590861 15.9947L0.00488281 5.43594e-05C4.42027 5.43594e-05 15.9998 0 15.9998 0ZM5.73493 11.1815H4.18339C3.85736 11.1815 3.69632 11.1815 3.59813 11.1187C3.49207 11.0499 3.42726 10.936 3.4194 10.8103C3.41351 10.6945 3.49404 10.553 3.65508 10.2702L7.48603 3.51765C7.64905 3.2309 7.73153 3.08753 7.83562 3.03451C7.94756 2.97755 8.08112 2.97755 8.19307 3.03451C8.29716 3.08753 8.37965 3.2309 8.54265 3.51765L9.33022 4.89243L9.33423 4.89945C9.51029 5.20707 9.59958 5.36307 9.63856 5.52679C9.68176 5.70552 9.68176 5.89406 9.63856 6.07278C9.59928 6.23775 9.5109 6.39488 9.33218 6.70715L7.31987 10.2643L7.31466 10.2734C7.13744 10.5836 7.04762 10.7408 6.92315 10.8594C6.78763 10.9891 6.62462 11.0833 6.44589 11.1364C6.28288 11.1815 6.10024 11.1815 5.73493 11.1815ZM9.65309 11.1815H11.8763C12.2043 11.1815 12.3693 11.1815 12.4675 11.1168C12.5735 11.048 12.6403 10.9321 12.6463 10.8065C12.6519 10.6944 12.5731 10.5584 12.4188 10.2921C12.4134 10.283 12.4081 10.2738 12.4027 10.2644L11.2891 8.35932L11.2764 8.33787C11.1199 8.07325 11.0409 7.93962 10.9395 7.88797C10.8276 7.831 10.6959 7.831 10.584 7.88797C10.4819 7.94099 10.3994 8.08044 10.2364 8.36128L9.12674 10.2663L9.12294 10.2729C8.9605 10.5533 8.87932 10.6934 8.88518 10.8084C8.89303 10.9341 8.95784 11.0499 9.06389 11.1187C9.16014 11.1815 9.32511 11.1815 9.65309 11.1815Z" fill="#E84142"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_298_130193">
|
||||
<rect width="16" height="16" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.8 KiB |
@@ -1,11 +0,0 @@
|
||||
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 14C0 6.26801 6.26801 0 14 0V0C21.732 0 28 6.26801 28 14V14C28 21.732 21.732 28 14 28V28C6.26801 28 0 21.732 0 14V14Z" fill="#0052FF"/>
|
||||
<g clip-path="url(#clip0_13924_33076)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.3332 14.0003C23.3332 19.155 19.1472 23.3337 13.9836 23.3337C9.08459 23.3337 5.06565 19.5724 4.6665 14.7849H17.0245V13.2158H4.6665C5.06565 8.42825 9.08459 4.66699 13.9836 4.66699C19.1472 4.66699 23.3332 8.84566 23.3332 14.0003Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_13924_33076">
|
||||
<rect width="18.6667" height="18.6667" fill="white" transform="translate(4.66675 4.66699)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 745 B |
@@ -1,11 +0,0 @@
|
||||
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="28" height="28" rx="8" fill="#0052FF"/>
|
||||
<g clip-path="url(#clip0_13921_13252)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.3332 14.0003C23.3332 19.155 19.1472 23.3337 13.9836 23.3337C9.08459 23.3337 5.06565 19.5724 4.6665 14.7849H17.0245V13.2158H4.6665C5.06565 8.42825 9.08459 4.66699 13.9836 4.66699C19.1472 4.66699 23.3332 8.84566 23.3332 14.0003Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_13921_13252">
|
||||
<rect width="18.6667" height="18.6667" fill="white" transform="translate(4.66675 4.66699)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 651 B |
@@ -1,21 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect x="0" y="0" width="16" height="16" rx="3" fill="#F0B90B"/>
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 2496 2496" style="enable-background:new 0 0 2496 2496;" xml:space="preserve">
|
||||
<g>
|
||||
<path style="fill-rule:evenodd;clip-rule:evenodd;fill:#F0B90B;" d="M1248,0c689.3,0,1248,558.7,1248,1248s-558.7,1248-1248,1248
|
||||
S0,1937.3,0,1248S558.7,0,1248,0L1248,0z"/>
|
||||
<path style="fill:#FFFFFF;" d="M685.9,1248l0.9,330l280.4,165v193.2l-444.5-260.7v-524L685.9,1248L685.9,1248z M685.9,918v192.3
|
||||
l-163.3-96.6V821.4l163.3-96.6l164.1,96.6L685.9,918L685.9,918z M1084.3,821.4l163.3-96.6l164.1,96.6L1247.6,918L1084.3,821.4
|
||||
L1084.3,821.4z"/>
|
||||
<path style="fill:#FFFFFF;" d="M803.9,1509.6v-193.2l163.3,96.6v192.3L803.9,1509.6L803.9,1509.6z M1084.3,1812.2l163.3,96.6
|
||||
l164.1-96.6v192.3l-164.1,96.6l-163.3-96.6V1812.2L1084.3,1812.2z M1645.9,821.4l163.3-96.6l164.1,96.6v192.3l-164.1,96.6V918
|
||||
L1645.9,821.4L1645.9,821.4L1645.9,821.4z M1809.2,1578l0.9-330l163.3-96.6v524l-444.5,260.7v-193.2L1809.2,1578L1809.2,1578
|
||||
L1809.2,1578z"/>
|
||||
<polygon style="fill:#FFFFFF;" points="1692.1,1509.6 1528.8,1605.3 1528.8,1413 1692.1,1316.4 1692.1,1509.6 "/>
|
||||
<path style="fill:#FFFFFF;" d="M1692.1,986.4l0.9,193.2l-281.2,165v330.8l-163.3,95.7l-163.3-95.7v-330.8l-281.2-165V986.4
|
||||
L968,889.8l279.5,165.8l281.2-165.8l164.1,96.6H1692.1L1692.1,986.4z M803.9,656.5l443.7-261.6l444.5,261.6l-163.3,96.6
|
||||
l-281.2-165.8L967.2,753.1L803.9,656.5L803.9,656.5z"/>
|
||||
</g>
|
||||
</svg>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.6 KiB |
@@ -1,5 +0,0 @@
|
||||
<svg width="250" height="250" viewBox="0 0 250 250" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect width="250" height="250" rx="40" fill="#FCFF52"/>
|
||||
<path style="fill:black;" d="M188.9,60.7H60.7v128.2h128.2v-44.8h-21.3c-7.3,16.3-23.8,27.7-42.7,27.7c-26,0-47.1-21.3-47.1-47.1c0-25.9,21.1-47,47.1-47
|
||||
c19.3,0,35.8,11.7,43.1,28.4h20.9V60.7z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 398 B |
@@ -1,16 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect x="0" y="0" width="16" height="16" rx="3" fill="#627EEA"/>
|
||||
<circle cx="8" cy="8" r="8"/>
|
||||
<g clip-path="url(#clip0_12246_121533)">
|
||||
<circle cx="8" cy="8" r="8" fill="url(#pattern0)"/>
|
||||
</g>
|
||||
<defs>
|
||||
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0_12246_121533" transform="scale(0.0078125)"/>
|
||||
</pattern>
|
||||
<clipPath id="clip0_12246_121533">
|
||||
<rect x="0" y="0" width="16" height="16" rx="8" fill="white"/>
|
||||
</clipPath>
|
||||
<image id="image0_12246_121533" width="128" height="128" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAADd9JREFUeNrtXdtzE+cV38kweWpm+tI8JZP8EZ0pL+UhferkfyAzFqEpadq0hbRNUlsYQ2ycBEgCgQQIgVxMbC6BAHbEJZg7dW4OpeCWwDTNDOyuLFuybMsXfT2/tWVkWavd1e5K58g6M9+Q8cTS+ju//b5z/R1Nq0F5Ppr46cpm8xcroubyFU3m+oYmY39Do97d0KRfoH/76d/b9K9JP89Yy/pv62f9s/9PN34Hv4vPwGfhM7W68JNVUfWTp9fqv440Ge2RRqOXFHiPFKhCWfTZ+A58F74T313XQIUlGlUP0lv5RCRqtkQa9YukjMnQFO6w8N3WM9Cz4JnwbHUNhSQrovGlkSZ9K216vFoKdwGIOJ4Rz1rXWADyTDTxeCSqv0wbe5Or0kuA4SaeHX9DXZMepSFq/Jw28FBDo5GVpviFy8hafwv9TXXNOh3zzfov6Qjtka90u1NB78HfWNd0gUTWmr+yLPgaVfwCIMCToL+5/sZH44+Qa9W5WBRfxK3sxB4sRlduSSRqrKYjMbVolX//WkhhL7Ani+O4j+rL6Ai8ttgVX+RauIa9qfG3Xm+tDcs+RI+B9qjmToNVLfFHKWJ2vq5gt6eBfr5mbIPIWuNJK9lSV6zXZWLvJB/5D1AApK1+5PsOIrVhL8UlbMiy7agrMKArgfZSTKKpoc14iHLpMUkb/OZHQ6pxa5x5zID2lPaWefIm9TC5M32SlP/MOl0Zg1PqWG9aUY6fu6vY99yG1M94GnsticfozhqQdryeOJ9W09NZ9cU/Rq2TQIBdMIC9ZvfmS1T+39+Kq6mp7BwATl8dVX/caIoAAfaczZ0v7djPrYE7EwqSAwDW/u6UlMhhX9VtAlim0gy+3Np9KKlykg8ArPXvDApJJhmxqnkHlp8v1NV77hVDJUembQHQfSFtGYeCXMTKxwlmgjwy/erevlGVL4UAwHqna1hS+VlbFcK7MiN8698dVNls1hEAWC+8bsqJGFYqbIzEjtTY/oqorn64O6kKxQ4AB0+NIF8vJncA3YSf0hWc1YOFX0zsAIDVvichKosYaip5Jp8vU/l/ftVUY+NZzwCIXRpVz24wBOUN9NbQKnkkZ/a+vD6u7KQUALDeP5KUVlSyLISjX24Z16Z9Q6qUOAEA6+U344KuAuNaoFcBoWqNVOX/pllXOiV7/ALg6NkR9XRUVC3BmsBKtyVX70JxTuIGAFhvfDgkKDagpwIpKyPLskuq8l98I64mJ7OBAeD0lVH1fJshySvo8t2xI7mS5vr3GeVG3AIA6+MTKVF74KsDSXK7FkK5bsULALCatw9KMgh7y27UlKp8+O1DqenQAIAiEhiXYiKg5TSkSu7SxV3tRbwCAGt7p6Rkkd7jze2jXnapysfxDIWGDQCs1a+ZcvbGCz/BDDmDyEZLdefHCeVVygXAgZicZBF06rK+L/G41JDvh8eSqhwpFwBYbbsTYkLEruhqwGsjUfko5hwdm644AGKX0mrVehmxAejWTdh3QCIArvSPqXLFDwCwdh9OSrkGbjqFfZdKVP6rlLP3I34BgPXiFhnJopIUduC4k6b8ldTNc9ecrDoAjpwZsSqOBBjKW+0bOhmTMNqtw6dHlF8JAgBYSDsLuAbiRUvJQXUqTfl/3WyqiYksGwCcogDU71sNAdeA+UQR699skQaA7/6dUUFIUADAgivK3xswW4qlfS9KUv62/cMqKAkSAFjRbbyTRdD1/FJvoj2vJuu217WqxVCDw1NsAXD8XNoyThnbAZPzqO7BfS/p7f/8YloFKUEDAGtrB2+DEDrPj/23S1F+07a452RPNQBwhlrNUYrO+BRoF1n4ceuHiUCVjzax67cy6pOeVOAg6Pw8xdgOyCsUCXXMSoAL9flBSYbcR/QKwHWDsta+PahadyXU3qNJq54gKBBs2MnUICSdW8rHMCQJyod/PTI67VvxQ8lpdfGbsQVKBgByC/wAOw8Mqx6yNfwCAPbKb1t47qk1CAsTsSQA4MLXY74U/6M+qc5SW/gZG0XlAyC31lFxyVtkzKG03A8Idh7kWT0E3dP9bz7FXfk4msuVgTsZetud3+RiAMhfm/YlrDu9XBAgaskwIrgc+f8NrN0VSrDg7fUiE9QL8PUNut8vuz/CnQCQWxupAOSDz5IWoZQXACBnwa16CLrXZocqsgVAVyzlWvGgfbn07ZirN75cAMzZCUQ0sYuO9pgHO+G195lVD5HuWVf/riGGjvGMs89/15hUvV/a3+9hACC3mncMqm1kJxxzYSecujxq8ROxqhbmnAP45sZ4ScX/578ZdSYgl61cAOSvzWQnHIiVthP2HU3yygk0YF4uU/7eYjJJxI7f3oT/ng40aBMEAHKr/b2ElRW0sxMY8RL3a7NDk9nx95qJ+ckexACufDcWaJAmLADk1gayE3YfGlYnL80HKxteYtK9xpHwCdm0nNyLT6lzX83E1sNQfJgAmIsnUGBp+/4hdbz3PhCY8BKb2uz4dHb8vbf/NxG60isFgDmDkQJLW4hj4OCpFA9eYtI9OwAcOzcyF5+v5KoEAObZCXvIaPxgiAEAmF0BSKGCzq3WAfA3KiNn0GFssjQCc02ex3rTNQcAXHG/40I7N2sE9nMOA2+hYxIBFOkAQJ0g7nxm4WDLDbwggd17z6dJsQAA5zDLcTSke5wA3XL6AOIWf68UALxEJFVcawFmVze7ZJBT2hRH6Cs7E6rnAt9IICJ9bhpE/lBtxjErGcQsHbyRwqiXKaPnxL6BaCF6A05f5QOAKC14MU73fO5KA41dVesBmsz1aAlbzu1ogvWPmj3k0J1cJRhWHx1PVR0AuJ5WNjuWYltkk4hzcIgEWgUhHEvCYP3nqn+RE8Cb7vQ7OHaPfjFScQDArXvWBUEE3FqEuPFdqHHg4A1YJWFci0L/sokYP8bvF4HeuJ2xegKcBkKg6OLk5fABALfODWsorrL8knPQz3NpILWKQjmXhReSPaKBA/kBpw3EG7mLsnBhAQCFKk7E0Whfe/fAwmdYt2OQiwt4T0RjCEq4CyVNqWHc+06EDPC/u2KpwAAAo81pmhieCYwlsUsLvRSMqmPZGMK5NQxvkh6fsi31dlNnhzp/sHuWCwDYF25KuWAPgCnEjm5+JSN20XmtYdybQ3FsIkVsJ6gAdoofYPNhedsVlNi5dX9qd3brYAugAsiWZfwqvwlk85pDJbSHoya/lIAWHlY2TgynDiPU5TkBAEaoU4s3XFR0ATvFIl7fy6saeEF7uASCCLyFbujf0fq1y0Unzks0AubTvON6LnxLP3cCERbKvbpdRCM7GNLLLyCIkEIRg+M4lXbXH/g9VRS1OMwABqgQeUT/HlxMN6FZXDUHTrqLNyBczXHiWFGKGCkkUYikeWn9Rk8hgOMUVnbyKJDDf++wt4wko+pfZ5IoSTRxqA/wIpgXCHewHNoW+Pub93mvSeBKJ29LEyeJKBIWfbERsE4Cd9JLDB5eQDlVSchhcJ0wZksUKY0qFj53uRyB/yRGkFJzAJHR6yizLhGJHqcrhy1V7GxQ6KYUEMCd88MLhJxBfn0eijd2dA77yiqilV0sWbREuviv/jXuizgCXgVoYXLegB/lc+r7K5suXtrACIRo/XIGBsEShiCUU55AxMAIiSNjQNrghzpuMdDFux4ZI3Vo1Gdn01UDAJM+v9LLy9AoiWPjVkTL5xD0AwDkKLgPjvI8Nk7q4MgXCqqIwgYAcv4i6OHLGRwpdXSsl5GxfgHAprrHbeHHYhke7ZVTsBwAoORMwl74Gh49Wy/YKQ0ASOfei0+FBgBUH6+UMDuYdKf5FQodPkJGREoaCHA8T05lAwcAij/WCBgZC51Bd1oQEokaqyVeBU5VROUAgB3Xn23Uz1itBSWUPlxCxsQ1aQCwqohuZQIDwMcnUjL+btIVdKYFKRRHXiZxpjAyc2AQ9QsAq7pHxIhYIwtdaWEIfXCrxKsAJBN+AYD0s4yjX2/VwpKZq0A/LxEEpaqInADw9idCXD7STeBHf6Gsaok/ypFb0E8VUSkAHDrFt7qnkPAJutEqIZG1xpMS7QFUAWWKVBHZAQCnRtW5/Nze+6QTrZJC6cU2iVfB3iJVRHYAABOJDG/HaNMqLXTXPEC+ZodEEGBYlBMA9h5JSvH3O6ALrRqC8mLimYlJA0BhFVEhAPhX98xx/MRsS7wrJQ1txkMUeOiTBoK2vCqiQgCA7kVAsKcPe69xkGeiqYfJEBmQBgK0bBcCAJ1HAoy+Aey5xkkiLYnHpIEgV0WUA4CE6h7sMfZa4yhApbTrAH37YBxBdQ+neT52xz67N7+YTSDNMEQfH1i8uBt8bO58N96BVBeRsav3oCZJrDiBFSySFzFkFeGjPayanx9c2Fhe7oBDbL/i4d0wE0hSs4jVyupVLLFTwSthyUw9Qf1KcCjmaA09pVvVK4GqVSSWl1WijCu0Sh6OpwGhfY3EauMwqnexFzX91pcsOW/UuxbxXd8VWOm26GuBulcktqH5adfy3bFTkycCNTFK60r22qVbdqPmYhL0ss+QVNSCx2AFcw557s+vywxdzQxnkbxUs5W1o2d3TctSF0eDcSk47jiTWeLZ8IyOVGx18ZdoAtUp+G5BelxNlnN8t/UM9Cx4JnEJm5oIMxPtObjvMQDB8iTCHH9Dn21Z8PRd+M4FlOt14SEYhoSJWJFG8ylrLiINSIQFPkuJ3z87MNvE+HRrWf9t/ax/5lQhTwS/Q7+Lz8BnzQ1YqjH5P29N0rBVv2N5AAAAAElFTkSuQmCC"/>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 5.4 KiB |
3
src/assets/svg/expando-icon-closed.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.6376 8.86202C11.8982 9.12269 11.8982 9.54407 11.6376 9.80473L8.97089 12.4714C8.84089 12.6014 8.6702 12.6667 8.49954 12.6667C8.32887 12.6667 8.15818 12.6014 8.02818 12.4714L5.36152 9.80473C5.10085 9.54407 5.10085 9.12269 5.36152 8.86202C5.62218 8.60136 6.04356 8.60136 6.30422 8.86202L8.49954 11.0573L10.6948 8.86202C10.9555 8.60136 11.3769 8.60136 11.6376 8.86202ZM6.30422 7.13807L8.49954 4.94275L10.6948 7.13807C10.8248 7.26807 10.9955 7.33338 11.1662 7.33338C11.3369 7.33338 11.5076 7.26807 11.6376 7.13807C11.8982 6.8774 11.8982 6.45602 11.6376 6.19536L8.97089 3.52869C8.71022 3.26802 8.28885 3.26802 8.02818 3.52869L5.36152 6.19536C5.10085 6.45602 5.10085 6.8774 5.36152 7.13807C5.62218 7.39873 6.04356 7.39873 6.30422 7.13807Z" fill="#5E5E5E"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 866 B |
3
src/assets/svg/expando-icon-opened.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.1376 11.5287C11.3982 11.7894 11.3982 12.2107 11.1376 12.4714C11.0076 12.6014 10.8369 12.6667 10.6662 12.6667C10.4955 12.6667 10.3248 12.6014 10.1948 12.4714L7.99954 10.2761L5.80422 12.4714C5.54356 12.7321 5.12218 12.7321 4.86152 12.4714C4.60085 12.2107 4.60085 11.7894 4.86152 11.5287L7.52818 8.86202C7.78885 8.60136 8.21022 8.60136 8.47089 8.86202L11.1376 11.5287ZM7.52818 7.13807C7.65818 7.26807 7.82887 7.33338 7.99954 7.33338C8.1702 7.33338 8.34089 7.26807 8.47089 7.13807L11.1376 4.4714C11.3982 4.21073 11.3982 3.78936 11.1376 3.52869C10.8769 3.26802 10.4555 3.26802 10.1948 3.52869L7.99954 5.724L5.80422 3.52869C5.54356 3.26802 5.12218 3.26802 4.86152 3.52869C4.60085 3.78936 4.60085 4.21073 4.86152 4.4714L7.52818 7.13807Z" fill="#5E5E5E"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 864 B |
|
Before Width: | Height: | Size: 32 KiB |
@@ -1,5 +0,0 @@
|
||||
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="250" cy="250" r="250" fill="#FF0420"/>
|
||||
<path d="M177.133 316.446C162.247 316.446 150.051 312.943 140.544 305.938C131.162 298.808 126.471 288.676 126.471 275.541C126.471 272.789 126.784 269.411 127.409 265.408C129.036 256.402 131.35 245.581 134.352 232.947C142.858 198.547 164.812 181.347 200.213 181.347C209.845 181.347 218.476 182.973 226.107 186.225C233.738 189.352 239.742 194.106 244.12 200.486C248.498 206.74 250.688 214.246 250.688 223.002C250.688 225.629 250.375 228.944 249.749 232.947C247.873 244.08 245.621 254.901 242.994 265.408C238.616 282.546 231.048 295.368 220.29 303.874C209.532 312.255 195.147 316.446 177.133 316.446ZM179.76 289.426C186.766 289.426 192.707 287.362 197.586 283.234C202.59 279.106 206.155 272.789 208.281 264.283C211.158 252.524 213.348 242.266 214.849 233.51C215.349 230.883 215.599 228.194 215.599 225.441C215.599 214.058 209.657 208.366 197.774 208.366C190.768 208.366 184.764 210.43 179.76 214.558C174.882 218.687 171.379 225.004 169.253 233.51C167.001 241.891 164.749 252.149 162.498 264.283C161.997 266.784 161.747 269.411 161.747 272.163C161.747 283.672 167.752 289.426 179.76 289.426Z" fill="white"/>
|
||||
<path d="M259.303 314.57C257.927 314.57 256.863 314.132 256.113 313.256C255.487 312.255 255.3 311.13 255.55 309.879L281.444 187.914C281.694 186.538 282.382 185.412 283.508 184.536C284.634 183.661 285.822 183.223 287.073 183.223H336.985C350.87 183.223 362.003 186.1 370.384 191.854C378.891 197.609 383.144 205.927 383.144 216.81C383.144 219.937 382.769 223.19 382.018 226.567C378.891 240.953 372.574 251.586 363.067 258.466C353.685 265.346 340.8 268.786 324.413 268.786H299.082L290.451 309.879C290.2 311.255 289.512 312.38 288.387 313.256C287.261 314.132 286.072 314.57 284.822 314.57H259.303ZM325.727 242.892C330.98 242.892 335.546 241.453 339.424 238.576C343.427 235.699 346.054 231.571 347.305 226.192C347.68 224.065 347.868 222.189 347.868 220.563C347.868 216.935 346.805 214.183 344.678 212.307C342.551 210.305 338.924 209.305 333.795 209.305H311.278L304.148 242.892H325.727Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.1 KiB |
@@ -1 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 500 500"><defs><style>.cls-1{fill:url(#linear-gradient);}</style><linearGradient id="linear-gradient" x1="54.83" y1="392.31" x2="459.03" y2="97.58" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#a726c1"/><stop offset=".88" stop-color="#803bdf"/><stop offset="1" stop-color="#7b3fe4"/></linearGradient></defs><path class="cls-1" d="m364.03,335.08l111.55-64.4c5.9-3.41,9.57-9.76,9.57-16.58V125.28c0-6.81-3.67-13.17-9.57-16.58l-111.55-64.4c-5.9-3.41-13.24-3.4-19.14,0l-111.55,64.4c-5.9,3.41-9.57,9.76-9.57,16.58v230.19l-78.22,45.15-78.22-45.15v-90.33l78.22-45.15,51.6,29.78v-60.59l-42.03-24.26c-2.9-1.67-6.21-2.55-9.57-2.55s-6.67.88-9.57,2.55L24.42,229.33c-5.9,3.41-9.57,9.76-9.57,16.58v128.81c0,6.81,3.67,13.17,9.57,16.58l111.55,64.41c5.9,3.4,13.23,3.4,19.14,0l111.55-64.4c5.9-3.41,9.57-9.77,9.57-16.58v-230.19l1.41-.81,76.81-44.34,78.22,45.16v90.32l-78.22,45.16-51.52-29.74v60.59l41.95,24.23c5.9,3.4,13.24,3.4,19.14,0Z"/></svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -1 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 500 500"><defs><style>.cls-1{fill:#fff;}.cls-2{fill:url(#linear-gradient);}</style><linearGradient id="linear-gradient" x1="-116.09" y1="25.97" x2="437.45" y2="364.71" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#a229c5"/><stop offset="1" stop-color="#7b3fe4"/></linearGradient></defs><rect class="cls-2" x="-18.1" y="-18.1" width="536.2" height="536.2"/><path class="cls-1" d="m320.83,302.85l69.29-40.01c3.67-2.12,5.94-6.06,5.94-10.3v-80.01c0-4.23-2.28-8.18-5.94-10.3l-69.29-40.01c-3.67-2.12-8.22-2.11-11.89,0l-69.29,40.01c-3.67,2.12-5.94,6.07-5.94,10.3v142.99l-48.59,28.05-48.59-28.05v-56.11l48.59-28.05,32.05,18.5v-37.64l-26.11-15.07c-1.8-1.04-3.86-1.59-5.95-1.59s-4.15.55-5.94,1.59l-69.29,40.01c-3.67,2.12-5.94,6.06-5.94,10.3v80.01c0,4.23,2.28,8.18,5.94,10.3l69.29,40.01c3.66,2.11,8.22,2.11,11.89,0l69.29-40c3.67-2.12,5.94-6.07,5.94-10.3v-142.99l.88-.5,47.71-27.55,48.59,28.05v56.11l-48.59,28.05-32-18.48v37.64l26.06,15.05c3.67,2.11,8.22,2.11,11.89,0Z"/></svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -9,7 +9,7 @@ import { Power } from 'components/Icons/Power'
|
||||
import { Settings } from 'components/Icons/Settings'
|
||||
import { AutoRow } from 'components/Row'
|
||||
import { LoadingBubble } from 'components/Tokens/loading'
|
||||
import { DeltaArrow, formatDelta } from 'components/Tokens/TokenDetails/Delta'
|
||||
import { DeltaArrow } from 'components/Tokens/TokenDetails/Delta'
|
||||
import Tooltip from 'components/Tooltip'
|
||||
import { getConnection } from 'connection'
|
||||
import { useDisableNFTRoutes } from 'hooks/useDisableNFTRoutes'
|
||||
@@ -161,7 +161,7 @@ export default function AuthenticatedHeader({ account, openSettings }: { account
|
||||
const clearCollectionFilters = useWalletCollections((state) => state.clearCollectionFilters)
|
||||
const isClaimAvailable = useIsNftClaimAvailable((state) => state.isClaimAvailable)
|
||||
const shouldShowBuyFiatButton = useIsNotOriginCountry('GB')
|
||||
const { formatNumber } = useFormatter()
|
||||
const { formatNumber, formatPercent } = useFormatter()
|
||||
|
||||
const shouldDisableNFTRoutes = useDisableNFTRoutes()
|
||||
|
||||
@@ -284,7 +284,7 @@ export default function AuthenticatedHeader({ account, openSettings }: { account
|
||||
{`${formatNumber({
|
||||
input: Math.abs(absoluteChange as number),
|
||||
type: NumberType.PortfolioBalance,
|
||||
})} (${formatDelta(percentChange)})`}
|
||||
})} (${formatPercent(percentChange)})`}
|
||||
</ThemedText.BodySecondary>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -21,6 +21,7 @@ import { gqlToCurrency, logSentryErrorForUnsupportedChain, supportedChainIdFromG
|
||||
import ms from 'ms'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { isAddress } from 'utils'
|
||||
import { isSameAddress } from 'utils/addresses'
|
||||
import { NumberType, useFormatter } from 'utils/formatNumbers'
|
||||
|
||||
import { MOONPAY_SENDER_ADDRESSES, OrderStatusTable, OrderTextTable } from '../constants'
|
||||
@@ -77,10 +78,6 @@ const COMMON_CONTRACTS: { [key: string]: Partial<Activity> | undefined } = {
|
||||
},
|
||||
}
|
||||
|
||||
function isSameAddress(a?: string, b?: string) {
|
||||
return a === b || a?.toLowerCase() === b?.toLowerCase() // Lazy-lowercases the addresses
|
||||
}
|
||||
|
||||
function callsPositionManagerContract(assetActivity: TransactionActivity) {
|
||||
const supportedChain = supportedChainIdFromGQLChain(assetActivity.chain)
|
||||
if (!supportedChain) return false
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import { BigNumber } from '@ethersproject/bignumber'
|
||||
import { ChainId, WETH9 } from '@uniswap/sdk-core'
|
||||
import { FeeAmount, Pool, Position } from '@uniswap/v3-sdk'
|
||||
import { USDC_MAINNET } from 'constants/tokens'
|
||||
import { mocked } from 'test-utils/mocked'
|
||||
import { owner, useMultiChainPositionsReturnValue } from 'test-utils/pools/fixtures'
|
||||
import { render } from 'test-utils/render'
|
||||
|
||||
import Pools from '.'
|
||||
@@ -12,53 +9,6 @@ jest.mock('./useMultiChainPositions')
|
||||
|
||||
jest.spyOn(console, 'warn').mockImplementation()
|
||||
|
||||
const owner = '0xf5b6bb25f5beaea03dd014c6ef9fa9f3926bf36c'
|
||||
|
||||
const pool = new Pool(
|
||||
USDC_MAINNET,
|
||||
WETH9[ChainId.MAINNET],
|
||||
FeeAmount.MEDIUM,
|
||||
'1851127709498178402383049949138810',
|
||||
'7076437181775065414',
|
||||
201189
|
||||
)
|
||||
|
||||
const position = new Position({
|
||||
pool,
|
||||
liquidity: 1341008833950736,
|
||||
tickLower: 200040,
|
||||
tickUpper: 202560,
|
||||
})
|
||||
const details = {
|
||||
nonce: BigNumber.from('0'),
|
||||
tokenId: BigNumber.from('0'),
|
||||
operator: '0x0',
|
||||
token0: USDC_MAINNET.address,
|
||||
token1: WETH9[ChainId.MAINNET].address,
|
||||
fee: FeeAmount.MEDIUM,
|
||||
tickLower: -100,
|
||||
tickUpper: 100,
|
||||
liquidity: BigNumber.from('9000'),
|
||||
feeGrowthInside0LastX128: BigNumber.from('0'),
|
||||
feeGrowthInside1LastX128: BigNumber.from('0'),
|
||||
tokensOwed0: BigNumber.from('0'),
|
||||
tokensOwed1: BigNumber.from('0'),
|
||||
}
|
||||
const useMultiChainPositionsReturnValue = {
|
||||
positions: [
|
||||
{
|
||||
owner,
|
||||
chainId: ChainId.MAINNET,
|
||||
position,
|
||||
pool,
|
||||
details,
|
||||
inRange: true,
|
||||
closed: false,
|
||||
},
|
||||
],
|
||||
loading: false,
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
mocked(useMultiChainPositions).mockReturnValue(useMultiChainPositionsReturnValue)
|
||||
})
|
||||
|
||||
@@ -6,6 +6,7 @@ import { TraceEvent } from 'analytics'
|
||||
import { useToggleAccountDrawer } from 'components/AccountDrawer'
|
||||
import Row from 'components/Row'
|
||||
import { MouseoverTooltip } from 'components/Tooltip'
|
||||
import { BIPS_BASE } from 'constants/misc'
|
||||
import { useFilterPossiblyMaliciousPositions } from 'hooks/useFilterPossiblyMaliciousPositions'
|
||||
import { useSwitchChain } from 'hooks/useSwitchChain'
|
||||
import { EmptyWalletModule } from 'nft/components/profile/view/EmptyWalletContent'
|
||||
@@ -162,7 +163,7 @@ function PositionListItem({ positionInfo }: { positionInfo: PositionInfo }) {
|
||||
</ThemedText.SubHeader>
|
||||
</Row>
|
||||
}
|
||||
descriptor={<ThemedText.BodySmall>{`${pool.fee / 10000}%`}</ThemedText.BodySmall>}
|
||||
descriptor={<ThemedText.BodySmall>{`${pool.fee / BIPS_BASE}%`}</ThemedText.BodySmall>}
|
||||
right={
|
||||
<>
|
||||
<MouseoverTooltip
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ChainId } from '@uniswap/sdk-core'
|
||||
import { BRIDGED_USDC_ARBITRUM, DAI, DAI_ARBITRUM_ONE, USDC_MAINNET } from 'constants/tokens'
|
||||
import { DAI, DAI_ARBITRUM_ONE, USDC_ARBITRUM, USDC_MAINNET } from 'constants/tokens'
|
||||
import { render } from 'test-utils/render'
|
||||
|
||||
import { PortfolioLogo } from './PortfolioLogo'
|
||||
@@ -12,7 +12,7 @@ describe('PortfolioLogo', () => {
|
||||
|
||||
it('renders with L2 icon', () => {
|
||||
const { container } = render(
|
||||
<PortfolioLogo chainId={ChainId.ARBITRUM_ONE} currencies={[DAI_ARBITRUM_ONE, BRIDGED_USDC_ARBITRUM]} />
|
||||
<PortfolioLogo chainId={ChainId.ARBITRUM_ONE} currencies={[DAI_ARBITRUM_ONE, USDC_ARBITRUM]} />
|
||||
)
|
||||
expect(container).toMatchSnapshot()
|
||||
})
|
||||
|
||||
@@ -2,8 +2,8 @@ import { ChainId, Currency } from '@uniswap/sdk-core'
|
||||
import blankTokenUrl from 'assets/svg/blank_token.svg'
|
||||
import { ReactComponent as UnknownStatus } from 'assets/svg/contract-interaction.svg'
|
||||
import { MissingImageLogo } from 'components/Logo/AssetLogo'
|
||||
import { ChainLogo, getDefaultBorderRadius } from 'components/Logo/ChainLogo'
|
||||
import { Unicon } from 'components/Unicon'
|
||||
import { getChainInfo } from 'constants/chainInfo'
|
||||
import useTokenLogoSource from 'hooks/useAssetLogoSource'
|
||||
import useENSAvatar from 'hooks/useENSAvatar'
|
||||
import React from 'react'
|
||||
@@ -48,25 +48,14 @@ const ENSAvatarImg = styled.img`
|
||||
width: 40px;
|
||||
`
|
||||
|
||||
const StyledChainLogo = styled.img`
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
`
|
||||
|
||||
const SquareChainLogo = styled.img`
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
`
|
||||
|
||||
const CircleLogoImage = styled.img<{ size: string }>`
|
||||
width: ${({ size }) => size};
|
||||
height: ${({ size }) => size};
|
||||
border-radius: 50%;
|
||||
`
|
||||
|
||||
const L2LogoContainer = styled.div<{ hasSquareLogo?: boolean }>`
|
||||
background-color: ${({ theme, hasSquareLogo }) => (hasSquareLogo ? theme.surface2 : theme.neutral1)};
|
||||
border-radius: 2px;
|
||||
const L2LogoContainer = styled.div`
|
||||
border-radius: ${getDefaultBorderRadius(16)}px;
|
||||
height: 16px;
|
||||
left: 60%;
|
||||
position: absolute;
|
||||
@@ -152,27 +141,21 @@ interface PortfolioLogoProps {
|
||||
|
||||
function SquareL2Logo({ chainId }: { chainId: ChainId }) {
|
||||
if (chainId === ChainId.MAINNET) return null
|
||||
const { squareLogoUrl, logoUrl } = getChainInfo(chainId)
|
||||
|
||||
const chainLogo = squareLogoUrl ?? logoUrl
|
||||
|
||||
return (
|
||||
<L2LogoContainer hasSquareLogo={!!squareLogoUrl}>
|
||||
{squareLogoUrl ? (
|
||||
<SquareChainLogo src={chainLogo} alt="chainLogo" />
|
||||
) : (
|
||||
<StyledChainLogo src={chainLogo} alt="chainLogo" />
|
||||
)}
|
||||
<L2LogoContainer>
|
||||
<ChainLogo chainId={chainId} />
|
||||
</L2LogoContainer>
|
||||
)
|
||||
}
|
||||
|
||||
// TODO(WEB-2983)
|
||||
/**
|
||||
* Renders an image by prioritizing a list of sources, and then eventually a fallback contract icon
|
||||
*/
|
||||
export function PortfolioLogo(props: PortfolioLogoProps) {
|
||||
return (
|
||||
<StyledLogoParentContainer>
|
||||
<StyledLogoParentContainer style={props.style}>
|
||||
{getLogo(props)}
|
||||
<SquareL2Logo chainId={props.chainId} />
|
||||
</StyledLogoParentContainer>
|
||||
|
||||
@@ -2,7 +2,7 @@ import { BrowserEvent, InterfaceElementName, SharedEventName } from '@uniswap/an
|
||||
import { TraceEvent } from 'analytics'
|
||||
import { useCachedPortfolioBalancesQuery } from 'components/PrefetchBalancesWrapper/PrefetchBalancesWrapper'
|
||||
import Row from 'components/Row'
|
||||
import { DeltaArrow, formatDelta } from 'components/Tokens/TokenDetails/Delta'
|
||||
import { DeltaArrow } from 'components/Tokens/TokenDetails/Delta'
|
||||
import { TokenBalance } from 'graphql/data/__generated__/types-and-hooks'
|
||||
import { getTokenDetailsURL, gqlToCurrency, logSentryErrorForUnsupportedChain } from 'graphql/data/util'
|
||||
import { useAtomValue } from 'jotai/utils'
|
||||
@@ -71,6 +71,7 @@ const TokenNameText = styled(ThemedText.SubHeader)`
|
||||
type PortfolioToken = NonNullable<TokenBalance['token']>
|
||||
|
||||
function TokenRow({ token, quantity, denominatedValue, tokenProjectMarket }: TokenBalance & { token: PortfolioToken }) {
|
||||
const { formatPercent } = useFormatter()
|
||||
const percentChange = tokenProjectMarket?.pricePercentChange?.value ?? 0
|
||||
|
||||
const navigate = useNavigate()
|
||||
@@ -120,7 +121,7 @@ function TokenRow({ token, quantity, denominatedValue, tokenProjectMarket }: Tok
|
||||
</ThemedText.SubHeader>
|
||||
<Row justify="flex-end">
|
||||
<DeltaArrow delta={percentChange} />
|
||||
<ThemedText.BodySecondary>{formatDelta(percentChange)}</ThemedText.BodySecondary>
|
||||
<ThemedText.BodySecondary>{formatPercent(percentChange)}</ThemedText.BodySecondary>
|
||||
</Row>
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -37,11 +37,6 @@ exports[`PortfolioLogo renders with L2 icon 1`] = `
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.c4 {
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
}
|
||||
|
||||
.c2 {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
@@ -49,8 +44,7 @@ exports[`PortfolioLogo renders with L2 icon 1`] = `
|
||||
}
|
||||
|
||||
.c3 {
|
||||
background-color: #222222;
|
||||
border-radius: 2px;
|
||||
border-radius: 4px;
|
||||
height: 16px;
|
||||
left: 60%;
|
||||
position: absolute;
|
||||
@@ -84,17 +78,41 @@ exports[`PortfolioLogo renders with L2 icon 1`] = `
|
||||
/>
|
||||
<img
|
||||
class="c2"
|
||||
src="https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/arbitrum/assets/0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8/logo.png"
|
||||
src="https://raw.githubusercontent.com/Uniswap/assets/master/blockchains/arbitrum/assets/0xaf88d065e77c8cC2239327C5EDb3A432268e5831/logo.png"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="c3"
|
||||
>
|
||||
<img
|
||||
alt="chainLogo"
|
||||
class="c4"
|
||||
src="arbitrum_logo.svg"
|
||||
/>
|
||||
<svg
|
||||
aria-labelledby="titleID"
|
||||
height="16"
|
||||
width="16"
|
||||
>
|
||||
<title
|
||||
id="titleID"
|
||||
>
|
||||
Arbitrum logo
|
||||
</title>
|
||||
<rect
|
||||
fill="#F9F9F9"
|
||||
height="16"
|
||||
rx="4"
|
||||
width="16"
|
||||
/>
|
||||
<rect
|
||||
fill="#00A3FF33"
|
||||
height="16"
|
||||
rx="4"
|
||||
width="16"
|
||||
/>
|
||||
<svg
|
||||
height="16"
|
||||
width="16"
|
||||
>
|
||||
arbitrum.svg
|
||||
</svg>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { animated, useSpring } from 'react-spring'
|
||||
import { animated, useSpring, UseSpringProps } from 'react-spring'
|
||||
import useResizeObserver from 'use-resize-observer'
|
||||
|
||||
type AnimatedDropdownProps = React.PropsWithChildren<{ open: boolean; springProps?: UseSpringProps }>
|
||||
/**
|
||||
* @param open conditional to show content or hide
|
||||
* @param springProps additional props to include in spring animation
|
||||
* @returns Wrapper to smoothly hide and expand content
|
||||
*/
|
||||
export default function AnimatedDropdown({ open, children }: React.PropsWithChildren<{ open: boolean }>) {
|
||||
export default function AnimatedDropdown({ open, springProps, children }: AnimatedDropdownProps) {
|
||||
const { ref, height } = useResizeObserver()
|
||||
|
||||
const props = useSpring({
|
||||
@@ -20,6 +22,7 @@ export default function AnimatedDropdown({ open, children }: React.PropsWithChil
|
||||
clamp: true,
|
||||
velocity: 0.01,
|
||||
},
|
||||
...springProps,
|
||||
})
|
||||
return (
|
||||
<animated.div
|
||||
|
||||
@@ -20,7 +20,7 @@ import { ThemedText } from 'theme/components'
|
||||
import { textFadeIn } from 'theme/styles'
|
||||
import { useFormatter } from 'utils/formatNumbers'
|
||||
|
||||
import { calculateDelta, DeltaArrow, formatDelta } from '../../Tokens/TokenDetails/Delta'
|
||||
import { calculateDelta, DeltaArrow } from '../../Tokens/TokenDetails/Delta'
|
||||
|
||||
const CHART_MARGIN = { top: 100, bottom: 48, crosshair: 72 }
|
||||
|
||||
@@ -52,9 +52,11 @@ interface ChartDeltaProps {
|
||||
|
||||
function ChartDelta({ startingPrice, endingPrice, noColor }: ChartDeltaProps) {
|
||||
const delta = calculateDelta(startingPrice.value, endingPrice.value)
|
||||
const { formatPercent } = useFormatter()
|
||||
|
||||
return (
|
||||
<DeltaContainer>
|
||||
{formatDelta(delta)}
|
||||
{formatPercent(delta)}
|
||||
<DeltaArrow delta={delta} noColor={noColor} />
|
||||
</DeltaContainer>
|
||||
)
|
||||
|
||||
@@ -35,12 +35,12 @@ export default function DoubleCurrencyLogo({
|
||||
<Wrapper sizeraw={size} margin={margin}>
|
||||
{currency0 && (
|
||||
<HigherLogoWrapper>
|
||||
<CurrencyLogo hideL2Icon currency={currency0} size={size.toString() + 'px'} />
|
||||
<CurrencyLogo currency={currency0} size={`${size}px`} />
|
||||
</HigherLogoWrapper>
|
||||
)}
|
||||
{currency1 && (
|
||||
<CoveredLogoWapper sizeraw={size}>
|
||||
<CurrencyLogo hideL2Icon currency={currency1} size={size.toString() + 'px'} />
|
||||
<CurrencyLogo currency={currency1} size={`${size}px`} />
|
||||
</CoveredLogoWapper>
|
||||
)}
|
||||
</Wrapper>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { ChainId } from '@uniswap/sdk-core'
|
||||
import Column from 'components/Column'
|
||||
import { BaseVariant, FeatureFlag, featureFlagSettings, useUpdateFlag } from 'featureFlags'
|
||||
import { BaseVariant, FeatureFlag, featureFlagSettings, useUpdateConfig, useUpdateFlag } from 'featureFlags'
|
||||
import { DynamicConfigName } from 'featureFlags/dynamicConfig'
|
||||
import { useQuickRouteChains } from 'featureFlags/dynamicConfig/quickRouteChains'
|
||||
import { useCurrencyConversionFlag } from 'featureFlags/flags/currencyConversion'
|
||||
import { useFallbackProviderEnabledFlag } from 'featureFlags/flags/fallbackProvider'
|
||||
import { useFotAdjustmentsFlag } from 'featureFlags/flags/fotAdjustments'
|
||||
@@ -8,12 +11,14 @@ import { useInfoLiveViewsFlag } from 'featureFlags/flags/infoLiveViews'
|
||||
import { useInfoPoolPageFlag } from 'featureFlags/flags/infoPoolPage'
|
||||
import { useInfoTDPFlag } from 'featureFlags/flags/infoTDP'
|
||||
import { useMultichainUXFlag } from 'featureFlags/flags/multichainUx'
|
||||
import { useProgressIndicatorV2Flag } from 'featureFlags/flags/progressIndicatorV2'
|
||||
import { useQuickRouteMainnetFlag } from 'featureFlags/flags/quickRouteMainnet'
|
||||
import { TraceJsonRpcVariant, useTraceJsonRpcFlag } from 'featureFlags/flags/traceJsonRpc'
|
||||
import { useUniswapXDefaultEnabledFlag } from 'featureFlags/flags/uniswapXDefault'
|
||||
import { useUniswapXEthOutputFlag } from 'featureFlags/flags/uniswapXEthOutput'
|
||||
import { useUniswapXExactOutputFlag } from 'featureFlags/flags/uniswapXExactOutput'
|
||||
import { useUniswapXSyntheticQuoteFlag } from 'featureFlags/flags/uniswapXUseSyntheticQuote'
|
||||
import { useFeesEnabledFlag } from 'featureFlags/flags/useFees'
|
||||
import { useUpdateAtom } from 'jotai/utils'
|
||||
import { Children, PropsWithChildren, ReactElement, ReactNode, useCallback, useState } from 'react'
|
||||
import { X } from 'react-feather'
|
||||
@@ -218,19 +223,57 @@ function FeatureFlagOption({ value, variant, featureFlag, label }: FeatureFlagPr
|
||||
)
|
||||
}
|
||||
|
||||
interface DynamicConfigDropdownProps {
|
||||
configName: DynamicConfigName
|
||||
label: string
|
||||
options: any[]
|
||||
selected: any[]
|
||||
parser: (opt: string) => any
|
||||
}
|
||||
|
||||
function DynamicConfigDropdown({ configName, label, options, selected, parser }: DynamicConfigDropdownProps) {
|
||||
const updateConfig = useUpdateConfig()
|
||||
const handleSelectChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
const selectedValues = Array.from(e.target.selectedOptions, (opt) => parser(opt.value))
|
||||
// Saved to atom as { [configName]: { [configName]: values } } to match Statsig return format
|
||||
updateConfig(configName, { [configName]: selectedValues })
|
||||
}
|
||||
return (
|
||||
<Row key={configName}>
|
||||
<FlagInfo>
|
||||
<FlagName>{configName}</FlagName>
|
||||
<FlagDescription>{label}</FlagDescription>
|
||||
</FlagInfo>
|
||||
<select multiple onChange={handleSelectChange}>
|
||||
{options.map((opt) => (
|
||||
<option key={opt} value={opt} selected={selected.includes(opt)}>
|
||||
{opt}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
|
||||
export default function FeatureFlagModal() {
|
||||
const open = useModalIsOpen(ApplicationModal.FEATURE_FLAGS)
|
||||
const toggle = useToggleFeatureFlags()
|
||||
const toggleModal = useToggleFeatureFlags()
|
||||
|
||||
return (
|
||||
<Modal open={open}>
|
||||
<FlagsColumn>
|
||||
<Header>
|
||||
Feature Flag Settings
|
||||
<CloseButton onClick={toggle}>
|
||||
<CloseButton onClick={toggleModal}>
|
||||
<X size={24} />
|
||||
</CloseButton>
|
||||
</Header>
|
||||
<FeatureFlagOption
|
||||
variant={BaseVariant}
|
||||
value={useFeesEnabledFlag()}
|
||||
featureFlag={FeatureFlag.feesEnabled}
|
||||
label="Enable Swap Fees"
|
||||
/>
|
||||
<FeatureFlagOption
|
||||
variant={BaseVariant}
|
||||
value={useFallbackProviderEnabledFlag()}
|
||||
@@ -255,6 +298,12 @@ export default function FeatureFlagModal() {
|
||||
featureFlag={FeatureFlag.fotAdjustedmentsEnabled}
|
||||
label="Enable fee-on-transfer UI and slippage adjustments"
|
||||
/>
|
||||
<FeatureFlagOption
|
||||
variant={BaseVariant}
|
||||
value={useProgressIndicatorV2Flag()}
|
||||
featureFlag={FeatureFlag.progressIndicatorV2}
|
||||
label="Refreshed swap progress indicator"
|
||||
/>
|
||||
<FeatureFlagGroup name="Quick routes">
|
||||
<FeatureFlagOption
|
||||
variant={BaseVariant}
|
||||
@@ -262,6 +311,13 @@ export default function FeatureFlagModal() {
|
||||
featureFlag={FeatureFlag.quickRouteMainnet}
|
||||
label="Enable quick routes for Mainnet"
|
||||
/>
|
||||
<DynamicConfigDropdown
|
||||
selected={useQuickRouteChains()}
|
||||
options={Object.values(ChainId).filter((v) => !isNaN(Number(v))) as ChainId[]}
|
||||
parser={Number.parseInt}
|
||||
configName={DynamicConfigName.quickRouteChains}
|
||||
label="Enable quick routes for these chains"
|
||||
/>
|
||||
</FeatureFlagGroup>
|
||||
<FeatureFlagGroup name="UniswapX Flags">
|
||||
<FeatureFlagOption
|
||||
|
||||
17
src/components/FiatOnrampModal/constants.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
export const MOONPAY_SUPPORTED_CURRENCY_CODES = [
|
||||
'eth',
|
||||
'eth_arbitrum',
|
||||
'eth_optimism',
|
||||
'eth_polygon',
|
||||
'weth',
|
||||
'wbtc',
|
||||
'matic_polygon',
|
||||
'polygon',
|
||||
'usdc_arbitrum',
|
||||
'usdc_optimism',
|
||||
'usdc_polygon',
|
||||
'usdc',
|
||||
'usdt',
|
||||
] as const
|
||||
|
||||
export type MoonpaySupportedCurrencyCode = (typeof MOONPAY_SUPPORTED_CURRENCY_CODES)[number]
|
||||
@@ -10,6 +10,8 @@ import { useIsDarkMode } from 'theme/components/ThemeToggle'
|
||||
|
||||
import Circle from '../../assets/images/blue-loader.svg'
|
||||
import Modal from '../Modal'
|
||||
import { MOONPAY_SUPPORTED_CURRENCY_CODES } from './constants'
|
||||
import { getDefaultCurrencyCode, parsePathParts } from './utils'
|
||||
|
||||
const MOONPAY_DARK_BACKGROUND = '#1c1c1e'
|
||||
const Wrapper = styled.div<{ isDarkMode: boolean }>`
|
||||
@@ -55,20 +57,6 @@ const StyledSpinner = styled(CustomLightSpinner)`
|
||||
top: 0;
|
||||
`
|
||||
|
||||
const MOONPAY_SUPPORTED_CURRENCY_CODES = [
|
||||
'eth',
|
||||
'eth_arbitrum',
|
||||
'eth_optimism',
|
||||
'eth_polygon',
|
||||
'weth',
|
||||
'wbtc',
|
||||
'matic_polygon',
|
||||
'polygon',
|
||||
'usdc_arbitrum',
|
||||
'usdc_optimism',
|
||||
'usdc_polygon',
|
||||
]
|
||||
|
||||
export default function FiatOnrampModal() {
|
||||
const { account } = useWeb3React()
|
||||
const theme = useTheme()
|
||||
@@ -76,6 +64,8 @@ export default function FiatOnrampModal() {
|
||||
const closeModal = useCloseModal()
|
||||
const fiatOnrampModalOpen = useModalIsOpen(ApplicationModal.FIAT_ONRAMP)
|
||||
|
||||
const { network, tokenAddress } = parsePathParts(location.pathname)
|
||||
|
||||
const [signedIframeUrl, setSignedIframeUrl] = useState<string | null>(null)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
const [loading, setLoading] = useState(false)
|
||||
@@ -100,7 +90,7 @@ export default function FiatOnrampModal() {
|
||||
body: JSON.stringify({
|
||||
theme: isDarkMode ? 'dark' : 'light',
|
||||
colorCode: theme.accent1,
|
||||
defaultCurrencyCode: 'eth',
|
||||
defaultCurrencyCode: getDefaultCurrencyCode(tokenAddress, network),
|
||||
redirectUrl: swapUrl,
|
||||
walletAddresses: JSON.stringify(
|
||||
MOONPAY_SUPPORTED_CURRENCY_CODES.reduce(
|
||||
@@ -121,7 +111,7 @@ export default function FiatOnrampModal() {
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}, [account, isDarkMode, swapUrl, theme.accent1])
|
||||
}, [account, isDarkMode, network, swapUrl, theme.accent1, tokenAddress])
|
||||
|
||||
useEffect(() => {
|
||||
fetchSignedIframeUrl()
|
||||
|
||||
78
src/components/FiatOnrampModal/utils.test.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { ChainId, WETH9 } from '@uniswap/sdk-core'
|
||||
import {
|
||||
MATIC,
|
||||
USDC_ARBITRUM,
|
||||
USDC_MAINNET,
|
||||
USDC_OPTIMISM,
|
||||
USDC_POLYGON,
|
||||
USDT,
|
||||
WBTC,
|
||||
WETH_POLYGON,
|
||||
} from 'constants/tokens'
|
||||
|
||||
import { getDefaultCurrencyCode, parsePathParts } from './utils'
|
||||
|
||||
describe('getDefaultCurrencyCode', () => {
|
||||
it('NATIVE/arbitrum should return the correct currency code', () => {
|
||||
expect(getDefaultCurrencyCode('NATIVE', 'arbitrum')).toBe('eth_arbitrum')
|
||||
})
|
||||
it('NATIVE/optimism should return the correct currency code', () => {
|
||||
expect(getDefaultCurrencyCode('NATIVE', 'optimism')).toBe('eth_optimism')
|
||||
})
|
||||
it('WETH/polygon should return the correct currency code', () => {
|
||||
expect(getDefaultCurrencyCode(WETH_POLYGON.address, 'polygon')).toBe('eth_polygon')
|
||||
})
|
||||
it('WETH/ethereum should return the correct currency code', () => {
|
||||
expect(getDefaultCurrencyCode(WETH9[ChainId.MAINNET].address, 'ethereum')).toBe('weth')
|
||||
})
|
||||
it('WBTC/ethereum should return the correct currency code', () => {
|
||||
expect(getDefaultCurrencyCode(WBTC.address, 'ethereum')).toBe('wbtc')
|
||||
})
|
||||
it('NATIVE/polygon should return the correct currency code', () => {
|
||||
expect(getDefaultCurrencyCode('NATIVE', 'polygon')).toBe('matic_polygon')
|
||||
})
|
||||
it('MATIC/ethereum should return the correct currency code', () => {
|
||||
expect(getDefaultCurrencyCode(MATIC.address, 'ethereum')).toBe('polygon')
|
||||
})
|
||||
it('USDC/arbitrum should return the correct currency code', () => {
|
||||
expect(getDefaultCurrencyCode(USDC_ARBITRUM.address, 'arbitrum')).toBe('usdc_arbitrum')
|
||||
})
|
||||
it('USDC/optimism should return the correct currency code', () => {
|
||||
expect(getDefaultCurrencyCode(USDC_OPTIMISM.address, 'optimism')).toBe('usdc_optimism')
|
||||
})
|
||||
it('USDC/polygon should return the correct currency code', () => {
|
||||
expect(getDefaultCurrencyCode(USDC_POLYGON.address, 'polygon')).toBe('usdc_polygon')
|
||||
})
|
||||
it('native/ethereum should return the correct currency code', () => {
|
||||
expect(getDefaultCurrencyCode('NATIVE', 'ethereum')).toBe('eth')
|
||||
})
|
||||
it('usdc/ethereum should return the correct currency code', () => {
|
||||
expect(getDefaultCurrencyCode(USDC_MAINNET.address, 'ethereum')).toBe('usdc')
|
||||
})
|
||||
it('usdt/ethereum should return the correct currency code', () => {
|
||||
expect(getDefaultCurrencyCode(USDT.address, 'ethereum')).toBe('usdt')
|
||||
})
|
||||
it('chain/token mismatch should default to eth', () => {
|
||||
expect(getDefaultCurrencyCode(USDC_ARBITRUM.address, 'ethereum')).toBe('eth')
|
||||
expect(getDefaultCurrencyCode(USDC_OPTIMISM.address, 'ethereum')).toBe('eth')
|
||||
expect(getDefaultCurrencyCode(USDC_POLYGON.address, 'ethereum')).toBe('eth')
|
||||
expect(getDefaultCurrencyCode(MATIC.address, 'arbitrum')).toBe('eth')
|
||||
})
|
||||
})
|
||||
|
||||
describe('parseLocation', () => {
|
||||
it('should parse the URL correctly', () => {
|
||||
expect(parsePathParts('/tokens/ethereum/0x2260fac5e5542a773aa44fbcfedf7c193bc2c599')).toEqual({
|
||||
network: 'ethereum',
|
||||
tokenAddress: '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599',
|
||||
})
|
||||
expect(parsePathParts('tokens/ethereum/0x2260fac5e5542a773aa44fbcfedf7c193bc2c599')).toEqual({
|
||||
network: 'ethereum',
|
||||
tokenAddress: '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599',
|
||||
})
|
||||
expect(parsePathParts('/swap')).toEqual({
|
||||
network: undefined,
|
||||
tokenAddress: undefined,
|
||||
})
|
||||
})
|
||||
})
|
||||
72
src/components/FiatOnrampModal/utils.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { ChainId, WETH9 } from '@uniswap/sdk-core'
|
||||
import {
|
||||
MATIC,
|
||||
USDC_ARBITRUM,
|
||||
USDC_MAINNET,
|
||||
USDC_OPTIMISM,
|
||||
USDC_POLYGON,
|
||||
USDT,
|
||||
WBTC,
|
||||
WETH_POLYGON,
|
||||
} from 'constants/tokens'
|
||||
import { Chain } from 'graphql/data/__generated__/types-and-hooks'
|
||||
import { validateUrlChainParam } from 'graphql/data/util'
|
||||
|
||||
import { MoonpaySupportedCurrencyCode } from './constants'
|
||||
|
||||
type MoonpaySupportedChain = Chain.Ethereum | Chain.Polygon | Chain.Arbitrum | Chain.Optimism
|
||||
const moonPaySupportedChains = [Chain.Ethereum, Chain.Polygon, Chain.Arbitrum, Chain.Optimism]
|
||||
|
||||
const CURRENCY_CODES: {
|
||||
[K in MoonpaySupportedChain]: {
|
||||
[key: string]: MoonpaySupportedCurrencyCode
|
||||
native: MoonpaySupportedCurrencyCode
|
||||
}
|
||||
} = {
|
||||
[Chain.Ethereum]: {
|
||||
[WETH9[ChainId.MAINNET]?.address.toLowerCase()]: 'weth',
|
||||
[USDC_MAINNET.address.toLowerCase()]: 'usdc',
|
||||
[USDT.address.toLowerCase()]: 'usdt',
|
||||
[WBTC.address.toLowerCase()]: 'wbtc',
|
||||
[MATIC.address.toLowerCase()]: 'polygon',
|
||||
native: 'eth',
|
||||
},
|
||||
[Chain.Arbitrum]: {
|
||||
[USDC_ARBITRUM.address.toLowerCase()]: 'usdc_arbitrum',
|
||||
native: 'eth_arbitrum',
|
||||
},
|
||||
[Chain.Optimism]: {
|
||||
[USDC_OPTIMISM.address.toLowerCase()]: 'usdc_optimism',
|
||||
native: 'eth_optimism',
|
||||
},
|
||||
[Chain.Polygon]: {
|
||||
[USDC_POLYGON.address.toLowerCase()]: 'usdc_polygon',
|
||||
[WETH_POLYGON.address.toLowerCase()]: 'eth_polygon',
|
||||
native: 'matic_polygon',
|
||||
},
|
||||
}
|
||||
|
||||
export function getDefaultCurrencyCode(
|
||||
address: string | undefined,
|
||||
chainName: string | undefined
|
||||
): MoonpaySupportedCurrencyCode {
|
||||
const chain = validateUrlChainParam(chainName)
|
||||
if (!address || !chain) return 'eth'
|
||||
if (moonPaySupportedChains.includes(chain)) {
|
||||
const code = CURRENCY_CODES[chain as MoonpaySupportedChain]?.[address.toLowerCase()]
|
||||
return code ?? 'eth'
|
||||
}
|
||||
return 'eth'
|
||||
}
|
||||
|
||||
/**
|
||||
* You should use useParams() from react-router-dom instead of this function if possible.
|
||||
* This function is only used in the case where we need to parse the path outside the scope of the router.
|
||||
*/
|
||||
export function parsePathParts(pathname: string): { network?: string; tokenAddress?: string } {
|
||||
const pathParts = pathname.split('/')
|
||||
// Matches the /tokens/<network>/<tokenAddress> path.
|
||||
const network = pathParts.length > 2 ? pathParts[pathParts.length - 2] : undefined
|
||||
const tokenAddress = pathParts.length > 2 ? pathParts[pathParts.length - 1] : undefined
|
||||
return { network, tokenAddress }
|
||||
}
|
||||
22
src/components/Icons/Etherscan.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import { ComponentProps } from 'react'
|
||||
|
||||
export const EtherscanLogo = (props: ComponentProps<'svg'>) => (
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 18 18"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
stroke="transparent"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M5.08042 8.66148C5.08043 8.58693 5.09517 8.51313 5.12378 8.44429C5.1524 8.37546 5.19432 8.31297 5.24716 8.26038C5.30001 8.2078 5.3627 8.16617 5.43167 8.13788C5.50064 8.1096 5.57452 8.09522 5.64907 8.09557L6.59187 8.09865C6.74218 8.09865 6.88635 8.15836 6.99263 8.26465C7.09893 8.37094 7.15865 8.5151 7.15865 8.66543V12.2303C7.26478 12.1988 7.4011 12.1652 7.55026 12.1301C7.65387 12.1058 7.74621 12.0471 7.8123 11.9637C7.87839 11.8803 7.91434 11.777 7.91432 11.6705V7.24848C7.91432 7.09814 7.97403 6.95397 8.08032 6.84766C8.1866 6.74135 8.33077 6.68162 8.4811 6.68158H9.42577C9.57609 6.68162 9.72026 6.74135 9.82655 6.84766C9.93284 6.95397 9.99255 7.09814 9.99255 7.24848V11.3526C9.99255 11.3526 10.2291 11.2569 10.4595 11.1596C10.545 11.1234 10.6181 11.0629 10.6694 10.9854C10.7208 10.908 10.7482 10.8172 10.7483 10.7242V5.83152C10.7483 5.68122 10.808 5.53707 10.9143 5.43078C11.0206 5.32449 11.1647 5.26478 11.315 5.26474H12.2597C12.41 5.26474 12.5542 5.32445 12.6604 5.43075C12.7667 5.53704 12.8265 5.6812 12.8265 5.83152V9.86056C13.6455 9.267 14.4754 8.55315 15.1341 7.69474C15.2297 7.57015 15.2929 7.42383 15.3181 7.26887C15.3434 7.1139 15.3299 6.95509 15.2788 6.8066C14.9739 5.9294 14.4894 5.12551 13.856 4.44636C13.2226 3.76722 12.4544 3.22777 11.6005 2.86256C10.7467 2.49734 9.82602 2.31439 8.89742 2.32542C7.96882 2.33645 7.05275 2.54121 6.20783 2.9266C5.36291 3.31199 4.60774 3.86952 3.99066 4.56352C3.37358 5.25751 2.90817 6.07269 2.62422 6.95689C2.34027 7.84107 2.24403 8.7748 2.34166 9.69832C2.43929 10.6218 2.72863 11.5148 3.19118 12.3201C3.27176 12.459 3.39031 12.572 3.53289 12.6459C3.67548 12.7198 3.83618 12.7514 3.99614 12.7372C4.17482 12.7215 4.3973 12.6992 4.66181 12.6681C4.77695 12.655 4.88326 12.6001 4.96048 12.5137C5.0377 12.4273 5.08043 12.3155 5.08053 12.1996L5.08042 8.66148Z"
|
||||
fill={props.fill ?? '#607BEE'}
|
||||
/>
|
||||
<path
|
||||
d="M5.05957 14.3792C6.05531 15.1036 7.23206 15.5384 8.45961 15.6356C9.68716 15.7326 10.9176 15.4883 12.0149 14.9294C13.1122 14.3705 14.0334 13.519 14.6768 12.4691C15.3201 11.4191 15.6605 10.2116 15.6601 8.98024C15.6601 8.82658 15.653 8.67457 15.6428 8.52344C13.2041 12.1605 8.70139 13.8609 5.05978 14.3786"
|
||||
fill={props.fill ?? '#607BEE'}
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
18
src/components/Icons/Globe.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import { ComponentProps } from 'react'
|
||||
|
||||
export const Globe = (props: ComponentProps<'svg'>) => (
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 18 18"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
stroke="transparent"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M5.12245 9.5625C5.23495 11.8725 6.01495 14.2275 7.37245 16.32C4.19245 15.615 1.76996 12.8925 1.52246 9.5625H5.12245ZM7.37245 1.67999C4.19245 2.38499 1.76996 5.1075 1.52246 8.4375H5.12245C5.23495 6.1275 6.01495 3.77249 7.37245 1.67999ZM9.14997 1.5H8.84995L8.62496 1.82249C7.19996 3.84749 6.36745 6.1725 6.24745 8.4375H11.7525C11.6325 6.1725 10.8 3.84749 9.37496 1.82249L9.14997 1.5ZM6.24745 9.5625C6.36745 11.8275 7.19996 14.1525 8.62496 16.1775L8.84995 16.5H9.14997L9.37496 16.1775C10.8 14.1525 11.6325 11.8275 11.7525 9.5625H6.24745ZM12.8775 9.5625C12.765 11.8725 11.985 14.2275 10.6275 16.32C13.8075 15.615 16.23 12.8925 16.4775 9.5625H12.8775ZM16.4775 8.4375C16.23 5.1075 13.8075 2.38499 10.6275 1.67999C11.985 3.77249 12.765 6.1275 12.8775 8.4375H16.4775Z"
|
||||
fill={props.fill ?? '#607BEE'}
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
18
src/components/Icons/TwitterX.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import { ComponentProps } from 'react'
|
||||
|
||||
export const TwitterXLogo = (props: ComponentProps<'svg'>) => (
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 18 18"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
stroke="transparent"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M12.8761 3H14.9451L10.4251 8.16609L15.7425 15.196H11.579L8.31797 10.9324L4.58662 15.196H2.51644L7.35104 9.67026L2.25 3H6.51922L9.46689 6.89708L12.8761 3ZM12.15 13.9576H13.2964L5.89628 4.17332H4.66605L12.15 13.9576Z"
|
||||
fill={props.fill ?? '#607BEE'}
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
@@ -32,6 +32,13 @@ export const LoadingRows = styled.div`
|
||||
}
|
||||
`
|
||||
|
||||
export const LoadingRow = styled.div<{ height: number; width: number }>`
|
||||
${shimmerMixin}
|
||||
border-radius: 12px;
|
||||
height: ${({ height }) => height}px;
|
||||
width: ${({ width }) => width}px;
|
||||
`
|
||||
|
||||
export const loadingOpacityMixin = css<{ $loading: boolean }>`
|
||||
filter: ${({ $loading }) => ($loading ? 'grayscale(1)' : 'none')};
|
||||
opacity: ${({ $loading }) => ($loading ? '0.6' : '1')};
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { ChainId } from '@uniswap/sdk-core'
|
||||
import { getChainInfo } from 'constants/chainInfo'
|
||||
import useTokenLogoSource from 'hooks/useAssetLogoSource'
|
||||
import React, { useState } from 'react'
|
||||
import styled from 'styled-components'
|
||||
@@ -42,7 +41,6 @@ export type AssetLogoBaseProps = {
|
||||
backupImg?: string | null
|
||||
size?: string
|
||||
style?: React.CSSProperties
|
||||
hideL2Icon?: boolean
|
||||
}
|
||||
type AssetLogoProps = AssetLogoBaseProps & { isNative?: boolean; address?: string | null; chainId?: number }
|
||||
|
||||
@@ -51,19 +49,6 @@ const LogoContainer = styled.div`
|
||||
display: flex;
|
||||
`
|
||||
|
||||
const L2NetworkLogo = styled.div<{ networkUrl?: string; parentSize: string }>`
|
||||
--size: ${({ parentSize }) => `calc(${parentSize} / 2)`};
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 0;
|
||||
background: url(${({ networkUrl }) => networkUrl});
|
||||
background-repeat: no-repeat;
|
||||
background-size: ${({ parentSize }) => `calc(${parentSize} / 2) calc(${parentSize} / 2)`};
|
||||
display: ${({ networkUrl }) => !networkUrl && 'none'};
|
||||
`
|
||||
|
||||
/**
|
||||
* Renders an image by prioritizing a list of sources, and then eventually a fallback triangle alert
|
||||
*/
|
||||
@@ -75,10 +60,8 @@ export default function AssetLogo({
|
||||
backupImg,
|
||||
size = '24px',
|
||||
style,
|
||||
hideL2Icon = false,
|
||||
}: AssetLogoProps) {
|
||||
const [src, nextSrc] = useTokenLogoSource(address, chainId, isNative, backupImg)
|
||||
const L2Icon = getChainInfo(chainId)?.circleLogoUrl
|
||||
const [imgLoaded, setImgLoaded] = useState(() => {
|
||||
const img = document.createElement('img')
|
||||
img.src = src ?? ''
|
||||
@@ -104,7 +87,6 @@ export default function AssetLogo({
|
||||
{symbol?.toUpperCase().replace('$', '').replace(/\s+/g, '').slice(0, 3)}
|
||||
</MissingImageLogo>
|
||||
)}
|
||||
{!hideL2Icon && <L2NetworkLogo networkUrl={L2Icon} parentSize={size} />}
|
||||
</LogoContainer>
|
||||
)
|
||||
}
|
||||
|
||||
122
src/components/Logo/ChainLogo.tsx
Normal file
@@ -0,0 +1,122 @@
|
||||
import { ChainId } from '@uniswap/sdk-core'
|
||||
import { getChainInfo } from 'constants/chainInfo'
|
||||
import { isSupportedChain, SupportedInterfaceChain } from 'constants/chains'
|
||||
import { CSSProperties, FunctionComponent } from 'react'
|
||||
import { useTheme } from 'styled-components'
|
||||
import { useIsDarkMode } from 'theme/components/ThemeToggle'
|
||||
|
||||
import { ReactComponent as arbitrum } from './ChainSymbols/arbitrum.svg'
|
||||
import { ReactComponent as avax } from './ChainSymbols/avax.svg'
|
||||
import { ReactComponent as base } from './ChainSymbols/base.svg'
|
||||
import { ReactComponent as bnb } from './ChainSymbols/bnb.svg'
|
||||
import { ReactComponent as celo } from './ChainSymbols/celo.svg'
|
||||
import { ReactComponent as celoLight } from './ChainSymbols/celo_light.svg'
|
||||
import { ReactComponent as ethereum } from './ChainSymbols/ethereum.svg'
|
||||
import { ReactComponent as optimism } from './ChainSymbols/optimism.svg'
|
||||
import { ReactComponent as polygon } from './ChainSymbols/polygon.svg'
|
||||
|
||||
type SVG = FunctionComponent<React.SVGProps<SVGSVGElement>>
|
||||
type ChainUI = { Symbol: SVG; bgColor: string; textColor: string }
|
||||
|
||||
export function getChainUI(chainId: SupportedInterfaceChain, darkMode: boolean): ChainUI
|
||||
export function getChainUI(chainId: ChainId, darkMode: boolean): ChainUI | undefined {
|
||||
switch (chainId) {
|
||||
case ChainId.MAINNET:
|
||||
case ChainId.GOERLI:
|
||||
case ChainId.SEPOLIA:
|
||||
return {
|
||||
Symbol: ethereum,
|
||||
bgColor: '#6B8AFF33',
|
||||
textColor: '#6B8AFF',
|
||||
}
|
||||
case ChainId.POLYGON:
|
||||
case ChainId.POLYGON_MUMBAI:
|
||||
return {
|
||||
Symbol: polygon,
|
||||
bgColor: '#9558FF33',
|
||||
textColor: '#9558FF',
|
||||
}
|
||||
case ChainId.ARBITRUM_ONE:
|
||||
case ChainId.ARBITRUM_GOERLI:
|
||||
return {
|
||||
Symbol: arbitrum,
|
||||
bgColor: '#00A3FF33',
|
||||
textColor: '#00A3FF',
|
||||
}
|
||||
case ChainId.OPTIMISM:
|
||||
case ChainId.OPTIMISM_GOERLI:
|
||||
return {
|
||||
Symbol: optimism,
|
||||
bgColor: '#FF042033',
|
||||
textColor: '#FF0420',
|
||||
}
|
||||
case ChainId.CELO:
|
||||
case ChainId.CELO_ALFAJORES:
|
||||
return darkMode
|
||||
? {
|
||||
Symbol: celo,
|
||||
bgColor: '#FCFF5233',
|
||||
textColor: '#FCFF52',
|
||||
}
|
||||
: {
|
||||
Symbol: celoLight,
|
||||
bgColor: '#FCFF5299',
|
||||
textColor: '#655947',
|
||||
}
|
||||
case ChainId.AVALANCHE:
|
||||
return {
|
||||
Symbol: avax,
|
||||
bgColor: '#E8414233',
|
||||
textColor: '#E84142',
|
||||
}
|
||||
case ChainId.BNB:
|
||||
return {
|
||||
Symbol: bnb,
|
||||
bgColor: '#EAB20033',
|
||||
textColor: '#EAB200',
|
||||
}
|
||||
case ChainId.BASE:
|
||||
return {
|
||||
Symbol: base,
|
||||
bgColor: '#0052FF33',
|
||||
textColor: '#0052FF',
|
||||
}
|
||||
default:
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
export const getDefaultBorderRadius = (size: number) => size / 2 - 4
|
||||
|
||||
type ChainLogoProps = {
|
||||
chainId: ChainId
|
||||
className?: string
|
||||
size?: number
|
||||
borderRadius?: number
|
||||
style?: CSSProperties
|
||||
testId?: string
|
||||
}
|
||||
export function ChainLogo({
|
||||
chainId,
|
||||
className,
|
||||
style,
|
||||
size = 16,
|
||||
borderRadius = getDefaultBorderRadius(size),
|
||||
testId,
|
||||
}: ChainLogoProps) {
|
||||
const darkMode = useIsDarkMode()
|
||||
const { surface2 } = useTheme()
|
||||
|
||||
if (!isSupportedChain(chainId)) return null
|
||||
const { label } = getChainInfo(chainId)
|
||||
|
||||
const { Symbol, bgColor } = getChainUI(chainId, darkMode)
|
||||
return (
|
||||
<svg width={size} height={size} className={className} style={style} aria-labelledby="titleID" data-testid={testId}>
|
||||
<title id="titleID">{`${label} logo`}</title>
|
||||
<rect rx={borderRadius} fill={surface2} width={size} height={size} />
|
||||
<rect rx={borderRadius} fill={bgColor} width={size} height={size} />
|
||||
<Symbol width={size} height={size} />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
9
src/components/Logo/ChainSymbols/arbitrum.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g opacity="0.9">
|
||||
<path d="M13.2427 13.2169L12.4311 15.3416C12.409 15.4007 12.409 15.465 12.4311 15.5241L13.8274 19.1799L15.4425 18.2896L13.5041 13.2169C13.4601 13.1001 13.2867 13.1001 13.2427 13.2169Z" fill="#00A3FF"/>
|
||||
<path d="M14.8703 9.6438C14.8263 9.52694 14.653 9.52694 14.6089 9.6438L13.7973 11.7685C13.7753 11.8275 13.7753 11.8919 13.7973 11.951L16.0851 17.9362L17.7001 17.0459L14.8703 9.6438Z" fill="#00A3FF"/>
|
||||
<path d="M12.0006 4.99142C12.0405 4.99142 12.0804 5.00192 12.1161 5.0203L18.2752 8.41475C18.3467 8.45415 18.3907 8.52768 18.3907 8.60516V15.3927C18.3907 15.4715 18.3467 15.5437 18.2752 15.5831L12.1161 18.9776C12.0817 18.9973 12.0405 19.0065 12.0006 19.0065C11.9607 19.0065 11.9208 18.996 11.885 18.9776L5.72599 15.5858C5.65446 15.5464 5.61043 15.4728 5.61043 15.3954V8.60647C5.61043 8.52768 5.65446 8.45546 5.72599 8.41607L11.885 5.02162C11.9208 5.00192 11.9607 4.99142 12.0006 4.99142ZM12.0006 4C11.7818 4 11.5617 4.05384 11.365 4.16283L5.20735 7.55596C4.8139 7.77263 4.57178 8.17314 4.57178 8.60647V15.3941C4.57178 15.8274 4.8139 16.2279 5.20735 16.4446L11.3664 19.839C11.5631 19.9467 11.7818 20.0018 12.002 20.0018C12.2207 20.0018 12.4408 19.948 12.6375 19.839L18.7966 16.4446C19.19 16.2279 19.4321 15.8274 19.4321 15.3941V8.60647C19.4321 8.17314 19.19 7.77263 18.7966 7.55596L12.6362 4.16283C12.4394 4.05384 12.2193 4 12.0006 4Z" fill="#00A3FF"/>
|
||||
<path d="M11.4819 8.12061H9.92048C9.80355 8.12061 9.69899 8.1902 9.6591 8.29525L6.31201 17.0538L7.92709 17.9441L11.6126 8.29919C11.647 8.21252 11.5796 8.12061 11.4819 8.12061Z" fill="#00A3FF"/>
|
||||
<path d="M14.2143 8.12061H12.6529C12.536 8.12061 12.4314 8.1902 12.3915 8.29525L8.56982 18.2961L10.1849 19.1864L14.345 8.29919C14.378 8.21252 14.3106 8.12061 14.2143 8.12061Z" fill="#00A3FF"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
10
src/components/Logo/ChainSymbols/avax.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_2121_13838)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.33367 18.0688H5.8578C5.33754 18.0688 5.08056 18.0688 4.92387 17.9685C4.75462 17.8588 4.6512 17.677 4.63867 17.4764C4.62925 17.2916 4.75776 17.0659 5.01475 16.6146L11.128 5.83913C11.3881 5.38156 11.5197 5.15278 11.6858 5.06816C11.8645 4.97728 12.0776 4.97728 12.2562 5.06816C12.4223 5.15278 12.554 5.38156 12.8141 5.83913L14.0709 8.03295L14.0773 8.04415C14.3582 8.53503 14.5007 8.78396 14.5629 9.04523C14.6318 9.33043 14.6318 9.63129 14.5629 9.9165C14.5002 10.1797 14.3592 10.4305 14.074 10.9288L10.8628 16.6052L10.8545 16.6197C10.5717 17.1146 10.4284 17.3655 10.2298 17.5547C10.0135 17.7616 9.75339 17.912 9.46819 17.9967C9.20807 18.0688 8.91661 18.0688 8.33367 18.0688ZM14.5861 18.0688H18.1337C18.6571 18.0688 18.9204 18.0688 19.0772 17.9655C19.2464 17.8558 19.3529 17.6708 19.3624 17.4703C19.3714 17.2914 19.2457 17.0745 18.9994 16.6494C18.9909 16.635 18.9824 16.6202 18.9738 16.6052L17.1967 13.5652L17.1765 13.531C16.9268 13.1087 16.8007 12.8955 16.6388 12.8131C16.4603 12.7222 16.2502 12.7222 16.0716 12.8131C15.9086 12.8977 15.777 13.1202 15.5169 13.5684L13.7462 16.6084L13.7401 16.6188C13.4809 17.0663 13.3513 17.2899 13.3607 17.4734C13.3732 17.674 13.4766 17.8588 13.6459 17.9685C13.7994 18.0688 14.0627 18.0688 14.5861 18.0688Z" fill="#E84142"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_2121_13838">
|
||||
<rect width="24" height="24" rx="8" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
3
src/components/Logo/ChainSymbols/base.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M20 12C20 16.4183 16.412 20 11.986 20C7.78693 20 4.34212 16.7761 4 12.6725H14.5926V11.3275H4C4.34212 7.22393 7.78693 4 11.986 4C16.412 4 20 7.58171 20 12Z" fill="#0052FF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 325 B |
3
src/components/Logo/ChainSymbols/bnb.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.279 11.3421L16.2704 9.48437H16.2771L14.6992 8.55553L11.9954 10.1498L9.30786 8.55553L7.73094 9.48437V11.3421L10.4348 12.9286V16.1094L12.005 17.0296L13.5752 16.1094V12.9286L16.279 11.3421ZM11.9963 3.79688L7.72998 6.31226L9.30017 7.24111L11.9963 5.64687L14.7002 7.24111L16.2704 6.31226L11.9963 3.79688ZM6.60375 15.1726L6.5951 11.9995L5.02586 11.0716V16.1101L9.2999 18.6168V16.7591L6.60375 15.1726ZM6.5951 10.6755V8.82644L8.17298 7.8976L6.5951 6.96875L5.0249 7.8976V9.74663L6.5951 10.6755ZM11.9961 6.96875L10.4259 7.8976L11.9961 8.82644L13.5739 7.8976L11.9961 6.96875ZM9.29968 13.5861L7.72949 12.6572V14.5149L9.29968 15.4351V13.5861ZM11.9958 18.3534L10.4256 17.4245V19.2736L11.9958 20.2024L13.5737 19.2736V17.4245L11.9958 18.3534ZM17.3958 6.96875L15.8256 7.8976L17.3958 8.82644V10.6755L18.9737 9.74663V7.8976L17.3958 6.96875ZM18.9747 11.0707L17.4045 11.9995L17.3958 15.1726L14.7006 16.7582V18.6159L18.9747 16.1091V11.0707ZM16.2699 14.5149L14.6997 15.4351V13.5861L16.2699 12.6572V14.5149Z" fill="#EAB200"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
3
src/components/Logo/ChainSymbols/celo.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M17.9844 5.95312H6.01562V17.9219H17.9844V13.7438H15.9969C15.3125 15.2688 13.7719 16.3281 12.0094 16.3281C9.57812 16.3281 7.60938 14.3406 7.60938 11.9281C7.60625 9.51563 9.57812 7.54688 12.0094 7.54688C13.8063 7.54688 15.3469 8.64062 16.0312 10.2H17.9844V5.95312Z" fill="#FCFF52"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 393 B |
3
src/components/Logo/ChainSymbols/celo_light.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M17.9844 5.95312H6.01562V17.9219H17.9844V13.7438H15.9969C15.3125 15.2688 13.7719 16.3281 12.0094 16.3281C9.57812 16.3281 7.60938 14.3406 7.60938 11.9281C7.60625 9.51563 9.57812 7.54688 12.0094 7.54688C13.8063 7.54688 15.3469 8.64062 16.0312 10.2H17.9844V5.95312Z" fill="#655947" fill-opacity="0.72"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 413 B |
4
src/components/Logo/ChainSymbols/ethereum.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.4817 4.29043L7.08715 11.516C6.91315 11.8019 7.00806 12.1725 7.29743 12.3421L11.692 14.9163C11.8818 15.0279 12.1182 15.0279 12.308 14.9163L16.7026 12.3421C16.9919 12.1725 17.0869 11.8019 16.9129 11.516L12.5192 4.29043C12.2838 3.90319 11.7171 3.90319 11.4817 4.29043Z" fill="#6B8AFF"/>
|
||||
<path d="M15.7897 15.0102C15.7897 14.999 15.7878 14.9888 15.7869 14.9786C15.785 14.9684 15.7831 14.9582 15.7813 14.948C15.7785 14.9359 15.7748 14.9248 15.7711 14.9127C15.7683 14.9035 15.7655 14.8951 15.7608 14.8868C15.7552 14.8738 15.7478 14.8608 15.7404 14.8487C15.7366 14.8422 15.7329 14.8348 15.7283 14.8283C15.7153 14.8098 15.7013 14.7912 15.6846 14.7754C15.6678 14.7597 15.6502 14.7448 15.6316 14.7318C15.625 14.7272 15.6185 14.7244 15.6111 14.7198C15.599 14.7123 15.586 14.7049 15.573 14.6993C15.5646 14.6956 15.5553 14.6928 15.546 14.6891C15.5348 14.6854 15.5228 14.6817 15.5107 14.6789C15.5004 14.6761 15.4902 14.6743 15.48 14.6734C15.4697 14.6715 15.4595 14.6706 15.4484 14.6706C15.4363 14.6706 15.4251 14.6697 15.413 14.6706C15.4046 14.6706 15.3963 14.6724 15.387 14.6734C15.374 14.6752 15.3609 14.6761 15.3479 14.6789C15.3442 14.6789 15.3405 14.6817 15.3368 14.6826C15.2968 14.6928 15.2586 14.7086 15.2233 14.7318L12.3311 16.4363C12.1265 16.5569 11.8735 16.5569 11.6689 16.4363L8.77673 14.7318C8.74139 14.7086 8.70326 14.6928 8.66327 14.6826C8.65955 14.6817 8.65583 14.6799 8.65211 14.6789C8.63909 14.6761 8.62607 14.6752 8.61305 14.6734C8.60468 14.6724 8.59631 14.6715 8.58701 14.6706C8.57492 14.6706 8.56376 14.6706 8.55167 14.6706C8.54144 14.6706 8.53029 14.6724 8.52006 14.6734C8.50983 14.6752 8.4996 14.6771 8.48937 14.6789C8.47728 14.6817 8.46612 14.6854 8.45403 14.6891C8.44473 14.6919 8.43636 14.6956 8.42706 14.6993C8.41404 14.7049 8.40102 14.7123 8.38893 14.7198C8.38242 14.7235 8.37498 14.7272 8.36847 14.7318C8.34987 14.7448 8.33127 14.7587 8.31546 14.7754C8.29965 14.7921 8.28477 14.8098 8.27175 14.8283C8.2671 14.8348 8.26431 14.8413 8.25966 14.8487C8.25222 14.8617 8.24478 14.8738 8.2392 14.8868C8.23548 14.8951 8.23269 14.9044 8.22897 14.9127C8.22525 14.9248 8.22153 14.9359 8.21874 14.948C8.21595 14.9582 8.21409 14.9684 8.21316 14.9786C8.2113 14.9888 8.21037 15 8.21037 15.0102C8.21037 15.0213 8.20944 15.0334 8.21037 15.0445C8.21037 15.0538 8.21223 15.0621 8.21316 15.0714C8.21502 15.0844 8.21595 15.0974 8.21874 15.1095C8.21967 15.115 8.22153 15.1197 8.22339 15.1243C8.23455 15.167 8.25315 15.2069 8.28012 15.244L11.4681 19.7265C11.7275 20.0911 12.2706 20.0911 12.5301 19.7265L15.718 15.244C15.745 15.2069 15.7636 15.167 15.7748 15.1243C15.7757 15.1197 15.7785 15.1141 15.7794 15.1095C15.7822 15.0965 15.7831 15.0844 15.785 15.0714C15.7859 15.0621 15.7869 15.0538 15.7878 15.0445C15.7878 15.0334 15.7878 15.0213 15.7878 15.0102H15.7897Z" fill="#6B8AFF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
4
src/components/Logo/ChainSymbols/optimism.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.21407 16.0001C6.35029 16.0001 5.64303 15.7928 5.0923 15.3783C4.54737 14.9579 4.2749 14.3539 4.2749 13.5782C4.2749 13.4124 4.29229 13.2169 4.32708 12.9801C4.41983 12.4471 4.55317 11.8076 4.72708 11.0556C5.21984 9.01852 6.49522 8 8.54742 8C9.10395 8 9.6083 8.09475 10.0489 8.29016C10.4895 8.47373 10.8373 8.75797 11.0924 9.13695C11.3475 9.51001 11.475 9.95413 11.475 10.4693C11.475 10.6233 11.4576 10.8187 11.4228 11.0556C11.3127 11.7129 11.1851 12.3583 11.0286 12.9801C10.7735 13.9927 10.3387 14.7566 9.71265 15.2599C9.09235 15.7573 8.25756 16.0001 7.21407 16.0001ZM7.37059 14.4013C7.77639 14.4013 8.11843 14.2769 8.40249 14.0341C8.69235 13.7913 8.90105 13.4183 9.02279 12.909C9.1909 12.2103 9.31844 11.6063 9.4054 11.0852C9.43439 10.9312 9.45178 10.7713 9.45178 10.6055C9.45178 9.93045 9.10974 9.59291 8.41988 9.59291C8.01408 9.59291 7.66625 9.71727 7.37639 9.96005C7.09233 10.2028 6.88943 10.5759 6.76769 11.0852C6.63435 11.5826 6.50681 12.1866 6.37348 12.909C6.34449 13.0571 6.3271 13.211 6.3271 13.3768C6.3213 14.0637 6.67493 14.4013 7.37059 14.4013Z" fill="#FF0420"/>
|
||||
<path d="M11.9672 16.0001C11.8796 16.0001 11.817 15.9757 11.7669 15.9209C11.7293 15.8601 11.7168 15.7931 11.7293 15.7139L13.3509 8.28615C13.3634 8.20092 13.4073 8.13394 13.4824 8.07915C13.5513 8.02435 13.6264 8 13.7078 8H16.8321C17.7024 8 18.3974 8.17656 18.9233 8.5236C19.4555 8.87672 19.7247 9.38206 19.7247 10.0457C19.7247 10.2344 19.6997 10.4353 19.6558 10.6423C19.4617 11.5191 19.0673 12.1644 18.4662 12.5845C17.8777 13.0046 17.07 13.2116 16.0432 13.2116H14.4591L13.9207 15.7139C13.9019 15.7992 13.8643 15.8662 13.7892 15.9209C13.7203 15.9757 13.6452 16.0001 13.5638 16.0001H11.9672ZM16.1246 11.6347C16.4564 11.6347 16.7382 11.5495 16.9824 11.3729C17.2328 11.1964 17.3956 10.9468 17.477 10.618C17.502 10.4901 17.5145 10.3745 17.5145 10.277C17.5145 10.0579 17.4457 9.88739 17.3142 9.77171C17.1827 9.64994 16.951 9.58906 16.6317 9.58906H15.223L14.7785 11.6347H16.1246Z" fill="#FF0420"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
3
src/components/Logo/ChainSymbols/polygon.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15.8793 14.9238L19.6748 12.7103C19.8758 12.5934 20 12.3751 20 12.1404V7.71327C20 7.4786 19.8748 7.26022 19.6748 7.14336L15.8793 4.9298C15.6783 4.81295 15.429 4.81295 15.228 4.9298L11.4325 7.14336C11.2315 7.26022 11.1073 7.4786 11.1073 7.71327V15.625L8.44587 17.1767L5.78441 15.625V12.5206L8.44587 10.9689L10.2009 11.9929V9.91054L8.77108 9.07627C8.67247 9.0188 8.55964 8.98815 8.44587 8.98815C8.33209 8.98815 8.21831 9.0188 8.12065 9.07627L4.32521 11.2898C4.12421 11.4067 4 11.6251 4 11.8597V16.2868C4 16.5206 4.12516 16.7399 4.32521 16.8568L8.12065 19.0703C8.32166 19.1872 8.57102 19.1872 8.77203 19.0703L12.5675 16.8568C12.7685 16.7399 12.8927 16.5215 12.8927 16.2868V8.37514L12.941 8.34736L15.5541 6.82344L18.2156 8.37514V11.4795L15.5541 13.0312L13.801 12.0092V14.0915L15.228 14.9238C15.429 15.0407 15.6783 15.0407 15.8793 14.9238Z" fill="#9558FF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 965 B |
@@ -15,7 +15,6 @@ export default function CurrencyLogo(
|
||||
address={props.currency?.wrapped.address}
|
||||
symbol={props.symbol ?? props.currency?.symbol}
|
||||
backupImg={(props.currency as TokenInfo)?.logoURI}
|
||||
hideL2Icon={props.hideL2Icon ?? true}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -1,32 +1,21 @@
|
||||
import { NATIVE_CHAIN_ID } from 'constants/tokens'
|
||||
import { TokenStandard } from 'graphql/data/__generated__/types-and-hooks'
|
||||
import { ChainId } from '@uniswap/sdk-core'
|
||||
import { PortfolioLogo } from 'components/AccountDrawer/MiniPortfolio/PortfolioLogo'
|
||||
import { SearchToken } from 'graphql/data/SearchTokens'
|
||||
import { TokenQueryData } from 'graphql/data/Token'
|
||||
import { TopToken } from 'graphql/data/TopTokens'
|
||||
import { supportedChainIdFromGQLChain } from 'graphql/data/util'
|
||||
import { gqlToCurrency, supportedChainIdFromGQLChain } from 'graphql/data/util'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import AssetLogo, { AssetLogoBaseProps } from './AssetLogo'
|
||||
import { AssetLogoBaseProps } from './AssetLogo'
|
||||
|
||||
export default function QueryTokenLogo(
|
||||
props: AssetLogoBaseProps & {
|
||||
token?: TopToken | TokenQueryData | SearchToken
|
||||
}
|
||||
) {
|
||||
const chainId = props.token?.chain ? supportedChainIdFromGQLChain(props.token?.chain) : undefined
|
||||
const chainId =
|
||||
(props.token?.chain ? supportedChainIdFromGQLChain(props.token?.chain) : ChainId.MAINNET) ?? ChainId.MAINNET
|
||||
const currency = props.token ? gqlToCurrency(props.token) : undefined
|
||||
|
||||
return (
|
||||
<AssetLogo
|
||||
isNative={
|
||||
// TODO(cartcrom): simplify this check after backend fixes token standard on assetActivities tokens
|
||||
!props.token?.address ||
|
||||
props.token?.standard === TokenStandard.Native ||
|
||||
props.token?.address === NATIVE_CHAIN_ID
|
||||
}
|
||||
chainId={chainId}
|
||||
address={props.token?.address}
|
||||
symbol={props.token?.symbol}
|
||||
backupImg={props.token?.project?.logoUrl}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
return <PortfolioLogo currencies={useMemo(() => [currency], [currency])} chainId={chainId} {...props} />
|
||||
}
|
||||
|
||||
@@ -14,10 +14,3 @@ export const ChainSelector = style([
|
||||
background: 'none',
|
||||
}),
|
||||
])
|
||||
|
||||
export const Image = style([
|
||||
sprinkles({
|
||||
width: '24',
|
||||
height: '24',
|
||||
}),
|
||||
])
|
||||
|
||||
@@ -2,6 +2,7 @@ import { t } from '@lingui/macro'
|
||||
import { ChainId } from '@uniswap/sdk-core'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { showTestnetsAtom } from 'components/AccountDrawer/TestnetsToggle'
|
||||
import { ChainLogo } from 'components/Logo/ChainLogo'
|
||||
import { MouseoverTooltip } from 'components/Tooltip'
|
||||
import { getConnection } from 'connection'
|
||||
import { ConnectionType } from 'connection/types'
|
||||
@@ -145,7 +146,7 @@ export const ChainSelector = ({ leftAlign }: ChainSelectorProps) => {
|
||||
{!isSupported ? (
|
||||
<AlertTriangle size={20} color={theme.neutral2} />
|
||||
) : (
|
||||
<img src={info.logoUrl} alt={info.label} className={styles.Image} data-testid="chain-selector-logo" />
|
||||
<ChainLogo chainId={chainId} size={24} testId="chain-selector-logo" />
|
||||
)}
|
||||
{isOpen ? <ChevronUp {...chevronProps} /> : <ChevronDown {...chevronProps} />}
|
||||
</Row>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { ChainId } from '@uniswap/sdk-core'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { TraceEvent } from 'analytics'
|
||||
import Loader from 'components/Icons/LoadingSpinner'
|
||||
import { ChainLogo } from 'components/Logo/ChainLogo'
|
||||
import { getChainInfo } from 'constants/chainInfo'
|
||||
import { CheckMarkIcon } from 'nft/components/icons'
|
||||
import styled, { useTheme } from 'styled-components'
|
||||
@@ -36,14 +37,12 @@ const Container = styled.button<{ disabled: boolean }>`
|
||||
background-color: ${({ disabled, theme }) => (disabled ? 'none' : theme.surface3)};
|
||||
}
|
||||
`
|
||||
|
||||
const Label = styled.div`
|
||||
grid-column: 2;
|
||||
grid-row: 1;
|
||||
font-size: 16px;
|
||||
font-weight: 485;
|
||||
`
|
||||
|
||||
const Status = styled.div`
|
||||
grid-column: 3;
|
||||
grid-row: 1;
|
||||
@@ -51,7 +50,6 @@ const Status = styled.div`
|
||||
align-items: center;
|
||||
width: ${LOGO_SIZE}px;
|
||||
`
|
||||
|
||||
const CaptionText = styled.div`
|
||||
color: ${({ theme }) => theme.neutral2};
|
||||
font-size: 12px;
|
||||
@@ -59,11 +57,6 @@ const CaptionText = styled.div`
|
||||
grid-row: 2;
|
||||
`
|
||||
|
||||
const Logo = styled.img`
|
||||
height: ${LOGO_SIZE}px;
|
||||
width: ${LOGO_SIZE}px;
|
||||
margin-right: 12px;
|
||||
`
|
||||
interface ChainSelectorRowProps {
|
||||
disabled?: boolean
|
||||
targetChain: ChainId
|
||||
@@ -75,7 +68,6 @@ export default function ChainSelectorRow({ disabled, targetChain, onSelectChain,
|
||||
const active = chainId === targetChain
|
||||
const chainInfo = getChainInfo(targetChain)
|
||||
const label = chainInfo?.label
|
||||
const logoUrl = chainInfo?.logoUrl
|
||||
|
||||
const theme = useTheme()
|
||||
|
||||
@@ -88,7 +80,7 @@ export default function ChainSelectorRow({ disabled, targetChain, onSelectChain,
|
||||
if (!disabled) onSelectChain(targetChain)
|
||||
}}
|
||||
>
|
||||
{logoUrl && <Logo src={logoUrl} alt={label} />}
|
||||
<ChainLogo chainId={targetChain} size={LOGO_SIZE} style={{ marginRight: '12px' }} />
|
||||
{label && <Label>{label}</Label>}
|
||||
{disabled && (
|
||||
<CaptionText>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useWeb3React } from '@web3-react/core'
|
||||
import { useTrace } from 'analytics'
|
||||
import clsx from 'clsx'
|
||||
import Badge from 'components/Badge'
|
||||
import { getChainInfo } from 'constants/chainInfo'
|
||||
import { ChainLogo } from 'components/Logo/ChainLogo'
|
||||
import { HistoryDuration, SafetyLevel } from 'graphql/data/__generated__/types-and-hooks'
|
||||
import { useTrendingCollections } from 'graphql/data/nft/TrendingCollections'
|
||||
import { SearchToken } from 'graphql/data/SearchTokens'
|
||||
@@ -107,11 +107,6 @@ function isKnownToken(token: SearchToken) {
|
||||
return token.project?.safetyLevel == SafetyLevel.Verified || token.project?.safetyLevel == SafetyLevel.MediumWarning
|
||||
}
|
||||
|
||||
const ChainLogo = styled.img`
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
margin-right: 8px;
|
||||
`
|
||||
const ChainComingSoonBadge = styled(Badge)`
|
||||
align-items: center;
|
||||
background-color: ${({ theme }) => theme.surface2};
|
||||
@@ -123,6 +118,7 @@ const ChainComingSoonBadge = styled(Badge)`
|
||||
padding: 8px;
|
||||
margin: 16px 16px 4px;
|
||||
width: calc(100% - 32px);
|
||||
gap: 8px;
|
||||
`
|
||||
|
||||
interface SearchBarDropdownProps {
|
||||
@@ -138,7 +134,6 @@ export const SearchBarDropdown = (props: SearchBarDropdownProps) => {
|
||||
const { isLoading } = props
|
||||
const { chainId } = useWeb3React()
|
||||
const showChainComingSoonBadge = chainId && BACKEND_NOT_YET_SUPPORTED_CHAIN_IDS.includes(chainId) && !isLoading
|
||||
const logoUri = getChainInfo(chainId)?.logoUrl
|
||||
|
||||
return (
|
||||
<Column overflow="hidden" className={clsx(styles.searchBarDropdownNft, styles.searchBarScrollable)}>
|
||||
@@ -150,7 +145,7 @@ export const SearchBarDropdown = (props: SearchBarDropdownProps) => {
|
||||
</SuspenseWithPreviousRenderAsFallback>
|
||||
{showChainComingSoonBadge && (
|
||||
<ChainComingSoonBadge>
|
||||
<ChainLogo src={logoUri} />
|
||||
<ChainLogo chainId={chainId} size={20} />
|
||||
<ThemedText.BodySmall color="neutral2" fontSize="14px" fontWeight="400" lineHeight="20px">
|
||||
<ComingSoonText chainId={chainId} />
|
||||
</ThemedText.BodySmall>
|
||||
|
||||
@@ -128,7 +128,7 @@ interface TokenRowProps {
|
||||
export const TokenRow = ({ token, isHovered, setHoveredIndex, toggleOpen, index, eventProperties }: TokenRowProps) => {
|
||||
const addRecentlySearchedAsset = useAddRecentlySearchedAsset()
|
||||
const navigate = useNavigate()
|
||||
const { formatFiatPrice } = useFormatter()
|
||||
const { formatFiatPrice, formatPercent } = useFormatter()
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
const address = !token.address && token.standard === TokenStandard.Native ? 'NATIVE' : token.address
|
||||
@@ -191,7 +191,7 @@ export const TokenRow = ({ token, isHovered, setHoveredIndex, toggleOpen, index,
|
||||
<DeltaArrow delta={token.market?.pricePercentChange?.value} />
|
||||
<ThemedText.BodySmall>
|
||||
<DeltaText delta={token.market?.pricePercentChange?.value}>
|
||||
{Math.abs(token.market?.pricePercentChange?.value ?? 0).toFixed(2)}%
|
||||
{formatPercent(Math.abs(token.market?.pricePercentChange?.value ?? 0))}
|
||||
</DeltaText>
|
||||
</ThemedText.BodySmall>
|
||||
</PriceChangeContainer>
|
||||
|
||||
82
src/components/NavBar/UkBanner.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import { t, Trans } from '@lingui/macro'
|
||||
import { useOpenModal } from 'state/application/hooks'
|
||||
import { ApplicationModal } from 'state/application/reducer'
|
||||
import styled from 'styled-components'
|
||||
import { ButtonText, ThemedText } from 'theme/components'
|
||||
import { Z_INDEX } from 'theme/zIndex'
|
||||
|
||||
export const UK_BANNER_HEIGHT = 65
|
||||
export const UK_BANNER_HEIGHT_MD = 113
|
||||
export const UK_BANNER_HEIGHT_SM = 137
|
||||
|
||||
const BannerWrapper = styled.div`
|
||||
position: relative;
|
||||
display: flex;
|
||||
background-color: ${({ theme }) => theme.surface1};
|
||||
padding: 20px;
|
||||
border-bottom: 1px solid ${({ theme }) => theme.surface3};
|
||||
z-index: ${Z_INDEX.fixed};
|
||||
box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
|
||||
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.md}px`}) {
|
||||
flex-direction: column;
|
||||
}
|
||||
`
|
||||
|
||||
const BannerTextWrapper = styled(ThemedText.BodySecondary)`
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.md}px`}) {
|
||||
@supports (-webkit-line-clamp: 2) {
|
||||
white-space: initial;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.sm}px`}) {
|
||||
@supports (-webkit-line-clamp: 3) {
|
||||
white-space: initial;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const ReadMoreWrapper = styled(ButtonText)`
|
||||
flex-shrink: 0;
|
||||
width: max-content;
|
||||
|
||||
:focus {
|
||||
text-decoration: none;
|
||||
}
|
||||
`
|
||||
|
||||
export const bannerText = t`
|
||||
This web application is provided as a tool for users to interact with the Uniswap Protocol on
|
||||
their own initiative, with no endorsement or recommendation of cryptocurrency trading activities. In doing so,
|
||||
Uniswap is not recommending that users or potential users engage in cryptoasset trading activity, and users or
|
||||
potential users of the web application should not regard this webpage or its contents as involving any form of
|
||||
recommendation, invitation or inducement to deal in cryptoassets.
|
||||
`
|
||||
|
||||
export function UkBanner() {
|
||||
const openDisclaimer = useOpenModal(ApplicationModal.UK_DISCLAIMER)
|
||||
|
||||
return (
|
||||
<BannerWrapper>
|
||||
<BannerTextWrapper lineHeight="24px">{t`UK disclaimer:` + ' ' + bannerText}</BannerTextWrapper>
|
||||
<ReadMoreWrapper>
|
||||
<ThemedText.BodySecondary lineHeight="24px" color="accent1" onClick={openDisclaimer}>
|
||||
<Trans>Read more</Trans>
|
||||
</ThemedText.BodySecondary>
|
||||
</ReadMoreWrapper>
|
||||
</BannerWrapper>
|
||||
)
|
||||
}
|
||||
62
src/components/NavBar/UkDisclaimerModal.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { ButtonEmphasis, ButtonSize, ThemeButton } from 'components/Button'
|
||||
import Column from 'components/Column'
|
||||
import Modal from 'components/Modal'
|
||||
import { X } from 'react-feather'
|
||||
import { useCloseModal, useModalIsOpen } from 'state/application/hooks'
|
||||
import { ApplicationModal } from 'state/application/reducer'
|
||||
import styled from 'styled-components'
|
||||
import { ButtonText, ThemedText } from 'theme/components'
|
||||
|
||||
import { bannerText } from './UkBanner'
|
||||
|
||||
const Wrapper = styled(Column)`
|
||||
padding: 8px;
|
||||
`
|
||||
|
||||
const ButtonContainer = styled(Column)`
|
||||
padding: 8px 12px 4px;
|
||||
`
|
||||
|
||||
const CloseIconWrapper = styled(ButtonText)`
|
||||
display: flex;
|
||||
color: ${({ theme }) => theme.neutral1};
|
||||
justify-content: flex-end;
|
||||
padding: 8px 0px 4px;
|
||||
|
||||
:focus {
|
||||
text-decoration: none;
|
||||
}
|
||||
`
|
||||
|
||||
const StyledThemeButton = styled(ThemeButton)`
|
||||
width: 100%;
|
||||
`
|
||||
|
||||
export function UkDisclaimerModal() {
|
||||
const isOpen = useModalIsOpen(ApplicationModal.UK_DISCLAIMER)
|
||||
const closeModal = useCloseModal()
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onDismiss={closeModal}>
|
||||
<Wrapper gap="md">
|
||||
<CloseIconWrapper onClick={() => closeModal()}>
|
||||
<X size={24} />
|
||||
</CloseIconWrapper>
|
||||
<Column gap="sm">
|
||||
<ThemedText.HeadlineLarge padding="0px 8px" fontSize="24px" lineHeight="32px">
|
||||
<Trans>Disclaimer for UK residents</Trans>
|
||||
</ThemedText.HeadlineLarge>
|
||||
<ThemedText.BodyPrimary padding="8px 8px 12px" lineHeight="24px">
|
||||
{bannerText}
|
||||
</ThemedText.BodyPrimary>
|
||||
</Column>
|
||||
<ButtonContainer gap="md">
|
||||
<StyledThemeButton size={ButtonSize.large} emphasis={ButtonEmphasis.medium} onClick={() => closeModal()}>
|
||||
<Trans>Dismiss</Trans>
|
||||
</StyledThemeButton>
|
||||
</ButtonContainer>
|
||||
</Wrapper>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
@@ -114,7 +114,7 @@ export function AddRemoveTabs({
|
||||
)}
|
||||
</AddRemoveTitleText>
|
||||
{children && <Box style={{ marginRight: '.5rem' }}>{children}</Box>}
|
||||
<SettingsTab autoSlippage={autoSlippage} chainId={chainId} showRoutingSettings={false} />
|
||||
<SettingsTab autoSlippage={autoSlippage} chainId={chainId} hideRoutingSettings />
|
||||
</RowBetween>
|
||||
</Tabs>
|
||||
)
|
||||
|
||||
@@ -1,200 +1,75 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { ChainId } from '@uniswap/sdk-core'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { getChainUI } from 'components/Logo/ChainLogo'
|
||||
import { RowBetween } from 'components/Row'
|
||||
import { getChainInfo } from 'constants/chainInfo'
|
||||
import { isSupportedChain } from 'constants/chains'
|
||||
import { ArrowUpRight } from 'react-feather'
|
||||
import styled from 'styled-components'
|
||||
import { colors } from 'theme/colors'
|
||||
import { ExternalLink, HideSmall } from 'theme/components'
|
||||
import { useDarkModeManager } from 'theme/components/ThemeToggle'
|
||||
import { ExternalLink, HideSmall, ThemedText } from 'theme/components'
|
||||
import { useIsDarkMode } from 'theme/components/ThemeToggle'
|
||||
|
||||
import Column from '../Column'
|
||||
|
||||
const L2Icon = styled.img`
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 16px;
|
||||
`
|
||||
|
||||
const BodyText = styled.div`
|
||||
const BridgeLink = styled(ExternalLink)<{ bgColor: string }>`
|
||||
color: ${({ color }) => color};
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
margin: 8px;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
`
|
||||
const RootWrapper = styled.div`
|
||||
margin-top: 16px;
|
||||
`
|
||||
|
||||
const SHOULD_SHOW_ALERT = {
|
||||
[ChainId.OPTIMISM]: true,
|
||||
[ChainId.OPTIMISM_GOERLI]: true,
|
||||
[ChainId.ARBITRUM_ONE]: true,
|
||||
[ChainId.ARBITRUM_GOERLI]: true,
|
||||
[ChainId.POLYGON]: true,
|
||||
[ChainId.POLYGON_MUMBAI]: true,
|
||||
[ChainId.CELO]: true,
|
||||
[ChainId.CELO_ALFAJORES]: true,
|
||||
[ChainId.BNB]: true,
|
||||
[ChainId.AVALANCHE]: true,
|
||||
[ChainId.BASE]: true,
|
||||
}
|
||||
|
||||
type NetworkAlertChains = keyof typeof SHOULD_SHOW_ALERT
|
||||
|
||||
const BG_COLORS_BY_DARK_MODE_AND_CHAIN_ID: {
|
||||
[darkMode in 'dark' | 'light']: { [chainId in NetworkAlertChains]: string }
|
||||
} = {
|
||||
dark: {
|
||||
[ChainId.POLYGON]:
|
||||
'radial-gradient(100% 93.36% at 0% 6.64%, rgba(160, 108, 247, 0.1) 0%, rgba(82, 32, 166, 0.1) 100%)',
|
||||
[ChainId.POLYGON_MUMBAI]:
|
||||
'radial-gradient(100% 93.36% at 0% 6.64%, rgba(160, 108, 247, 0.1) 0%, rgba(82, 32, 166, 0.1) 100%)',
|
||||
[ChainId.CELO]:
|
||||
'radial-gradient(182.71% 150.59% at 2.81% 7.69%, rgba(90, 190, 170, 0.15) 0%, rgba(80, 160, 40, 0.15) 100%)',
|
||||
[ChainId.CELO_ALFAJORES]:
|
||||
'radial-gradient(182.71% 150.59% at 2.81% 7.69%, rgba(90, 190, 170, 0.15) 0%, rgba(80, 160, 40, 0.15) 100%)',
|
||||
[ChainId.BNB]:
|
||||
'radial-gradient(182.71% 150.59% at 2.81% 7.69%, rgba(240, 185, 11, 0.16) 0%, rgba(255, 168, 0, 0.16) 100%)',
|
||||
[ChainId.OPTIMISM]:
|
||||
'radial-gradient(948% 292% at 42% 0%, rgba(255, 58, 212, 0.01) 0%, rgba(255, 255, 255, 0.04) 100%),radial-gradient(98% 96% at 2% 0%, rgba(255, 39, 39, 0.01) 0%, rgba(235, 0, 255, 0.01) 96%)',
|
||||
[ChainId.OPTIMISM_GOERLI]:
|
||||
'radial-gradient(948% 292% at 42% 0%, rgba(255, 58, 212, 0.04) 0%, rgba(255, 255, 255, 0.04) 100%),radial-gradient(98% 96% at 2% 0%, rgba(255, 39, 39, 0.04) 0%, rgba(235, 0, 255, 0.01 96%)',
|
||||
[ChainId.ARBITRUM_ONE]:
|
||||
'radial-gradient(285% 8200% at 30% 50%, rgba(40, 160, 240, 0.01) 0%, rgba(219, 255, 0, 0) 100%),radial-gradient(75% 75% at 0% 0%, rgba(150, 190, 220, 0.05) 0%, rgba(33, 114, 229, 0.05) 100%), hsla(0, 0%, 100%, 0.05)',
|
||||
[ChainId.ARBITRUM_GOERLI]:
|
||||
'radial-gradient(285% 8200% at 30% 50%, rgba(40, 160, 240, 0.05) 0%, rgba(219, 255, 0, 0) 100%),radial-gradient(75% 75% at 0% 0%, rgba(150, 190, 220, 0.05) 0%, rgba(33, 114, 229, 0.1) 100%), hsla(0, 0%, 100%, 0.05)',
|
||||
[ChainId.AVALANCHE]:
|
||||
'radial-gradient(948% 292% at 42% 0%, rgba(255, 58, 212, 0.01) 0%, rgba(255, 255, 255, 0.04) 100%),radial-gradient(98% 96% at 2% 0%, rgba(255, 39, 39, 0.01) 0%, rgba(235, 0, 255, 0.01) 96%)',
|
||||
[ChainId.BASE]:
|
||||
'radial-gradient(100% 100% at 50% 0%, rgba(10, 41, 75, 0.7) 0%, rgba(0, 82, 255, .1) 40%, rgba(0, 82, 255, 0) 100%), rgb(13, 14, 14);',
|
||||
},
|
||||
light: {
|
||||
[ChainId.POLYGON]:
|
||||
'radial-gradient(182.71% 205.59% at 2.81% 7.69%, rgba(130, 71, 229, 0.2) 0%, rgba(167, 202, 255, 0.2) 100%)',
|
||||
[ChainId.POLYGON_MUMBAI]:
|
||||
'radial-gradient(182.71% 205.59% at 2.81% 7.69%, rgba(130, 71, 229, 0.2) 0%, rgba(167, 202, 255, 0.2) 100%)',
|
||||
[ChainId.CELO]:
|
||||
'radial-gradient(182.71% 150.59% at 2.81% 7.69%, rgba(63, 208, 137, 0.15) 0%, rgba(49, 205, 50, 0.15) 100%)',
|
||||
[ChainId.CELO_ALFAJORES]:
|
||||
'radial-gradient(182.71% 150.59% at 2.81% 7.69%, rgba(63, 208, 137, 0.15) 0%, rgba(49, 205, 50, 0.15) 100%)',
|
||||
[ChainId.BNB]:
|
||||
'radial-gradient(182.71% 150.59% at 2.81% 7.69%, rgba(240, 185, 11, 0.16) 0%, rgba(255, 168, 0, 0.16) 100%)',
|
||||
[ChainId.OPTIMISM]:
|
||||
'radial-gradient(92% 105% at 50% 7%, rgba(255, 58, 212, 0.04) 0%, rgba(255, 255, 255, 0.03) 100%),radial-gradient(100% 97% at 0% 12%, rgba(235, 0, 255, 0.1) 0%, rgba(243, 19, 19, 0.1) 100%), hsla(0, 0%, 100%, 0.1)',
|
||||
[ChainId.OPTIMISM_GOERLI]:
|
||||
'radial-gradient(92% 105% at 50% 7%, rgba(255, 58, 212, 0.04) 0%, rgba(255, 255, 255, 0.03) 100%),radial-gradient(100% 97% at 0% 12%, rgba(235, 0, 255, 0.1) 0%, rgba(243, 19, 19, 0.1) 100%), hsla(0, 0%, 100%, 0.1)',
|
||||
[ChainId.ARBITRUM_ONE]:
|
||||
'radial-gradient(285% 8200% at 30% 50%, rgba(40, 160, 240, 0.1) 0%, rgba(219, 255, 0, 0) 100%),radial-gradient(circle at top left, hsla(206, 50%, 75%, 0.01), hsla(215, 79%, 51%, 0.12)), hsla(0, 0%, 100%, 0.1)',
|
||||
[ChainId.ARBITRUM_GOERLI]:
|
||||
'radial-gradient(285% 8200% at 30% 50%, rgba(40, 160, 240, 0.1) 0%, rgba(219, 255, 0, 0) 100%),radial-gradient(circle at top left, hsla(206, 50%, 75%, 0.01), hsla(215, 79%, 51%, 0.12)), hsla(0, 0%, 100%, 0.1)',
|
||||
[ChainId.AVALANCHE]:
|
||||
'radial-gradient(92% 105% at 50% 7%, rgba(255, 58, 212, 0.04) 0%, rgba(255, 255, 255, 0.03) 100%),radial-gradient(100% 97% at 0% 12%, rgba(235, 0, 255, 0.1) 0%, rgba(243, 19, 19, 0.1) 100%), hsla(0, 0%, 100%, 0.1)',
|
||||
[ChainId.BASE]:
|
||||
'radial-gradient(100% 100% at 50% 0%, rgba(0, 82, 255, 0.20) 0%, rgba(0, 82, 255, 0.08) 40.0%, rgba(252, 255, 82, 0.00) 100%), rgb(255, 255, 255)',
|
||||
},
|
||||
}
|
||||
|
||||
const ContentWrapper = styled.div<{ chainId: NetworkAlertChains; darkMode: boolean; logoUrl: string }>`
|
||||
background: ${({ chainId, darkMode }) => BG_COLORS_BY_DARK_MODE_AND_CHAIN_ID[darkMode ? 'dark' : 'light'][chainId]};
|
||||
border-radius: 20px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
:before {
|
||||
background-image: url(${({ logoUrl }) => logoUrl});
|
||||
background-repeat: no-repeat;
|
||||
background-size: 300px;
|
||||
content: '';
|
||||
height: 300px;
|
||||
opacity: 0.1;
|
||||
position: absolute;
|
||||
transform: rotate(25deg) translate(-90px, -40px);
|
||||
width: 300px;
|
||||
pointer-events: none;
|
||||
}
|
||||
`
|
||||
const Header = styled.h2`
|
||||
font-weight: 535;
|
||||
font-size: 16px;
|
||||
margin: 0;
|
||||
`
|
||||
|
||||
const LinkOutToBridge = styled(ExternalLink)`
|
||||
background: ${({ bgColor }) => bgColor};
|
||||
align-items: center;
|
||||
border-radius: 8px;
|
||||
color: white;
|
||||
display: flex;
|
||||
font-size: 16px;
|
||||
justify-content: space-between;
|
||||
padding: 6px 8px;
|
||||
padding: 12px 18px 12px 12px;
|
||||
text-decoration: none !important;
|
||||
width: 100%;
|
||||
|
||||
border-radius: 20px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 12px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
margin-top: 16px;
|
||||
`
|
||||
|
||||
const StyledArrowUpRight = styled(ArrowUpRight)`
|
||||
margin-left: 12px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
const TitleText = styled(ThemedText.BodyPrimary)<{ $color: string }>`
|
||||
font-weight: 535;
|
||||
color: ${({ $color }) => $color};
|
||||
`
|
||||
|
||||
const TEXT_COLORS: { [chainId in NetworkAlertChains]: string } = {
|
||||
[ChainId.POLYGON]: 'rgba(130, 71, 229)',
|
||||
[ChainId.POLYGON_MUMBAI]: 'rgba(130, 71, 229)',
|
||||
[ChainId.CELO]: 'rgba(53, 178, 97)',
|
||||
[ChainId.CELO_ALFAJORES]: 'rgba(53, 178, 97)',
|
||||
[ChainId.OPTIMISM]: '#ff3856',
|
||||
[ChainId.OPTIMISM_GOERLI]: '#ff3856',
|
||||
[ChainId.ARBITRUM_ONE]: '#0490ed',
|
||||
[ChainId.BNB]: colors.gold400,
|
||||
[ChainId.ARBITRUM_GOERLI]: '#0490ed',
|
||||
[ChainId.AVALANCHE]: '#ff3856',
|
||||
[ChainId.BASE]: colors.networkBase,
|
||||
}
|
||||
|
||||
function shouldShowAlert(chainId: number | undefined): chainId is NetworkAlertChains {
|
||||
return Boolean(chainId && SHOULD_SHOW_ALERT[chainId as unknown as NetworkAlertChains])
|
||||
}
|
||||
const SubtitleText = styled(ThemedText.BodySmall)<{ $color: string }>`
|
||||
line-height: 20px;
|
||||
color: ${({ $color }) => $color};
|
||||
`
|
||||
|
||||
export function NetworkAlert() {
|
||||
const { chainId } = useWeb3React()
|
||||
const [darkMode] = useDarkModeManager()
|
||||
const darkMode = useIsDarkMode()
|
||||
|
||||
if (!shouldShowAlert(chainId)) {
|
||||
return null
|
||||
}
|
||||
if (!chainId || !isSupportedChain(chainId)) return null
|
||||
|
||||
const chainInfo = getChainInfo(chainId)
|
||||
|
||||
if (!chainInfo) return null
|
||||
|
||||
const { label, logoUrl, bridge } = chainInfo
|
||||
const textColor = TEXT_COLORS[chainId]
|
||||
const { Symbol: ChainSymbol, bgColor, textColor } = getChainUI(chainId, darkMode)
|
||||
const { label, bridge } = getChainInfo(chainId)
|
||||
|
||||
return bridge ? (
|
||||
<RootWrapper>
|
||||
<ContentWrapper chainId={chainId} darkMode={darkMode} logoUrl={logoUrl}>
|
||||
<LinkOutToBridge href={bridge}>
|
||||
<BodyText color={textColor}>
|
||||
<L2Icon src={logoUrl} />
|
||||
<Column>
|
||||
<Header>
|
||||
<Trans>{label} token bridge</Trans>
|
||||
</Header>
|
||||
<HideSmall>
|
||||
<Trans>Deposit tokens to the {label} network.</Trans>
|
||||
</HideSmall>
|
||||
</Column>
|
||||
</BodyText>
|
||||
<StyledArrowUpRight color={textColor} />
|
||||
</LinkOutToBridge>
|
||||
</ContentWrapper>
|
||||
</RootWrapper>
|
||||
<BridgeLink href={bridge} bgColor={bgColor}>
|
||||
<ChainSymbol width={40} height={40} stroke="none" />
|
||||
<RowBetween>
|
||||
<Column>
|
||||
<TitleText $color={textColor}>
|
||||
<Trans>{label} token bridge</Trans>
|
||||
</TitleText>
|
||||
<HideSmall>
|
||||
<SubtitleText $color={textColor}>
|
||||
<Trans>Deposit tokens to the {label} network.</Trans>
|
||||
</SubtitleText>
|
||||
</HideSmall>
|
||||
</Column>
|
||||
<ArrowUpRight width="24px" height="24px" color={textColor} />
|
||||
</RowBetween>
|
||||
</BridgeLink>
|
||||
) : null
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { Break } from 'components/earn/styled'
|
||||
import CurrencyLogo from 'components/Logo/CurrencyLogo'
|
||||
import RateToggle from 'components/RateToggle'
|
||||
import { RowBetween, RowFixed } from 'components/Row'
|
||||
import { BIPS_BASE } from 'constants/misc'
|
||||
import JSBI from 'jsbi'
|
||||
import { ReactNode, useCallback, useState } from 'react'
|
||||
import { Bound } from 'state/mint/v3/actions'
|
||||
@@ -104,7 +105,7 @@ export const PositionPreview = ({
|
||||
<Trans>Fee tier</Trans>
|
||||
</ThemedText.DeprecatedLabel>
|
||||
<ThemedText.DeprecatedLabel>
|
||||
<Trans>{position?.pool?.fee / 10000}%</Trans>
|
||||
<Trans>{position?.pool?.fee / BIPS_BASE}%</Trans>
|
||||
</ThemedText.DeprecatedLabel>
|
||||
</RowBetween>
|
||||
</AutoColumn>
|
||||
|
||||
@@ -15,6 +15,7 @@ function useHasUpdatedTx() {
|
||||
return !!prevPendingActivityCount && pendingActivityCount < prevPendingActivityCount
|
||||
}
|
||||
|
||||
// TODO(WEB-3004) - Add useCachedPortfolioBalanceUsd to simplify usage of useCachedPortfolioBalancesQuery
|
||||
export function useCachedPortfolioBalancesQuery({ account }: { account?: string }) {
|
||||
return usePortfolioBalancesQuery({
|
||||
skip: !account,
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { QuoteMethod, SubmittableTrade } from 'state/routing/types'
|
||||
import { isUniswapXTrade } from 'state/routing/utils'
|
||||
import { DefaultTheme } from 'styled-components'
|
||||
import { ThemedText } from 'theme/components'
|
||||
|
||||
import UniswapXRouterLabel from './UniswapXRouterLabel'
|
||||
|
||||
export default function RouterLabel({ trade }: { trade: SubmittableTrade }) {
|
||||
export default function RouterLabel({ trade, color }: { trade: SubmittableTrade; color?: keyof DefaultTheme }) {
|
||||
if (isUniswapXTrade(trade)) {
|
||||
return (
|
||||
<UniswapXRouterLabel>
|
||||
@@ -12,8 +13,10 @@ export default function RouterLabel({ trade }: { trade: SubmittableTrade }) {
|
||||
</UniswapXRouterLabel>
|
||||
)
|
||||
}
|
||||
if (trade.quoteMethod === QuoteMethod.CLIENT_SIDE || trade.quoteMethod === QuoteMethod.CLIENT_SIDE_FALLBACK) {
|
||||
return <ThemedText.BodySmall>Uniswap Client</ThemedText.BodySmall>
|
||||
|
||||
if (trade.quoteMethod === QuoteMethod.CLIENT_SIDE_FALLBACK) {
|
||||
return <ThemedText.BodySmall color={color}>Uniswap Client</ThemedText.BodySmall>
|
||||
}
|
||||
return <ThemedText.BodySmall>Uniswap API</ThemedText.BodySmall>
|
||||
|
||||
return <ThemedText.BodySmall color={color}>Uniswap API</ThemedText.BodySmall>
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import Badge from 'components/Badge'
|
||||
import DoubleCurrencyLogo from 'components/DoubleLogo'
|
||||
import CurrencyLogo from 'components/Logo/CurrencyLogo'
|
||||
import Row, { AutoRow } from 'components/Row'
|
||||
import { BIPS_BASE } from 'constants/misc'
|
||||
import { useTokenInfoFromActiveList } from 'hooks/useTokenInfoFromActiveList'
|
||||
import { Box } from 'rebass'
|
||||
import styled from 'styled-components'
|
||||
@@ -14,7 +15,7 @@ import { Z_INDEX } from 'theme/zIndex'
|
||||
import { RoutingDiagramEntry } from 'utils/getRoutingDiagramEntries'
|
||||
|
||||
import { ReactComponent as DotLine } from '../../assets/svg/dot_line.svg'
|
||||
import { MouseoverTooltip } from '../Tooltip'
|
||||
import { MouseoverTooltip, TooltipSize } from '../Tooltip'
|
||||
|
||||
const Wrapper = styled(Box)`
|
||||
align-items: center;
|
||||
@@ -142,12 +143,13 @@ function Pool({ currency0, currency1, feeAmount }: { currency0: Currency; curren
|
||||
return (
|
||||
<MouseoverTooltip
|
||||
text={<Trans>{tokenInfo0?.symbol + '/' + tokenInfo1?.symbol + ' ' + feeAmount / 10000}% pool</Trans>}
|
||||
size={TooltipSize.ExtraSmall}
|
||||
>
|
||||
<PoolBadge>
|
||||
<Box margin="0 4px 0 12px">
|
||||
<DoubleCurrencyLogo currency0={tokenInfo1} currency1={tokenInfo0} size={20} />
|
||||
</Box>
|
||||
<BadgeText>{feeAmount / 10000}%</BadgeText>
|
||||
<BadgeText>{feeAmount / BIPS_BASE}%</BadgeText>
|
||||
</PoolBadge>
|
||||
</MouseoverTooltip>
|
||||
)
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { BrowserEvent, InterfaceElementName, InterfaceEventName } from '@uniswap/analytics-events'
|
||||
import { Currency } from '@uniswap/sdk-core'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { TraceEvent } from 'analytics'
|
||||
import CurrencyLogo from 'components/Logo/CurrencyLogo'
|
||||
import { useCachedPortfolioBalancesQuery } from 'components/PrefetchBalancesWrapper/PrefetchBalancesWrapper'
|
||||
import { AutoRow } from 'components/Row'
|
||||
import { COMMON_BASES } from 'constants/routing'
|
||||
import { useTokenInfoFromActiveList } from 'hooks/useTokenInfoFromActiveList'
|
||||
@@ -30,13 +32,19 @@ const BaseWrapper = styled.div<{ disable?: boolean }>`
|
||||
background-color: ${({ theme, disable }) => disable && theme.surface3};
|
||||
`
|
||||
|
||||
const formatAnalyticsEventProperties = (currency: Currency, searchQuery: string, isAddressSearch: string | false) => ({
|
||||
const formatAnalyticsEventProperties = (
|
||||
currency: Currency,
|
||||
searchQuery: string,
|
||||
isAddressSearch: string | false,
|
||||
portfolioBalanceUsd: number | undefined
|
||||
) => ({
|
||||
token_symbol: currency?.symbol,
|
||||
token_chain_id: currency?.chainId,
|
||||
token_address: getTokenAddress(currency),
|
||||
is_suggested_token: true,
|
||||
is_selected_from_list: false,
|
||||
is_imported_by_user: false,
|
||||
total_balances_usd: portfolioBalanceUsd,
|
||||
...(isAddressSearch === false
|
||||
? { search_token_symbol_input: searchQuery }
|
||||
: { search_token_address_input: isAddressSearch }),
|
||||
@@ -54,8 +62,12 @@ export default function CommonBases({
|
||||
onSelect: (currency: Currency) => void
|
||||
searchQuery: string
|
||||
isAddressSearch: string | false
|
||||
portfolioBalanceUsd?: number
|
||||
}) {
|
||||
const bases = chainId !== undefined ? COMMON_BASES[chainId] ?? [] : []
|
||||
const { account } = useWeb3React()
|
||||
const { data } = useCachedPortfolioBalancesQuery({ account })
|
||||
const portfolioBalanceUsd = data?.portfolios?.[0].tokensTotalDenominatedValue?.value
|
||||
|
||||
return bases.length > 0 ? (
|
||||
<AutoRow gap="4px">
|
||||
@@ -66,7 +78,7 @@ export default function CommonBases({
|
||||
<TraceEvent
|
||||
events={[BrowserEvent.onClick, BrowserEvent.onKeyPress]}
|
||||
name={InterfaceEventName.TOKEN_SELECTED}
|
||||
properties={formatAnalyticsEventProperties(currency, searchQuery, isAddressSearch)}
|
||||
properties={formatAnalyticsEventProperties(currency, searchQuery, isAddressSearch, portfolioBalanceUsd)}
|
||||
element={InterfaceElementName.COMMON_BASES_CURRENCY_BUTTON}
|
||||
key={currencyId(currency)}
|
||||
>
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { TraceEvent } from 'analytics'
|
||||
import Loader from 'components/Icons/LoadingSpinner'
|
||||
import { useCachedPortfolioBalancesQuery } from 'components/PrefetchBalancesWrapper/PrefetchBalancesWrapper'
|
||||
import TokenSafetyIcon from 'components/TokenSafety/TokenSafetyIcon'
|
||||
import { checkWarning } from 'constants/tokenSafety'
|
||||
import { TokenBalances } from 'lib/hooks/useTokenList/sorting'
|
||||
@@ -128,13 +129,15 @@ export function CurrencyRow({
|
||||
const warning = currency.isNative ? null : checkWarning(currency.address)
|
||||
const isBlockedToken = !!warning && !warning.canProceed
|
||||
const blockedTokenOpacity = '0.6'
|
||||
const { data } = useCachedPortfolioBalancesQuery({ account })
|
||||
const portfolioBalanceUsd = data?.portfolios?.[0].tokensTotalDenominatedValue?.value
|
||||
|
||||
// only show add or remove buttons if not on selected list
|
||||
return (
|
||||
<TraceEvent
|
||||
events={[BrowserEvent.onClick, BrowserEvent.onKeyPress]}
|
||||
name={InterfaceEventName.TOKEN_SELECTED}
|
||||
properties={{ is_imported_by_user: customAdded, ...eventProperties }}
|
||||
properties={{ is_imported_by_user: customAdded, ...eventProperties, total_balances_usd: portfolioBalanceUsd }}
|
||||
element={InterfaceElementName.TOKEN_SELECTOR_ROW}
|
||||
>
|
||||
<MenuItem
|
||||
|
||||
@@ -46,7 +46,7 @@ describe('MaxSlippageSettings', () => {
|
||||
|
||||
fireEvent.change(getSlippageInput(), { target: { value: '0.5' } })
|
||||
|
||||
expect(screen.queryAllByText('0.50%').length).toEqual(1)
|
||||
expect(screen.queryAllByText('0.5%').length).toEqual(1)
|
||||
})
|
||||
it('updates input value on blur with the slippage in store', () => {
|
||||
renderSlippageSettings()
|
||||
@@ -56,7 +56,7 @@ describe('MaxSlippageSettings', () => {
|
||||
fireEvent.change(input, { target: { value: '0.5' } })
|
||||
fireEvent.blur(input)
|
||||
|
||||
expect(input.value).toBe('0.50')
|
||||
expect(input.value).toBe('0.5')
|
||||
})
|
||||
it('clears errors on blur and overwrites incorrect value with the latest correct value', () => {
|
||||
renderSlippageSettings()
|
||||
@@ -68,7 +68,7 @@ describe('MaxSlippageSettings', () => {
|
||||
fireEvent.change(input, { target: { value: '500' } })
|
||||
fireEvent.blur(input)
|
||||
|
||||
expect(input.value).toBe('50.00')
|
||||
expect(input.value).toBe('50')
|
||||
})
|
||||
it('does not allow to enter more than 2 digits after the decimal point', () => {
|
||||
renderSlippageSettings()
|
||||
|
||||
@@ -8,6 +8,7 @@ import { useUserSlippageTolerance } from 'state/user/hooks'
|
||||
import { SlippageTolerance } from 'state/user/types'
|
||||
import styled from 'styled-components'
|
||||
import { CautionTriangle, ThemedText } from 'theme/components'
|
||||
import { useFormatter } from 'utils/formatNumbers'
|
||||
|
||||
import { Input, InputContainer } from '../Input'
|
||||
|
||||
@@ -37,15 +38,23 @@ const NUMBER_WITH_MAX_TWO_DECIMAL_PLACES = /^(?:\d*\.\d{0,2}|\d+)$/
|
||||
const MINIMUM_RECOMMENDED_SLIPPAGE = new Percent(5, 10_000)
|
||||
const MAXIMUM_RECOMMENDED_SLIPPAGE = new Percent(1, 100)
|
||||
|
||||
function useFormatSlippageInput() {
|
||||
const { formatSlippage } = useFormatter()
|
||||
|
||||
return (slippage: Percent) => formatSlippage(slippage).slice(0, -1) // remove % sign
|
||||
}
|
||||
|
||||
export default function MaxSlippageSettings({ autoSlippage }: { autoSlippage: Percent }) {
|
||||
const [userSlippageTolerance, setUserSlippageTolerance] = useUserSlippageTolerance()
|
||||
const { formatSlippage } = useFormatter()
|
||||
const formatSlippageInput = useFormatSlippageInput()
|
||||
|
||||
// In order to trigger `custom` mode, we need to set `userSlippageTolerance` to a value that is not `auto`.
|
||||
// To do so, we use `autoSlippage` value. However, since users are likely to change that value,
|
||||
// we render it as a placeholder instead of a value.
|
||||
const defaultSlippageInputValue =
|
||||
userSlippageTolerance !== SlippageTolerance.Auto && !userSlippageTolerance.equalTo(autoSlippage)
|
||||
? userSlippageTolerance.toFixed(2)
|
||||
? formatSlippageInput(userSlippageTolerance)
|
||||
: ''
|
||||
|
||||
// If user has previously entered a custom slippage, we want to show that value in the input field
|
||||
@@ -101,7 +110,7 @@ export default function MaxSlippageSettings({ autoSlippage }: { autoSlippage: Pe
|
||||
header={
|
||||
<Row width="auto">
|
||||
<ThemedText.BodySecondary>
|
||||
<Trans>Max slippage</Trans>
|
||||
<Trans>Max. slippage</Trans>
|
||||
</ThemedText.BodySecondary>
|
||||
<QuestionHelper
|
||||
text={
|
||||
@@ -115,7 +124,7 @@ export default function MaxSlippageSettings({ autoSlippage }: { autoSlippage: Pe
|
||||
{userSlippageTolerance === SlippageTolerance.Auto ? (
|
||||
<Trans>Auto</Trans>
|
||||
) : (
|
||||
`${userSlippageTolerance.toFixed(2)}%`
|
||||
formatSlippage(userSlippageTolerance)
|
||||
)}
|
||||
</ThemedText.BodyPrimary>
|
||||
}
|
||||
@@ -149,7 +158,7 @@ export default function MaxSlippageSettings({ autoSlippage }: { autoSlippage: Pe
|
||||
<InputContainer gap="md" error={!!slippageError}>
|
||||
<Input
|
||||
data-testid="slippage-input"
|
||||
placeholder={autoSlippage.toFixed(2)}
|
||||
placeholder={formatSlippageInput(autoSlippage)}
|
||||
value={slippageInput}
|
||||
onChange={(e) => parseSlippageInput(e.target.value)}
|
||||
onBlur={() => {
|
||||
@@ -167,7 +176,7 @@ export default function MaxSlippageSettings({ autoSlippage }: { autoSlippage: Pe
|
||||
<ThemedText.BodySmall color="deprecated_accentWarning">
|
||||
{tooLow ? (
|
||||
<Trans>
|
||||
Slippage below {MINIMUM_RECOMMENDED_SLIPPAGE.toFixed(2)}% may result in a failed transaction
|
||||
Slippage below {formatSlippage(MINIMUM_RECOMMENDED_SLIPPAGE)} may result in a failed transaction
|
||||
</Trans>
|
||||
) : (
|
||||
<Trans>Your transaction may be frontrun and result in an unfavorable trade.</Trans>
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import { t, Trans } from '@lingui/macro'
|
||||
import { Settings } from 'components/Icons/Settings'
|
||||
import Row from 'components/Row'
|
||||
import { InterfaceTrade } from 'state/routing/types'
|
||||
import { isUniswapXTrade } from 'state/routing/utils'
|
||||
import { useUserSlippageTolerance } from 'state/user/hooks'
|
||||
import { SlippageTolerance } from 'state/user/types'
|
||||
import styled from 'styled-components'
|
||||
import { ThemedText } from 'theme/components'
|
||||
import { useFormatter } from 'utils/formatNumbers'
|
||||
import validateUserSlippageTolerance, { SlippageValidationResult } from 'utils/validateUserSlippageTolerance'
|
||||
|
||||
const Icon = styled(Settings)`
|
||||
@@ -44,10 +47,11 @@ const IconContainerWithSlippage = styled(IconContainer)<{ displayWarning?: boole
|
||||
displayWarning ? theme.deprecated_accentWarningSoft : theme.surface2};
|
||||
`
|
||||
|
||||
const ButtonContent = () => {
|
||||
const ButtonContent = ({ trade }: { trade?: InterfaceTrade }) => {
|
||||
const [userSlippageTolerance] = useUserSlippageTolerance()
|
||||
const { formatSlippage } = useFormatter()
|
||||
|
||||
if (userSlippageTolerance === SlippageTolerance.Auto) {
|
||||
if (userSlippageTolerance === SlippageTolerance.Auto || isUniswapXTrade(trade)) {
|
||||
return (
|
||||
<IconContainer>
|
||||
<Icon />
|
||||
@@ -60,7 +64,7 @@ const ButtonContent = () => {
|
||||
return (
|
||||
<IconContainerWithSlippage data-testid="settings-icon-with-slippage" gap="sm" displayWarning={isInvalidSlippage}>
|
||||
<ThemedText.BodySmall>
|
||||
<Trans>{userSlippageTolerance.toFixed(2)}% slippage</Trans>
|
||||
<Trans>{formatSlippage(userSlippageTolerance)} slippage</Trans>
|
||||
</ThemedText.BodySmall>
|
||||
<Icon />
|
||||
</IconContainerWithSlippage>
|
||||
@@ -71,10 +75,12 @@ export default function MenuButton({
|
||||
disabled,
|
||||
onClick,
|
||||
isActive,
|
||||
trade,
|
||||
}: {
|
||||
disabled: boolean
|
||||
onClick: () => void
|
||||
isActive: boolean
|
||||
trade?: InterfaceTrade
|
||||
}) {
|
||||
return (
|
||||
<Button
|
||||
@@ -85,7 +91,7 @@ export default function MenuButton({
|
||||
data-testid="open-settings-dialog-button"
|
||||
aria-label={t`Transaction Settings`}
|
||||
>
|
||||
<ButtonContent />
|
||||
<ButtonContent trade={trade} />
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -24,18 +24,4 @@ describe('RouterPreferenceSettings', () => {
|
||||
expect(uniswapXToggle).toHaveAttribute('aria-selected', 'false')
|
||||
expect(store.getState().user.userRouterPreference).toEqual(RouterPreference.API)
|
||||
})
|
||||
it('toggles `Local Routing` router preference', () => {
|
||||
render(<RouterPreferenceSettings />)
|
||||
|
||||
const localRoutingToggle = screen.getByTestId('toggle-local-routing-button')
|
||||
|
||||
fireEvent.click(localRoutingToggle)
|
||||
expect(localRoutingToggle).toHaveAttribute('aria-selected', 'true')
|
||||
expect(store.getState().user.userRouterPreference).toEqual(RouterPreference.CLIENT)
|
||||
|
||||
fireEvent.click(localRoutingToggle)
|
||||
|
||||
expect(localRoutingToggle).toHaveAttribute('aria-selected', 'false')
|
||||
expect(store.getState().user.userRouterPreference).toEqual(RouterPreference.API)
|
||||
})
|
||||
})
|
||||
|
||||