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:
Moody Salem 2020-07-09 09:55:20 -04:00 committed by GitHub
parent 21c1484c0e
commit 0fa238af0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 68 additions and 42 deletions

@ -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' }} />
}

@ -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