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
9b2fe0bd
Unverified
Commit
9b2fe0bd
authored
May 08, 2020
by
Moody Salem
Committed by
GitHub
May 08, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use best trade to get the best route (#731)
parent
cb00e0ba
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
286 additions
and
321 deletions
+286
-321
index.tsx
src/components/ExchangePage/index.tsx
+158
-189
swap-store.ts
src/components/ExchangePage/swap-store.ts
+36
-0
Application.tsx
src/contexts/Application.tsx
+28
-12
Routes.tsx
src/contexts/Routes.tsx
+0
-110
Transactions.tsx
src/contexts/Transactions.tsx
+9
-3
Trades.ts
src/hooks/Trades.ts
+51
-0
index.tsx
src/index.tsx
+3
-6
index.ts
src/utils/index.ts
+1
-1
No files found.
src/components/ExchangePage/index.tsx
View file @
9b2fe0bd
import
React
,
{
useState
,
useReducer
,
useCallback
,
useEffect
}
from
'
react
'
import
React
,
{
useState
,
useCallback
,
useEffect
}
from
'
react
'
import
{
parseEther
,
parseUnits
}
from
'
@ethersproject/units
'
import
{
Fraction
,
JSBI
,
Percent
,
TokenAmount
,
TradeType
,
WETH
}
from
'
@uniswap/sdk
'
import
{
ArrowDown
,
ChevronDown
,
ChevronUp
,
Repeat
}
from
'
react-feather
'
import
{
withRouter
}
from
'
react-router-dom
'
import
{
parseUnits
,
parseEther
}
from
'
@ethersproject/units
'
import
{
BigNumber
}
from
'
@ethersproject/bignumber
'
import
{
Zero
,
MaxUint256
}
from
'
@ethersproject/constants
'
import
{
Contract
}
from
'
@ethersproject/contracts
'
import
{
WETH
,
TradeType
,
Pair
,
Trade
,
TokenAmount
,
JSBI
,
Percent
,
Fraction
}
from
'
@uniswap/sdk
'
import
{
Field
,
initializeSwapState
,
reducer
,
SwapAction
}
from
'
./swap-store
'
import
{
Field
,
SwapAction
,
useSwapStateReducer
}
from
'
./swap-store
'
import
{
Text
}
from
'
rebass
'
import
Card
,
{
BlueCard
,
GreyCard
,
YellowCard
}
from
'
../../components/Card
'
import
{
AutoColumn
,
ColumnCenter
}
from
'
../../components/Column
'
import
{
AutoRow
,
RowBetween
,
RowFixed
}
from
'
../../components/Row
'
import
{
ROUTER_ADDRESS
}
from
'
../../constants
'
import
{
useAddressAllowance
}
from
'
../../contexts/Allowances
'
import
{
useUserAdvanced
}
from
'
../../contexts/Application
'
import
{
useAddressBalance
,
useAllBalances
}
from
'
../../contexts/Balances
'
import
{
useDarkModeManager
,
useLocalStorageTokens
}
from
'
../../contexts/LocalStorage
'
import
{
usePair
}
from
'
../../contexts/Pairs
'
import
{
useAllTokens
,
useToken
}
from
'
../../contexts/Tokens
'
import
{
usePendingApproval
,
useTransactionAdder
}
from
'
../../contexts/Transactions
'
import
{
useTokenContract
,
useWeb3React
}
from
'
../../hooks
'
import
{
useTradeExactIn
,
useTradeExactOut
}
from
'
../../hooks/Trades
'
import
{
Hover
,
theme
,
TYPE
}
from
'
../../theme
'
import
{
Link
}
from
'
../../theme/components
'
import
{
calculateGasMargin
,
getEtherscanLink
,
getProviderOrSigner
,
getRouterContract
,
isWETH
}
from
'
../../utils
'
import
Copy
from
'
../AccountDetails/Copy
'
import
AddressInputPanel
from
'
../AddressInputPanel
'
import
{
ButtonError
,
ButtonLight
,
ButtonPrimary
}
from
'
../Button
'
import
ConfirmationModal
from
'
../ConfirmationModal
'
import
CurrencyInputPanel
from
'
../CurrencyInputPanel
'
import
QuestionHelper
from
'
../Question
'
import
SlippageTabs
from
'
../SlippageTabs
'
import
TokenLogo
from
'
../TokenLogo
'
import
{
AdvancedDropwdown
,
ArrowWrapper
,
...
...
@@ -22,36 +47,8 @@ import {
TruncatedText
,
Wrapper
}
from
'
./styleds
'
import
Copy
from
'
../AccountDetails/Copy
'
import
TokenLogo
from
'
../TokenLogo
'
import
SlippageTabs
from
'
../SlippageTabs
'
import
QuestionHelper
from
'
../Question
'
import
AddressInputPanel
from
'
../AddressInputPanel
'
import
ConfirmationModal
from
'
../ConfirmationModal
'
import
CurrencyInputPanel
from
'
../CurrencyInputPanel
'
// import BalanceCard from '../BalanceCard'
import
{
Link
}
from
'
../../theme/components
'
import
{
Text
}
from
'
rebass
'
import
{
theme
,
TYPE
,
Hover
}
from
'
../../theme
'
import
{
AutoColumn
,
ColumnCenter
}
from
'
../../components/Column
'
import
{
RowBetween
,
RowFixed
,
AutoRow
}
from
'
../../components/Row
'
import
{
ArrowDown
,
ChevronDown
,
ChevronUp
,
Repeat
}
from
'
react-feather
'
import
{
ButtonPrimary
,
ButtonError
,
ButtonLight
}
from
'
../Button
'
import
Card
,
{
GreyCard
,
BlueCard
,
YellowCard
}
from
'
../../components/Card
'
import
{
usePair
}
from
'
../../contexts/Pairs
'
import
{
useRoute
}
from
'
../../contexts/Routes
'
import
{
useAddressAllowance
}
from
'
../../contexts/Allowances
'
import
{
useToken
,
useAllTokens
}
from
'
../../contexts/Tokens
'
import
{
useWeb3React
,
useTokenContract
}
from
'
../../hooks
'
import
{
useAddressBalance
,
useAllBalances
}
from
'
../../contexts/Balances
'
import
{
useTransactionAdder
,
usePendingApproval
}
from
'
../../contexts/Transactions
'
import
{
useUserAdvanced
}
from
'
../../contexts/Application
'
import
{
ROUTER_ADDRESS
}
from
'
../../constants
'
import
{
getRouterContract
,
calculateGasMargin
,
getProviderOrSigner
,
getEtherscanLink
,
isWETH
}
from
'
../../utils
'
import
{
useLocalStorageTokens
}
from
'
../../contexts/LocalStorage
'
import
{
useDarkModeManager
}
from
'
../../contexts/LocalStorage
'
// import BalanceCard from '../BalanceCard'
function
hex
(
value
:
JSBI
)
{
return
BigNumber
.
from
(
value
.
toString
())
...
...
@@ -79,7 +76,6 @@ const ALLOWED_SLIPPAGE_HIGH = 500
function
ExchangePage
({
sendingInput
=
false
,
history
,
params
})
{
// text translation
// const { t } = useTranslation()
const
{
chainId
,
account
,
library
}
=
useWeb3React
()
// adding notifications on txns
...
...
@@ -92,33 +88,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
const
[
ENS
,
setENS
]
=
useState
<
string
>
(
''
)
// trade details, check query params for initial state
const
[
state
,
dispatch
]
=
useReducer
(
reducer
,
{
independentField
:
params
.
outputTokenAddress
&&
!
params
.
inputTokenAddress
?
Field
.
OUTPUT
:
Field
.
INPUT
,
inputTokenAddress
:
params
.
inputTokenAddress
?
params
.
inputTokenAddress
:
WETH
[
chainId
].
address
,
outputTokenAddress
:
params
.
outputTokenAddress
?
params
.
outputTokenAddress
:
''
,
typedValue
:
params
.
inputTokenAddress
&&
!
params
.
outputTokenAddress
?
params
.
inputTokenAmount
?
params
.
inputTokenAmount
:
''
:
!
params
.
inputTokenAddress
&&
params
.
outputTokenAddress
?
params
.
outputTokenAmount
?
params
.
outputTokenAmount
:
''
:
params
.
inputTokenAddress
&&
params
.
outputTokenAddress
?
params
.
inputTokenAmount
?
params
.
inputTokenAmount
:
''
:
''
?
''
:
''
?
''
:
''
},
initializeSwapState
)
const
[
state
,
dispatch
]
=
useSwapStateReducer
(
params
)
const
{
independentField
,
typedValue
,
...
fieldData
}
=
state
const
dependentField
:
Field
=
independentField
===
Field
.
INPUT
?
Field
.
OUTPUT
:
Field
.
INPUT
...
...
@@ -161,13 +131,6 @@ function ExchangePage({ sendingInput = false, history, params }) {
// check on pending approvals for token amounts
const
pendingApprovalInput
=
usePendingApproval
(
tokens
[
Field
.
INPUT
]?.
address
)
// entities for swap
const
pair
:
Pair
=
usePair
(
tokens
[
Field
.
INPUT
],
tokens
[
Field
.
OUTPUT
])
const
route
=
useRoute
(
tokens
[
Field
.
INPUT
],
tokens
[
Field
.
OUTPUT
])
// check for invalid selection
const
noRoute
:
boolean
=
!
route
&&
!!
tokens
[
Field
.
INPUT
]
&&
!!
tokens
[
Field
.
OUTPUT
]
// modal and loading
const
[
showConfirm
,
setShowConfirm
]
=
useState
<
boolean
>
(
false
)
const
[
showAdvanced
,
setShowAdvanced
]
=
useState
<
boolean
>
(
false
)
...
...
@@ -202,14 +165,16 @@ function ExchangePage({ sendingInput = false, history, params }) {
}
}
// get trade
let
trade
:
Trade
try
{
trade
=
!!
route
&&
!!
parsedAmounts
[
independentField
]
?
new
Trade
(
route
,
parsedAmounts
[
independentField
],
tradeType
)
:
undefined
}
catch
(
error
)
{}
const
pair
=
usePair
(
tokens
[
Field
.
INPUT
],
tokens
[
Field
.
OUTPUT
])
let
bestTradeExactIn
=
useTradeExactIn
(
tradeType
===
TradeType
.
EXACT_INPUT
?
parsedAmounts
[
independentField
]
:
null
,
tokens
[
Field
.
OUTPUT
])
let
bestTradeExactOut
=
useTradeExactOut
(
tokens
[
Field
.
INPUT
],
tradeType
===
TradeType
.
EXACT_OUTPUT
?
parsedAmounts
[
independentField
]
:
null
)
const
trade
=
tradeType
===
TradeType
.
EXACT_INPUT
?
bestTradeExactIn
:
bestTradeExactOut
const
route
=
trade
?.
route
const
userHasSpecifiedInputOutput
=
!!
parsedAmounts
[
independentField
]
&&
parsedAmounts
[
independentField
].
greaterThan
(
JSBI
.
BigInt
(
0
))
&&
!!
tokens
[
Field
.
INPUT
]
&&
!!
tokens
[
Field
.
OUTPUT
]
const
noRoute
=
!
route
const
slippageFromTrade
:
Percent
=
trade
&&
trade
.
slippage
...
...
@@ -241,18 +206,18 @@ function ExchangePage({ sendingInput = false, history, params }) {
type
:
SwapAction
.
SELECT_TOKEN
,
payload
:
{
field
,
address
}
})
},
[])
},
[
dispatch
])
const
onSwapTokens
=
useCallback
(()
=>
{
dispatch
({
type
:
SwapAction
.
SWITCH_TOKENS
,
payload
:
undefined
})
},
[])
},
[
dispatch
])
const
onUserInput
=
useCallback
((
field
:
Field
,
typedValue
:
string
)
=>
{
dispatch
({
type
:
SwapAction
.
TYPE
,
payload
:
{
field
,
typedValue
}
})
},
[])
},
[
dispatch
])
const
onMaxInput
=
useCallback
((
typedValue
:
string
)
=>
{
dispatch
({
...
...
@@ -262,7 +227,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
typedValue
}
})
},
[])
},
[
dispatch
])
const
onMaxOutput
=
useCallback
((
typedValue
:
string
)
=>
{
dispatch
({
...
...
@@ -272,7 +237,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
typedValue
}
})
},
[])
},
[
dispatch
])
// reset field if sending with with swap is cancled
useEffect
(()
=>
{
...
...
@@ -295,7 +260,8 @@ function ExchangePage({ sendingInput = false, history, params }) {
?
userBalances
[
Field
.
INPUT
].
subtract
(
MIN_ETHER
)
:
userBalances
[
Field
.
INPUT
]
:
undefined
}
catch
{}
}
catch
{
}
const
atMaxAmountInput
:
boolean
=
!!
maxAmountInput
&&
!!
parsedAmounts
[
Field
.
INPUT
]
...
...
@@ -340,7 +306,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
return
null
}
const
slippageAdjustedAmounts
:
{
[
field
:
number
]:
TokenAmount
}
=
{
const
slippageAdjustedAmounts
:
{
[
field
in
Field
]:
TokenAmount
}
=
{
[
Field
.
INPUT
]:
Field
.
INPUT
===
independentField
?
parsedAmounts
[
Field
.
INPUT
]
...
...
@@ -582,7 +548,6 @@ function ExchangePage({ sendingInput = false, history, params }) {
if
(
parsedAmounts
[
Field
.
INPUT
]
&&
pair
&&
route
&&
JSBI
.
greaterThan
(
parsedAmounts
[
Field
.
INPUT
].
raw
,
route
.
pairs
[
0
].
reserveOf
(
tokens
[
Field
.
INPUT
]).
raw
)
)
{
...
...
@@ -593,7 +558,6 @@ function ExchangePage({ sendingInput = false, history, params }) {
if
(
!
ignoreOutput
&&
parsedAmounts
[
Field
.
OUTPUT
]
&&
pair
&&
route
&&
JSBI
.
greaterThan
(
parsedAmounts
[
Field
.
OUTPUT
].
raw
,
...
...
@@ -631,11 +595,10 @@ function ExchangePage({ sendingInput = false, history, params }) {
dependentField
,
ignoreOutput
,
independentField
,
pair
,
parsedAmounts
,
recipientError
,
route
,
tokens
,
route
,
trade
,
userBalances
])
...
...
@@ -669,7 +632,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
<
Text
fontSize=
{
36
}
fontWeight=
{
500
}
>
{
parsedAmounts
[
Field
.
INPUT
]?.
toSignificant
(
6
)
}
{
tokens
[
Field
.
INPUT
]?.
symbol
}
</
Text
>
<
TokenLogo
address=
{
tokens
[
Field
.
INPUT
]?.
address
}
size=
{
'
30px
'
}
/>
<
TokenLogo
address=
{
tokens
[
Field
.
INPUT
]?.
address
}
size=
{
'
30px
'
}
/>
</
RowBetween
>
<
TYPE
.
darkGray
fontSize=
{
20
}
>
To
</
TYPE
.
darkGray
>
{
ENS
?
(
...
...
@@ -681,7 +644,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
{
recipient
?.
slice
(
0
,
8
)
}
...
{
recipient
?.
slice
(
34
,
42
)
}
↗
</
TYPE
.
blue
>
</
Link
>
<
Copy
toCopy=
{
recipient
}
/>
<
Copy
toCopy=
{
recipient
}
/>
</
AutoRow
>
</
AutoColumn
>
)
:
(
...
...
@@ -691,7 +654,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
{
recipient
?.
slice
(
0
,
6
)
}
...
{
recipient
?.
slice
(
36
,
42
)
}
↗
</
TYPE
.
blue
>
</
Link
>
<
Copy
toCopy=
{
recipient
}
/>
<
Copy
toCopy=
{
recipient
}
/>
</
AutoRow
>
)
}
</
AutoColumn
>
...
...
@@ -703,7 +666,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
<
AutoColumn
gap=
"lg"
style=
{
{
marginTop
:
'
40px
'
}
}
>
<
AutoColumn
gap=
"sm"
>
<
AutoRow
gap=
"10px"
>
<
TokenLogo
address=
{
tokens
[
Field
.
OUTPUT
]?.
address
}
size=
{
'
30px
'
}
/>
<
TokenLogo
address=
{
tokens
[
Field
.
OUTPUT
]?.
address
}
size=
{
'
30px
'
}
/>
<
Text
fontSize=
{
36
}
fontWeight=
{
500
}
>
{
slippageAdjustedAmounts
[
Field
.
OUTPUT
]?.
toSignificant
(
4
)
}
{
tokens
[
Field
.
OUTPUT
]?.
symbol
}
</
Text
>
...
...
@@ -731,14 +694,14 @@ function ExchangePage({ sendingInput = false, history, params }) {
{
/* {!!slippageAdjustedAmounts[Field.INPUT] && slippageAdjustedAmounts[Field.INPUT].toSignificant(6)} */
}
</
TruncatedText
>
<
RowFixed
gap=
"4px"
>
<
TokenLogo
address=
{
tokens
[
Field
.
INPUT
]?.
address
}
size=
{
'
24px
'
}
/>
<
TokenLogo
address=
{
tokens
[
Field
.
INPUT
]?.
address
}
size=
{
'
24px
'
}
/>
<
Text
fontSize=
{
24
}
fontWeight=
{
500
}
style=
{
{
marginLeft
:
'
10px
'
}
}
>
{
tokens
[
Field
.
INPUT
]?.
symbol
||
''
}
</
Text
>
</
RowFixed
>
</
RowBetween
>
<
RowFixed
>
<
ArrowDown
size=
"16"
color=
{
theme
(
isDark
).
text2
}
/>
<
ArrowDown
size=
"16"
color=
{
theme
(
isDark
).
text2
}
/>
</
RowFixed
>
<
RowBetween
align=
"flex-end"
>
<
TruncatedText
fontSize=
{
24
}
fontWeight=
{
500
}
color=
{
warningHigh
?
theme
(
isDark
).
red1
:
''
}
>
...
...
@@ -747,7 +710,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
{
/* {!!slippageAdjustedAmounts[Field.OUTPUT] && slippageAdjustedAmounts[Field.OUTPUT].toSignificant(6)} */
}
</
TruncatedText
>
<
RowFixed
gap=
"4px"
>
<
TokenLogo
address=
{
tokens
[
Field
.
OUTPUT
]?.
address
}
size=
{
'
24px
'
}
/>
<
TokenLogo
address=
{
tokens
[
Field
.
OUTPUT
]?.
address
}
size=
{
'
24px
'
}
/>
<
Text
fontSize=
{
24
}
fontWeight=
{
500
}
style=
{
{
marginLeft
:
'
10px
'
}
}
>
{
tokens
[
Field
.
OUTPUT
]?.
symbol
||
''
}
</
Text
>
...
...
@@ -805,19 +768,19 @@ function ExchangePage({ sendingInput = false, history, params }) {
color=
{
theme
(
isDark
).
text2
}
style=
{
{
justifyContent
:
'
center
'
,
alignItems
:
'
center
'
,
display
:
'
flex
'
}
}
>
{
pair
&&
showInverted
?
route
.
midPrice
.
invert
().
toSignificant
(
6
)
+
{
trade
&&
showInverted
?
(
trade
?.
executionPrice
?.
invert
()?.
toSignificant
(
6
)
??
''
)
+
'
'
+
tokens
[
Field
.
INPUT
]?.
symbol
+
'
/
'
+
tokens
[
Field
.
OUTPUT
]?.
symbol
:
route
.
midPrice
.
toSignificant
(
6
)
+
:
(
trade
?.
executionPrice
?.
toSignificant
(
6
)
??
''
)
+
'
'
+
tokens
[
Field
.
OUTPUT
]?.
symbol
+
'
/
'
+
tokens
[
Field
.
INPUT
]?.
symbol
}
<
StyledBalanceMaxMini
onClick=
{
()
=>
setShowInverted
(
!
showInverted
)
}
>
<
Repeat
size=
{
14
}
/>
<
Repeat
size=
{
14
}
/>
</
StyledBalanceMaxMini
>
</
Text
>
</
RowBetween
>
...
...
@@ -827,7 +790,8 @@ function ExchangePage({ sendingInput = false, history, params }) {
<
TYPE
.
black
fontSize=
{
14
}
fontWeight=
{
400
}
>
{
independentField
===
Field
.
INPUT
?
(
sending
?
'
Min sent
'
:
'
Minimum received
'
)
:
'
Maximum sold
'
}
</
TYPE
.
black
>
<
QuestionHelper
text=
"A boundary is set so you are protected from large price movements after you submit your trade."
/>
<
QuestionHelper
text=
"A boundary is set so you are protected from large price movements after you submit your trade."
/>
</
RowFixed
>
<
RowFixed
>
<
TYPE
.
black
fontSize=
{
14
}
>
...
...
@@ -857,7 +821,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
<
TYPE
.
black
color=
{
theme
(
isDark
).
text1
}
fontSize=
{
14
}
fontWeight=
{
400
}
>
Price impact
</
TYPE
.
black
>
<
QuestionHelper
text=
"The difference between the market price and your price due to trade size."
/>
<
QuestionHelper
text=
"The difference between the market price and your price due to trade size."
/>
</
RowFixed
>
<
ErrorText
fontWeight=
{
500
}
...
...
@@ -878,7 +842,8 @@ function ExchangePage({ sendingInput = false, history, params }) {
<
TYPE
.
black
fontSize=
{
14
}
fontWeight=
{
400
}
>
Liquidity Provider Fee
</
TYPE
.
black
>
<
QuestionHelper
text=
"A portion of each trade (0.3%) goes to liquidity providers to incentivize liquidity on the protocol."
/>
<
QuestionHelper
text=
"A portion of each trade (0.3%) goes to liquidity providers to incentivize liquidity on the protocol."
/>
</
RowFixed
>
<
TYPE
.
black
fontSize=
{
14
}
>
{
feeTimesInputFormatted
...
...
@@ -900,12 +865,12 @@ function ExchangePage({ sendingInput = false, history, params }) {
}
}
const
PriceBar
=
function
()
{
const
PriceBar
=
function
()
{
return
(
<
AutoRow
justify=
"space-between"
>
<
AutoColumn
justify=
"center"
>
<
Text
fontWeight=
{
500
}
fontSize=
{
16
}
color=
{
theme
(
isDark
).
text2
}
>
{
pair
?
`${route.mid
Price.toSignificant(6)} `
:
'
-
'
}
{
trade
?
`${trade.execution
Price.toSignificant(6)} `
:
'
-
'
}
</
Text
>
<
Text
fontWeight=
{
500
}
fontSize=
{
16
}
color=
{
theme
(
isDark
).
text3
}
pt=
{
1
}
>
{
tokens
[
Field
.
OUTPUT
]?.
symbol
}
/
{
tokens
[
Field
.
INPUT
]?.
symbol
}
...
...
@@ -913,7 +878,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
</
AutoColumn
>
<
AutoColumn
justify=
"center"
>
<
Text
fontWeight=
{
500
}
fontSize=
{
16
}
color=
{
theme
(
isDark
).
text2
}
>
{
pair
?
`${route.mid
Price.invert().toSignificant(6)} `
:
'
-
'
}
{
trade
?
`${trade.execution
Price.invert().toSignificant(6)} `
:
'
-
'
}
</
Text
>
<
Text
fontWeight=
{
500
}
fontSize=
{
16
}
color=
{
theme
(
isDark
).
text3
}
pt=
{
1
}
>
{
tokens
[
Field
.
INPUT
]?.
symbol
}
/
{
tokens
[
Field
.
OUTPUT
]?.
symbol
}
...
...
@@ -1002,7 +967,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
Max
</MaxButton>
)}
<StyledNumerical value={formattedAmounts[Field.INPUT]} onUserInput={val => onUserInput(Field.INPUT, val)}
/>
<StyledNumerical value={formattedAmounts[Field.INPUT]} onUserInput={val => onUserInput(Field.INPUT, val)}/>
<CurrencyInputPanel
field={Field.INPUT}
value={formattedAmounts[Field.INPUT]}
...
...
@@ -1048,7 +1013,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
<ColumnCenter>
<RowBetween padding="0 12px">
<ArrowWrapper onClick={onSwapTokens}>
<ArrowDown size="16" color={theme(isDark).text2} onClick={onSwapTokens}
/>
<ArrowDown size="16" color={theme(isDark).text2} onClick={onSwapTokens}/>
</ArrowWrapper>
<StyledBalanceMaxMini onClick={() => setSendingWithSwap(false)} style={{ marginRight: '0px' }}>
<TYPE.blue>Remove Swap</TYPE.blue>
...
...
@@ -1086,7 +1051,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
/>
{sendingWithSwap && (
<RowBetween padding="0 12px">
<ArrowDown size="16"
/>
<ArrowDown size="16"/>
</RowBetween>
)}
</>
...
...
@@ -1118,7 +1083,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
{!noRoute && tokens[Field.OUTPUT] && tokens[Field.INPUT] && (
<Card padding={advanced ? '.25rem 1.25rem 0 .75rem' : '.25rem .7rem .25rem 1.25rem'} borderRadius={'20px'}>
{advanced ? (
<PriceBar
/>
<PriceBar/>
) : (
<AutoColumn gap="4px">
{' '}
...
...
@@ -1132,23 +1097,23 @@ function ExchangePage({ sendingInput = false, history, params }) {
color={theme(isDark).text2}
style={{ justifyContent: 'center', alignItems: 'center', display: 'flex' }}
>
{
pair
&& showInverted
?
route.midPrice.invert().toSignificant(6
) +
{
trade
&& showInverted
?
(trade?.executionPrice?.invert()?.toSignificant(6) ?? ''
) +
' ' +
tokens[Field.INPUT]?.symbol +
' per ' +
tokens[Field.OUTPUT]?.symbol
:
route.midPrice.toSignificant(6
) +
:
(trade?.executionPrice?.toSignificant(6) ?? ''
) +
' ' +
tokens[Field.OUTPUT]?.symbol +
' per ' +
tokens[Field.INPUT]?.symbol}
<StyledBalanceMaxMini onClick={() => setShowInverted(!showInverted)}>
<Repeat size={14}
/>
<Repeat size={14}/>
</StyledBalanceMaxMini>
</Text>
</RowBetween>
{
pair
&& (warningHigh || warningMedium) && (
{
trade
&& (warningHigh || warningMedium) && (
<RowBetween>
<TYPE.main
style={{ justifyContent: 'center', alignItems: 'center', display: 'flex' }}
...
...
@@ -1164,7 +1129,8 @@ function ExchangePage({ sendingInput = false, history, params }) {
: priceSlippage.toFixed(4) + '%'
: '-'}{' '}
</ErrorText>
<QuestionHelper text="The difference between the market price and your quoted price due to trade size." />
<QuestionHelper
text="The difference between the market price and your quoted price due to trade size."/>
</RowFixed>
</RowBetween>
)}
...
...
@@ -1174,7 +1140,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
)}
</AutoColumn>
<BottomGrouping>
{noRoute ? (
{noRoute
&& userHasSpecifiedInputOutput
? (
<GreyCard style={{ textAlign: 'center' }}>
<TYPE.main>No path found.</TYPE.main>
...
...
@@ -1240,7 +1206,7 @@ function ExchangePage({ sendingInput = false, history, params }) {
<Text fontSize={16} fontWeight={500} style={{ userSelect: 'none' }}>
Show Advanced
</Text>
<ChevronDown color={theme(isDark).text2}
/>
<ChevronDown color={theme(isDark).text2}/>
</RowBetween>
</Hover>
)}
...
...
@@ -1251,10 +1217,10 @@ function ExchangePage({ sendingInput = false, history, params }) {
<Text fontSize={16} color={theme(isDark).text2} fontWeight={500} style={{ userSelect: 'none' }}>
Hide Advanced
</Text>
<ChevronUp color={theme(isDark).text2}
/>
<ChevronUp color={theme(isDark).text2}/>
</RowBetween>
</Hover>
<SectionBreak
/>
<SectionBreak/>
<AutoColumn style={{ padding: '0 20px' }}>
<RowBetween>
<RowFixed>
...
...
@@ -1307,7 +1273,8 @@ function ExchangePage({ sendingInput = false, history, params }) {
<TYPE.black fontSize={14} fontWeight={400} color={theme(isDark).text1}>
Price Impact
</TYPE.black>
<QuestionHelper text="The difference between the market price and your quoted price due to trade size." />
<QuestionHelper
text="The difference between the market price and your quoted price due to trade size."/>
</RowFixed>
<ErrorText
fontWeight={500}
...
...
@@ -1328,7 +1295,8 @@ function ExchangePage({ sendingInput = false, history, params }) {
<TYPE.black fontSize={14} fontWeight={400} color={theme(isDark).text1}>
Liquidity Provider Fee
</TYPE.black>
<QuestionHelper text="A portion of each trade (0.03%) goes to liquidity providers to incentivize liquidity on the protocol." />
<QuestionHelper
text="A portion of each trade (0.03%) goes to liquidity providers to incentivize liquidity on the protocol."/>
</RowFixed>
<TYPE.black fontSize={14} color={theme(isDark).text1}>
{feeTimesInputFormatted
...
...
@@ -1337,12 +1305,13 @@ function ExchangePage({ sendingInput = false, history, params }) {
</TYPE.black>
</RowBetween>
</AutoColumn>
<SectionBreak
/>
<SectionBreak/>
<RowFixed padding={'0 20px'}>
<TYPE.black fontWeight={400} fontSize={14} color={theme(isDark).text1}>
Set front running resistance
</TYPE.black>
<QuestionHelper text="Your transaction will revert if the price changes more than this amount after you submit your trade." />
<QuestionHelper
text="Your transaction will revert if the price changes more than this amount after you submit your trade."/>
</RowFixed>
<SlippageTabs
rawSlippage={allowedSlippage}
...
...
src/components/ExchangePage/swap-store.ts
View file @
9b2fe0bd
import
{
WETH
}
from
'
@uniswap/sdk
'
import
{
useReducer
}
from
'
react
'
import
{
useWeb3React
}
from
'
../../hooks
'
import
{
QueryParams
}
from
'
../../utils
'
export
enum
Field
{
INPUT
,
OUTPUT
...
...
@@ -93,3 +98,34 @@ export function reducer(
}
}
}
export
function
useSwapStateReducer
(
params
:
QueryParams
)
{
const
{
chainId
}
=
useWeb3React
()
return
useReducer
(
reducer
,
{
independentField
:
params
.
outputTokenAddress
&&
!
params
.
inputTokenAddress
?
Field
.
OUTPUT
:
Field
.
INPUT
,
inputTokenAddress
:
params
.
inputTokenAddress
?
params
.
inputTokenAddress
:
WETH
[
chainId
].
address
,
outputTokenAddress
:
params
.
outputTokenAddress
?
params
.
outputTokenAddress
:
''
,
typedValue
:
params
.
inputTokenAddress
&&
!
params
.
outputTokenAddress
?
params
.
inputTokenAmount
?
params
.
inputTokenAmount
:
''
:
!
params
.
inputTokenAddress
&&
params
.
outputTokenAddress
?
params
.
outputTokenAmount
?
params
.
outputTokenAmount
:
''
:
params
.
inputTokenAddress
&&
params
.
outputTokenAddress
?
params
.
inputTokenAmount
?
params
.
inputTokenAmount
:
''
:
''
?
''
:
''
?
''
:
''
},
initializeSwapState
)
}
src/contexts/Application.
js
→
src/contexts/Application.
tsx
View file @
9b2fe0bd
...
...
@@ -16,13 +16,29 @@ const ADD_POPUP = 'ADD_POPUP'
const
USER_ADVANCED
=
'
USER_ADVANCED
'
const
TOGGLE_USER_ADVANCED
=
'
TOGGLE_USER_ADVANCED
'
const
ApplicationContext
=
createContext
()
interface
ApplicationState
{
BLOCK_NUMBER
:
{},
USD_PRICE
:
{},
POPUP_LIST
:
Array
<
{
key
:
number
;
show
:
boolean
;
content
:
React
.
ReactElement
}
>
,
POPUP_KEY
:
number
,
WALLET_MODAL_OPEN
:
boolean
,
USER_ADVANCED
:
boolean
}
const
ApplicationContext
=
createContext
<
[
ApplicationState
,
{
[
updater
:
string
]:
(...
args
:
any
[])
=>
void
}]
>
([{
[
BLOCK_NUMBER
]:
{},
[
USD_PRICE
]:
{},
[
POPUP_LIST
]:
[],
[
POPUP_KEY
]:
0
,
[
WALLET_MODAL_OPEN
]:
false
,
[
USER_ADVANCED
]:
false
},
{}])
function
useApplicationContext
()
{
return
useContext
(
ApplicationContext
)
}
function
reducer
(
state
,
{
type
,
payload
})
{
function
reducer
(
state
:
ApplicationState
,
{
type
,
payload
}):
ApplicationState
{
switch
(
type
)
{
case
UPDATE_BLOCK_NUMBER
:
{
const
{
networkId
,
blockNumber
}
=
payload
...
...
@@ -66,19 +82,19 @@ export default function Provider({ children }) {
const
updateBlockNumber
=
useCallback
((
networkId
,
blockNumber
)
=>
{
dispatch
({
type
:
UPDATE_BLOCK_NUMBER
,
payload
:
{
networkId
,
blockNumber
}
})
},
[])
},
[
dispatch
])
const
toggleWalletModal
=
useCallback
(()
=>
{
dispatch
({
type
:
TOGGLE_WALLET_MODAL
})
},
[])
dispatch
({
type
:
TOGGLE_WALLET_MODAL
,
payload
:
null
})
},
[
dispatch
])
const
toggleUserAdvanced
=
useCallback
(()
=>
{
dispatch
({
type
:
TOGGLE_USER_ADVANCED
})
},
[])
dispatch
({
type
:
TOGGLE_USER_ADVANCED
,
payload
:
null
})
},
[
dispatch
])
const
setPopups
=
useCallback
(
newList
=>
{
dispatch
({
type
:
ADD_POPUP
,
payload
:
{
newList
}
})
},
[])
},
[
dispatch
])
return
(
<
ApplicationContext
.
Provider
...
...
@@ -105,7 +121,7 @@ export function Updater() {
if
(
library
)
{
let
stale
=
false
function
update
()
{
const
update
=
()
=>
{
library
.
getBlockNumber
()
.
then
(
blockNumber
=>
{
...
...
@@ -164,13 +180,13 @@ export function useToggleUserAdvanced() {
return
toggleUserAdvanced
}
export
function
usePopups
()
{
export
function
usePopups
()
:
[
ApplicationState
[
'
POPUP_LIST
'
],
(
content
:
React
.
ReactElement
)
=>
void
,
(
key
:
number
)
=>
void
]
{
const
[
state
,
{
setPopups
}]
=
useApplicationContext
()
const
index
=
state
[
POPUP_KEY
]
const
currentPopups
=
state
[
POPUP_LIST
]
function
addPopup
(
content
)
{
function
addPopup
(
content
:
React
.
ReactElement
):
void
{
const
newItem
=
{
show
:
true
,
key
:
index
,
...
...
@@ -180,7 +196,7 @@ export function usePopups() {
setPopups
(
currentPopups
)
}
function
removePopup
(
key
)
{
function
removePopup
(
key
:
number
):
void
{
currentPopups
.
map
(
item
=>
{
if
(
key
===
item
.
key
)
{
item
.
show
=
false
...
...
src/contexts/Routes.tsx
deleted
100644 → 0
View file @
cb00e0ba
import
React
,
{
createContext
,
useContext
,
useReducer
,
useMemo
,
useCallback
,
useEffect
}
from
'
react
'
import
{
WETH
,
Token
,
Route
,
JSBI
}
from
'
@uniswap/sdk
'
import
{
useWeb3React
}
from
'
../hooks
'
import
{
usePair
}
from
'
../contexts/Pairs
'
import
{
isWETH
}
from
'
../utils
'
const
UPDATE
=
'
UPDATE
'
interface
RouteState
{
[
chainId
:
number
]:
{
[
tokenAddress
:
string
]:
{
[
tokenAddress
:
string
]:
{
route
:
Route
}
}
}
}
const
RouteContext
=
createContext
<
[
RouteState
,
{
[
k
:
string
]:
(...
args
:
any
)
=>
void
}]
>
([{},
{}])
function
useRouteContext
()
{
return
useContext
(
RouteContext
)
}
function
reducer
(
state
:
RouteState
,
{
type
,
payload
})
{
switch
(
type
)
{
case
UPDATE
:
{
const
{
tokens
,
route
,
chainId
}
=
payload
return
{
...
state
,
[
chainId
]:
{
...
state
[
chainId
],
[
tokens
[
0
]]:
{
...
state
[
chainId
]?.[
tokens
[
0
]],
[
tokens
[
1
]]:
{
route
}
}
}
}
}
default
:
{
throw
Error
(
`Unexpected action type in ExchangesContext reducer: '
${
type
}
'.`
)
}
}
}
export
default
function
Provider
({
children
})
{
const
[
state
,
dispatch
]
=
useReducer
(
reducer
,
{})
const
update
=
useCallback
((
tokens
,
route
,
chainId
)
=>
{
dispatch
({
type
:
UPDATE
,
payload
:
{
tokens
,
route
,
chainId
}
})
},
[])
return
(
<
RouteContext
.
Provider
value=
{
useMemo
(()
=>
[
state
,
{
update
}],
[
state
,
update
])
}
>
{
children
}
</
RouteContext
.
Provider
>
)
}
/**
* @param tokenA input to token to be sold
* @param tokenB output token to be bought
*
* This hook finds either a direct pair between tokenA and tokenB or,
* a one-hop route that goes through token<->WETH pairs
*
* if neither exists returns null
*/
export
function
useRoute
(
tokenA
:
Token
,
tokenB
:
Token
)
{
const
[
state
,
{
update
}]
=
useRouteContext
()
const
{
chainId
}
=
useWeb3React
()
let
route
:
Route
=
state
?.[
chainId
]?.[
tokenA
?.
address
]?.[
tokenB
?.
address
]?.
route
// check for direct pair between tokens
const
defaultPair
=
usePair
(
tokenA
,
tokenB
)
// get token<->WETH pairs
const
aToETH
=
usePair
(
tokenA
&&
!
isWETH
(
tokenA
)
?
tokenA
:
null
,
WETH
[
chainId
])
const
bToETH
=
usePair
(
tokenB
&&
!
isWETH
(
tokenB
)
?
tokenB
:
null
,
WETH
[
chainId
])
// needs to route through WETH
const
requiresHop
=
defaultPair
&&
JSBI
.
equal
(
defaultPair
?.
reserve0
?.
raw
,
JSBI
.
BigInt
(
0
))
&&
JSBI
.
equal
(
defaultPair
?.
reserve1
?.
raw
,
JSBI
.
BigInt
(
0
))
useEffect
(()
=>
{
if
(
!
route
&&
tokenA
&&
tokenB
)
{
if
(
!
requiresHop
&&
defaultPair
)
{
update
([
tokenA
.
address
,
tokenB
.
address
],
new
Route
([
defaultPair
],
tokenA
),
chainId
)
}
if
(
requiresHop
&&
aToETH
&&
bToETH
&&
// check there is liquidity in both token<->ETH pairs
JSBI
.
notEqual
(
JSBI
.
BigInt
(
0
),
aToETH
.
reserve0
.
raw
)
&&
JSBI
.
notEqual
(
JSBI
.
BigInt
(
0
),
bToETH
.
reserve0
.
raw
)
)
{
const
routeThroughETH
=
new
Route
([
aToETH
,
bToETH
],
tokenA
)
update
([
tokenA
.
address
,
tokenB
.
address
],
routeThroughETH
,
chainId
)
}
}
},
[
route
,
requiresHop
,
update
,
chainId
,
tokenA
,
tokenB
,
defaultPair
,
aToETH
,
bToETH
])
return
useMemo
(()
=>
route
,
[
route
])
}
src/contexts/Transactions.
js
→
src/contexts/Transactions.
tsx
View file @
9b2fe0bd
...
...
@@ -16,7 +16,11 @@ const ADD = 'ADD'
const
CHECK
=
'
CHECK
'
const
FINALIZE
=
'
FINALIZE
'
const
TransactionsContext
=
createContext
()
interface
TransactionState
{
}
const
TransactionsContext
=
createContext
<
[
TransactionState
,
{
[
updater
:
string
]:
(...
args
:
any
[])
=>
void
}]
>
([{},
{}])
export
function
useTransactionsContext
()
{
return
useContext
(
TransactionsContext
)
...
...
@@ -134,10 +138,12 @@ export function Updater() {
finalize
(
chainId
,
hash
,
receipt
)
// add success or failure popup
if
(
receipt
.
status
===
1
)
{
addPopup
(
<
TxnPopup
hash
=
{
hash
}
success
=
{
true
}
summary
=
{
allTransactions
[
hash
]?.
response
?.
summary
}
/>
)
addPopup
(<
TxnPopup
popKey=
{
1
}
hash=
{
hash
}
success=
{
true
}
summary=
{
allTransactions
[
hash
]?.
response
?.
summary
}
/>)
}
else
{
addPopup
(
<
TxnPopup
hash
=
{
hash
}
success
=
{
false
}
summary
=
{
allTransactions
[
hash
]?.
response
?.
summary
}
/
>
<
TxnPopup
popKey=
{
2
}
hash=
{
hash
}
success=
{
false
}
summary=
{
allTransactions
[
hash
]?.
response
?.
summary
}
/>
)
}
}
...
...
src/hooks/Trades.ts
0 → 100644
View file @
9b2fe0bd
import
{
useMemo
}
from
'
react
'
import
{
WETH
,
Token
,
TokenAmount
,
Trade
}
from
'
@uniswap/sdk
'
import
{
useWeb3React
}
from
'
./index
'
import
{
usePair
}
from
'
../contexts/Pairs
'
import
{
isWETH
}
from
'
../utils
'
/**
* Returns the best trade for the exact amount of tokens in to the given token out
*/
export
function
useTradeExactIn
(
amountIn
?:
TokenAmount
,
tokenOut
?:
Token
):
Trade
|
null
{
const
{
chainId
}
=
useWeb3React
()
// check for direct pair between tokens
const
pairBetween
=
usePair
(
amountIn
?.
token
,
tokenOut
)
// get token<->WETH pairs
const
aToETH
=
usePair
(
amountIn
&&
!
isWETH
(
amountIn
.
token
)
?
amountIn
.
token
:
null
,
WETH
[
chainId
])
const
bToETH
=
usePair
(
tokenOut
&&
!
isWETH
(
tokenOut
)
?
tokenOut
:
null
,
WETH
[
chainId
])
return
useMemo
(()
=>
{
const
allPairs
=
[
pairBetween
,
aToETH
,
bToETH
].
filter
(
p
=>
!!
p
)
if
(
amountIn
&&
allPairs
.
length
>
0
&&
tokenOut
)
{
return
Trade
.
bestTradeExactIn
(
allPairs
,
amountIn
,
tokenOut
)[
0
]
??
null
}
return
null
},
[
aToETH
,
bToETH
,
pairBetween
,
amountIn
,
tokenOut
])
}
/**
* Returns the best trade for the token in to the exact amount of token out
*/
export
function
useTradeExactOut
(
tokenIn
?:
Token
,
amountOut
?:
TokenAmount
):
Trade
|
null
{
const
{
chainId
}
=
useWeb3React
()
// check for direct pair between tokens
const
pairBetween
=
usePair
(
amountOut
?.
token
,
tokenIn
)
// get token<->WETH pairs
const
aToETH
=
usePair
(
amountOut
&&
!
isWETH
(
amountOut
.
token
)
?
amountOut
.
token
:
null
,
WETH
[
chainId
])
const
bToETH
=
usePair
(
tokenIn
&&
!
isWETH
(
tokenIn
)
?
tokenIn
:
null
,
WETH
[
chainId
])
return
useMemo
(()
=>
{
const
allPairs
=
[
pairBetween
,
aToETH
,
bToETH
].
filter
(
p
=>
!!
p
)
if
(
amountOut
&&
allPairs
.
length
>
0
&&
tokenIn
)
{
return
Trade
.
bestTradeExactOut
(
allPairs
,
tokenIn
,
amountOut
)[
0
]
??
null
}
return
null
},
[
pairBetween
,
aToETH
,
bToETH
,
amountOut
,
tokenIn
])
}
src/index.tsx
View file @
9b2fe0bd
...
...
@@ -12,7 +12,6 @@ import TransactionContextProvider, { Updater as TransactionContextUpdater } from
import
BalancesContextProvider
,
{
Updater
as
BalancesContextUpdater
}
from
'
./contexts/Balances
'
import
ExchangesContextProvider
from
'
./contexts/Pairs
'
import
AllowancesContextProvider
from
'
./contexts/Allowances
'
import
RoutesContextProvider
from
'
./contexts/Routes
'
import
App
from
'
./pages/App
'
import
ThemeProvider
,
{
GlobalStyle
}
from
'
./theme
'
import
'
./i18n
'
...
...
@@ -42,11 +41,9 @@ function ContextProviders({ children }) {
<
ApplicationContextProvider
>
<
TransactionContextProvider
>
<
ExchangesContextProvider
>
<
RoutesContextProvider
>
<
BalancesContextProvider
>
<
AllowancesContextProvider
>
{
children
}
</
AllowancesContextProvider
>
</
BalancesContextProvider
>
</
RoutesContextProvider
>
</
ExchangesContextProvider
>
</
TransactionContextProvider
>
</
ApplicationContextProvider
>
...
...
src/utils/index.ts
View file @
9b2fe0bd
...
...
@@ -69,7 +69,7 @@ function parseUrlTokenAmount(paramName: string): string {
return
value
}
interface
QueryParams
{
export
interface
QueryParams
{
readonly
inputTokenAddress
:
string
readonly
outputTokenAddress
:
string
readonly
inputTokenAmount
:
string
...
...
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