Merge branch 'beta' into production
This commit is contained in:
commit
31499ee2b1
12
README.md
12
README.md
@ -11,10 +11,18 @@ This an an open source interface for Uniswap - a protocol for decentralized exch
|
|||||||
- Twitter: [@UniswapExchange](https://twitter.com/UniswapExchange)
|
- Twitter: [@UniswapExchange](https://twitter.com/UniswapExchange)
|
||||||
- Reddit: [/r/Uniswap](https://www.reddit.com/r/UniSwap/)
|
- Reddit: [/r/Uniswap](https://www.reddit.com/r/UniSwap/)
|
||||||
- Email: [contact@uniswap.io](mailto:contact@uniswap.io)
|
- Email: [contact@uniswap.io](mailto:contact@uniswap.io)
|
||||||
- Slack: [uni-swap.slack.com/](https://join.slack.com/t/uni-swap/shared_invite/enQtNDYwMjg1ODc5ODA4LWEyYmU0OGU1ZGQ3NjE4YzhmNzcxMDAyM2ExNzNkZjZjZjcxYTkwNzU0MGE3M2JkNzMxOTA2MzE2ZWM0YWQwNjU)
|
- Discord: [Uniswap](https://discord.gg/Y7TF6QA)
|
||||||
- Whitepaper: [Link](https://hackmd.io/C-DvwDSfSxuh-Gd4WKE_ig)
|
- Whitepaper: [Link](https://hackmd.io/C-DvwDSfSxuh-Gd4WKE_ig)
|
||||||
|
|
||||||
## To Start Development
|
## Run Uniswap Locally
|
||||||
|
|
||||||
|
1. Download and unzip the `build.zip` file from the latest release in the [Releases tab](https://github.com/Uniswap/uniswap-frontend/releases/latest).
|
||||||
|
|
||||||
|
2. Serve the `build/` folder locally, and access the application via a browser.
|
||||||
|
|
||||||
|
For more information on running a local server see [https://developer.mozilla.org/en-US/docs/Learn/Common_questions/set_up_a_local_testing_server](https://developer.mozilla.org/en-US/docs/Learn/Common_questions/set_up_a_local_testing_server). This simple approach has one downside: refreshing the page will give a `404` because of how React handles client-side routing. To fix this issue, consider running `serve -s` courtesy of the [serve](https://github.com/zeit/serve) package.
|
||||||
|
|
||||||
|
## Development Uniswap Locally
|
||||||
|
|
||||||
### Install Dependencies
|
### Install Dependencies
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ import { ReactComponent as Close } from '../../assets/images/x.svg'
|
|||||||
import { transparentize } from 'polished'
|
import { transparentize } from 'polished'
|
||||||
import { Spinner } from '../../theme'
|
import { Spinner } from '../../theme'
|
||||||
import Circle from '../../assets/images/circle-grey.svg'
|
import Circle from '../../assets/images/circle-grey.svg'
|
||||||
import { useUSDPrice } from '../../contexts/Application'
|
import { useETHPriceInUSD, useAllBalances } from '../../contexts/Balances'
|
||||||
|
|
||||||
const GAS_MARGIN = ethers.utils.bigNumberify(1000)
|
const GAS_MARGIN = ethers.utils.bigNumberify(1000)
|
||||||
|
|
||||||
@ -439,7 +439,7 @@ export default function CurrencyInputPanel({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function CurrencySelectModal({ isOpen, onDismiss, onTokenSelect, allBalances }) {
|
function CurrencySelectModal({ isOpen, onDismiss, onTokenSelect }) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
const [searchQuery, setSearchQuery] = useState('')
|
const [searchQuery, setSearchQuery] = useState('')
|
||||||
@ -450,19 +450,24 @@ function CurrencySelectModal({ isOpen, onDismiss, onTokenSelect, allBalances })
|
|||||||
const { account } = useWeb3React()
|
const { account } = useWeb3React()
|
||||||
|
|
||||||
// BigNumber.js instance
|
// BigNumber.js instance
|
||||||
const ethPrice = useUSDPrice()
|
const ethPrice = useETHPriceInUSD()
|
||||||
|
|
||||||
|
// all balances for both account and exchanges
|
||||||
|
let allBalances = useAllBalances()
|
||||||
|
|
||||||
const _usdAmounts = Object.keys(allTokens).map(k => {
|
const _usdAmounts = Object.keys(allTokens).map(k => {
|
||||||
if (
|
if (ethPrice && allBalances[account] && allBalances[account][k]) {
|
||||||
ethPrice &&
|
let ethRate = 1 // default for ETH
|
||||||
allBalances &&
|
let exchangeDetails = allBalances[allTokens[k].exchangeAddress]
|
||||||
allBalances[k] &&
|
if (exchangeDetails && exchangeDetails[k] && exchangeDetails['ETH']) {
|
||||||
allBalances[k].ethRate &&
|
const tokenBalance = new BigNumber(exchangeDetails[k].value.toString())
|
||||||
!allBalances[k].ethRate.isNaN() &&
|
const ethBalance = new BigNumber(exchangeDetails['ETH'].value.toString())
|
||||||
allBalances[k].balance
|
ethRate = ethBalance.div(tokenBalance)
|
||||||
) {
|
}
|
||||||
const USDRate = ethPrice.times(allBalances[k].ethRate)
|
const USDRate = ethPrice
|
||||||
const balanceBigNumber = new BigNumber(allBalances[k].balance.toString())
|
.times(ethRate)
|
||||||
|
.times(new BigNumber(10).pow(allTokens[k].decimals).div(new BigNumber(10).pow(18)))
|
||||||
|
const balanceBigNumber = new BigNumber(allBalances[account][k].value.toString())
|
||||||
const usdBalance = balanceBigNumber.times(USDRate).div(new BigNumber(10).pow(allTokens[k].decimals))
|
const usdBalance = balanceBigNumber.times(USDRate).div(new BigNumber(10).pow(allTokens[k].decimals))
|
||||||
return usdBalance
|
return usdBalance
|
||||||
} else {
|
} else {
|
||||||
@ -506,11 +511,11 @@ function CurrencySelectModal({ isOpen, onDismiss, onTokenSelect, allBalances })
|
|||||||
let balance
|
let balance
|
||||||
let usdBalance
|
let usdBalance
|
||||||
// only update if we have data
|
// only update if we have data
|
||||||
if (k === 'ETH' && allBalances && allBalances[k]) {
|
if (k === 'ETH' && allBalances[account] && allBalances[account][k]) {
|
||||||
balance = formatEthBalance(allBalances[k].balance)
|
balance = formatEthBalance(allBalances[account][k].value)
|
||||||
usdBalance = usdAmounts[k]
|
usdBalance = usdAmounts[k]
|
||||||
} else if (allBalances && allBalances[k]) {
|
} else if (allBalances[account] && allBalances[account][k]) {
|
||||||
balance = formatTokenBalance(allBalances[k].balance, allTokens[k].decimals)
|
balance = formatTokenBalance(allBalances[account][k].value, allTokens[k].decimals)
|
||||||
usdBalance = usdAmounts[k]
|
usdBalance = usdAmounts[k]
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@ -521,7 +526,7 @@ function CurrencySelectModal({ isOpen, onDismiss, onTokenSelect, allBalances })
|
|||||||
usdBalance: usdBalance
|
usdBalance: usdBalance
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, [allBalances, allTokens, usdAmounts])
|
}, [allBalances, allTokens, usdAmounts, account])
|
||||||
|
|
||||||
const filteredTokenList = useMemo(() => {
|
const filteredTokenList = useMemo(() => {
|
||||||
return tokenList.filter(tokenEntry => {
|
return tokenList.filter(tokenEntry => {
|
||||||
@ -580,7 +585,13 @@ function CurrencySelectModal({ isOpen, onDismiss, onTokenSelect, allBalances })
|
|||||||
'-'
|
'-'
|
||||||
)}
|
)}
|
||||||
<TokenRowUsd>
|
<TokenRowUsd>
|
||||||
{usdBalance ? (usdBalance.lt(0.01) ? '<$0.01' : '$' + formatToUsd(usdBalance)) : ''}
|
{usdBalance
|
||||||
|
? usdBalance.isZero()
|
||||||
|
? ''
|
||||||
|
: usdBalance.lt(0.01)
|
||||||
|
? '<$0.01'
|
||||||
|
: '$' + formatToUsd(usdBalance)
|
||||||
|
: ''}
|
||||||
</TokenRowUsd>
|
</TokenRowUsd>
|
||||||
</TokenRowRight>
|
</TokenRowRight>
|
||||||
</TokenModalRow>
|
</TokenModalRow>
|
||||||
|
@ -17,7 +17,6 @@ import { useExchangeContract } from '../../hooks'
|
|||||||
import { useTokenDetails } from '../../contexts/Tokens'
|
import { useTokenDetails } from '../../contexts/Tokens'
|
||||||
import { useTransactionAdder } from '../../contexts/Transactions'
|
import { useTransactionAdder } from '../../contexts/Transactions'
|
||||||
import { useAddressBalance, useExchangeReserves } from '../../contexts/Balances'
|
import { useAddressBalance, useExchangeReserves } from '../../contexts/Balances'
|
||||||
import { useFetchAllBalances } from '../../contexts/AllBalances'
|
|
||||||
import { useAddressAllowance } from '../../contexts/Allowances'
|
import { useAddressAllowance } from '../../contexts/Allowances'
|
||||||
import { useWalletModalToggle } from '../../contexts/Application'
|
import { useWalletModalToggle } from '../../contexts/Application'
|
||||||
|
|
||||||
@ -33,7 +32,7 @@ const ALLOWED_SLIPPAGE_DEFAULT = 100
|
|||||||
const TOKEN_ALLOWED_SLIPPAGE_DEFAULT = 100
|
const TOKEN_ALLOWED_SLIPPAGE_DEFAULT = 100
|
||||||
|
|
||||||
// 15 minutes, denominated in seconds
|
// 15 minutes, denominated in seconds
|
||||||
const DEADLINE_FROM_NOW = 60 * 15
|
const DEFAULT_DEADLINE_FROM_NOW = 60 * 15
|
||||||
|
|
||||||
// % above the calculated gas cost that we actually send, denominated in bips
|
// % above the calculated gas cost that we actually send, denominated in bips
|
||||||
const GAS_MARGIN = ethers.utils.bigNumberify(1000)
|
const GAS_MARGIN = ethers.utils.bigNumberify(1000)
|
||||||
@ -267,6 +266,8 @@ export default function ExchangePage({ initialCurrency, sending = false, params
|
|||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const [deadlineFromNow, setDeadlineFromNow] = useState(DEFAULT_DEADLINE_FROM_NOW)
|
||||||
|
|
||||||
const [rawSlippage, setRawSlippage] = useState(() => initialSlippage())
|
const [rawSlippage, setRawSlippage] = useState(() => initialSlippage())
|
||||||
const [rawTokenSlippage, setRawTokenSlippage] = useState(() => initialSlippage(true))
|
const [rawTokenSlippage, setRawTokenSlippage] = useState(() => initialSlippage(true))
|
||||||
|
|
||||||
@ -554,8 +555,8 @@ export default function ExchangePage({ initialCurrency, sending = false, params
|
|||||||
const highSlippageWarning = percentSlippage && percentSlippage.gte(ethers.utils.parseEther('.2')) // [20+%
|
const highSlippageWarning = percentSlippage && percentSlippage.gte(ethers.utils.parseEther('.2')) // [20+%
|
||||||
|
|
||||||
const isValid = sending
|
const isValid = sending
|
||||||
? exchangeRate && inputError === null && independentError === null && recipientError === null
|
? exchangeRate && inputError === null && independentError === null && recipientError === null && deadlineFromNow
|
||||||
: exchangeRate && inputError === null && independentError === null
|
: exchangeRate && inputError === null && independentError === null && deadlineFromNow
|
||||||
|
|
||||||
const estimatedText = `(${t('estimated')})`
|
const estimatedText = `(${t('estimated')})`
|
||||||
function formatBalance(value) {
|
function formatBalance(value) {
|
||||||
@ -563,7 +564,7 @@ export default function ExchangePage({ initialCurrency, sending = false, params
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function onSwap() {
|
async function onSwap() {
|
||||||
const deadline = Math.ceil(Date.now() / 1000) + DEADLINE_FROM_NOW
|
const deadline = Math.ceil(Date.now() / 1000) + deadlineFromNow
|
||||||
|
|
||||||
let estimate, method, args, value
|
let estimate, method, args, value
|
||||||
if (independentField === INPUT) {
|
if (independentField === INPUT) {
|
||||||
@ -645,15 +646,12 @@ export default function ExchangePage({ initialCurrency, sending = false, params
|
|||||||
|
|
||||||
const [customSlippageError, setcustomSlippageError] = useState('')
|
const [customSlippageError, setcustomSlippageError] = useState('')
|
||||||
|
|
||||||
const allBalances = useFetchAllBalances()
|
|
||||||
|
|
||||||
const toggleWalletModal = useWalletModalToggle()
|
const toggleWalletModal = useWalletModalToggle()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CurrencyInputPanel
|
<CurrencyInputPanel
|
||||||
title={t('input')}
|
title={t('input')}
|
||||||
allBalances={allBalances}
|
|
||||||
description={inputValueFormatted && independentField === OUTPUT ? estimatedText : ''}
|
description={inputValueFormatted && independentField === OUTPUT ? estimatedText : ''}
|
||||||
extraText={inputBalanceFormatted && formatBalance(inputBalanceFormatted)}
|
extraText={inputBalanceFormatted && formatBalance(inputBalanceFormatted)}
|
||||||
extraTextClickHander={() => {
|
extraTextClickHander={() => {
|
||||||
@ -702,7 +700,6 @@ export default function ExchangePage({ initialCurrency, sending = false, params
|
|||||||
</OversizedPanel>
|
</OversizedPanel>
|
||||||
<CurrencyInputPanel
|
<CurrencyInputPanel
|
||||||
title={t('output')}
|
title={t('output')}
|
||||||
allBalances={allBalances}
|
|
||||||
description={outputValueFormatted && independentField === INPUT ? estimatedText : ''}
|
description={outputValueFormatted && independentField === INPUT ? estimatedText : ''}
|
||||||
extraText={outputBalanceFormatted && formatBalance(outputBalanceFormatted)}
|
extraText={outputBalanceFormatted && formatBalance(outputBalanceFormatted)}
|
||||||
onCurrencySelected={outputCurrency => {
|
onCurrencySelected={outputCurrency => {
|
||||||
@ -764,6 +761,8 @@ export default function ExchangePage({ initialCurrency, sending = false, params
|
|||||||
rawSlippage={rawSlippage}
|
rawSlippage={rawSlippage}
|
||||||
slippageWarning={slippageWarning}
|
slippageWarning={slippageWarning}
|
||||||
highSlippageWarning={highSlippageWarning}
|
highSlippageWarning={highSlippageWarning}
|
||||||
|
setDeadline={setDeadlineFromNow}
|
||||||
|
deadline={deadlineFromNow}
|
||||||
inputError={inputError}
|
inputError={inputError}
|
||||||
independentError={independentError}
|
independentError={independentError}
|
||||||
inputCurrency={inputCurrency}
|
inputCurrency={inputCurrency}
|
||||||
|
@ -260,7 +260,7 @@ const LastSummaryText = styled.div`
|
|||||||
const SlippageSelector = styled.div`
|
const SlippageSelector = styled.div`
|
||||||
background-color: ${({ theme }) => darken(0.04, theme.concreteGray)};
|
background-color: ${({ theme }) => darken(0.04, theme.concreteGray)};
|
||||||
padding: 1rem 1.25rem 1rem 1.25rem;
|
padding: 1rem 1.25rem 1rem 1.25rem;
|
||||||
border-radius: 12px;
|
border-radius: 12px 12px 0 0;
|
||||||
`
|
`
|
||||||
|
|
||||||
const Percent = styled.div`
|
const Percent = styled.div`
|
||||||
@ -294,6 +294,14 @@ const ValueWrapper = styled.span`
|
|||||||
font-variant: tabular-nums;
|
font-variant: tabular-nums;
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const DeadlineSelector = styled.div`
|
||||||
|
background-color: ${({ theme }) => darken(0.04, theme.concreteGray)};
|
||||||
|
padding: 1rem 1.25rem 1rem 1.25rem;
|
||||||
|
border-radius: 0 0 12px 12px;
|
||||||
|
`
|
||||||
|
const DeadlineRow = SlippageRow
|
||||||
|
const DeadlineInput = OptionCustom
|
||||||
|
|
||||||
export default function TransactionDetails(props) {
|
export default function TransactionDetails(props) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
@ -314,6 +322,8 @@ export default function TransactionDetails(props) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const [deadlineInput, setDeadlineInput] = useState('')
|
||||||
|
|
||||||
function renderSummary() {
|
function renderSummary() {
|
||||||
let contextualInfo = ''
|
let contextualInfo = ''
|
||||||
let isError = false
|
let isError = false
|
||||||
@ -492,6 +502,14 @@ export default function TransactionDetails(props) {
|
|||||||
</BottomError>
|
</BottomError>
|
||||||
</SlippageRow>
|
</SlippageRow>
|
||||||
</SlippageSelector>
|
</SlippageSelector>
|
||||||
|
<DeadlineSelector>
|
||||||
|
Set swap deadline (minutes from now)
|
||||||
|
<DeadlineRow wrap>
|
||||||
|
<DeadlineInput>
|
||||||
|
<Input placeholder={'Deadline'} value={deadlineInput} onChange={parseDeadlineInput} />
|
||||||
|
</DeadlineInput>
|
||||||
|
</DeadlineRow>
|
||||||
|
</DeadlineSelector>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -507,6 +525,7 @@ export default function TransactionDetails(props) {
|
|||||||
const setRawSlippage = props.setRawSlippage
|
const setRawSlippage = props.setRawSlippage
|
||||||
const setRawTokenSlippage = props.setRawTokenSlippage
|
const setRawTokenSlippage = props.setRawTokenSlippage
|
||||||
const setcustomSlippageError = props.setcustomSlippageError
|
const setcustomSlippageError = props.setcustomSlippageError
|
||||||
|
const setDeadline = props.setDeadline
|
||||||
|
|
||||||
const updateSlippage = useCallback(
|
const updateSlippage = useCallback(
|
||||||
newSlippage => {
|
newSlippage => {
|
||||||
@ -604,6 +623,22 @@ export default function TransactionDetails(props) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const [initialDeadline] = useState(props.deadline)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setDeadlineInput(initialDeadline / 60)
|
||||||
|
}, [initialDeadline])
|
||||||
|
|
||||||
|
const parseDeadlineInput = e => {
|
||||||
|
const input = e.target.value
|
||||||
|
|
||||||
|
const acceptableValues = [/^$/, /^\d+$/]
|
||||||
|
if (acceptableValues.some(re => re.test(input))) {
|
||||||
|
setDeadlineInput(input)
|
||||||
|
setDeadline(parseInt(input) * 60)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const b = text => <Bold>{text}</Bold>
|
const b = text => <Bold>{text}</Bold>
|
||||||
|
|
||||||
const renderTransactionDetails = () => {
|
const renderTransactionDetails = () => {
|
||||||
|
@ -1,100 +0,0 @@
|
|||||||
import React, { createContext, useContext, useReducer, useMemo, useCallback } from 'react'
|
|
||||||
import { ethers } from 'ethers'
|
|
||||||
import { getTokenReserves, getMarketDetails, BigNumber } from '@uniswap/sdk'
|
|
||||||
|
|
||||||
import { useWeb3React } from '../hooks'
|
|
||||||
import { safeAccess, isAddress, getEtherBalance, getTokenBalance } from '../utils'
|
|
||||||
import { useAllTokenDetails } from './Tokens'
|
|
||||||
|
|
||||||
const ZERO = ethers.utils.bigNumberify(0)
|
|
||||||
const ONE = new BigNumber(1)
|
|
||||||
|
|
||||||
const UPDATE = 'UPDATE'
|
|
||||||
|
|
||||||
const AllBalancesContext = createContext()
|
|
||||||
|
|
||||||
function useAllBalancesContext() {
|
|
||||||
return useContext(AllBalancesContext)
|
|
||||||
}
|
|
||||||
|
|
||||||
function reducer(state, { type, payload }) {
|
|
||||||
switch (type) {
|
|
||||||
case UPDATE: {
|
|
||||||
const { allBalanceData, networkId, address } = payload
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
[networkId]: {
|
|
||||||
...(safeAccess(state, [networkId]) || {}),
|
|
||||||
[address]: {
|
|
||||||
...(safeAccess(state, [networkId, address]) || {}),
|
|
||||||
allBalanceData
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
throw Error(`Unexpected action type in AllBalancesContext reducer: '${type}'.`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Provider({ children }) {
|
|
||||||
const [state, dispatch] = useReducer(reducer, {})
|
|
||||||
|
|
||||||
const update = useCallback((allBalanceData, networkId, address) => {
|
|
||||||
dispatch({ type: UPDATE, payload: { allBalanceData, networkId, address } })
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<AllBalancesContext.Provider value={useMemo(() => [state, { update }], [state, update])}>
|
|
||||||
{children}
|
|
||||||
</AllBalancesContext.Provider>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useFetchAllBalances() {
|
|
||||||
const { library, chainId, account } = useWeb3React()
|
|
||||||
|
|
||||||
const allTokens = useAllTokenDetails()
|
|
||||||
|
|
||||||
const [state, { update }] = useAllBalancesContext()
|
|
||||||
|
|
||||||
const { allBalanceData } = safeAccess(state, [chainId, account]) || {}
|
|
||||||
|
|
||||||
const getData = async () => {
|
|
||||||
if (!!library && !!account) {
|
|
||||||
const newBalances = {}
|
|
||||||
await Promise.all(
|
|
||||||
Object.keys(allTokens).map(async k => {
|
|
||||||
let balance = null
|
|
||||||
let ethRate = null
|
|
||||||
if (isAddress(k) || k === 'ETH') {
|
|
||||||
if (k === 'ETH') {
|
|
||||||
balance = await getEtherBalance(account, library).catch(() => null)
|
|
||||||
ethRate = ONE
|
|
||||||
} else {
|
|
||||||
balance = await getTokenBalance(k, account, library).catch(() => null)
|
|
||||||
// only get values for tokens with positive balances
|
|
||||||
if (!!balance && balance.gt(ZERO)) {
|
|
||||||
const tokenReserves = await getTokenReserves(k, library).catch(() => null)
|
|
||||||
if (!!tokenReserves) {
|
|
||||||
const marketDetails = getMarketDetails(tokenReserves)
|
|
||||||
if (marketDetails.marketRate && marketDetails.marketRate.rate) {
|
|
||||||
ethRate = marketDetails.marketRate.rate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (newBalances[k] = { balance, ethRate })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
update(newBalances, chainId, account)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useMemo(getData, [account])
|
|
||||||
|
|
||||||
return allBalanceData
|
|
||||||
}
|
|
@ -2,14 +2,12 @@ import React, { createContext, useContext, useReducer, useMemo, useCallback, use
|
|||||||
|
|
||||||
import { useWeb3React } from '../hooks'
|
import { useWeb3React } from '../hooks'
|
||||||
import { safeAccess } from '../utils'
|
import { safeAccess } from '../utils'
|
||||||
import { getUSDPrice } from '../utils/price'
|
|
||||||
|
|
||||||
const BLOCK_NUMBER = 'BLOCK_NUMBER'
|
const BLOCK_NUMBER = 'BLOCK_NUMBER'
|
||||||
const USD_PRICE = 'USD_PRICE'
|
const USD_PRICE = 'USD_PRICE'
|
||||||
const WALLET_MODAL_OPEN = 'WALLET_MODAL_OPEN'
|
const WALLET_MODAL_OPEN = 'WALLET_MODAL_OPEN'
|
||||||
|
|
||||||
const UPDATE_BLOCK_NUMBER = 'UPDATE_BLOCK_NUMBER'
|
const UPDATE_BLOCK_NUMBER = 'UPDATE_BLOCK_NUMBER'
|
||||||
const UPDATE_USD_PRICE = 'UPDATE_USD_PRICE'
|
|
||||||
const TOGGLE_WALLET_MODAL = 'TOGGLE_WALLET_MODAL'
|
const TOGGLE_WALLET_MODAL = 'TOGGLE_WALLET_MODAL'
|
||||||
|
|
||||||
const ApplicationContext = createContext()
|
const ApplicationContext = createContext()
|
||||||
@ -30,16 +28,7 @@ function reducer(state, { type, payload }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case UPDATE_USD_PRICE: {
|
|
||||||
const { networkId, USDPrice } = payload
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
[USD_PRICE]: {
|
|
||||||
...(safeAccess(state, [USD_PRICE]) || {}),
|
|
||||||
[networkId]: USDPrice
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case TOGGLE_WALLET_MODAL: {
|
case TOGGLE_WALLET_MODAL: {
|
||||||
return { ...state, [WALLET_MODAL_OPEN]: !state[WALLET_MODAL_OPEN] }
|
return { ...state, [WALLET_MODAL_OPEN]: !state[WALLET_MODAL_OPEN] }
|
||||||
}
|
}
|
||||||
@ -60,20 +49,15 @@ export default function Provider({ children }) {
|
|||||||
dispatch({ type: UPDATE_BLOCK_NUMBER, payload: { networkId, blockNumber } })
|
dispatch({ type: UPDATE_BLOCK_NUMBER, payload: { networkId, blockNumber } })
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const updateUSDPrice = useCallback((networkId, USDPrice) => {
|
|
||||||
dispatch({ type: UPDATE_USD_PRICE, payload: { networkId, USDPrice } })
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const toggleWalletModal = useCallback(() => {
|
const toggleWalletModal = useCallback(() => {
|
||||||
dispatch({ type: TOGGLE_WALLET_MODAL })
|
dispatch({ type: TOGGLE_WALLET_MODAL })
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ApplicationContext.Provider
|
<ApplicationContext.Provider
|
||||||
value={useMemo(() => [state, { updateBlockNumber, updateUSDPrice, toggleWalletModal }], [
|
value={useMemo(() => [state, { updateBlockNumber, toggleWalletModal }], [
|
||||||
state,
|
state,
|
||||||
updateBlockNumber,
|
updateBlockNumber,
|
||||||
updateUSDPrice,
|
|
||||||
toggleWalletModal
|
toggleWalletModal
|
||||||
])}
|
])}
|
||||||
>
|
>
|
||||||
@ -85,27 +69,7 @@ export default function Provider({ children }) {
|
|||||||
export function Updater() {
|
export function Updater() {
|
||||||
const { library, chainId } = useWeb3React()
|
const { library, chainId } = useWeb3React()
|
||||||
|
|
||||||
const globalBlockNumber = useBlockNumber()
|
const [, { updateBlockNumber }] = useApplicationContext()
|
||||||
const [, { updateBlockNumber, updateUSDPrice }] = useApplicationContext()
|
|
||||||
|
|
||||||
// update usd price
|
|
||||||
useEffect(() => {
|
|
||||||
if (library && chainId === 1) {
|
|
||||||
let stale = false
|
|
||||||
|
|
||||||
getUSDPrice(library)
|
|
||||||
.then(([price]) => {
|
|
||||||
if (!stale) {
|
|
||||||
updateUSDPrice(chainId, price)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
if (!stale) {
|
|
||||||
updateUSDPrice(chainId, null)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}, [globalBlockNumber, library, chainId, updateUSDPrice])
|
|
||||||
|
|
||||||
// update block number
|
// update block number
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -148,14 +112,6 @@ export function useBlockNumber() {
|
|||||||
return safeAccess(state, [BLOCK_NUMBER, chainId])
|
return safeAccess(state, [BLOCK_NUMBER, chainId])
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useUSDPrice() {
|
|
||||||
const { chainId } = useWeb3React()
|
|
||||||
|
|
||||||
const [state] = useApplicationContext()
|
|
||||||
|
|
||||||
return safeAccess(state, [USD_PRICE, chainId])
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useWalletModalOpen() {
|
export function useWalletModalOpen() {
|
||||||
const [state] = useApplicationContext()
|
const [state] = useApplicationContext()
|
||||||
|
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
import React, { createContext, useContext, useReducer, useMemo, useCallback, useEffect } from 'react'
|
import React, { createContext, useContext, useReducer, useMemo, useCallback, useEffect, useRef, useState } from 'react'
|
||||||
|
import { BigNumber } from '@uniswap/sdk'
|
||||||
|
|
||||||
import { useWeb3React } from '../hooks'
|
import { useWeb3React } from '../hooks'
|
||||||
import { safeAccess, isAddress, getEtherBalance, getTokenBalance } from '../utils'
|
import { safeAccess, isAddress, getEtherBalance, getTokenBalance } from '../utils'
|
||||||
import { useBlockNumber } from './Application'
|
import { useBlockNumber } from './Application'
|
||||||
import { useTokenDetails } from './Tokens'
|
import { useTokenDetails, useAllTokenDetails } from './Tokens'
|
||||||
|
import { getUSDPrice } from '../utils/price'
|
||||||
|
|
||||||
const UPDATE = 'UPDATE'
|
const UPDATE = 'UPDATE'
|
||||||
|
const UPDATE_ALL_FOR_ACCOUNT = 'UPDATE_ALL_FOR_ACCOUNT'
|
||||||
|
const UPDATE_ALL_FOR_EXCHANGES = 'UPDATE_ALL_FOR_EXCHANGES'
|
||||||
|
|
||||||
const BalancesContext = createContext()
|
const BalancesContext = createContext()
|
||||||
|
|
||||||
@ -31,6 +35,40 @@ function reducer(state, { type, payload }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case UPDATE_ALL_FOR_ACCOUNT: {
|
||||||
|
const { networkId, address, tokenAddresses, values } = payload
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
[networkId]: {
|
||||||
|
...(safeAccess(state, [networkId]) || {}),
|
||||||
|
[address]: {
|
||||||
|
...tokenAddresses.reduce((accumulator, currentValue, i) => {
|
||||||
|
accumulator[currentValue] = { value: values[i] }
|
||||||
|
return accumulator
|
||||||
|
}, {}),
|
||||||
|
...(safeAccess(state, [networkId, address]) || {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case UPDATE_ALL_FOR_EXCHANGES: {
|
||||||
|
const { networkId, exchangeAddresses, tokenAddresses, values } = payload
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
[networkId]: {
|
||||||
|
...(safeAccess(state, [networkId]) || {}),
|
||||||
|
...exchangeAddresses.reduce((accumulator, currentValue, i) => {
|
||||||
|
accumulator[currentValue] = {
|
||||||
|
...safeAccess(state, [networkId, currentValue]),
|
||||||
|
[tokenAddresses[i]]: {
|
||||||
|
value: values[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return accumulator
|
||||||
|
}, {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
throw Error(`Unexpected action type in BalancesContext reducer: '${type}'.`)
|
throw Error(`Unexpected action type in BalancesContext reducer: '${type}'.`)
|
||||||
}
|
}
|
||||||
@ -44,13 +82,111 @@ export default function Provider({ children }) {
|
|||||||
dispatch({ type: UPDATE, payload: { networkId, address, tokenAddress, value, blockNumber } })
|
dispatch({ type: UPDATE, payload: { networkId, address, tokenAddress, value, blockNumber } })
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
const updateAllForAccount = useCallback((networkId, address, tokenAddresses, values) => {
|
||||||
|
dispatch({ type: UPDATE_ALL_FOR_ACCOUNT, payload: { networkId, address, tokenAddresses, values } })
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const updateAllForExchanges = useCallback((networkId, exchangeAddresses, tokenAddresses, values) => {
|
||||||
|
dispatch({ type: UPDATE_ALL_FOR_EXCHANGES, payload: { networkId, exchangeAddresses, tokenAddresses, values } })
|
||||||
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BalancesContext.Provider value={useMemo(() => [state, { update }], [state, update])}>
|
<BalancesContext.Provider
|
||||||
|
value={useMemo(() => [state, { update, updateAllForAccount, updateAllForExchanges }], [
|
||||||
|
state,
|
||||||
|
update,
|
||||||
|
updateAllForAccount,
|
||||||
|
updateAllForExchanges
|
||||||
|
])}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</BalancesContext.Provider>
|
</BalancesContext.Provider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const STAGGER_TIME = 2500
|
||||||
|
export function Updater() {
|
||||||
|
const { library, chainId, account } = useWeb3React()
|
||||||
|
|
||||||
|
const allTokens = useAllTokenDetails()
|
||||||
|
|
||||||
|
const [state, { updateAllForAccount, updateAllForExchanges }] = useBalancesContext()
|
||||||
|
const stateRef = useRef(state)
|
||||||
|
stateRef.current = state
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const getData = async () => {
|
||||||
|
if (chainId && library && account) {
|
||||||
|
// get 1 eth + all token balances for the account
|
||||||
|
Promise.all(
|
||||||
|
Object.keys(allTokens).map(async tokenAddress => {
|
||||||
|
await new Promise(resolve => setTimeout(resolve, STAGGER_TIME * Math.random()))
|
||||||
|
|
||||||
|
const { value: existingValue } = safeAccess(stateRef.current, [chainId, account, tokenAddress]) || {}
|
||||||
|
return (
|
||||||
|
existingValue ||
|
||||||
|
(await (tokenAddress === 'ETH'
|
||||||
|
? getEtherBalance(account, library).catch(() => null)
|
||||||
|
: getTokenBalance(tokenAddress, account, library).catch(() => null)))
|
||||||
|
)
|
||||||
|
})
|
||||||
|
).then(balances => {
|
||||||
|
updateAllForAccount(chainId, account, Object.keys(allTokens), balances)
|
||||||
|
})
|
||||||
|
|
||||||
|
const allTokensWithAnExchange = Object.keys(allTokens).filter(tokenAddress => tokenAddress !== 'ETH')
|
||||||
|
// get all eth balances for all exchanges
|
||||||
|
Promise.all(
|
||||||
|
allTokensWithAnExchange.map(async tokenAddress => {
|
||||||
|
await new Promise(resolve => setTimeout(resolve, STAGGER_TIME * Math.random()))
|
||||||
|
|
||||||
|
const exchangeAddress = allTokens[tokenAddress].exchangeAddress
|
||||||
|
const { value: existingValue } = safeAccess(stateRef.current, [chainId, exchangeAddress, 'ETH']) || {}
|
||||||
|
return existingValue || (await getEtherBalance(exchangeAddress, library).catch(() => null))
|
||||||
|
})
|
||||||
|
).then(ethBalances => {
|
||||||
|
updateAllForExchanges(
|
||||||
|
chainId,
|
||||||
|
allTokensWithAnExchange.map(tokenAddress => allTokens[tokenAddress].exchangeAddress),
|
||||||
|
Array(allTokensWithAnExchange.length).fill('ETH'),
|
||||||
|
ethBalances
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
// get all token balances for all exchanges
|
||||||
|
Promise.all(
|
||||||
|
allTokensWithAnExchange.map(async tokenAddress => {
|
||||||
|
await new Promise(resolve => setTimeout(resolve, STAGGER_TIME * Math.random()))
|
||||||
|
|
||||||
|
const exchangeAddress = allTokens[tokenAddress].exchangeAddress
|
||||||
|
const { value: existingValue } =
|
||||||
|
safeAccess(stateRef.current, [chainId, exchangeAddress, tokenAddress]) || {}
|
||||||
|
return existingValue || (await getTokenBalance(tokenAddress, exchangeAddress, library).catch(() => null))
|
||||||
|
})
|
||||||
|
).then(tokenBalances => {
|
||||||
|
updateAllForExchanges(
|
||||||
|
chainId,
|
||||||
|
allTokensWithAnExchange.map(tokenAddress => allTokens[tokenAddress].exchangeAddress),
|
||||||
|
allTokensWithAnExchange.map(tokenAddress => tokenAddress),
|
||||||
|
tokenBalances
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getData()
|
||||||
|
}, [chainId, library, account, allTokens, updateAllForAccount, updateAllForExchanges])
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useAllBalances() {
|
||||||
|
const { chainId } = useWeb3React()
|
||||||
|
const [state] = useBalancesContext()
|
||||||
|
const balances = safeAccess(state, [chainId]) || {}
|
||||||
|
return balances
|
||||||
|
}
|
||||||
|
|
||||||
export function useAddressBalance(address, tokenAddress) {
|
export function useAddressBalance(address, tokenAddress) {
|
||||||
const { library, chainId } = useWeb3React()
|
const { library, chainId } = useWeb3React()
|
||||||
|
|
||||||
@ -96,3 +232,79 @@ export function useExchangeReserves(tokenAddress) {
|
|||||||
|
|
||||||
return { reserveETH, reserveToken }
|
return { reserveETH, reserveToken }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const buildReserveObject = (chainId, tokenAddress, ethReserveAmount, tokenReserveAmount, decimals) => ({
|
||||||
|
token: {
|
||||||
|
chainId,
|
||||||
|
address: tokenAddress,
|
||||||
|
decimals
|
||||||
|
},
|
||||||
|
ethReserve: {
|
||||||
|
token: {
|
||||||
|
chainId,
|
||||||
|
decimals: 18
|
||||||
|
},
|
||||||
|
amount: ethReserveAmount
|
||||||
|
},
|
||||||
|
tokenReserve: {
|
||||||
|
token: {
|
||||||
|
chainId,
|
||||||
|
address: tokenAddress,
|
||||||
|
decimals
|
||||||
|
},
|
||||||
|
amount: tokenReserveAmount
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const daiTokenAddress = '0x6B175474E89094C44Da98b954EedeAC495271d0F'
|
||||||
|
const daiExchangeAddress = '0x2a1530C4C41db0B0b2bB646CB5Eb1A67b7158667'
|
||||||
|
const usdcTokenAddress = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'
|
||||||
|
const usdcExchangeAddress = '0x97deC872013f6B5fB443861090ad931542878126'
|
||||||
|
const tusdTokenAddress = '0x0000000000085d4780B73119b644AE5ecd22b376'
|
||||||
|
const tusdExchangeAddress = '0x5048b9d01097498Fd72F3F14bC9Bc74A5aAc8fA7'
|
||||||
|
export function useETHPriceInUSD() {
|
||||||
|
const { chainId } = useWeb3React()
|
||||||
|
|
||||||
|
let daiReserveETH = useAddressBalance(daiExchangeAddress, 'ETH')
|
||||||
|
let daiReserveToken = useAddressBalance(daiExchangeAddress, daiTokenAddress)
|
||||||
|
let usdcReserveETH = useAddressBalance(usdcExchangeAddress, 'ETH')
|
||||||
|
let usdcReserveToken = useAddressBalance(usdcExchangeAddress, usdcTokenAddress)
|
||||||
|
let tusdReserveETH = useAddressBalance(tusdExchangeAddress, 'ETH')
|
||||||
|
let tusdReserveToken = useAddressBalance(tusdExchangeAddress, tusdTokenAddress)
|
||||||
|
|
||||||
|
const [price, setPrice] = useState()
|
||||||
|
useEffect(() => {
|
||||||
|
if (daiReserveETH && daiReserveToken && usdcReserveETH && usdcReserveToken && tusdReserveETH && tusdReserveToken) {
|
||||||
|
const daiReservesObject = buildReserveObject(
|
||||||
|
chainId,
|
||||||
|
daiTokenAddress,
|
||||||
|
new BigNumber(daiReserveETH.toString()),
|
||||||
|
new BigNumber(daiReserveToken.toString()),
|
||||||
|
18
|
||||||
|
)
|
||||||
|
const tusdReservesObject = buildReserveObject(
|
||||||
|
chainId,
|
||||||
|
tusdTokenAddress,
|
||||||
|
new BigNumber(tusdReserveETH.toString()),
|
||||||
|
new BigNumber(tusdReserveToken.toString()),
|
||||||
|
18
|
||||||
|
)
|
||||||
|
const usdcReservesObject = buildReserveObject(
|
||||||
|
chainId,
|
||||||
|
usdcTokenAddress,
|
||||||
|
new BigNumber(usdcReserveETH.toString()),
|
||||||
|
new BigNumber(usdcReserveToken.toString()),
|
||||||
|
6
|
||||||
|
)
|
||||||
|
|
||||||
|
const stablecoinReserves = [daiReservesObject, usdcReservesObject, tusdReservesObject]
|
||||||
|
|
||||||
|
try {
|
||||||
|
setPrice(getUSDPrice(stablecoinReserves))
|
||||||
|
} catch {
|
||||||
|
setPrice(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [daiReserveETH, daiReserveToken, usdcReserveETH, usdcReserveToken, tusdReserveETH, tusdReserveToken, chainId])
|
||||||
|
|
||||||
|
return price
|
||||||
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import React, { createContext, useContext, useReducer, useMemo, useCallback, useEffect } from 'react'
|
import React, { createContext, useContext, useReducer, useMemo, useCallback, useEffect } from 'react'
|
||||||
import { ethers } from 'ethers'
|
|
||||||
|
|
||||||
import { useWeb3React } from '../hooks'
|
import { useWeb3React } from '../hooks'
|
||||||
import {
|
import {
|
||||||
@ -615,23 +614,10 @@ export function useTokenDetails(tokenAddress) {
|
|||||||
return { name, symbol, decimals, exchangeAddress }
|
return { name, symbol, decimals, exchangeAddress }
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useAllTokenDetails(requireExchange = true) {
|
export function useAllTokenDetails() {
|
||||||
const { chainId } = useWeb3React()
|
const { chainId } = useWeb3React()
|
||||||
|
|
||||||
const [state] = useTokensContext()
|
const [state] = useTokensContext()
|
||||||
const tokenDetails = { ...ETH, ...(safeAccess(state, [chainId]) || {}) }
|
|
||||||
|
|
||||||
return requireExchange
|
return useMemo(() => ({ ...ETH, ...(safeAccess(state, [chainId]) || {}) }), [state, chainId])
|
||||||
? Object.keys(tokenDetails)
|
|
||||||
.filter(
|
|
||||||
tokenAddress =>
|
|
||||||
tokenAddress === 'ETH' ||
|
|
||||||
(safeAccess(tokenDetails, [tokenAddress, EXCHANGE_ADDRESS]) &&
|
|
||||||
safeAccess(tokenDetails, [tokenAddress, EXCHANGE_ADDRESS]) !== ethers.constants.AddressZero)
|
|
||||||
)
|
|
||||||
.reduce((accumulator, tokenAddress) => {
|
|
||||||
accumulator[tokenAddress] = tokenDetails[tokenAddress]
|
|
||||||
return accumulator
|
|
||||||
}, {})
|
|
||||||
: tokenDetails
|
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,9 @@ import { NetworkContextName } from './constants'
|
|||||||
import LocalStorageContextProvider, { Updater as LocalStorageContextUpdater } from './contexts/LocalStorage'
|
import LocalStorageContextProvider, { Updater as LocalStorageContextUpdater } from './contexts/LocalStorage'
|
||||||
import ApplicationContextProvider, { Updater as ApplicationContextUpdater } from './contexts/Application'
|
import ApplicationContextProvider, { Updater as ApplicationContextUpdater } from './contexts/Application'
|
||||||
import TransactionContextProvider, { Updater as TransactionContextUpdater } from './contexts/Transactions'
|
import TransactionContextProvider, { Updater as TransactionContextUpdater } from './contexts/Transactions'
|
||||||
|
import BalancesContextProvider, { Updater as BalancesContextUpdater } from './contexts/Balances'
|
||||||
import TokensContextProvider from './contexts/Tokens'
|
import TokensContextProvider from './contexts/Tokens'
|
||||||
import BalancesContextProvider from './contexts/Balances'
|
|
||||||
import AllowancesContextProvider from './contexts/Allowances'
|
import AllowancesContextProvider from './contexts/Allowances'
|
||||||
import AllBalancesContextProvider from './contexts/AllBalances'
|
|
||||||
import App from './pages/App'
|
import App from './pages/App'
|
||||||
import ThemeProvider, { GlobalStyle } from './theme'
|
import ThemeProvider, { GlobalStyle } from './theme'
|
||||||
import './i18n'
|
import './i18n'
|
||||||
@ -38,9 +37,7 @@ function ContextProviders({ children }) {
|
|||||||
<TransactionContextProvider>
|
<TransactionContextProvider>
|
||||||
<TokensContextProvider>
|
<TokensContextProvider>
|
||||||
<BalancesContextProvider>
|
<BalancesContextProvider>
|
||||||
<AllBalancesContextProvider>
|
|
||||||
<AllowancesContextProvider>{children}</AllowancesContextProvider>
|
<AllowancesContextProvider>{children}</AllowancesContextProvider>
|
||||||
</AllBalancesContextProvider>
|
|
||||||
</BalancesContextProvider>
|
</BalancesContextProvider>
|
||||||
</TokensContextProvider>
|
</TokensContextProvider>
|
||||||
</TransactionContextProvider>
|
</TransactionContextProvider>
|
||||||
@ -55,6 +52,7 @@ function Updaters() {
|
|||||||
<LocalStorageContextUpdater />
|
<LocalStorageContextUpdater />
|
||||||
<ApplicationContextUpdater />
|
<ApplicationContextUpdater />
|
||||||
<TransactionContextUpdater />
|
<TransactionContextUpdater />
|
||||||
|
<BalancesContextUpdater />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@ import { brokenTokens } from '../../constants'
|
|||||||
import { amountFormatter, calculateGasMargin } from '../../utils'
|
import { amountFormatter, calculateGasMargin } from '../../utils'
|
||||||
import { useTransactionAdder } from '../../contexts/Transactions'
|
import { useTransactionAdder } from '../../contexts/Transactions'
|
||||||
import { useTokenDetails } from '../../contexts/Tokens'
|
import { useTokenDetails } from '../../contexts/Tokens'
|
||||||
import { useFetchAllBalances } from '../../contexts/AllBalances'
|
|
||||||
import { useAddressBalance, useExchangeReserves } from '../../contexts/Balances'
|
import { useAddressBalance, useExchangeReserves } from '../../contexts/Balances'
|
||||||
import { useAddressAllowance } from '../../contexts/Allowances'
|
import { useAddressAllowance } from '../../contexts/Allowances'
|
||||||
|
|
||||||
@ -567,8 +566,6 @@ export default function AddLiquidity({ params }) {
|
|||||||
const isActive = active && account
|
const isActive = active && account
|
||||||
const isValid = (inputError === null || outputError === null) && !showUnlock && !brokenTokenWarning
|
const isValid = (inputError === null || outputError === null) && !showUnlock && !brokenTokenWarning
|
||||||
|
|
||||||
const allBalances = useFetchAllBalances()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isNewExchange ? (
|
{isNewExchange ? (
|
||||||
@ -585,7 +582,6 @@ export default function AddLiquidity({ params }) {
|
|||||||
|
|
||||||
<CurrencyInputPanel
|
<CurrencyInputPanel
|
||||||
title={t('deposit')}
|
title={t('deposit')}
|
||||||
allBalances={allBalances}
|
|
||||||
extraText={inputBalance && formatBalance(amountFormatter(inputBalance, 18, 4))}
|
extraText={inputBalance && formatBalance(amountFormatter(inputBalance, 18, 4))}
|
||||||
onValueChange={inputValue => {
|
onValueChange={inputValue => {
|
||||||
dispatchAddLiquidityState({ type: 'UPDATE_VALUE', payload: { value: inputValue, field: INPUT } })
|
dispatchAddLiquidityState({ type: 'UPDATE_VALUE', payload: { value: inputValue, field: INPUT } })
|
||||||
@ -613,7 +609,6 @@ export default function AddLiquidity({ params }) {
|
|||||||
</OversizedPanel>
|
</OversizedPanel>
|
||||||
<CurrencyInputPanel
|
<CurrencyInputPanel
|
||||||
title={t('deposit')}
|
title={t('deposit')}
|
||||||
allBalances={allBalances}
|
|
||||||
description={isNewExchange ? '' : outputValue ? `(${t('estimated')})` : ''}
|
description={isNewExchange ? '' : outputValue ? `(${t('estimated')})` : ''}
|
||||||
extraText={
|
extraText={
|
||||||
outputBalance && decimals && formatBalance(amountFormatter(outputBalance, decimals, Math.min(decimals, 4)))
|
outputBalance && decimals && formatBalance(amountFormatter(outputBalance, decimals, Math.min(decimals, 4)))
|
||||||
|
@ -14,7 +14,6 @@ import ArrowDown from '../../assets/svg/SVGArrowDown'
|
|||||||
import { useTransactionAdder } from '../../contexts/Transactions'
|
import { useTransactionAdder } from '../../contexts/Transactions'
|
||||||
import { useTokenDetails } from '../../contexts/Tokens'
|
import { useTokenDetails } from '../../contexts/Tokens'
|
||||||
import { useAddressBalance } from '../../contexts/Balances'
|
import { useAddressBalance } from '../../contexts/Balances'
|
||||||
import { useFetchAllBalances } from '../../contexts/AllBalances'
|
|
||||||
import { calculateGasMargin, amountFormatter } from '../../utils'
|
import { calculateGasMargin, amountFormatter } from '../../utils'
|
||||||
|
|
||||||
// denominated in bips
|
// denominated in bips
|
||||||
@ -334,13 +333,10 @@ export default function RemoveLiquidity({ params }) {
|
|||||||
|
|
||||||
const marketRate = getMarketRate(exchangeETHBalance, exchangeTokenBalance, decimals)
|
const marketRate = getMarketRate(exchangeETHBalance, exchangeTokenBalance, decimals)
|
||||||
|
|
||||||
const allBalances = useFetchAllBalances()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CurrencyInputPanel
|
<CurrencyInputPanel
|
||||||
title={t('poolTokens')}
|
title={t('poolTokens')}
|
||||||
allBalances={allBalances}
|
|
||||||
extraText={poolTokenBalance && formatBalance(amountFormatter(poolTokenBalance, 18, 4))}
|
extraText={poolTokenBalance && formatBalance(amountFormatter(poolTokenBalance, 18, 4))}
|
||||||
extraTextClickHander={() => {
|
extraTextClickHander={() => {
|
||||||
if (poolTokenBalance) {
|
if (poolTokenBalance) {
|
||||||
@ -363,7 +359,6 @@ export default function RemoveLiquidity({ params }) {
|
|||||||
</OversizedPanel>
|
</OversizedPanel>
|
||||||
<CurrencyInputPanel
|
<CurrencyInputPanel
|
||||||
title={t('output')}
|
title={t('output')}
|
||||||
allBalances={allBalances}
|
|
||||||
description={!!(ethWithdrawn && tokenWithdrawn) ? `(${t('estimated')})` : ''}
|
description={!!(ethWithdrawn && tokenWithdrawn) ? `(${t('estimated')})` : ''}
|
||||||
key="remove-liquidity-input"
|
key="remove-liquidity-input"
|
||||||
renderInput={() =>
|
renderInput={() =>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { getTokenReserves, getMarketDetails } from '@uniswap/sdk'
|
import { getMarketDetails } from '@uniswap/sdk'
|
||||||
import { getMedian, getMean } from './math'
|
import { getMedian, getMean } from './math'
|
||||||
|
|
||||||
const DAI = 'DAI'
|
const DAI = 'DAI'
|
||||||
@ -7,37 +7,29 @@ const TUSD = 'TUSD'
|
|||||||
|
|
||||||
const USD_STABLECOINS = [DAI, USDC, TUSD]
|
const USD_STABLECOINS = [DAI, USDC, TUSD]
|
||||||
|
|
||||||
const USD_STABLECOIN_ADDRESSES = [
|
|
||||||
'0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359',
|
|
||||||
'0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
||||||
'0x8dd5fbCe2F6a956C3022bA3663759011Dd51e73E'
|
|
||||||
]
|
|
||||||
|
|
||||||
function forEachStablecoin(runner) {
|
function forEachStablecoin(runner) {
|
||||||
return USD_STABLECOINS.map((stablecoin, index) => runner(index, stablecoin))
|
return USD_STABLECOINS.map((stablecoin, index) => runner(index, stablecoin))
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getUSDPrice(library) {
|
export function getUSDPrice(reserves) {
|
||||||
return Promise.all(forEachStablecoin(i => getTokenReserves(USD_STABLECOIN_ADDRESSES[i], library))).then(reserves => {
|
|
||||||
const ethReserves = forEachStablecoin(i => reserves[i].ethReserve.amount)
|
|
||||||
const marketDetails = forEachStablecoin(i => getMarketDetails(reserves[i], undefined))
|
const marketDetails = forEachStablecoin(i => getMarketDetails(reserves[i], undefined))
|
||||||
|
|
||||||
const ethPrices = forEachStablecoin(i => marketDetails[i].marketRate.rateInverted)
|
const ethPrices = forEachStablecoin(i => marketDetails[i].marketRate.rateInverted)
|
||||||
|
|
||||||
const [median, medianWeights] = getMedian(ethPrices)
|
const [median] = getMedian(ethPrices)
|
||||||
const [mean, meanWeights] = getMean(ethPrices)
|
const [mean] = getMean(ethPrices)
|
||||||
const [weightedMean, weightedMeanWeights] = getMean(ethPrices, ethReserves)
|
const [weightedMean] = getMean(
|
||||||
|
ethPrices,
|
||||||
|
forEachStablecoin(i => reserves[i].ethReserve.amount)
|
||||||
|
)
|
||||||
|
|
||||||
const ethPrice = getMean([median, mean, weightedMean])[0]
|
// const _stablecoinWeights = [
|
||||||
const _stablecoinWeights = [
|
// getMean([medianWeights[0], meanWeights[0], weightedMeanWeights[0]])[0],
|
||||||
getMean([medianWeights[0], meanWeights[0], weightedMeanWeights[0]])[0],
|
// getMean([medianWeights[1], meanWeights[1], weightedMeanWeights[1]])[0],
|
||||||
getMean([medianWeights[1], meanWeights[1], weightedMeanWeights[1]])[0],
|
// getMean([medianWeights[2], meanWeights[2], weightedMeanWeights[2]])[0]
|
||||||
getMean([medianWeights[2], meanWeights[2], weightedMeanWeights[2]])[0]
|
// ]
|
||||||
]
|
// const stablecoinWeights = forEachStablecoin((i, stablecoin) => ({
|
||||||
const stablecoinWeights = forEachStablecoin((i, stablecoin) => ({
|
// [stablecoin]: _stablecoinWeights[i]
|
||||||
[stablecoin]: _stablecoinWeights[i]
|
// })).reduce((accumulator, currentValue) => ({ ...accumulator, ...currentValue }), {})
|
||||||
})).reduce((accumulator, currentValue) => ({ ...accumulator, ...currentValue }), {})
|
|
||||||
|
|
||||||
return [ethPrice, stablecoinWeights]
|
return getMean([median, mean, weightedMean])[0]
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user