Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
I
interface
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
LuckySwap
interface
Commits
ae664dc2
Unverified
Commit
ae664dc2
authored
Feb 16, 2022
by
Zach Pomerantz
Committed by
GitHub
Feb 16, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: compute insufficient balance and approval off of input (#3312)
parent
b152b115
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
113 additions
and
64 deletions
+113
-64
Input.tsx
src/lib/components/Swap/Input.tsx
+21
-8
Output.tsx
src/lib/components/Swap/Output.tsx
+3
-3
index.tsx
src/lib/components/Swap/Summary/index.tsx
+4
-5
SwapButton.tsx
src/lib/components/Swap/SwapButton.tsx
+38
-24
index.ts
src/lib/hooks/swap/index.ts
+38
-9
useSwapApproval.ts
src/lib/hooks/swap/useSwapApproval.ts
+5
-4
useSwapInfo.tsx
src/lib/hooks/swap/useSwapInfo.tsx
+4
-8
swap.ts
src/lib/state/swap.ts
+0
-3
No files found.
src/lib/components/Swap/Input.tsx
View file @
ae664dc2
import
{
useLingui
}
from
'
@lingui/react
'
import
{
useLingui
}
from
'
@lingui/react
'
import
{
useUSDCValue
}
from
'
hooks/useUSDCPrice
'
import
{
useUSDCValue
}
from
'
hooks/useUSDCPrice
'
import
{
useAtomValue
}
from
'
jotai/utils
'
import
{
loadingOpacityCss
}
from
'
lib/css/loading
'
import
{
loadingOpacityCss
}
from
'
lib/css/loading
'
import
{
useSwapAmount
,
useSwapCurrency
,
useSwapInfo
}
from
'
lib/hooks/swap
'
import
{
useIsSwapFieldIndependent
,
useSwapAmount
,
useSwapCurrency
,
useSwapCurrencyAmount
,
useSwapInfo
,
}
from
'
lib/hooks/swap
'
import
{
usePrefetchCurrencyColor
}
from
'
lib/hooks/useCurrencyColor
'
import
{
usePrefetchCurrencyColor
}
from
'
lib/hooks/useCurrencyColor
'
import
{
Field
,
independentFieldAtom
}
from
'
lib/state/swap
'
import
{
Field
}
from
'
lib/state/swap
'
import
styled
,
{
ThemedText
}
from
'
lib/theme
'
import
styled
,
{
ThemedText
}
from
'
lib/theme
'
import
{
useMemo
}
from
'
react
'
import
{
useMemo
}
from
'
react
'
import
{
TradeState
}
from
'
state/routing/types
'
import
{
TradeState
}
from
'
state/routing/types
'
...
@@ -45,18 +50,19 @@ export default function Input({ disabled, focused }: InputProps) {
...
@@ -45,18 +50,19 @@ export default function Input({ disabled, focused }: InputProps) {
const
{
const
{
trade
:
{
state
:
tradeState
},
trade
:
{
state
:
tradeState
},
currencyBalances
:
{
[
Field
.
INPUT
]:
balance
},
currencyBalances
:
{
[
Field
.
INPUT
]:
balance
},
currencyAmounts
:
{
[
Field
.
INPUT
]:
i
nputCurrencyAmount
},
currencyAmounts
:
{
[
Field
.
INPUT
]:
swapI
nputCurrencyAmount
},
}
=
useSwapInfo
()
}
=
useSwapInfo
()
const
inputUSDC
=
useUSDCValue
(
i
nputCurrencyAmount
)
const
inputUSDC
=
useUSDCValue
(
swapI
nputCurrencyAmount
)
const
[
swapInputAmount
,
updateSwapInputAmount
]
=
useSwapAmount
(
Field
.
INPUT
)
const
[
swapInputAmount
,
updateSwapInputAmount
]
=
useSwapAmount
(
Field
.
INPUT
)
const
[
swapInputCurrency
,
updateSwapInputCurrency
]
=
useSwapCurrency
(
Field
.
INPUT
)
const
[
swapInputCurrency
,
updateSwapInputCurrency
]
=
useSwapCurrency
(
Field
.
INPUT
)
const
inputCurrencyAmount
=
useSwapCurrencyAmount
(
Field
.
INPUT
)
// extract eagerly in case of reversal
// extract eagerly in case of reversal
usePrefetchCurrencyColor
(
swapInputCurrency
)
usePrefetchCurrencyColor
(
swapInputCurrency
)
const
isRouteLoading
=
tradeState
===
TradeState
.
SYNCING
||
tradeState
===
TradeState
.
LOADING
const
isRouteLoading
=
tradeState
===
TradeState
.
SYNCING
||
tradeState
===
TradeState
.
LOADING
const
isDependentField
=
useAtomValue
(
independentFieldAtom
)
!==
Field
.
INPUT
const
isDependentField
=
!
useIsSwapFieldIndependent
(
Field
.
INPUT
)
const
isLoading
=
isRouteLoading
&&
isDependentField
const
isLoading
=
isRouteLoading
&&
isDependentField
//TODO(ianlapham): mimic logic from app swap page
//TODO(ianlapham): mimic logic from app swap page
...
@@ -72,11 +78,18 @@ export default function Input({ disabled, focused }: InputProps) {
...
@@ -72,11 +78,18 @@ export default function Input({ disabled, focused }: InputProps) {
return
return
},
[
maxAmount
,
updateSwapInputAmount
])
},
[
maxAmount
,
updateSwapInputAmount
])
const
balanceColor
=
useMemo
(()
=>
{
const
insufficientBalance
=
balance
&&
(
inputCurrencyAmount
?
inputCurrencyAmount
.
greaterThan
(
balance
)
:
swapInputCurrencyAmount
?.
greaterThan
(
balance
))
return
insufficientBalance
?
'
error
'
:
undefined
},
[
balance
,
inputCurrencyAmount
,
swapInputCurrencyAmount
])
return
(
return
(
<
InputColumn
gap=
{
0.5
}
approved=
{
mockApproved
}
>
<
InputColumn
gap=
{
0.5
}
approved=
{
mockApproved
}
>
<
TokenInput
<
TokenInput
currency=
{
swapInputCurrency
}
currency=
{
swapInputCurrency
}
amount=
{
(
swapInputAmount
!==
undefined
?
swapInputAmount
:
i
nputCurrencyAmount
?.
toSignificant
(
6
))
??
''
}
amount=
{
(
swapInputAmount
!==
undefined
?
swapInputAmount
:
swapI
nputCurrencyAmount
?.
toSignificant
(
6
))
??
''
}
disabled=
{
disabled
}
disabled=
{
disabled
}
onMax=
{
onMax
}
onMax=
{
onMax
}
onChangeInput=
{
updateSwapInputAmount
}
onChangeInput=
{
updateSwapInputAmount
}
...
@@ -87,7 +100,7 @@ export default function Input({ disabled, focused }: InputProps) {
...
@@ -87,7 +100,7 @@ export default function Input({ disabled, focused }: InputProps) {
<
Row
>
<
Row
>
<
LoadingRow
$loading=
{
isLoading
}
>
{
inputUSDC
?
`$${inputUSDC.toFixed(2)}`
:
'
-
'
}
</
LoadingRow
>
<
LoadingRow
$loading=
{
isLoading
}
>
{
inputUSDC
?
`$${inputUSDC.toFixed(2)}`
:
'
-
'
}
</
LoadingRow
>
{
balance
&&
(
{
balance
&&
(
<
Balance
color=
{
inputCurrencyAmount
?.
greaterThan
(
balance
)
?
'
error
'
:
undefined
}
focused=
{
focused
}
>
<
Balance
color=
{
balanceColor
}
focused=
{
focused
}
>
Balance:
<
span
style=
{
{
userSelect
:
'
text
'
}
}
>
{
formatCurrencyAmount
(
balance
,
4
,
i18n
.
locale
)
}
</
span
>
Balance:
<
span
style=
{
{
userSelect
:
'
text
'
}
}
>
{
formatCurrencyAmount
(
balance
,
4
,
i18n
.
locale
)
}
</
span
>
</
Balance
>
</
Balance
>
)
}
)
}
...
...
src/lib/components/Swap/Output.tsx
View file @
ae664dc2
...
@@ -4,9 +4,9 @@ import { useUSDCValue } from 'hooks/useUSDCPrice'
...
@@ -4,9 +4,9 @@ import { useUSDCValue } from 'hooks/useUSDCPrice'
import
{
atom
}
from
'
jotai
'
import
{
atom
}
from
'
jotai
'
import
{
useAtomValue
}
from
'
jotai/utils
'
import
{
useAtomValue
}
from
'
jotai/utils
'
import
BrandedFooter
from
'
lib/components/BrandedFooter
'
import
BrandedFooter
from
'
lib/components/BrandedFooter
'
import
{
useSwapAmount
,
useSwapCurrency
,
useSwapInfo
}
from
'
lib/hooks/swap
'
import
{
use
IsSwapFieldIndependent
,
use
SwapAmount
,
useSwapCurrency
,
useSwapInfo
}
from
'
lib/hooks/swap
'
import
useCurrencyColor
from
'
lib/hooks/useCurrencyColor
'
import
useCurrencyColor
from
'
lib/hooks/useCurrencyColor
'
import
{
Field
,
independentFieldAtom
}
from
'
lib/state/swap
'
import
{
Field
}
from
'
lib/state/swap
'
import
styled
,
{
DynamicThemeProvider
,
ThemedText
}
from
'
lib/theme
'
import
styled
,
{
DynamicThemeProvider
,
ThemedText
}
from
'
lib/theme
'
import
{
PropsWithChildren
,
useMemo
}
from
'
react
'
import
{
PropsWithChildren
,
useMemo
}
from
'
react
'
import
{
TradeState
}
from
'
state/routing/types
'
import
{
TradeState
}
from
'
state/routing/types
'
...
@@ -50,7 +50,7 @@ export default function Output({ disabled, focused, children }: PropsWithChildre
...
@@ -50,7 +50,7 @@ export default function Output({ disabled, focused, children }: PropsWithChildre
const
[
swapOutputCurrency
,
updateSwapOutputCurrency
]
=
useSwapCurrency
(
Field
.
OUTPUT
)
const
[
swapOutputCurrency
,
updateSwapOutputCurrency
]
=
useSwapCurrency
(
Field
.
OUTPUT
)
const
isRouteLoading
=
tradeState
===
TradeState
.
SYNCING
||
tradeState
===
TradeState
.
LOADING
const
isRouteLoading
=
tradeState
===
TradeState
.
SYNCING
||
tradeState
===
TradeState
.
LOADING
const
isDependentField
=
useAtomValue
(
independentFieldAtom
)
!==
Field
.
OUTPUT
const
isDependentField
=
!
useIsSwapFieldIndependent
(
Field
.
OUTPUT
)
const
isLoading
=
isRouteLoading
&&
isDependentField
const
isLoading
=
isRouteLoading
&&
isDependentField
const
overrideColor
=
useAtomValue
(
colorAtom
)
const
overrideColor
=
useAtomValue
(
colorAtom
)
...
...
src/lib/components/Swap/Summary/index.tsx
View file @
ae664dc2
...
@@ -2,12 +2,11 @@ import { Trans } from '@lingui/macro'
...
@@ -2,12 +2,11 @@ import { Trans } from '@lingui/macro'
import
{
useLingui
}
from
'
@lingui/react
'
import
{
useLingui
}
from
'
@lingui/react
'
import
{
Trade
}
from
'
@uniswap/router-sdk
'
import
{
Trade
}
from
'
@uniswap/router-sdk
'
import
{
Currency
,
Percent
,
TradeType
}
from
'
@uniswap/sdk-core
'
import
{
Currency
,
Percent
,
TradeType
}
from
'
@uniswap/sdk-core
'
import
{
useAtomValue
}
from
'
jotai/utils
'
import
{
IconButton
}
from
'
lib/components/Button
'
import
{
IconButton
}
from
'
lib/components/Button
'
import
{
useSwapTradeType
}
from
'
lib/hooks/swap
'
import
{
getSlippageWarning
}
from
'
lib/hooks/useAllowedSlippage
'
import
{
getSlippageWarning
}
from
'
lib/hooks/useAllowedSlippage
'
import
useScrollbar
from
'
lib/hooks/useScrollbar
'
import
useScrollbar
from
'
lib/hooks/useScrollbar
'
import
{
AlertTriangle
,
BarChart
,
Expando
,
Info
}
from
'
lib/icons
'
import
{
AlertTriangle
,
BarChart
,
Expando
,
Info
}
from
'
lib/icons
'
import
{
Field
,
independentFieldAtom
}
from
'
lib/state/swap
'
import
styled
,
{
ThemedText
}
from
'
lib/theme
'
import
styled
,
{
ThemedText
}
from
'
lib/theme
'
import
formatLocaleNumber
from
'
lib/utils/formatLocaleNumber
'
import
formatLocaleNumber
from
'
lib/utils/formatLocaleNumber
'
import
{
useMemo
,
useState
}
from
'
react
'
import
{
useMemo
,
useState
}
from
'
react
'
...
@@ -89,7 +88,7 @@ export function SummaryDialog({ trade, allowedSlippage, onConfirm }: SummaryDial
...
@@ -89,7 +88,7 @@ export function SummaryDialog({ trade, allowedSlippage, onConfirm }: SummaryDial
const
inputCurrency
=
inputAmount
.
currency
const
inputCurrency
=
inputAmount
.
currency
const
outputCurrency
=
outputAmount
.
currency
const
outputCurrency
=
outputAmount
.
currency
const
priceImpact
=
useMemo
(()
=>
computeRealizedPriceImpact
(
trade
),
[
trade
])
const
priceImpact
=
useMemo
(()
=>
computeRealizedPriceImpact
(
trade
),
[
trade
])
const
independentField
=
useAtomValue
(
independentFieldAtom
)
const
tradeType
=
useSwapTradeType
(
)
const
{
i18n
}
=
useLingui
()
const
{
i18n
}
=
useLingui
()
const
[
open
,
setOpen
]
=
useState
(
false
)
const
[
open
,
setOpen
]
=
useState
(
false
)
...
@@ -160,14 +159,14 @@ export function SummaryDialog({ trade, allowedSlippage, onConfirm }: SummaryDial
...
@@ -160,14 +159,14 @@ export function SummaryDialog({ trade, allowedSlippage, onConfirm }: SummaryDial
</
DetailsColumn
>
</
DetailsColumn
>
<
Estimate
color=
"secondary"
>
<
Estimate
color=
"secondary"
>
<
Trans
>
Output is estimated.
</
Trans
>
<
Trans
>
Output is estimated.
</
Trans
>
{
independentField
===
Field
.
INPUT
&&
(
{
tradeType
===
TradeType
.
EXACT_
INPUT
&&
(
<
Trans
>
<
Trans
>
You will receive at least
{
'
'
}
You will receive at least
{
'
'
}
{
formatCurrencyAmount
(
trade
.
minimumAmountOut
(
allowedSlippage
),
6
,
i18n
.
locale
)
}
{
outputCurrency
.
symbol
}{
'
'
}
{
formatCurrencyAmount
(
trade
.
minimumAmountOut
(
allowedSlippage
),
6
,
i18n
.
locale
)
}
{
outputCurrency
.
symbol
}{
'
'
}
or the transaction will revert.
or the transaction will revert.
</
Trans
>
</
Trans
>
)
}
)
}
{
independentField
===
Field
.
OUTPUT
&&
(
{
tradeType
===
TradeType
.
EXACT_
OUTPUT
&&
(
<
Trans
>
<
Trans
>
You will send at most
{
formatCurrencyAmount
(
trade
.
maximumAmountIn
(
allowedSlippage
),
6
,
i18n
.
locale
)
}{
'
'
}
You will send at most
{
formatCurrencyAmount
(
trade
.
maximumAmountIn
(
allowedSlippage
),
6
,
i18n
.
locale
)
}{
'
'
}
{
inputCurrency
.
symbol
}
or the transaction will revert.
{
inputCurrency
.
symbol
}
or the transaction will revert.
...
...
src/lib/components/Swap/SwapButton.tsx
View file @
ae664dc2
import
{
Trans
}
from
'
@lingui/macro
'
import
{
Trans
}
from
'
@lingui/macro
'
import
{
Token
,
TradeType
}
from
'
@uniswap/sdk-core
'
import
{
Token
}
from
'
@uniswap/sdk-core
'
import
{
useERC20PermitFromTrade
}
from
'
hooks/useERC20Permit
'
import
{
useERC20PermitFromTrade
}
from
'
hooks/useERC20Permit
'
import
{
useUpdateAtom
}
from
'
jotai/utils
'
import
{
useUpdateAtom
}
from
'
jotai/utils
'
import
{
useAtomValue
}
from
'
jotai/utils
'
import
{
useSwapCurrencyAmount
,
useSwapInfo
,
useSwapTradeType
}
from
'
lib/hooks/swap
'
import
{
useSwapInfo
}
from
'
lib/hooks/swap
'
import
useSwapApproval
,
{
import
useSwapApproval
,
{
ApprovalState
,
ApprovalState
,
useSwapApprovalOptimizedTrade
,
useSwapApprovalOptimizedTrade
,
...
@@ -15,7 +14,7 @@ import { usePendingApproval } from 'lib/hooks/transactions'
...
@@ -15,7 +14,7 @@ import { usePendingApproval } from 'lib/hooks/transactions'
import
useActiveWeb3React
from
'
lib/hooks/useActiveWeb3React
'
import
useActiveWeb3React
from
'
lib/hooks/useActiveWeb3React
'
import
useTransactionDeadline
from
'
lib/hooks/useTransactionDeadline
'
import
useTransactionDeadline
from
'
lib/hooks/useTransactionDeadline
'
import
{
Link
,
Spinner
}
from
'
lib/icons
'
import
{
Link
,
Spinner
}
from
'
lib/icons
'
import
{
displayTxHashAtom
,
Field
,
independentFieldAtom
}
from
'
lib/state/swap
'
import
{
displayTxHashAtom
,
Field
}
from
'
lib/state/swap
'
import
{
TransactionType
}
from
'
lib/state/transactions
'
import
{
TransactionType
}
from
'
lib/state/transactions
'
import
{
useTheme
}
from
'
lib/theme
'
import
{
useTheme
}
from
'
lib/theme
'
import
{
useCallback
,
useEffect
,
useMemo
,
useState
}
from
'
react
'
import
{
useCallback
,
useEffect
,
useMemo
,
useState
}
from
'
react
'
...
@@ -50,7 +49,7 @@ export default function SwapButton({ disabled }: SwapButtonProps) {
...
@@ -50,7 +49,7 @@ export default function SwapButton({ disabled }: SwapButtonProps) {
feeOptions
,
feeOptions
,
}
=
useSwapInfo
()
}
=
useSwapInfo
()
const
independentField
=
useAtomValue
(
independentFieldAtom
)
const
tradeType
=
useSwapTradeType
(
)
const
[
activeTrade
,
setActiveTrade
]
=
useState
<
typeof
trade
.
trade
|
undefined
>
()
const
[
activeTrade
,
setActiveTrade
]
=
useState
<
typeof
trade
.
trade
|
undefined
>
()
useEffect
(()
=>
{
useEffect
(()
=>
{
...
@@ -61,7 +60,14 @@ export default function SwapButton({ disabled }: SwapButtonProps) {
...
@@ -61,7 +60,14 @@ export default function SwapButton({ disabled }: SwapButtonProps) {
const
optimizedTrade
=
const
optimizedTrade
=
// Use trade.trade if there is no swap optimized trade. This occurs if approvals are still pending.
// Use trade.trade if there is no swap optimized trade. This occurs if approvals are still pending.
useSwapApprovalOptimizedTrade
(
trade
.
trade
,
allowedSlippage
,
useIsPendingApproval
)
||
trade
.
trade
useSwapApprovalOptimizedTrade
(
trade
.
trade
,
allowedSlippage
,
useIsPendingApproval
)
||
trade
.
trade
const
[
approval
,
getApproval
]
=
useSwapApproval
(
optimizedTrade
,
allowedSlippage
,
useIsPendingApproval
)
const
approvalCurrencyAmount
=
useSwapCurrencyAmount
(
Field
.
INPUT
)
const
[
approval
,
getApproval
]
=
useSwapApproval
(
optimizedTrade
,
allowedSlippage
,
useIsPendingApproval
,
approvalCurrencyAmount
)
const
approvalHash
=
usePendingApproval
(
const
approvalHash
=
usePendingApproval
(
inputCurrency
?.
isToken
?
inputCurrency
:
undefined
,
inputCurrency
?.
isToken
?
inputCurrency
:
undefined
,
useSwapRouterAddress
(
optimizedTrade
)
useSwapRouterAddress
(
optimizedTrade
)
...
@@ -77,11 +83,17 @@ export default function SwapButton({ disabled }: SwapButtonProps) {
...
@@ -77,11 +83,17 @@ export default function SwapButton({ disabled }: SwapButtonProps) {
},
[
addTransaction
,
getApproval
])
},
[
addTransaction
,
getApproval
])
const
actionProps
=
useMemo
(():
Partial
<
ActionButtonProps
>
|
undefined
=>
{
const
actionProps
=
useMemo
(():
Partial
<
ActionButtonProps
>
|
undefined
=>
{
if
(
disabled
)
return
{
disabled
:
true
}
if
(
!
disabled
&&
chainId
)
{
if
(
approval
===
ApprovalState
.
NOT_APPROVED
)
{
if
(
chainId
&&
inputCurrencyAmount
)
{
const
currency
=
inputCurrency
||
approvalCurrencyAmount
?.
currency
if
(
!
inputCurrencyBalance
||
inputCurrencyBalance
.
lessThan
(
inputCurrencyAmount
))
{
invariant
(
currency
)
return
{
disabled
:
true
}
return
{
action
:
{
message
:
<
Trans
>
Approve
{
currency
.
symbol
}
first
</
Trans
>,
onClick
:
addApprovalTransaction
,
children
:
<
Trans
>
Approve
</
Trans
>,
},
}
}
else
if
(
approval
===
ApprovalState
.
PENDING
)
{
}
else
if
(
approval
===
ApprovalState
.
PENDING
)
{
return
{
return
{
disabled
:
true
,
disabled
:
true
,
...
@@ -100,20 +112,22 @@ export default function SwapButton({ disabled }: SwapButtonProps) {
...
@@ -100,20 +112,22 @@ export default function SwapButton({ disabled }: SwapButtonProps) {
children
:
<
Trans
>
Approve
</
Trans
>,
children
:
<
Trans
>
Approve
</
Trans
>,
},
},
}
}
}
else
if
(
approval
===
ApprovalState
.
NOT_APPROVED
)
{
}
else
if
(
inputCurrencyAmount
&&
inputCurrencyBalance
&&
!
inputCurrencyBalance
.
lessThan
(
inputCurrencyAmount
))
{
return
{
return
{}
action
:
{
message
:
<
Trans
>
Approve
{
inputCurrencyAmount
.
currency
.
symbol
}
first
</
Trans
>,
onClick
:
addApprovalTransaction
,
children
:
<
Trans
>
Approve
</
Trans
>,
},
}
}
}
return
{}
}
}
return
{
disabled
:
true
}
return
{
disabled
:
true
}
},
[
addApprovalTransaction
,
approval
,
approvalHash
,
chainId
,
disabled
,
inputCurrencyAmount
,
inputCurrencyBalance
])
},
[
addApprovalTransaction
,
approval
,
approvalCurrencyAmount
?.
currency
,
approvalHash
,
chainId
,
disabled
,
inputCurrency
,
inputCurrencyAmount
,
inputCurrencyBalance
,
])
const
deadline
=
useTransactionDeadline
()
const
deadline
=
useTransactionDeadline
()
const
{
signatureData
}
=
useERC20PermitFromTrade
(
optimizedTrade
,
allowedSlippage
,
deadline
)
const
{
signatureData
}
=
useERC20PermitFromTrade
(
optimizedTrade
,
allowedSlippage
,
deadline
)
...
@@ -139,7 +153,7 @@ export default function SwapButton({ disabled }: SwapButtonProps) {
...
@@ -139,7 +153,7 @@ export default function SwapButton({ disabled }: SwapButtonProps) {
addTransaction
({
addTransaction
({
response
,
response
,
type
:
TransactionType
.
SWAP
,
type
:
TransactionType
.
SWAP
,
tradeType
:
independentField
===
Field
.
INPUT
?
TradeType
.
EXACT_INPUT
:
TradeType
.
EXACT_OUTPUT
,
tradeType
,
inputCurrencyAmount
,
inputCurrencyAmount
,
outputCurrencyAmount
,
outputCurrencyAmount
,
})
})
...
@@ -151,7 +165,7 @@ export default function SwapButton({ disabled }: SwapButtonProps) {
...
@@ -151,7 +165,7 @@ export default function SwapButton({ disabled }: SwapButtonProps) {
.
finally
(()
=>
{
.
finally
(()
=>
{
setActiveTrade
(
undefined
)
setActiveTrade
(
undefined
)
})
})
},
[
addTransaction
,
in
dependentField
,
inputCurrencyAmount
,
outputCurrencyAmount
,
setDisplayTxHash
,
swapCallback
])
},
[
addTransaction
,
in
putCurrencyAmount
,
outputCurrencyAmount
,
setDisplayTxHash
,
swapCallback
,
tradeType
])
return
(
return
(
<>
<>
...
...
src/lib/hooks/swap/index.ts
View file @
ae664dc2
import
{
Currency
}
from
'
@uniswap/sdk-core
'
import
{
Currency
,
CurrencyAmount
,
TradeType
}
from
'
@uniswap/sdk-core
'
import
{
useAtom
}
from
'
jotai
'
import
{
useAtom
}
from
'
jotai
'
import
{
useAtomValue
,
useUpdateAtom
}
from
'
jotai/utils
'
import
{
useAtomValue
,
useUpdateAtom
}
from
'
jotai/utils
'
import
{
pickAtom
}
from
'
lib/state/atoms
'
import
{
pickAtom
}
from
'
lib/state/atoms
'
import
{
Field
,
independentFieldAtom
,
swapAtom
}
from
'
lib/state/swap
'
import
{
Field
,
swapAtom
}
from
'
lib/state/swap
'
import
tryParseCurrencyAmount
from
'
lib/utils/tryParseCurrencyAmount
'
import
{
useCallback
,
useMemo
}
from
'
react
'
import
{
useCallback
,
useMemo
}
from
'
react
'
export
{
default
as
useSwapInfo
}
from
'
./useSwapInfo
'
export
{
default
as
useSwapInfo
}
from
'
./useSwapInfo
'
export
const
amountAtom
=
pickAtom
(
swapAtom
,
'
amount
'
)
function
otherField
(
field
:
Field
)
{
function
otherField
(
field
:
Field
)
{
switch
(
field
)
{
switch
(
field
)
{
case
Field
.
INPUT
:
case
Field
.
INPUT
:
...
@@ -57,10 +56,34 @@ export function useSwapCurrency(field: Field): [Currency | undefined, (currency?
...
@@ -57,10 +56,34 @@ export function useSwapCurrency(field: Field): [Currency | undefined, (currency?
return
[
currency
,
setOrSwitchCurrency
]
return
[
currency
,
setOrSwitchCurrency
]
}
}
const
independentFieldAtom
=
pickAtom
(
swapAtom
,
'
independentField
'
)
export
function
useIsSwapFieldIndependent
(
field
:
Field
):
boolean
{
const
independentField
=
useAtomValue
(
independentFieldAtom
)
return
independentField
===
field
}
export
function
useSwapTradeType
():
TradeType
{
const
independentField
=
useAtomValue
(
independentFieldAtom
)
switch
(
independentField
)
{
case
Field
.
INPUT
:
return
TradeType
.
EXACT_INPUT
case
Field
.
OUTPUT
:
return
TradeType
.
EXACT_OUTPUT
}
}
const
amountAtom
=
pickAtom
(
swapAtom
,
'
amount
'
)
// check if any amount has been entered by user
export
function
useIsAmountPopulated
()
{
return
Boolean
(
useAtomValue
(
amountAtom
))
}
export
function
useSwapAmount
(
field
:
Field
):
[
string
|
undefined
,
(
amount
:
string
)
=>
void
]
{
export
function
useSwapAmount
(
field
:
Field
):
[
string
|
undefined
,
(
amount
:
string
)
=>
void
]
{
const
amount
=
useAtomValue
(
amountAtom
)
const
amount
=
useAtomValue
(
amountAtom
)
const
i
ndependentField
=
useAtomValue
(
independentFieldAtom
)
const
i
sFieldIndependent
=
useIsSwapFieldIndependent
(
field
)
const
value
=
useMemo
(()
=>
(
i
ndependentField
===
field
?
amount
:
undefined
),
[
amount
,
independentField
,
field
])
const
value
=
useMemo
(()
=>
(
i
sFieldIndependent
?
amount
:
undefined
),
[
amount
,
isFieldIndependent
])
const
updateSwap
=
useUpdateAtom
(
swapAtom
)
const
updateSwap
=
useUpdateAtom
(
swapAtom
)
const
updateAmount
=
useCallback
(
const
updateAmount
=
useCallback
(
(
amount
:
string
)
=>
(
amount
:
string
)
=>
...
@@ -73,7 +96,13 @@ export function useSwapAmount(field: Field): [string | undefined, (amount: strin
...
@@ -73,7 +96,13 @@ export function useSwapAmount(field: Field): [string | undefined, (amount: strin
return
[
value
,
updateAmount
]
return
[
value
,
updateAmount
]
}
}
// check if any amount has been entered by user
export
function
useSwapCurrencyAmount
(
field
:
Field
):
CurrencyAmount
<
Currency
>
|
undefined
{
export
function
useIsAmountPopulated
()
{
const
isFieldIndependent
=
useIsSwapFieldIndependent
(
field
)
return
Boolean
(
useAtomValue
(
amountAtom
))
const
isAmountPopulated
=
useIsAmountPopulated
()
const
[
swapAmount
]
=
useSwapAmount
(
field
)
const
[
swapCurrency
]
=
useSwapCurrency
(
field
)
if
(
isFieldIndependent
&&
isAmountPopulated
)
{
return
tryParseCurrencyAmount
(
swapAmount
,
swapCurrency
)
}
return
}
}
src/lib/hooks/swap/useSwapApproval.ts
View file @
ae664dc2
import
{
Protocol
,
Trade
}
from
'
@uniswap/router-sdk
'
import
{
Protocol
,
Trade
}
from
'
@uniswap/router-sdk
'
import
{
Currency
,
Percent
,
Token
,
TradeType
}
from
'
@uniswap/sdk-core
'
import
{
Currency
,
CurrencyAmount
,
Percent
,
Token
,
TradeType
}
from
'
@uniswap/sdk-core
'
import
{
Pair
,
Route
as
V2Route
,
Trade
as
V2Trade
}
from
'
@uniswap/v2-sdk
'
import
{
Pair
,
Route
as
V2Route
,
Trade
as
V2Trade
}
from
'
@uniswap/v2-sdk
'
import
{
Pool
,
Route
as
V3Route
,
Trade
as
V3Trade
}
from
'
@uniswap/v3-sdk
'
import
{
Pool
,
Route
as
V3Route
,
Trade
as
V3Trade
}
from
'
@uniswap/v3-sdk
'
import
{
SWAP_ROUTER_ADDRESSES
,
V2_ROUTER_ADDRESS
,
V3_ROUTER_ADDRESS
}
from
'
constants/addresses
'
import
{
SWAP_ROUTER_ADDRESSES
,
V2_ROUTER_ADDRESS
,
V3_ROUTER_ADDRESS
}
from
'
constants/addresses
'
...
@@ -63,11 +63,12 @@ export default function useSwapApproval(
...
@@ -63,11 +63,12 @@ export default function useSwapApproval(
|
Trade
<
Currency
,
Currency
,
TradeType
>
|
Trade
<
Currency
,
Currency
,
TradeType
>
|
undefined
,
|
undefined
,
allowedSlippage
:
Percent
,
allowedSlippage
:
Percent
,
useIsPendingApproval
:
(
token
?:
Token
,
spender
?:
string
)
=>
boolean
useIsPendingApproval
:
(
token
?:
Token
,
spender
?:
string
)
=>
boolean
,
amount
?:
CurrencyAmount
<
Currency
>
// defaults to trade.maximumAmountIn(allowedSlippage)
)
{
)
{
const
amountToApprove
=
useMemo
(
const
amountToApprove
=
useMemo
(
()
=>
(
trade
&&
trade
.
inputAmount
.
currency
.
isToken
?
trade
.
maximumAmountIn
(
allowedSlippage
)
:
undefined
),
()
=>
amount
||
(
trade
&&
trade
.
inputAmount
.
currency
.
isToken
?
trade
.
maximumAmountIn
(
allowedSlippage
)
:
undefined
),
[
trade
,
allowedSlippage
]
[
amount
,
trade
,
allowedSlippage
]
)
)
const
spender
=
useSwapRouterAddress
(
trade
)
const
spender
=
useSwapRouterAddress
(
trade
)
...
...
src/lib/hooks/swap/useSwapInfo.tsx
View file @
ae664dc2
...
@@ -57,8 +57,6 @@ function useComputeSwapInfo(): SwapInfo {
...
@@ -57,8 +57,6 @@ function useComputeSwapInfo(): SwapInfo {
()
=>
tryParseCurrencyAmount
(
amount
,
(
isExactIn
?
inputCurrency
:
outputCurrency
)
??
undefined
),
()
=>
tryParseCurrencyAmount
(
amount
,
(
isExactIn
?
inputCurrency
:
outputCurrency
)
??
undefined
),
[
inputCurrency
,
isExactIn
,
outputCurrency
,
amount
]
[
inputCurrency
,
isExactIn
,
outputCurrency
,
amount
]
)
)
const
parsedAmountIn
=
isExactIn
?
parsedAmount
:
undefined
const
parsedAmountOut
=
isExactIn
?
undefined
:
parsedAmount
//@TODO(ianlapham): this would eventually be replaced with routing api logic.
//@TODO(ianlapham): this would eventually be replaced with routing api logic.
const
trade
=
useBestTrade
(
const
trade
=
useBestTrade
(
...
@@ -85,10 +83,10 @@ function useComputeSwapInfo(): SwapInfo {
...
@@ -85,10 +83,10 @@ function useComputeSwapInfo(): SwapInfo {
const
currencyAmounts
=
useMemo
(
const
currencyAmounts
=
useMemo
(
()
=>
({
()
=>
({
[
Field
.
INPUT
]:
parsedAmountIn
||
trade
.
trade
?.
inputAmount
,
[
Field
.
INPUT
]:
trade
.
trade
?.
inputAmount
,
[
Field
.
OUTPUT
]:
parsedAmountOut
||
trade
.
trade
?.
outputAmount
,
[
Field
.
OUTPUT
]:
trade
.
trade
?.
outputAmount
,
}),
}),
[
parsedAmountIn
,
parsedAmountOut
,
trade
.
trade
?.
inputAmount
,
trade
.
trade
?.
outputAmount
]
[
trade
.
trade
?.
inputAmount
,
trade
.
trade
?.
outputAmount
]
)
)
const
allowedSlippage
=
useAllowedSlippage
(
trade
.
trade
)
const
allowedSlippage
=
useAllowedSlippage
(
trade
.
trade
)
...
@@ -153,9 +151,7 @@ const swapInfoAtom = atom<SwapInfo>({
...
@@ -153,9 +151,7 @@ const swapInfoAtom = atom<SwapInfo>({
export
function
SwapInfoUpdater
()
{
export
function
SwapInfoUpdater
()
{
const
setSwapInfo
=
useUpdateAtom
(
swapInfoAtom
)
const
setSwapInfo
=
useUpdateAtom
(
swapInfoAtom
)
const
swapInfo
=
useComputeSwapInfo
()
const
swapInfo
=
useComputeSwapInfo
()
useEffect
(()
=>
{
useEffect
(()
=>
setSwapInfo
(
swapInfo
),
[
swapInfo
,
setSwapInfo
])
setSwapInfo
(
swapInfo
)
},
[
swapInfo
,
setSwapInfo
])
return
null
return
null
}
}
...
...
src/lib/state/swap.ts
View file @
ae664dc2
...
@@ -4,7 +4,6 @@ import { SupportedChainId } from 'constants/chains'
...
@@ -4,7 +4,6 @@ import { SupportedChainId } from 'constants/chains'
import
{
nativeOnChain
}
from
'
constants/tokens
'
import
{
nativeOnChain
}
from
'
constants/tokens
'
import
{
atom
}
from
'
jotai
'
import
{
atom
}
from
'
jotai
'
import
{
atomWithImmer
}
from
'
jotai/immer
'
import
{
atomWithImmer
}
from
'
jotai/immer
'
import
{
pickAtom
}
from
'
lib/state/atoms
'
export
enum
Field
{
export
enum
Field
{
INPUT
=
'
INPUT
'
,
INPUT
=
'
INPUT
'
,
...
@@ -24,8 +23,6 @@ export const swapAtom = atomWithImmer<Swap>({
...
@@ -24,8 +23,6 @@ export const swapAtom = atomWithImmer<Swap>({
[
Field
.
INPUT
]:
nativeOnChain
(
SupportedChainId
.
MAINNET
),
[
Field
.
INPUT
]:
nativeOnChain
(
SupportedChainId
.
MAINNET
),
})
})
export
const
independentFieldAtom
=
pickAtom
(
swapAtom
,
'
independentField
'
)
// If set to a transaction hash, that transaction will display in a status dialog.
// If set to a transaction hash, that transaction will display in a status dialog.
export
const
displayTxHashAtom
=
atom
<
string
|
undefined
>
(
undefined
)
export
const
displayTxHashAtom
=
atom
<
string
|
undefined
>
(
undefined
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment