Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30f7385db7 | ||
|
|
c0f58ae810 | ||
|
|
54dd5476ca | ||
|
|
57786335df | ||
|
|
948e01a196 | ||
|
|
abf127c596 | ||
|
|
4d3f870b93 | ||
|
|
452f2dc3c0 | ||
|
|
b6bd59f2b1 | ||
|
|
0190b5a408 | ||
|
|
d6030dcd45 | ||
|
|
f0e2a491dc | ||
|
|
021aab6547 | ||
|
|
81af31eec1 | ||
|
|
d3898cf900 | ||
|
|
b8f61d5f90 |
@@ -49,7 +49,7 @@
|
||||
"@uniswap/v2-sdk": "^1.0.9",
|
||||
"@uniswap/v3-core": "1.0.0",
|
||||
"@uniswap/v3-periphery": "1.0.0",
|
||||
"@uniswap/v3-sdk": "^1.0.3",
|
||||
"@uniswap/v3-sdk": "^1.0.8",
|
||||
"@web3-react/core": "^6.0.9",
|
||||
"@web3-react/fortmatic-connector": "^6.0.9",
|
||||
"@web3-react/injected-connector": "^6.0.7",
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.4 MiB |
BIN
src/assets/images/sandtexture.webp
Normal file
BIN
src/assets/images/sandtexture.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 235 KiB |
@@ -6,7 +6,7 @@ import { NavLink, Link as HistoryLink } from 'react-router-dom'
|
||||
|
||||
import { ArrowLeft } from 'react-feather'
|
||||
import { RowBetween } from '../Row'
|
||||
import Settings from '../Settings'
|
||||
import SettingsTab from '../Settings'
|
||||
import { useDispatch } from 'react-redux'
|
||||
import { AppDispatch } from 'state'
|
||||
import { resetMintState } from 'state/mint/actions'
|
||||
@@ -80,7 +80,7 @@ export function FindPoolTabs({ origin }: { origin: string }) {
|
||||
<StyledArrowLeft />
|
||||
</HistoryLink>
|
||||
<ActiveText>Import Pool</ActiveText>
|
||||
<Settings />
|
||||
<SettingsTab />
|
||||
</RowBetween>
|
||||
</Tabs>
|
||||
)
|
||||
@@ -118,7 +118,7 @@ export function AddRemoveTabs({
|
||||
<TYPE.mediumHeader fontWeight={500} fontSize={20}>
|
||||
{creating ? 'Create a pair' : adding ? 'Add Liquidity' : 'Remove Liquidity'}
|
||||
</TYPE.mediumHeader>
|
||||
<Settings />
|
||||
<SettingsTab />
|
||||
</RowBetween>
|
||||
</Tabs>
|
||||
)
|
||||
|
||||
@@ -202,8 +202,8 @@ export default function PositionListItem({ positionDetails }: PositionListItemPr
|
||||
// prices
|
||||
let { priceLower, priceUpper, base, quote } = getPriceOrderingFromPositionForUI(position)
|
||||
const inverted = token1 ? base?.equals(token1) : undefined
|
||||
const currencyQuote = inverted ? currency0 : currency1
|
||||
const currencyBase = inverted ? currency1 : currency0
|
||||
const currencyQuote = inverted ? currency1 : currency0
|
||||
const currencyBase = inverted ? currency0 : currency1
|
||||
|
||||
// check if price is within range
|
||||
const outOfRange: boolean = pool ? pool.tickCurrent < tickLower || pool.tickCurrent >= tickUpper : false
|
||||
|
||||
@@ -107,9 +107,9 @@ export default function SlippageTabs({ rawSlippage, setRawSlippage, deadline, se
|
||||
let slippageError: SlippageError | undefined
|
||||
if (slippageInput !== '' && !slippageInputIsValid) {
|
||||
slippageError = SlippageError.InvalidInput
|
||||
} else if (slippageInputIsValid && rawSlippage < 50) {
|
||||
} else if (slippageInputIsValid && rawSlippage < 5) {
|
||||
slippageError = SlippageError.RiskyLow
|
||||
} else if (slippageInputIsValid && rawSlippage > 500) {
|
||||
} else if (slippageInputIsValid && rawSlippage > 100) {
|
||||
slippageError = SlippageError.RiskyHigh
|
||||
} else {
|
||||
slippageError = undefined
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react'
|
||||
import styled from 'styled-components'
|
||||
import Settings from '../Settings'
|
||||
import SettingsTab from '../Settings'
|
||||
|
||||
import { RowBetween, RowFixed } from '../Row'
|
||||
import { TYPE } from '../../theme'
|
||||
@@ -23,7 +23,7 @@ export default function SwapHeader() {
|
||||
<RowFixed>
|
||||
{/* <TradeInfo disabled={!trade} trade={trade} /> */}
|
||||
{/* <div style={{ width: '8px' }}></div> */}
|
||||
<Settings />
|
||||
<SettingsTab />
|
||||
</RowFixed>
|
||||
</RowBetween>
|
||||
</StyledSwapHeader>
|
||||
|
||||
@@ -160,10 +160,10 @@ export function useSocksController(): Unisocks | null {
|
||||
) as Unisocks | null
|
||||
}
|
||||
|
||||
export function useV3NFTPositionManagerContract(): NonfungiblePositionManager | null {
|
||||
export function useV3NFTPositionManagerContract(withSignerIfPossible?: boolean): NonfungiblePositionManager | null {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
const address = chainId ? NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[chainId] : undefined
|
||||
return useContract(address, NFTPositionManagerABI) as NonfungiblePositionManager | null
|
||||
return useContract(address, NFTPositionManagerABI, withSignerIfPossible) as NonfungiblePositionManager | null
|
||||
}
|
||||
|
||||
export function useV3Factory(): UniswapV3Factory | null {
|
||||
|
||||
@@ -1,126 +1,53 @@
|
||||
import { useSingleCallResult } from 'state/multicall/hooks'
|
||||
import { useMemo } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { PositionDetails } from 'types/position'
|
||||
import { useV3Pool } from './useContract'
|
||||
import { useV3NFTPositionManagerContract } from './useContract'
|
||||
import { BigNumber } from '@ethersproject/bignumber'
|
||||
import { computePoolAddress, Pool } from '@uniswap/v3-sdk'
|
||||
import { V3_CORE_FACTORY_ADDRESSES } from 'constants/v3'
|
||||
import { useActiveWeb3React } from 'hooks'
|
||||
import { Pool } from '@uniswap/v3-sdk'
|
||||
import { TokenAmount } from '@uniswap/sdk-core'
|
||||
import { useBlockNumber } from 'state/application/hooks'
|
||||
|
||||
// TODO port these utility functions to the SDK
|
||||
|
||||
function subIn256(x: BigNumber, y: BigNumber): BigNumber {
|
||||
const difference = x.sub(y)
|
||||
return difference.lt(0) ? BigNumber.from(2).pow(256).add(difference) : difference
|
||||
}
|
||||
|
||||
function getCounterfactualFees(
|
||||
feeGrowthGlobal: BigNumber,
|
||||
feeGrowthOutsideLower: BigNumber,
|
||||
feeGrowthOutsideUpper: BigNumber,
|
||||
feeGrowthInsideLast: BigNumber,
|
||||
pool: Pool,
|
||||
liquidity: BigNumber,
|
||||
tickLower: number,
|
||||
tickUpper: number
|
||||
) {
|
||||
let feeGrowthBelow: BigNumber
|
||||
if (pool.tickCurrent >= tickLower) {
|
||||
feeGrowthBelow = feeGrowthOutsideLower
|
||||
} else {
|
||||
feeGrowthBelow = subIn256(feeGrowthGlobal, feeGrowthOutsideLower)
|
||||
}
|
||||
|
||||
let feeGrowthAbove: BigNumber
|
||||
if (pool.tickCurrent < tickUpper) {
|
||||
feeGrowthAbove = feeGrowthOutsideUpper
|
||||
} else {
|
||||
feeGrowthAbove = subIn256(feeGrowthGlobal, feeGrowthOutsideUpper)
|
||||
}
|
||||
|
||||
const feeGrowthInside = subIn256(subIn256(feeGrowthGlobal, feeGrowthBelow), feeGrowthAbove)
|
||||
|
||||
return subIn256(feeGrowthInside, feeGrowthInsideLast).mul(liquidity).div(BigNumber.from(2).pow(128))
|
||||
}
|
||||
const MAX_UINT128 = BigNumber.from(2).pow(128).sub(1)
|
||||
|
||||
// compute current + counterfactual fees for a v3 position
|
||||
export function useV3PositionFees(
|
||||
pool?: Pool,
|
||||
positionDetails?: PositionDetails
|
||||
): [TokenAmount, TokenAmount] | [undefined, undefined] {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
const positionManager = useV3NFTPositionManagerContract(false)
|
||||
const owner = useSingleCallResult(positionDetails?.tokenId ? positionManager : null, 'ownerOf', [
|
||||
positionDetails?.tokenId,
|
||||
]).result?.[0]
|
||||
|
||||
const poolAddress = useMemo(() => {
|
||||
try {
|
||||
return chainId && V3_CORE_FACTORY_ADDRESSES[chainId] && pool && positionDetails
|
||||
? computePoolAddress({
|
||||
factoryAddress: V3_CORE_FACTORY_ADDRESSES[chainId] as string,
|
||||
tokenA: pool.token0,
|
||||
tokenB: pool.token1,
|
||||
fee: positionDetails.fee,
|
||||
})
|
||||
: undefined
|
||||
} catch {
|
||||
return undefined
|
||||
const tokenId = positionDetails?.tokenId?.toHexString()
|
||||
const latestBlockNumber = useBlockNumber()
|
||||
|
||||
// TODO find a way to get this into multicall
|
||||
// because fees don't ever go down, we don't actually need to clear this state
|
||||
// latestBlockNumber is included to ensure data stays up-to-date fresh
|
||||
const [amounts, setAmounts] = useState<[BigNumber, BigNumber]>()
|
||||
useEffect(() => {
|
||||
if (positionManager && tokenId && owner && typeof latestBlockNumber === 'number') {
|
||||
positionManager.callStatic
|
||||
.collect(
|
||||
{
|
||||
tokenId,
|
||||
recipient: owner, // some tokens might fail if transferred to address(0)
|
||||
amount0Max: MAX_UINT128,
|
||||
amount1Max: MAX_UINT128,
|
||||
},
|
||||
{ from: owner } // need to simulate the call as the owner
|
||||
)
|
||||
.then((results) => {
|
||||
setAmounts([results.amount0, results.amount1])
|
||||
})
|
||||
}
|
||||
}, [chainId, pool, positionDetails])
|
||||
const poolContract = useV3Pool(poolAddress)
|
||||
}, [positionManager, tokenId, owner, latestBlockNumber])
|
||||
|
||||
// data fetching
|
||||
const feeGrowthGlobal0: BigNumber | undefined = useSingleCallResult(poolContract, 'feeGrowthGlobal0X128')?.result?.[0]
|
||||
const feeGrowthGlobal1: BigNumber | undefined = useSingleCallResult(poolContract, 'feeGrowthGlobal1X128')?.result?.[0]
|
||||
const { feeGrowthOutside0X128: feeGrowthOutsideLower0 } = (useSingleCallResult(poolContract, 'ticks', [
|
||||
positionDetails?.tickLower,
|
||||
])?.result ?? {}) as { feeGrowthOutside0X128?: BigNumber }
|
||||
const { feeGrowthOutside1X128: feeGrowthOutsideLower1 } = (useSingleCallResult(poolContract, 'ticks', [
|
||||
positionDetails?.tickLower,
|
||||
])?.result ?? {}) as { feeGrowthOutside1X128?: BigNumber }
|
||||
const { feeGrowthOutside0X128: feeGrowthOutsideUpper0 } = (useSingleCallResult(poolContract, 'ticks', [
|
||||
positionDetails?.tickUpper,
|
||||
])?.result ?? {}) as { feeGrowthOutside0X128?: BigNumber }
|
||||
const { feeGrowthOutside1X128: feeGrowthOutsideUpper1 } = (useSingleCallResult(poolContract, 'ticks', [
|
||||
positionDetails?.tickUpper,
|
||||
])?.result ?? {}) as { feeGrowthOutside1X128?: BigNumber }
|
||||
|
||||
// calculate fees
|
||||
const counterfactualFees0 =
|
||||
positionDetails && pool && feeGrowthGlobal0 && feeGrowthOutsideLower0 && feeGrowthOutsideUpper0
|
||||
? getCounterfactualFees(
|
||||
feeGrowthGlobal0,
|
||||
feeGrowthOutsideLower0,
|
||||
feeGrowthOutsideUpper0,
|
||||
positionDetails.feeGrowthInside0LastX128,
|
||||
pool,
|
||||
positionDetails.liquidity,
|
||||
positionDetails.tickLower,
|
||||
positionDetails.tickUpper
|
||||
)
|
||||
: undefined
|
||||
const counterfactualFees1 =
|
||||
positionDetails && pool && feeGrowthGlobal1 && feeGrowthOutsideLower1 && feeGrowthOutsideUpper1
|
||||
? getCounterfactualFees(
|
||||
feeGrowthGlobal1,
|
||||
feeGrowthOutsideLower1,
|
||||
feeGrowthOutsideUpper1,
|
||||
positionDetails.feeGrowthInside1LastX128,
|
||||
pool,
|
||||
positionDetails.liquidity,
|
||||
positionDetails.tickLower,
|
||||
positionDetails.tickUpper
|
||||
)
|
||||
: undefined
|
||||
|
||||
if (
|
||||
pool &&
|
||||
positionDetails?.tokensOwed0 &&
|
||||
positionDetails?.tokensOwed1 &&
|
||||
counterfactualFees0 &&
|
||||
counterfactualFees1
|
||||
) {
|
||||
if (pool && positionDetails && amounts) {
|
||||
return [
|
||||
new TokenAmount(pool.token0, positionDetails.tokensOwed0.add(counterfactualFees0).toString()),
|
||||
new TokenAmount(pool.token1, positionDetails.tokensOwed1.add(counterfactualFees1).toString()),
|
||||
new TokenAmount(pool.token0, positionDetails.tokensOwed0.add(amounts[0]).toString()),
|
||||
new TokenAmount(pool.token1, positionDetails.tokensOwed1.add(amounts[1]).toString()),
|
||||
]
|
||||
} else {
|
||||
return [undefined, undefined]
|
||||
|
||||
@@ -6,7 +6,6 @@ import { Text } from 'rebass'
|
||||
import { AutoColumn } from '../../components/Column'
|
||||
import CurrencyLogo from '../../components/CurrencyLogo'
|
||||
import FormattedCurrencyAmount from '../../components/FormattedCurrencyAmount'
|
||||
import QuestionHelper from '../../components/QuestionHelper'
|
||||
import { AutoRow, RowBetween, RowFixed } from '../../components/Row'
|
||||
import { useV2LiquidityTokenPermit } from '../../hooks/useERC20Permit'
|
||||
import { useTotalSupply } from '../../hooks/useTotalSupply'
|
||||
@@ -16,7 +15,7 @@ import { usePairContract, useV2MigratorContract } from '../../hooks/useContract'
|
||||
import { NEVER_RELOAD, useSingleCallResult } from '../../state/multicall/hooks'
|
||||
import { useTokenBalance } from '../../state/wallet/hooks'
|
||||
import { BackArrow, ExternalLink, TYPE } from '../../theme'
|
||||
import { getEtherscanLink, isAddress } from '../../utils'
|
||||
import { calculateGasMargin, getEtherscanLink, isAddress } from '../../utils'
|
||||
import { BodyWrapper } from '../AppBody'
|
||||
import { V3_MIGRATOR_ADDRESSES } from 'constants/v3'
|
||||
import { PoolState, usePool } from 'hooks/usePools'
|
||||
@@ -46,6 +45,7 @@ import DoubleCurrencyLogo from 'components/DoubleLogo'
|
||||
import Badge, { BadgeVariant } from 'components/Badge'
|
||||
import { useDispatch } from 'react-redux'
|
||||
import { AppDispatch } from 'state'
|
||||
import SettingsTab from 'components/Settings'
|
||||
|
||||
const ZERO = JSBI.BigInt(0)
|
||||
|
||||
@@ -274,7 +274,7 @@ function V2PairMigration({
|
||||
|
||||
const deadlineToUse = signatureData?.deadline ?? deadline
|
||||
|
||||
const data = []
|
||||
const data: string[] = []
|
||||
|
||||
// permit if necessary
|
||||
if (signatureData) {
|
||||
@@ -324,19 +324,24 @@ function V2PairMigration({
|
||||
)
|
||||
|
||||
setConfirmingMigration(true)
|
||||
migrator
|
||||
.multicall(data)
|
||||
.then((response: TransactionResponse) => {
|
||||
ReactGA.event({
|
||||
category: 'Migrate',
|
||||
action: `${isNotUniswap ? 'SushiSwap' : 'V2'}->V3`,
|
||||
label: `${currency0.symbol}/${currency1.symbol}`,
|
||||
})
|
||||
|
||||
addTransaction(response, {
|
||||
summary: `Migrate ${currency0.symbol}/${currency1.symbol} liquidity to V3`,
|
||||
})
|
||||
setPendingMigrationHash(response.hash)
|
||||
migrator.estimateGas
|
||||
.multicall(data)
|
||||
.then((gasEstimate) => {
|
||||
return migrator
|
||||
.multicall(data, { gasLimit: calculateGasMargin(gasEstimate) })
|
||||
.then((response: TransactionResponse) => {
|
||||
ReactGA.event({
|
||||
category: 'Migrate',
|
||||
action: `${isNotUniswap ? 'SushiSwap' : 'V2'}->V3`,
|
||||
label: `${currency0.symbol}/${currency1.symbol}`,
|
||||
})
|
||||
|
||||
addTransaction(response, {
|
||||
summary: `Migrate ${currency0.symbol}/${currency1.symbol} liquidity to V3`,
|
||||
})
|
||||
setPendingMigrationHash(response.hash)
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
setConfirmingMigration(false)
|
||||
@@ -668,9 +673,7 @@ export default function MigrateV2Pair({
|
||||
<AutoRow style={{ alignItems: 'center', justifyContent: 'space-between' }} gap="8px">
|
||||
<BackArrow to="/migrate/v2" />
|
||||
<TYPE.mediumHeader>Migrate V2 Liquidity</TYPE.mediumHeader>
|
||||
<div style={{ opacity: 0 }}>
|
||||
<QuestionHelper text="Migrate your liquidity tokens from Uniswap V2 to Uniswap V3." />
|
||||
</div>
|
||||
<SettingsTab />
|
||||
</AutoRow>
|
||||
|
||||
{!account ? (
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import { ExternalLink } from '../../theme'
|
||||
import { AutoColumn } from 'components/Column'
|
||||
import Squiggle from '../../assets/images/squiggle.png'
|
||||
import Texture from '../../assets/images/sandtexture.png'
|
||||
import Texture from '../../assets/images/sandtexture.webp'
|
||||
import { RowBetween } from 'components/Row'
|
||||
|
||||
const CTASection = styled.section`
|
||||
|
||||
@@ -235,7 +235,7 @@ export default function Vote() {
|
||||
})}
|
||||
</TopSection>
|
||||
<TYPE.subHeader color="text3">
|
||||
A minimum threshhold of 1% of the total UNI supply is required to submit proposals
|
||||
A minimum threshold of 1% of the total UNI supply is required to submit proposals
|
||||
</TYPE.subHeader>
|
||||
</PageWrapper>
|
||||
)
|
||||
|
||||
@@ -10,11 +10,11 @@ export function formatTokenAmount(amount: TokenAmount | undefined, sigFigs: numb
|
||||
return '0'
|
||||
}
|
||||
|
||||
if (parseFloat(amount.toFixed(sigFigs)) < 0.0001) {
|
||||
if (parseFloat(amount.toFixed(Math.min(sigFigs, amount.token.decimals))) < 0.0001) {
|
||||
return '<0.0001'
|
||||
}
|
||||
|
||||
return amount.toSignificant(sigFigs)
|
||||
return amount.toFixed(Math.min(sigFigs, amount.token.decimals))
|
||||
}
|
||||
|
||||
export function formatPrice(price: Price | undefined, sigFigs: number) {
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
import { Web3Provider } from '@ethersproject/providers'
|
||||
import { Web3Provider, Network } from '@ethersproject/providers'
|
||||
|
||||
class WorkaroundWeb3Provider extends Web3Provider {
|
||||
private _detectNetworkResult: Promise<Network> | null = null
|
||||
|
||||
async detectNetwork(): Promise<Network> {
|
||||
return this._detectNetworkResult ?? (this._detectNetworkResult = this._uncachedDetectNetwork())
|
||||
}
|
||||
}
|
||||
|
||||
export default function getLibrary(provider: any): Web3Provider {
|
||||
// latest ethers version tries to detect the network which fails
|
||||
const library = new Web3Provider(
|
||||
const library = new WorkaroundWeb3Provider(
|
||||
provider,
|
||||
typeof provider.chainId === 'number'
|
||||
? provider.chainId
|
||||
|
||||
@@ -28,11 +28,40 @@ describe('utils', () => {
|
||||
describe('#calculateSlippageAmount', () => {
|
||||
it('bounds are correct', () => {
|
||||
const tokenAmount = new TokenAmount(new Token(ChainId.MAINNET, AddressZero, 0), '100')
|
||||
expect(() => calculateSlippageAmount(tokenAmount, new Percent(-1, 10_000))).toThrow()
|
||||
expect(() => calculateSlippageAmount(tokenAmount, new Percent(-1, 10_000))).toThrow('Unexpected slippage')
|
||||
expect(() => calculateSlippageAmount(tokenAmount, new Percent(10_001, 10_000))).toThrow('Unexpected slippage')
|
||||
expect(calculateSlippageAmount(tokenAmount, new Percent(0, 10_000)).map((bound) => bound.toString())).toEqual([
|
||||
'100',
|
||||
'100',
|
||||
])
|
||||
expect(calculateSlippageAmount(tokenAmount, new Percent(5, 100)).map((bound) => bound.toString())).toEqual([
|
||||
'95',
|
||||
'105',
|
||||
])
|
||||
expect(calculateSlippageAmount(tokenAmount, new Percent(100, 10_000)).map((bound) => bound.toString())).toEqual([
|
||||
'99',
|
||||
'101',
|
||||
])
|
||||
expect(calculateSlippageAmount(tokenAmount, new Percent(200, 10_000)).map((bound) => bound.toString())).toEqual([
|
||||
'98',
|
||||
'102',
|
||||
])
|
||||
expect(
|
||||
calculateSlippageAmount(tokenAmount, new Percent(10000, 10_000)).map((bound) => bound.toString())
|
||||
).toEqual(['0', '200'])
|
||||
})
|
||||
it('works for 18 decimals', () => {
|
||||
const tokenAmount = new TokenAmount(new Token(ChainId.MAINNET, AddressZero, 18), '100')
|
||||
expect(() => calculateSlippageAmount(tokenAmount, new Percent(-1, 10_000))).toThrow('Unexpected slippage')
|
||||
expect(() => calculateSlippageAmount(tokenAmount, new Percent(10_001, 10_000))).toThrow('Unexpected slippage')
|
||||
expect(calculateSlippageAmount(tokenAmount, new Percent(0, 10_000)).map((bound) => bound.toString())).toEqual([
|
||||
'100',
|
||||
'100',
|
||||
])
|
||||
expect(calculateSlippageAmount(tokenAmount, new Percent(5, 100)).map((bound) => bound.toString())).toEqual([
|
||||
'95',
|
||||
'105',
|
||||
])
|
||||
expect(calculateSlippageAmount(tokenAmount, new Percent(100, 10_000)).map((bound) => bound.toString())).toEqual([
|
||||
'99',
|
||||
'101',
|
||||
@@ -44,7 +73,6 @@ describe('utils', () => {
|
||||
expect(
|
||||
calculateSlippageAmount(tokenAmount, new Percent(10000, 10_000)).map((bound) => bound.toString())
|
||||
).toEqual(['0', '200'])
|
||||
expect(() => calculateSlippageAmount(tokenAmount, new Percent(10001, 10_000))).toThrow()
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { getAddress } from '@ethersproject/address'
|
||||
import { AddressZero } from '@ethersproject/constants'
|
||||
import { JsonRpcSigner, Web3Provider } from '@ethersproject/providers'
|
||||
import { BigNumber } from '@ethersproject/bignumber'
|
||||
import { ChainId, Percent, Token, CurrencyAmount, Currency, ETHER } from '@uniswap/sdk-core'
|
||||
import { ChainId, Percent, Token, CurrencyAmount, Currency, ETHER, Fraction } from '@uniswap/sdk-core'
|
||||
import { JSBI } from '@uniswap/v2-sdk'
|
||||
import { FeeAmount } from '@uniswap/v3-sdk/dist/'
|
||||
import { TokenAddressMap } from '../state/lists/hooks'
|
||||
@@ -63,16 +63,13 @@ export function calculateGasMargin(value: BigNumber): BigNumber {
|
||||
return value.mul(BigNumber.from(10000).add(BigNumber.from(1000))).div(BigNumber.from(10000))
|
||||
}
|
||||
|
||||
const ONE = new Fraction(1, 1)
|
||||
export function calculateSlippageAmount(value: CurrencyAmount, slippage: Percent): [JSBI, JSBI] {
|
||||
if (
|
||||
JSBI.lessThan(slippage.numerator, JSBI.BigInt(0)) ||
|
||||
JSBI.greaterThan(slippage.numerator, JSBI.BigInt(10_000)) ||
|
||||
!JSBI.equal(slippage.denominator, JSBI.BigInt(10_000))
|
||||
)
|
||||
throw new Error('Unexpected slippage')
|
||||
if (slippage.lessThan(0) || slippage.greaterThan(ONE)) throw new Error('Unexpected slippage')
|
||||
const decimalScaled = JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(value.currency.decimals))
|
||||
return [
|
||||
JSBI.divide(JSBI.multiply(value.raw, JSBI.subtract(JSBI.BigInt(10000), slippage.numerator)), JSBI.BigInt(10000)),
|
||||
JSBI.divide(JSBI.multiply(value.raw, JSBI.add(JSBI.BigInt(10000), slippage.numerator)), JSBI.BigInt(10000)),
|
||||
value.multiply(ONE.subtract(slippage)).multiply(decimalScaled).quotient,
|
||||
value.multiply(ONE.add(slippage)).multiply(decimalScaled).quotient,
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -4149,10 +4149,10 @@
|
||||
"@uniswap/v3-core" "1.0.0"
|
||||
base64-sol "1.0.1"
|
||||
|
||||
"@uniswap/v3-sdk@^1.0.3":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@uniswap/v3-sdk/-/v3-sdk-1.0.3.tgz#8f47b5f8cc8997992811a242ef202f9a8c4797cf"
|
||||
integrity sha512-izIrHTAXCeMhfye0nHntoAS0UTbpa8HyGSD++Zmy+kROeb2gSAcpXvnLHzRDIPxq0G4rOH0h05Y5fhHAxaXj5w==
|
||||
"@uniswap/v3-sdk@^1.0.8":
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/@uniswap/v3-sdk/-/v3-sdk-1.0.8.tgz#c85b229ac9448d19dfb1cb4a7891478c003a72f4"
|
||||
integrity sha512-Kg0P4KZI07m6B6L5EEtkEX/Q6QOdbWnVAHiy8y1XJOxORGw4DS0vklG5IRJAVhgLsVlosbmjxELsBjVMuKtypQ==
|
||||
dependencies:
|
||||
"@ethersproject/abi" "^5.0.12"
|
||||
"@ethersproject/solidity" "^5.0.9"
|
||||
|
||||
Reference in New Issue
Block a user