fix(swap): swap to account if recipient is null (#940)
* fix(swap): swap to account if recipient is null * fix naming and strict ts error
This commit is contained in:
parent
21c1484c0e
commit
0fa238af0b
@ -62,12 +62,13 @@ export function useSwapCallback(
|
||||
trade: Trade | undefined, // trade to execute, required
|
||||
allowedSlippage: number = INITIAL_ALLOWED_SLIPPAGE, // in bips
|
||||
deadline: number = DEFAULT_DEADLINE_FROM_NOW, // in seconds from now
|
||||
recipientAddressOrName: string // the ENS name or address of the recipient of the trade
|
||||
recipientAddressOrName: string | null // the ENS name or address of the recipient of the trade, or null if swap should be returned to sender
|
||||
): null | (() => Promise<string>) {
|
||||
const { account, chainId, library } = useActiveWeb3React()
|
||||
const addTransaction = useTransactionAdder()
|
||||
|
||||
const { address: recipient } = useENS(recipientAddressOrName)
|
||||
const { address: recipientAddress } = useENS(recipientAddressOrName)
|
||||
const recipient = recipientAddressOrName === null ? account : recipientAddress
|
||||
|
||||
const tradeVersion = getTradeVersion(trade)
|
||||
const v1Exchange = useV1ExchangeContract(useV1TradeExchangeAddress(trade), true)
|
||||
@ -284,7 +285,9 @@ export function useSwapCallback(
|
||||
recipient === account
|
||||
? base
|
||||
: `${base} to ${
|
||||
isAddress(recipientAddressOrName) ? shortenAddress(recipientAddressOrName) : recipientAddressOrName
|
||||
recipientAddressOrName && isAddress(recipientAddressOrName)
|
||||
? shortenAddress(recipientAddressOrName)
|
||||
: recipientAddressOrName
|
||||
}`
|
||||
|
||||
const withVersion =
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { JSBI, TokenAmount, WETH } from '@uniswap/sdk'
|
||||
import React, { useContext, useState, useEffect } from 'react'
|
||||
import React, { useContext, useState, useEffect, useCallback } from 'react'
|
||||
import { ArrowDown } from 'react-feather'
|
||||
import ReactGA from 'react-ga'
|
||||
import { Text } from 'rebass'
|
||||
@ -61,18 +61,19 @@ export default function Swap() {
|
||||
|
||||
// swap state
|
||||
const { independentField, typedValue, recipient } = useSwapState()
|
||||
const { bestTrade: bestTradeV2, tokenBalances, parsedAmount, tokens, error, v1Trade } = useDerivedSwapInfo()
|
||||
const { v1Trade, v2Trade, tokenBalances, parsedAmount, tokens, error } = useDerivedSwapInfo()
|
||||
const { address: recipientAddress } = useENSAddress(recipient)
|
||||
const toggledVersion = useToggledVersion()
|
||||
const trade = {
|
||||
[Version.v1]: v1Trade,
|
||||
[Version.v2]: bestTradeV2
|
||||
}[toggledVersion]
|
||||
const trade =
|
||||
{
|
||||
[Version.v1]: v1Trade,
|
||||
[Version.v2]: v2Trade
|
||||
}[toggledVersion] ?? undefined
|
||||
|
||||
const betterTradeLinkVersion: Version | undefined =
|
||||
toggledVersion === Version.v2 && isTradeBetter(bestTradeV2, v1Trade, BETTER_TRADE_LINK_THRESHOLD)
|
||||
toggledVersion === Version.v2 && isTradeBetter(v2Trade, v1Trade, BETTER_TRADE_LINK_THRESHOLD)
|
||||
? Version.v1
|
||||
: toggledVersion === Version.v1 && isTradeBetter(v1Trade, bestTradeV2)
|
||||
: toggledVersion === Version.v1 && isTradeBetter(v1Trade, v2Trade)
|
||||
? Version.v2
|
||||
: undefined
|
||||
|
||||
@ -85,6 +86,19 @@ export default function Swap() {
|
||||
const isValid = !error
|
||||
const dependentField: Field = independentField === Field.INPUT ? Field.OUTPUT : Field.INPUT
|
||||
|
||||
const handleTypeInput = useCallback(
|
||||
(field, value) => {
|
||||
onUserInput(Field.INPUT, value)
|
||||
},
|
||||
[onUserInput]
|
||||
)
|
||||
const handleTypeOutput = useCallback(
|
||||
(field, value) => {
|
||||
onUserInput(Field.OUTPUT, value)
|
||||
},
|
||||
[onUserInput]
|
||||
)
|
||||
|
||||
// modal and loading
|
||||
const [showConfirm, setShowConfirm] = useState<boolean>(false) // show confirmation modal
|
||||
const [attemptingTxn, setAttemptingTxn] = useState<boolean>(false) // waiting for user confirmaion/rejection
|
||||
@ -92,15 +106,13 @@ export default function Swap() {
|
||||
|
||||
const formattedAmounts = {
|
||||
[independentField]: typedValue,
|
||||
[dependentField]: parsedAmounts[dependentField] ? parsedAmounts[dependentField].toSignificant(6) : ''
|
||||
[dependentField]: parsedAmounts[dependentField]?.toSignificant(6) ?? ''
|
||||
}
|
||||
|
||||
const route = trade?.route
|
||||
const userHasSpecifiedInputOutput =
|
||||
!!tokens[Field.INPUT] &&
|
||||
!!tokens[Field.OUTPUT] &&
|
||||
!!parsedAmounts[independentField] &&
|
||||
parsedAmounts[independentField].greaterThan(JSBI.BigInt(0))
|
||||
const userHasSpecifiedInputOutput = Boolean(
|
||||
tokens[Field.INPUT] && tokens[Field.OUTPUT] && parsedAmounts[independentField]?.greaterThan(JSBI.BigInt(0))
|
||||
)
|
||||
const noRoute = !route
|
||||
|
||||
// check whether the user has approved the router on the input token
|
||||
@ -116,19 +128,22 @@ export default function Swap() {
|
||||
}
|
||||
}, [approval, approvalSubmitted])
|
||||
|
||||
const maxAmountInput: TokenAmount =
|
||||
!!tokenBalances[Field.INPUT] &&
|
||||
!!tokens[Field.INPUT] &&
|
||||
!!WETH[chainId] &&
|
||||
tokenBalances[Field.INPUT].greaterThan(
|
||||
new TokenAmount(tokens[Field.INPUT], tokens[Field.INPUT].equals(WETH[chainId]) ? MIN_ETH : '0')
|
||||
)
|
||||
? tokens[Field.INPUT].equals(WETH[chainId])
|
||||
? tokenBalances[Field.INPUT].subtract(new TokenAmount(WETH[chainId], MIN_ETH))
|
||||
: tokenBalances[Field.INPUT]
|
||||
: undefined
|
||||
const atMaxAmountInput: boolean =
|
||||
maxAmountInput && parsedAmounts[Field.INPUT] ? maxAmountInput.equalTo(parsedAmounts[Field.INPUT]) : undefined
|
||||
let maxAmountInput: TokenAmount | undefined
|
||||
{
|
||||
const inputToken = tokens[Field.INPUT]
|
||||
maxAmountInput =
|
||||
inputToken &&
|
||||
chainId &&
|
||||
WETH[chainId] &&
|
||||
tokenBalances[Field.INPUT]?.greaterThan(
|
||||
new TokenAmount(inputToken, inputToken.equals(WETH[chainId]) ? MIN_ETH : '0')
|
||||
)
|
||||
? inputToken.equals(WETH[chainId])
|
||||
? tokenBalances[Field.INPUT]?.subtract(new TokenAmount(WETH[chainId], MIN_ETH))
|
||||
: tokenBalances[Field.INPUT]
|
||||
: undefined
|
||||
}
|
||||
const atMaxAmountInput = Boolean(maxAmountInput && parsedAmounts[Field.INPUT]?.equalTo(maxAmountInput))
|
||||
|
||||
const slippageAdjustedAmounts = computeSlippageAdjustedAmounts(trade, allowedSlippage)
|
||||
|
||||
@ -141,6 +156,9 @@ export default function Swap() {
|
||||
if (priceImpactWithoutFee && !confirmPriceImpactWithoutFee(priceImpactWithoutFee)) {
|
||||
return
|
||||
}
|
||||
if (!swapCallback) {
|
||||
return
|
||||
}
|
||||
setAttemptingTxn(true)
|
||||
swapCallback()
|
||||
.then(hash => {
|
||||
@ -155,7 +173,9 @@ export default function Swap() {
|
||||
: (recipientAddress ?? recipient) === account
|
||||
? 'Swap w/o Send + recipient'
|
||||
: 'Swap w/ Send',
|
||||
label: [trade.inputAmount.token.symbol, trade.outputAmount.token.symbol, getTradeVersion(trade)].join('/')
|
||||
label: [trade?.inputAmount?.token?.symbol, trade?.outputAmount?.token?.symbol, getTradeVersion(trade)].join(
|
||||
'/'
|
||||
)
|
||||
})
|
||||
})
|
||||
.catch(error => {
|
||||
@ -248,7 +268,7 @@ export default function Swap() {
|
||||
value={formattedAmounts[Field.INPUT]}
|
||||
showMaxButton={!atMaxAmountInput}
|
||||
token={tokens[Field.INPUT]}
|
||||
onUserInput={onUserInput}
|
||||
onUserInput={handleTypeInput}
|
||||
onMax={() => {
|
||||
maxAmountInput && onUserInput(Field.INPUT, maxAmountInput.toExact())
|
||||
}}
|
||||
@ -284,7 +304,7 @@ export default function Swap() {
|
||||
<CurrencyInputPanel
|
||||
field={Field.OUTPUT}
|
||||
value={formattedAmounts[Field.OUTPUT]}
|
||||
onUserInput={onUserInput}
|
||||
onUserInput={handleTypeOutput}
|
||||
label={independentField === Field.INPUT ? 'To (estimated)' : 'To'}
|
||||
showMaxButton={false}
|
||||
token={tokens[Field.OUTPUT]}
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Redirects to swap but only replace the pathname
|
||||
import React from 'react'
|
||||
import { Redirect, RouteComponentProps } from 'react-router-dom'
|
||||
|
||||
// Redirects to swap but only replace the pathname
|
||||
export function RedirectPathToSwapOnly({ location }: RouteComponentProps) {
|
||||
return <Redirect to={{ ...location, pathname: '/swap' }} />
|
||||
}
|
||||
|
4
src/pages/Swap/tsconfig.json
Normal file
4
src/pages/Swap/tsconfig.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.strict.json",
|
||||
"include": ["**/*"]
|
||||
}
|
@ -91,7 +91,7 @@ export function useDerivedSwapInfo(): {
|
||||
tokens: { [field in Field]?: Token }
|
||||
tokenBalances: { [field in Field]?: TokenAmount }
|
||||
parsedAmount: TokenAmount | undefined
|
||||
bestTrade: Trade | null
|
||||
v2Trade: Trade | undefined
|
||||
error?: string
|
||||
v1Trade: Trade | undefined
|
||||
} {
|
||||
@ -123,7 +123,7 @@ export function useDerivedSwapInfo(): {
|
||||
const bestTradeExactIn = useTradeExactIn(isExactIn ? parsedAmount : undefined, tokenOut ?? undefined)
|
||||
const bestTradeExactOut = useTradeExactOut(tokenIn ?? undefined, !isExactIn ? parsedAmount : undefined)
|
||||
|
||||
const bestTrade = isExactIn ? bestTradeExactIn : bestTradeExactOut
|
||||
const v2Trade = isExactIn ? bestTradeExactIn : bestTradeExactOut
|
||||
|
||||
const tokenBalances = {
|
||||
[Field.INPUT]: relevantTokenBalances?.[tokenIn?.address ?? ''],
|
||||
@ -157,8 +157,7 @@ export function useDerivedSwapInfo(): {
|
||||
|
||||
const [allowedSlippage] = useUserSlippageTolerance()
|
||||
|
||||
const slippageAdjustedAmounts =
|
||||
bestTrade && allowedSlippage && computeSlippageAdjustedAmounts(bestTrade, allowedSlippage)
|
||||
const slippageAdjustedAmounts = v2Trade && allowedSlippage && computeSlippageAdjustedAmounts(v2Trade, allowedSlippage)
|
||||
|
||||
const slippageAdjustedAmountsV1 =
|
||||
v1Trade && allowedSlippage && computeSlippageAdjustedAmounts(v1Trade, allowedSlippage)
|
||||
@ -183,7 +182,7 @@ export function useDerivedSwapInfo(): {
|
||||
tokens,
|
||||
tokenBalances,
|
||||
parsedAmount,
|
||||
bestTrade,
|
||||
v2Trade: v2Trade ?? undefined,
|
||||
error,
|
||||
v1Trade
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { BLOCKED_PRICE_IMPACT_NON_EXPERT } from './../constants/index'
|
||||
import { BLOCKED_PRICE_IMPACT_NON_EXPERT } from '../constants'
|
||||
import { Fraction, JSBI, Percent, TokenAmount, Trade } from '@uniswap/sdk'
|
||||
import { ALLOWED_PRICE_IMPACT_HIGH, ALLOWED_PRICE_IMPACT_LOW, ALLOWED_PRICE_IMPACT_MEDIUM } from '../constants'
|
||||
import { Field } from '../state/swap/actions'
|
||||
@ -42,7 +42,7 @@ export function computeTradePriceBreakdown(
|
||||
|
||||
// computes the minimum amount out and maximum amount in for a trade given a user specified allowed slippage in bips
|
||||
export function computeSlippageAdjustedAmounts(
|
||||
trade: Trade,
|
||||
trade: Trade | undefined,
|
||||
allowedSlippage: number
|
||||
): { [field in Field]?: TokenAmount } {
|
||||
const pct = basisPointsToPercent(allowedSlippage)
|
||||
@ -52,7 +52,7 @@ export function computeSlippageAdjustedAmounts(
|
||||
}
|
||||
}
|
||||
|
||||
export function warningSeverity(priceImpact: Percent): 0 | 1 | 2 | 3 | 4 {
|
||||
export function warningSeverity(priceImpact: Percent | undefined): 0 | 1 | 2 | 3 | 4 {
|
||||
if (!priceImpact?.lessThan(BLOCKED_PRICE_IMPACT_NON_EXPERT)) return 4
|
||||
if (!priceImpact?.lessThan(ALLOWED_PRICE_IMPACT_HIGH)) return 3
|
||||
if (!priceImpact?.lessThan(ALLOWED_PRICE_IMPACT_MEDIUM)) return 2
|
||||
|
Loading…
Reference in New Issue
Block a user