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
4e2c5c1e
Commit
4e2c5c1e
authored
Mar 13, 2020
by
ianlapham
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
slippage without micro warnings on swap
parent
e43d9e03
Changes
20
Show whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
791 additions
and
505 deletions
+791
-505
index.js
src/components/Button/index.js
+38
-2
index.js
src/components/Card/index.js
+2
-2
index.js
src/components/ConfirmationModal/index.js
+20
-237
index.js
src/components/CurrencyInputPanel/index.js
+6
-1
index.tsx
src/components/ExchangePage/index.tsx
+433
-138
index.js
src/components/Header/index.js
+14
-4
index.js
src/components/Menu/index.js
+1
-2
index.tsx
src/components/NumericalInput/index.tsx
+5
-3
index.js
src/components/PoolFinder/index.js
+9
-6
index.js
src/components/PositionCard/index.js
+0
-5
index.js
src/components/Row/index.js
+1
-0
index.js
src/components/SearchModal/index.js
+12
-10
index.ts
src/constants/index.ts
+0
-7
Exchanges.tsx
src/contexts/Exchanges.tsx
+8
-8
App.js
src/pages/App.js
+1
-6
AddLiquidity.tsx
src/pages/Supply/AddLiquidity.tsx
+103
-28
RemoveLiquidity.tsx
src/pages/Supply/RemoveLiquidity.tsx
+110
-30
index.js
src/pages/Supply/index.js
+13
-16
components.js
src/theme/components.js
+1
-0
index.js
src/theme/index.js
+14
-0
No files found.
src/components/Button/index.js
View file @
4e2c5c1e
...
@@ -13,6 +13,7 @@ const Base = styled(RebassButton)`
...
@@ -13,6 +13,7 @@ const Base = styled(RebassButton)`
font-weight: 500;
font-weight: 500;
text-align: center;
text-align: center;
border-radius: 20px;
border-radius: 20px;
border-radius:
${({
borderRadius
})
=>
borderRadius
&&
borderRadius
}
;
outline: none;
outline: none;
border: 1px solid transparent;
border: 1px solid transparent;
color: white;
color: white;
...
@@ -40,8 +41,6 @@ export const ButtonPrimary = styled(Base)`
...
@@ -40,8 +41,6 @@ export const ButtonPrimary = styled(Base)`
background-color:
${({
theme
})
=>
theme
.
outlineGrey
}
;
background-color:
${({
theme
})
=>
theme
.
outlineGrey
}
;
color:
${({
theme
})
=>
theme
.
darkGrey
}
color:
${({
theme
})
=>
theme
.
darkGrey
}
cursor: auto;
cursor: auto;
outline: none;
border: none;
box-shadow: none;
box-shadow: none;
}
}
`
`
...
@@ -100,6 +99,27 @@ const ButtonConfirmedStyle = styled(Base)`
...
@@ -100,6 +99,27 @@ const ButtonConfirmedStyle = styled(Base)`
}
}
`
`
const
ButtonErrorStyle
=
styled
(
Base
)
`
background-color:
${({
theme
})
=>
theme
.
salmonRed
}
;
border: 1px solid
${({
theme
})
=>
theme
.
salmonRed
}
;
&:focus {
box-shadow: 0 0 0 1pt
${({
theme
})
=>
darken
(
0.05
,
theme
.
salmonRed
)}
;
background-color:
${({
theme
})
=>
darken
(
0.05
,
theme
.
salmonRed
)}
;
}
&:hover {
background-color:
${({
theme
})
=>
darken
(
0.05
,
theme
.
salmonRed
)}
;
}
&:active {
box-shadow: 0 0 0 1pt
${({
theme
})
=>
darken
(
0.1
,
theme
.
salmonRed
)}
;
background-color:
${({
theme
})
=>
darken
(
0.1
,
theme
.
salmonRed
)}
;
}
&:disabled {
opacity: 50%;
cursor: auto;
}
`
export
function
ButtonConfirmed
({
children
,
confirmed
,
...
rest
})
{
export
function
ButtonConfirmed
({
children
,
confirmed
,
...
rest
})
{
if
(
confirmed
)
{
if
(
confirmed
)
{
return
<
ButtonConfirmedStyle
{...
rest
}
>
{
children
}
<
/ButtonConfirmedStyle
>
return
<
ButtonConfirmedStyle
{...
rest
}
>
{
children
}
<
/ButtonConfirmedStyle
>
...
@@ -108,6 +128,14 @@ export function ButtonConfirmed({ children, confirmed, ...rest }) {
...
@@ -108,6 +128,14 @@ export function ButtonConfirmed({ children, confirmed, ...rest }) {
}
}
}
}
export
function
ButtonError
({
children
,
error
,
...
rest
})
{
if
(
error
)
{
return
<
ButtonErrorStyle
{...
rest
}
>
{
children
}
<
/ButtonErrorStyle
>
}
else
{
return
<
ButtonPrimary
{...
rest
}
>
{
children
}
<
/ButtonPrimary
>
}
}
export
function
ButtonDropwdown
({
disabled
,
children
,
...
rest
})
{
export
function
ButtonDropwdown
({
disabled
,
children
,
...
rest
})
{
return
(
return
(
<
ButtonPrimary
{...
rest
}
>
<
ButtonPrimary
{...
rest
}
>
...
@@ -129,3 +157,11 @@ export function ButtonDropwdownLight({ disabled, children, ...rest }) {
...
@@ -129,3 +157,11 @@ export function ButtonDropwdownLight({ disabled, children, ...rest }) {
<
/ButtonEmpty
>
<
/ButtonEmpty
>
)
)
}
}
export
function
ButtonRadio
({
active
,
children
,
...
rest
})
{
if
(
!
active
)
{
return
<
ButtonEmpty
{...
rest
}
>
{
children
}
<
/ButtonEmpty
>
}
else
{
return
<
ButtonPrimary
{...
rest
}
>
{
children
}
<
/ButtonPrimary
>
}
}
src/components/Card/index.js
View file @
4e2c5c1e
...
@@ -3,7 +3,7 @@ import { Box } from 'rebass/styled-components'
...
@@ -3,7 +3,7 @@ import { Box } from 'rebass/styled-components'
const
Card
=
styled
(
Box
)
`
const
Card
=
styled
(
Box
)
`
width: 100%;
width: 100%;
border-radius:
20
px;
border-radius:
8
px;
padding: 1rem;
padding: 1rem;
padding:
${({
padding
})
=>
padding
}
;
padding:
${({
padding
})
=>
padding
}
;
border:
${({
border
})
=>
border
}
;
border:
${({
border
})
=>
border
}
;
...
@@ -16,5 +16,5 @@ export const LightCard = styled(Card)`
...
@@ -16,5 +16,5 @@ export const LightCard = styled(Card)`
`
`
export
const
GreyCard
=
styled
(
Card
)
`
export
const
GreyCard
=
styled
(
Card
)
`
background-color: rgba(255, 255, 255, 0.
6
);
background-color: rgba(255, 255, 255, 0.
9
);
`
`
src/components/ConfirmationModal/index.js
View file @
4e2c5c1e
import
React
from
'
react
'
import
React
from
'
react
'
import
styled
from
'
styled-components
'
import
styled
from
'
styled-components
'
import
{
ButtonPrimary
}
from
'
../Button
'
import
{
AutoColumn
,
ColumnCenter
}
from
'
../Column
'
import
Row
,
{
RowBetween
,
RowFlat
,
RowFixed
}
from
'
../Row
'
import
{
ArrowDown
}
from
'
react-feather
'
import
{
ButtonConfirmed
}
from
'
../Button
'
import
{
Text
}
from
'
rebass
'
import
{
LightCard
}
from
'
../Card
'
import
Modal
from
'
../Modal
'
import
Modal
from
'
../Modal
'
import
{
CheckCircle
}
from
'
react-feather
'
import
DoubleTokenLogo
from
'
../DoubleLogo
'
import
TokenLogo
from
'
../TokenLogo
'
import
{
CloseIcon
}
from
'
../../theme/components
'
import
Loader
from
'
../Loader
'
import
Loader
from
'
../Loader
'
import
{
Link
}
from
'
../../theme
'
import
{
Link
}
from
'
../../theme
'
import
{
Text
}
from
'
rebass
'
import
{
CloseIcon
}
from
'
../../theme/components
'
import
{
RowBetween
}
from
'
../Row
'
import
{
CheckCircle
}
from
'
react-feather
'
import
{
ButtonPrimary
}
from
'
../Button
'
import
{
AutoColumn
,
ColumnCenter
}
from
'
../Column
'
import
{
useWeb3React
}
from
'
../../hooks
'
import
{
useWeb3React
}
from
'
../../hooks
'
import
{
getEtherscanLink
}
from
'
../../utils
'
import
{
getEtherscanLink
}
from
'
../../utils
'
import
{
TRANSACTION_TYPE
}
from
'
../../constants
'
const
Wrapper
=
styled
.
div
`
const
Wrapper
=
styled
.
div
`
width: 100%;
width: 100%;
`
`
const
Section
=
styled
(
AutoColumn
)
`
const
Section
=
styled
(
AutoColumn
)
`
padding: 2
rem
;
padding: 2
6px
;
`
`
const
BottomSection
=
styled
(
Section
)
`
const
BottomSection
=
styled
(
Section
)
`
...
@@ -36,29 +29,17 @@ const ConfirmedIcon = styled(ColumnCenter)`
...
@@ -36,29 +29,17 @@ const ConfirmedIcon = styled(ColumnCenter)`
padding: 60px 0;
padding: 60px 0;
`
`
const
ConfirmedText
=
styled
(
Text
)
`
color:
${({
theme
,
confirmed
})
=>
(
confirmed
?
theme
.
connectedGreen
:
theme
.
white
)}
;
`
export
default
function
ConfirmationModal
({
export
default
function
ConfirmationModal
({
isOpen
,
isOpen
,
onDismiss
,
onDismiss
,
liquidityAmount
=
undefined
,
poolTokenPercentage
=
undefined
,
amount0
,
amount1
,
price
,
transactionType
,
hash
,
hash
,
signed
=
false
,
topContent
,
contractCall
,
bottomContent
,
attempt
edRemoval
=
false
,
attempt
ingTxn
,
pendingConfirmation
,
pendingConfirmation
,
extraCall
=
undefined
pendingText
,
title
=
''
})
{
})
{
const
{
address
:
address0
,
symbol
:
symbol0
}
=
amount0
?.
token
||
{}
const
{
address
:
address1
,
symbol
:
symbol1
}
=
amount1
?.
token
||
{}
const
{
chainId
}
=
useWeb3React
()
const
{
chainId
}
=
useWeb3React
()
function
WrappedOnDismissed
()
{
function
WrappedOnDismissed
()
{
...
@@ -66,208 +47,19 @@ export default function ConfirmationModal({
...
@@ -66,208 +47,19 @@ export default function ConfirmationModal({
}
}
return
(
return
(
<
Modal
isOpen
=
{
isOpen
}
onDismiss
=
{
WrappedOnDismissed
}
>
<
Modal
isOpen
=
{
isOpen
}
onDismiss
=
{
WrappedOnDismissed
}
maxHeight
=
{
90
}
>
{
!
attempt
edRemoval
?
(
{
!
attempt
ingTxn
?
(
<
Wrapper
>
<
Wrapper
>
<
Section
gap
=
"
40px
"
>
<
Section
>
<
RowBetween
>
<
RowBetween
>
<
Text
fontWeight
=
{
500
}
fontSize
=
{
'
20px
'
}
>
<
Text
fontWeight
=
{
500
}
fontSize
=
{
20
}
>
{
t
ransactionType
===
TRANSACTION_TYPE
.
SWAP
?
'
Confirm Swap
'
:
'
You will receive
'
}
{
t
itle
}
<
/Text
>
<
/Text
>
<
CloseIcon
onClick
=
{
WrappedOnDismissed
}
/
>
<
CloseIcon
onClick
=
{
WrappedOnDismissed
}
/
>
<
/RowBetween
>
<
/RowBetween
>
{
transactionType
===
TRANSACTION_TYPE
.
SWAP
&&
(
{
topContent
()}
<
AutoColumn
gap
=
{
'
20px
'
}
>
<
LightCard
>
<
RowBetween
>
<
Text
fontSize
=
{
24
}
fontWeight
=
{
500
}
>
{
!!
amount0
&&
amount0
?.
toSignificant
(
6
)}
<
/Text
>
<
RowFixed
gap
=
"
10px
"
>
<
TokenLogo
address
=
{
amount0
?.
token
?.
address
}
size
=
{
'
24px
'
}
/
>
<
Text
fontSize
=
{
24
}
fontWeight
=
{
500
}
style
=
{{
marginLeft
:
'
10px
'
}}
>
{
symbol0
}
<
/Text
>
<
/RowFixed
>
<
/RowBetween
>
<
/LightCard
>
<
ColumnCenter
>
<
ArrowDown
size
=
"
16
"
color
=
"
#888D9B
"
/>
<
/ColumnCenter
>
<
LightCard
>
<
RowBetween
>
<
Text
fontSize
=
{
24
}
fontWeight
=
{
500
}
>
{
!!
amount1
&&
amount1
?.
toSignificant
(
6
)}
<
/Text
>
<
RowFixed
gap
=
"
10px
"
>
<
TokenLogo
address
=
{
amount1
?.
token
?.
address
}
size
=
{
'
24px
'
}
/
>
<
Text
fontSize
=
{
24
}
fontWeight
=
{
500
}
style
=
{{
marginLeft
:
'
10px
'
}}
>
{
symbol1
}
<
/Text
>
<
/RowFixed
>
<
/RowBetween
>
<
/LightCard
>
<
/AutoColumn
>
)}
{
transactionType
===
TRANSACTION_TYPE
.
ADD
&&
(
<
AutoColumn
gap
=
"
16px
"
>
<
RowFlat
>
<
Text
fontSize
=
"
48px
"
fontWeight
=
{
500
}
lineHeight
=
"
32px
"
marginRight
=
{
10
}
>
{
liquidityAmount
?.
toFixed
(
6
)}
<
/Text
>
<
DoubleTokenLogo
a0
=
{
address0
||
''
}
a1
=
{
address1
||
''
}
size
=
{
20
}
/
>
<
/RowFlat
>
<
Row
>
<
Text
fontSize
=
"
24px
"
>
{
symbol0
+
'
:
'
+
symbol1
+
'
Pool Tokens
'
}
<
/Text
>
<
/Row
>
<
/AutoColumn
>
)}
{
transactionType
===
TRANSACTION_TYPE
.
REMOVE
&&
(
<
AutoColumn
gap
=
"
16px
"
>
<
Row
>
<
TokenLogo
address
=
{
address0
}
size
=
{
'
30px
'
}
/
>
<
Text
fontSize
=
"
24px
"
marginLeft
=
{
10
}
>
{
symbol0
}
{
!!
amount0
&&
amount0
?.
toSignificant
(
8
)}
<
/Text
>
<
/Row
>
<
Row
>
<
TokenLogo
address
=
{
address1
}
size
=
{
'
30px
'
}
/
>
<
Text
fontSize
=
"
24px
"
marginLeft
=
{
10
}
>
{
symbol1
}
{
!!
amount1
&&
amount1
?.
toSignificant
(
8
)}
<
/Text
>
<
/Row
>
<
/AutoColumn
>
)}
<
/Section
>
<
/Section
>
<
BottomSection
gap
=
"
12px
"
>
<
BottomSection
gap
=
"
12px
"
>
{
bottomContent
()}
<
/BottomSection
>
<
AutoColumn
gap
=
"
12px
"
>
{
transactionType
===
TRANSACTION_TYPE
.
ADD
&&
(
<>
<
RowBetween
>
<
Text
color
=
"
#565A69
"
fontWeight
=
{
500
}
fontSize
=
{
16
}
>
{
symbol0
}
Deposited
<
/Text
>
<
RowFixed
>
<
TokenLogo
address
=
{
address0
||
''
}
style
=
{{
marginRight
:
'
8px
'
}}
/
>
<
Text
fontWeight
=
{
500
}
fontSize
=
{
16
}
>
{
!!
amount0
&&
amount0
?.
toSignificant
(
6
)}
<
/Text
>
<
/RowFixed
>
<
/RowBetween
>
<
RowBetween
>
<
Text
color
=
"
#565A69
"
fontWeight
=
{
500
}
fontSize
=
{
16
}
>
{
symbol1
}
Deposited
<
/Text
>
<
RowFixed
>
<
TokenLogo
address
=
{
address1
||
''
}
style
=
{{
marginRight
:
'
8px
'
}}
/
>
<
Text
fontWeight
=
{
500
}
fontSize
=
{
16
}
>
{
amount1
?.
toSignificant
(
6
)}
<
/Text
>
<
/RowFixed
>
<
/RowBetween
>
<
/
>
)}
{
transactionType
===
TRANSACTION_TYPE
.
REMOVE
&&
(
<
RowBetween
>
<
Text
color
=
"
#565A69
"
fontWeight
=
{
500
}
fontSize
=
{
16
}
>
{
'
UNI
'
+
symbol0
+
'
:
'
+
symbol1
}
Burned
<
/Text
>
<
RowFixed
>
<
DoubleTokenLogo
a0
=
{
address0
||
''
}
a1
=
{
address1
||
''
}
margin
=
{
true
}
/
>
<
Text
fontWeight
=
{
500
}
fontSize
=
{
16
}
>
{
liquidityAmount
?.
toSignificant
(
6
)}
<
/Text
>
<
/RowFixed
>
<
/RowBetween
>
)}
{
price
&&
price
?.
adjusted
&&
(
<
RowBetween
>
<
Text
color
=
"
#565A69
"
fontWeight
=
{
500
}
fontSize
=
{
16
}
>
Rate
<
/Text
>
<
Text
fontWeight
=
{
500
}
fontSize
=
{
16
}
>
{
`1
${
symbol0
}
=
${
price
.
adjusted
.
toFixed
(
8
)}
${
symbol1
}
`
}
<
/Text
>
<
/RowBetween
>
)}
{
transactionType
===
TRANSACTION_TYPE
.
ADD
&&
poolTokenPercentage
&&
(
<
RowBetween
>
<
Text
color
=
"
#565A69
"
fontWeight
=
{
500
}
fontSize
=
{
16
}
>
Minted
Pool
Share
:
<
/Text
>
<
Text
fontWeight
=
{
500
}
fontSize
=
{
16
}
>
{
poolTokenPercentage
?.
toFixed
(
6
)
+
'
%
'
}
<
/Text
>
<
/RowBetween
>
)}
{
transactionType
===
TRANSACTION_TYPE
.
REMOVE
?
(
<
RowBetween
gap
=
"
20px
"
>
<
ButtonConfirmed
style
=
{{
margin
:
'
20px 0
'
}}
width
=
"
48%
"
onClick
=
{()
=>
{
extraCall
()
}}
confirmed
=
{
signed
}
disabled
=
{
signed
}
>
<
ConfirmedText
fontWeight
=
{
500
}
fontSize
=
{
20
}
confirmed
=
{
signed
}
>
{
signed
?
'
Signed
'
:
'
Sign
'
}
<
/ConfirmedText
>
<
/ButtonConfirmed
>
<
ButtonPrimary
width
=
"
48%
"
disabled
=
{
!
signed
}
style
=
{{
margin
:
'
20px 0
'
}}
onClick
=
{()
=>
{
contractCall
()
}}
>
<
Text
fontWeight
=
{
500
}
fontSize
=
{
20
}
>
Confirm
Remove
<
/Text
>
<
/ButtonPrimary
>
<
/RowBetween
>
)
:
(
<
ButtonPrimary
style
=
{{
margin
:
'
20px 0
'
}}
onClick
=
{()
=>
{
contractCall
()
}}
>
<
Text
fontWeight
=
{
500
}
fontSize
=
{
20
}
>
Confirm
{
'
'
}
{
transactionType
===
TRANSACTION_TYPE
.
ADD
?
'
Supply
'
:
transactionType
===
TRANSACTION_TYPE
.
REMOVE
?
'
Remove
'
:
'
Swap
'
}
<
/Text
>
<
/ButtonPrimary
>
)}
{
transactionType
===
TRANSACTION_TYPE
.
ADD
&&
(
<
Text
fontSize
=
{
12
}
color
=
"
#565A69
"
textAlign
=
"
center
"
>
{
`Output is estimated. You will receive at least
${
liquidityAmount
?.
toFixed
(
6
)}
UNI
$
{
symbol0
}
/${symbol1} or the transaction will revert.`
}
<
/Text
>
)}
{
transactionType
===
TRANSACTION_TYPE
.
REMOVE
&&
(
<
Text
fontSize
=
{
12
}
color
=
"
#565A69
"
textAlign
=
"
center
"
>
{
`Output is estimated. You will receive at least
${
amount0
?.
toSignificant
(
6
)}
$
{
symbol0
}
at
least
$
{
amount1
?.
toSignificant
(
6
)}
$
{
symbol1
}
or
the
transaction
will
revert
.
`}
</Text>
)}
{transactionType === TRANSACTION_TYPE.SWAP && (
<Text fontSize={12} color="#565A69" textAlign="center">
{`
Output
is
estimated
.
You
will
receive
at
least
$
{
amount1
?.
toSignificant
(
6
)}
$
{
symbol1
}
or
the
transaction
will
revert
.
`}
</Text>
)}
</AutoColumn>
</BottomSection>
<
/Wrapper
>
<
/Wrapper
>
)
:
(
)
:
(
<
Wrapper
>
<
Wrapper
>
...
@@ -284,17 +76,8 @@ export default function ConfirmationModal({
...
@@ -284,17 +76,8 @@ export default function ConfirmationModal({
{
!
pendingConfirmation
?
'
Transaction Submitted
'
:
'
Waiting For Confirmation
'
}
{
!
pendingConfirmation
?
'
Transaction Submitted
'
:
'
Waiting For Confirmation
'
}
<
/Text
>
<
/Text
>
<
AutoColumn
gap
=
"
12px
"
justify
=
{
'
center
'
}
>
<
AutoColumn
gap
=
"
12px
"
justify
=
{
'
center
'
}
>
<Text fontWeight={500} fontSize={16} color="#2172E5">
{transactionType === TRANSACTION_TYPE.ADD
? 'Supplied'
: transactionType === TRANSACTION_TYPE.REMOVE
? 'Removed'
: 'Swapped'}
</Text>
<
Text
fontWeight
=
{
600
}
fontSize
=
{
16
}
color
=
"
#2172E5
"
>
<
Text
fontWeight
=
{
600
}
fontSize
=
{
16
}
color
=
"
#2172E5
"
>
{`
$
{
amount0
?.
toSignificant
(
6
)}
$
{
symbol0
}
$
{
{
pendingText
}
transactionType
===
TRANSACTION_TYPE
.
SWAP
?
'
for
'
:
'
and
'
}
$
{
amount1
?.
toSignificant
(
6
)}
$
{
symbol1
}
`}
<
/Text
>
<
/Text
>
<
/AutoColumn
>
<
/AutoColumn
>
{
!
pendingConfirmation
&&
(
{
!
pendingConfirmation
&&
(
...
...
src/components/CurrencyInputPanel/index.js
View file @
4e2c5c1e
...
@@ -251,7 +251,12 @@ export default function CurrencyInputPanel({
...
@@ -251,7 +251,12 @@ export default function CurrencyInputPanel({
<
/LabelRow
>
<
/LabelRow
>
)}
)}
<
InputRow
>
<
InputRow
>
<
NumericalInput
field
=
{
field
}
value
=
{
value
}
onUserInput
=
{
onUserInput
}
/
>
<
NumericalInput
value
=
{
value
}
onUserInput
=
{
val
=>
{
onUserInput
(
field
,
val
)
}}
/
>
{
!!
token
?.
address
&&
!
atMax
&&
<
StyledBalanceMax
onClick
=
{
onMax
}
>
MAX
<
/StyledBalanceMax>
}
{
!!
token
?.
address
&&
!
atMax
&&
<
StyledBalanceMax
onClick
=
{
onMax
}
>
MAX
<
/StyledBalanceMax>
}
{
renderUnlockButton
()}
{
renderUnlockButton
()}
<
CurrencySelect
<
CurrencySelect
...
...
src/components/ExchangePage/index.tsx
View file @
4e2c5c1e
...
@@ -4,6 +4,21 @@ import { ethers } from 'ethers'
...
@@ -4,6 +4,21 @@ import { ethers } from 'ethers'
import
{
parseUnits
,
parseEther
}
from
'
@ethersproject/units
'
import
{
parseUnits
,
parseEther
}
from
'
@ethersproject/units
'
import
{
WETH
,
TradeType
,
Route
,
Trade
,
TokenAmount
,
JSBI
}
from
'
@uniswap/sdk
'
import
{
WETH
,
TradeType
,
Route
,
Trade
,
TokenAmount
,
JSBI
}
from
'
@uniswap/sdk
'
import
TokenLogo
from
'
../TokenLogo
'
import
QuestionHelper
from
'
../Question
'
import
NumericalInput
from
'
../NumericalInput
'
import
ConfirmationModal
from
'
../ConfirmationModal
'
import
CurrencyInputPanel
from
'
../CurrencyInputPanel
'
import
{
Link
}
from
'
../../theme/components
'
import
{
Text
}
from
'
rebass
'
import
ThemeProvider
,
{
TYPE
}
from
'
../../theme
'
import
{
GreyCard
}
from
'
../../components/Card
'
import
{
ArrowDown
,
ArrowUp
}
from
'
react-feather
'
import
{
AutoColumn
,
ColumnCenter
}
from
'
../../components/Column
'
import
{
ButtonError
,
ButtonRadio
}
from
'
../Button
'
import
Row
,
{
RowBetween
,
RowFixed
}
from
'
../../components/Row
'
import
{
usePopups
}
from
'
../../contexts/Application
'
import
{
useToken
}
from
'
../../contexts/Tokens
'
import
{
useToken
}
from
'
../../contexts/Tokens
'
import
{
useExchange
}
from
'
../../contexts/Exchanges
'
import
{
useExchange
}
from
'
../../contexts/Exchanges
'
import
{
useWeb3React
}
from
'
../../hooks
'
import
{
useWeb3React
}
from
'
../../hooks
'
...
@@ -11,17 +26,13 @@ import { useAddressBalance } from '../../contexts/Balances'
...
@@ -11,17 +26,13 @@ import { useAddressBalance } from '../../contexts/Balances'
import
{
useTransactionAdder
}
from
'
../../contexts/Transactions
'
import
{
useTransactionAdder
}
from
'
../../contexts/Transactions
'
import
{
useAddressAllowance
}
from
'
../../contexts/Allowances
'
import
{
useAddressAllowance
}
from
'
../../contexts/Allowances
'
import
ConfirmationModal
from
'
../ConfirmationModal
'
import
{
ROUTER_ADDRESSES
}
from
'
../../constants
'
import
CurrencyInputPanel
from
'
../CurrencyInputPanel
'
import
{
Text
}
from
'
rebass
'
import
{
RowBetween
}
from
'
../../components/Row
'
import
{
ButtonPrimary
}
from
'
../Button
'
import
{
ArrowDown
,
ArrowUp
}
from
'
react-feather
'
import
{
AutoColumn
,
ColumnCenter
}
from
'
../../components/Column
'
import
{
TRANSACTION_TYPE
,
ROUTER_ADDRESSES
}
from
'
../../constants
'
import
{
getRouterContract
,
calculateGasMargin
}
from
'
../../utils
'
import
{
getRouterContract
,
calculateGasMargin
}
from
'
../../utils
'
const
Wrapper
=
styled
.
div
`
position: relative;
`
const
ArrowWrapper
=
styled
.
div
`
const
ArrowWrapper
=
styled
.
div
`
padding: 4px;
padding: 4px;
border: 1px solid
${({
theme
})
=>
theme
.
malibuBlue
}
;
border: 1px solid
${({
theme
})
=>
theme
.
malibuBlue
}
;
...
@@ -36,8 +47,24 @@ const ArrowWrapper = styled.div`
...
@@ -36,8 +47,24 @@ const ArrowWrapper = styled.div`
}
}
`
`
const
FixedBottom
=
styled
.
div
`
position: absolute;
bottom: -200px;
width: 100%;
`
const
ErrorText
=
styled
(
Text
)
`
const
ErrorText
=
styled
(
Text
)
`
color:
${({
theme
,
error
})
=>
(
error
?
theme
.
salmonRed
:
theme
.
chaliceGray
)}
;
color:
${({
theme
,
warningMedium
,
warningHigh
})
=>
warningHigh
?
theme
.
salmonRed
:
warningMedium
?
theme
.
warningYellow
:
theme
.
textColor
}
;
`
const
InputWrapper
=
styled
(
RowBetween
)
`
width: 200px;
background-color:
${({
theme
})
=>
theme
.
inputBackground
}
;
border-radius: 8px;
padding: 4px 8px;
border: 1px solid transparent;
border:
${({
active
,
theme
})
=>
active
&&
'
1px solid
'
+
theme
.
royalBlue
}
;
`
`
enum
Field
{
enum
Field
{
...
@@ -136,25 +163,74 @@ function reducer(
...
@@ -136,25 +163,74 @@ function reducer(
}
}
}
}
function
hex
(
value
:
JSBI
)
{
return
ethers
.
utils
.
bigNumberify
(
value
.
toString
())
}
const
SLIPPAGE_INDEX
=
{
1
:
1
,
2
:
2
,
3
:
3
,
4
:
4
}
const
SWAP_TYPE
=
{
EXACT_TOKENS_FOR_TOKENS
:
'
EXACT_TOKENS_FOR_TOKENS
'
,
EXACT_TOKENS_FOR_ETH
:
'
EXACT_TOKENS_FOR_ETH
'
,
EXACT_ETH_FOR_TOKENS
:
'
EXACT_ETH_FOR_TOKENS
'
,
TOKENS_FOR_EXACT_TOKENS
:
'
TOKENS_FOR_EXACT_TOKENS
'
,
TOKENS_FOR_EXACT_ETH
:
'
TOKENS_FOR_EXACT_ETH
'
,
ETH_FOR_EXACT_TOKENS
:
'
ETH_FOR_EXACT_TOKENS
'
}
const
GAS_MARGIN
=
ethers
.
utils
.
bigNumberify
(
1000
)
// default allowed slippage, in bips
const
INITIAL_ALLOWED_SLIPPAGE
=
200
// 15 minutes, denominated in seconds
const
DEFAULT_DEADLINE_FROM_NOW
=
60
*
15
// used for warning states based on slippage in bips
const
ALLOWED_IMPACT_MEDIUM
=
100
const
ALLOWED_IMPACT_HIGH
=
500
export
default
function
ExchangePage
()
{
export
default
function
ExchangePage
()
{
const
{
chainId
,
account
,
library
}
=
useWeb3React
()
const
{
chainId
,
account
,
library
}
=
useWeb3React
()
const
routerAddress
=
ROUTER_ADDRESSES
[
chainId
]
const
routerAddress
=
ROUTER_ADDRESSES
[
chainId
]
// adding notifications on txns
const
[,
addPopup
]
=
usePopups
()
// input details
const
[
state
,
dispatch
]
=
useReducer
(
reducer
,
WETH
[
chainId
].
address
,
initializeSwapState
)
const
[
state
,
dispatch
]
=
useReducer
(
reducer
,
WETH
[
chainId
].
address
,
initializeSwapState
)
const
{
independentField
,
typedValue
,
...
fieldData
}
=
state
const
{
independentField
,
typedValue
,
...
fieldData
}
=
state
// get derived state
const
dependentField
=
independentField
===
Field
.
INPUT
?
Field
.
OUTPUT
:
Field
.
INPUT
const
dependentField
=
independentField
===
Field
.
INPUT
?
Field
.
OUTPUT
:
Field
.
INPUT
const
tradeType
=
independentField
===
Field
.
INPUT
?
TradeType
.
EXACT_INPUT
:
TradeType
.
EXACT_OUTPUT
const
tradeType
=
independentField
===
Field
.
INPUT
?
TradeType
.
EXACT_INPUT
:
TradeType
.
EXACT_OUTPUT
const
[
tradeError
,
setTradeError
]
=
useState
(
''
)
// error for thinsg liek reserve sizes
// get basic SDK entities
const
tokens
=
{
const
tokens
=
{
[
Field
.
INPUT
]:
useToken
(
fieldData
[
Field
.
INPUT
].
address
),
[
Field
.
INPUT
]:
useToken
(
fieldData
[
Field
.
INPUT
].
address
),
[
Field
.
OUTPUT
]:
useToken
(
fieldData
[
Field
.
OUTPUT
].
address
)
[
Field
.
OUTPUT
]:
useToken
(
fieldData
[
Field
.
OUTPUT
].
address
)
}
}
const
exchange
=
useExchange
(
tokens
[
Field
.
INPUT
],
tokens
[
Field
.
OUTPUT
])
const
exchange
=
useExchange
(
tokens
[
Field
.
INPUT
],
tokens
[
Field
.
OUTPUT
])
const
route
=
!!
exchange
?
new
Route
([
exchange
],
tokens
[
Field
.
INPUT
])
:
undefined
// no useRoute hook
const
route
=
!!
exchange
?
new
Route
([
exchange
],
tokens
[
Field
.
INPUT
])
:
undefined
// modal state
const
addTransaction
=
useTransactionAdder
()
const
[
showConfirm
,
setShowConfirm
]
=
useState
(
true
)
const
[
pendingConfirmation
,
setPendingConfirmation
]
=
useState
(
true
)
// waiting for user confirmation
const
[
attemptingTxn
,
setAttemptingTxn
]
=
useState
(
false
)
// clicked confirmed
// txn values
const
[
txHash
,
setTxHash
]
=
useState
()
const
[
deadline
,
setDeadline
]
=
useState
(
DEFAULT_DEADLINE_FROM_NOW
)
const
[
allowedSlippage
,
setAllowedSlippage
]
=
useState
(
INITIAL_ALLOWED_SLIPPAGE
)
// approvals
const
inputApproval
=
useAddressAllowance
(
account
,
tokens
[
Field
.
INPUT
],
routerAddress
)
const
outputApproval
=
useAddressAllowance
(
account
,
tokens
[
Field
.
OUTPUT
],
routerAddress
)
// get user- and token-specific lookup data
// get user- and token-specific lookup data
const
userBalances
=
{
const
userBalances
=
{
...
@@ -164,14 +240,18 @@ export default function ExchangePage() {
...
@@ -164,14 +240,18 @@ export default function ExchangePage() {
const
parsedAmounts
:
{
[
field
:
number
]:
TokenAmount
}
=
{}
const
parsedAmounts
:
{
[
field
:
number
]:
TokenAmount
}
=
{}
// try to parse typed value
// try to parse typed value
if
(
typedValue
!==
''
&&
typedValue
!==
'
.
'
&&
tokens
[
independentField
])
{
// if (typedValue !== '' && typedValue !== '.' && tokens[independentField]) {
if
(
tokens
[
independentField
])
{
try
{
try
{
const
typedValueParsed
=
parseUnits
(
typedValue
,
tokens
[
independentField
].
decimals
).
toString
()
const
typedValueParsed
=
parseUnits
(
'
0.0001
'
,
tokens
[
independentField
].
decimals
).
toString
()
if
(
typedValueParsed
!==
'
0
'
)
if
(
typedValueParsed
!==
'
0
'
)
parsedAmounts
[
independentField
]
=
new
TokenAmount
(
tokens
[
independentField
],
typedValueParsed
)
parsedAmounts
[
independentField
]
=
new
TokenAmount
(
tokens
[
independentField
],
typedValueParsed
)
}
catch
(
error
)
{
}
catch
(
error
)
{
// should only fail if the user specifies too many decimal places of precision (or maybe exceed max uint?)
// should only fail if the user specifies too many decimal places of precision (or maybe exceed max uint?)
console
.
error
(
error
)
/**
* @todo reserve limit error here
*/
console
.
error
(
'
found error here
'
)
}
}
}
}
...
@@ -182,9 +262,9 @@ export default function ExchangePage() {
...
@@ -182,9 +262,9 @@ export default function ExchangePage() {
!!
route
&&
!!
parsedAmounts
[
independentField
]
!!
route
&&
!!
parsedAmounts
[
independentField
]
?
new
Trade
(
route
,
parsedAmounts
[
independentField
],
tradeType
)
?
new
Trade
(
route
,
parsedAmounts
[
independentField
],
tradeType
)
:
undefined
:
undefined
}
catch
(
error
)
{
}
catch
(
error
)
{
}
console
.
error
(
error
)
}
const
slippageFromTrade
=
trade
&&
trade
.
slippage
if
(
trade
)
if
(
trade
)
parsedAmounts
[
dependentField
]
=
tradeType
===
TradeType
.
EXACT_INPUT
?
trade
.
outputAmount
:
trade
.
inputAmount
parsedAmounts
[
dependentField
]
=
tradeType
===
TradeType
.
EXACT_INPUT
?
trade
.
outputAmount
:
trade
.
inputAmount
...
@@ -250,14 +330,8 @@ export default function ExchangePage() {
...
@@ -250,14 +330,8 @@ export default function ExchangePage() {
:
undefined
:
undefined
const
maxAmountOutput
=
const
maxAmountOutput
=
!!
userBalances
[
Field
.
OUTPUT
]
&&
!!
userBalances
[
Field
.
OUTPUT
]
&&
JSBI
.
greaterThan
(
userBalances
[
Field
.
OUTPUT
].
raw
,
JSBI
.
BigInt
(
0
))
JSBI
.
greaterThan
(
?
userBalances
[
Field
.
OUTPUT
]
userBalances
[
Field
.
OUTPUT
].
raw
,
tokens
[
Field
.
OUTPUT
].
equals
(
WETH
[
chainId
])
?
MIN_ETHER
.
raw
:
JSBI
.
BigInt
(
0
)
)
?
tokens
[
Field
.
OUTPUT
].
equals
(
WETH
[
chainId
])
?
userBalances
[
Field
.
OUTPUT
].
subtract
(
MIN_ETHER
)
:
userBalances
[
Field
.
OUTPUT
]
:
undefined
:
undefined
const
atMaxAmountOutput
=
const
atMaxAmountOutput
=
...
@@ -265,23 +339,6 @@ export default function ExchangePage() {
...
@@ -265,23 +339,6 @@ export default function ExchangePage() {
?
JSBI
.
equal
(
maxAmountOutput
.
raw
,
parsedAmounts
[
Field
.
OUTPUT
].
raw
)
?
JSBI
.
equal
(
maxAmountOutput
.
raw
,
parsedAmounts
[
Field
.
OUTPUT
].
raw
)
:
undefined
:
undefined
const
[
showConfirm
,
setShowConfirm
]
=
useState
(
false
)
const
[
pendingConfirmation
,
toggelPendingConfirmation
]
=
useState
(
true
)
// state for txn
const
addTransaction
=
useTransactionAdder
()
const
[
txHash
,
setTxHash
]
=
useState
()
const
SWAP_TYPE
=
{
EXACT_TOKENS_FOR_TOKENS
:
'
EXACT_TOKENS_FOR_TOKENS
'
,
EXACT_TOKENS_FOR_ETH
:
'
EXACT_TOKENS_FOR_ETH
'
,
EXACT_ETH_FOR_TOKENS
:
'
EXACT_ETH_FOR_TOKENS
'
,
TOKENS_FOR_EXACT_TOKENS
:
'
TOKENS_FOR_EXACT_TOKENS
'
,
TOKENS_FOR_EXACT_ETH
:
'
TOKENS_FOR_EXACT_ETH
'
,
ETH_FOR_EXACT_TOKENS
:
'
ETH_FOR_EXACT_TOKENS
'
}
function
getSwapType
()
{
function
getSwapType
()
{
if
(
tradeType
===
TradeType
.
EXACT_INPUT
)
{
if
(
tradeType
===
TradeType
.
EXACT_INPUT
)
{
if
(
tokens
[
Field
.
INPUT
]
===
WETH
[
chainId
])
{
if
(
tokens
[
Field
.
INPUT
]
===
WETH
[
chainId
])
{
...
@@ -302,51 +359,62 @@ export default function ExchangePage() {
...
@@ -302,51 +359,62 @@ export default function ExchangePage() {
}
}
}
}
const
ALLOWED_SLIPPAGE
=
100
function
calculateSlippageAmount
(
value
:
TokenAmount
):
JSBI
[]
{
function
calculateSlippageAmount
(
value
:
TokenAmount
):
JSBI
[]
{
if
(
value
&&
value
.
raw
)
{
if
(
value
&&
value
.
raw
)
{
const
offset
=
JSBI
.
divide
(
JSBI
.
multiply
(
JSBI
.
BigInt
(
ALLOWED_SLIPPAGE
),
value
.
raw
),
JSBI
.
BigInt
(
10000
))
const
offset
=
JSBI
.
divide
(
JSBI
.
multiply
(
JSBI
.
BigInt
(
allowedSlippage
),
value
.
raw
),
JSBI
.
BigInt
(
10000
))
return
[
JSBI
.
subtract
(
value
.
raw
,
offset
),
JSBI
.
add
(
value
.
raw
,
offset
)]
return
[
JSBI
.
subtract
(
value
.
raw
,
offset
),
JSBI
.
add
(
value
.
raw
,
offset
)]
}
}
return
null
return
null
}
}
function
hex
(
value
:
JSBI
)
{
const
slippageAdjustedAmounts
=
{
return
ethers
.
utils
.
bigNumberify
(
value
.
toString
())
}
const
slippageAdjustedAmountsRaw
=
{
[
Field
.
INPUT
]:
[
Field
.
INPUT
]:
Field
.
INPUT
===
independentField
Field
.
INPUT
===
independentField
?
parsedAmounts
[
Field
.
INPUT
]?.
raw
?
parsedAmounts
[
Field
.
INPUT
]
:
calculateSlippageAmount
(
parsedAmounts
[
Field
.
INPUT
])?.[
1
],
:
calculateSlippageAmount
(
parsedAmounts
[
Field
.
INPUT
])?.[
0
]
&&
new
TokenAmount
(
tokens
[
Field
.
INPUT
],
calculateSlippageAmount
(
parsedAmounts
[
Field
.
INPUT
])?.[
1
]),
[
Field
.
OUTPUT
]:
[
Field
.
OUTPUT
]:
Field
.
OUTPUT
===
independentField
Field
.
OUTPUT
===
independentField
?
parsedAmounts
[
Field
.
OUTPUT
]?.
raw
?
parsedAmounts
[
Field
.
OUTPUT
]
:
calculateSlippageAmount
(
parsedAmounts
[
Field
.
OUTPUT
])?.[
0
]
:
calculateSlippageAmount
(
parsedAmounts
[
Field
.
OUTPUT
])?.[
0
]
&&
new
TokenAmount
(
tokens
[
Field
.
INPUT
],
calculateSlippageAmount
(
parsedAmounts
[
Field
.
OUTPUT
])?.[
0
])
}
}
const
inputApproval
=
useAddressAllowance
(
account
,
tokens
[
Field
.
INPUT
],
routerAddress
)
const
showInputUnlock
=
const
outputApproval
=
useAddressAllowance
(
account
,
tokens
[
Field
.
OUTPUT
],
routerAddress
)
parsedAmounts
[
Field
.
INPUT
]
&&
inputApproval
&&
JSBI
.
greaterThan
(
parsedAmounts
[
Field
.
INPUT
].
raw
,
inputApproval
.
raw
)
const
[
showInputUnlock
,
setShowInputUnlock
]
=
useState
(
false
)
const
showOutputUnlock
=
parsedAmounts
[
Field
.
OUTPUT
]
&&
outputApproval
&&
JSBI
.
greaterThan
(
parsedAmounts
[
Field
.
OUTPUT
].
raw
,
outputApproval
.
raw
)
// monitor parsed amounts and update unlocked buttons
// modal state
useEffect
(()
=>
{
const
[
showAdvanced
,
setShowAdvanced
]
=
useState
(
true
)
if
(
const
[
activeIndex
,
setActiveIndex
]
=
useState
(
SLIPPAGE_INDEX
[
3
])
parsedAmounts
[
Field
.
INPUT
]
&&
const
[
customSlippage
,
setCustomSlippage
]
=
useState
()
inputApproval
&&
const
[
customDeadline
,
setCustomDeadline
]
=
useState
(
DEFAULT_DEADLINE_FROM_NOW
/
60
)
JSBI
.
greaterThan
(
parsedAmounts
[
Field
.
INPUT
].
raw
,
inputApproval
.
raw
)
)
{
const
[
slippageInputError
,
setSlippageInputError
]
=
useState
(
null
)
setShowInputUnlock
(
true
)
}
else
{
function
parseCustomInput
(
val
)
{
setShowInputUnlock
(
false
)
const
acceptableValues
=
[
/^$/
,
/^
\d{1,2}
$/
,
/^
\d{0,2}\.\d{0,2}
$/
]
if
(
acceptableValues
.
some
(
a
=>
a
.
test
(
val
)))
{
setCustomSlippage
(
val
)
setAllowedSlippage
(
val
*
100
)
}
}
function
parseCustomDeadline
(
val
)
{
const
acceptableValues
=
[
/^$/
,
/^
\d
+$/
]
if
(
acceptableValues
.
some
(
re
=>
re
.
test
(
val
)))
{
setCustomDeadline
(
val
)
setDeadline
(
val
*
60
)
}
}
}
},
[
inputApproval
,
outputApproval
,
parsedAmounts
])
async
function
onSwap
()
{
async
function
onSwap
()
{
const
routerContract
=
getRouterContract
(
chainId
,
library
,
account
)
const
routerContract
=
getRouterContract
(
chainId
,
library
,
account
)
setAttemptingTxn
(
true
)
const
path
=
Object
.
keys
(
route
.
path
).
map
(
key
=>
{
const
path
=
Object
.
keys
(
route
.
path
).
map
(
key
=>
{
return
route
.
path
[
key
].
address
return
route
.
path
[
key
].
address
...
@@ -354,7 +422,7 @@ export default function ExchangePage() {
...
@@ -354,7 +422,7 @@ export default function ExchangePage() {
let
estimate
:
Function
,
method
:
Function
,
args
,
value
let
estimate
:
Function
,
method
:
Function
,
args
,
value
const
deadline
=
1739591241
const
deadline
FromNow
=
Math
.
ceil
(
Date
.
now
()
/
1000
)
+
deadline
const
swapType
=
getSwapType
()
const
swapType
=
getSwapType
()
switch
(
swapType
)
{
switch
(
swapType
)
{
...
@@ -362,11 +430,11 @@ export default function ExchangePage() {
...
@@ -362,11 +430,11 @@ export default function ExchangePage() {
estimate
=
routerContract
.
estimate
.
swapExactTokensForTokens
estimate
=
routerContract
.
estimate
.
swapExactTokensForTokens
method
=
routerContract
.
swapExactTokensForTokens
method
=
routerContract
.
swapExactTokensForTokens
args
=
[
args
=
[
slippageAdjustedAmounts
Raw
[
Field
.
INPUT
]
.
toString
(),
slippageAdjustedAmounts
[
Field
.
INPUT
].
raw
.
toString
(),
slippageAdjustedAmounts
Raw
[
Field
.
OUTPUT
]
.
toString
(),
slippageAdjustedAmounts
[
Field
.
OUTPUT
].
raw
.
toString
(),
path
,
path
,
account
,
account
,
deadline
deadline
FromNow
]
]
value
=
ethers
.
constants
.
Zero
value
=
ethers
.
constants
.
Zero
break
break
...
@@ -374,29 +442,29 @@ export default function ExchangePage() {
...
@@ -374,29 +442,29 @@ export default function ExchangePage() {
estimate
=
routerContract
.
estimate
.
swapTokensForExactTokens
estimate
=
routerContract
.
estimate
.
swapTokensForExactTokens
method
=
routerContract
.
swapTokensForExactTokens
method
=
routerContract
.
swapTokensForExactTokens
args
=
[
args
=
[
slippageAdjustedAmounts
Raw
[
Field
.
OUTPUT
]
.
toString
(),
slippageAdjustedAmounts
[
Field
.
OUTPUT
].
raw
.
toString
(),
slippageAdjustedAmounts
Raw
[
Field
.
INPUT
]
.
toString
(),
slippageAdjustedAmounts
[
Field
.
INPUT
].
raw
.
toString
(),
path
,
path
,
account
,
account
,
deadline
deadline
FromNow
]
]
value
=
ethers
.
constants
.
Zero
value
=
ethers
.
constants
.
Zero
break
break
case
SWAP_TYPE
.
EXACT_ETH_FOR_TOKENS
:
case
SWAP_TYPE
.
EXACT_ETH_FOR_TOKENS
:
estimate
=
routerContract
.
estimate
.
swapExactETHForTokens
estimate
=
routerContract
.
estimate
.
swapExactETHForTokens
method
=
routerContract
.
swapExactETHForTokens
method
=
routerContract
.
swapExactETHForTokens
args
=
[
slippageAdjustedAmounts
Raw
[
Field
.
OUTPUT
].
toString
(),
path
,
account
,
deadline
]
args
=
[
slippageAdjustedAmounts
[
Field
.
OUTPUT
].
raw
.
toString
(),
path
,
account
,
deadlineFromNow
]
value
=
hex
(
slippageAdjustedAmounts
Raw
[
Field
.
INPUT
]
)
value
=
hex
(
slippageAdjustedAmounts
[
Field
.
INPUT
].
raw
)
break
break
case
SWAP_TYPE
.
TOKENS_FOR_EXACT_ETH
:
case
SWAP_TYPE
.
TOKENS_FOR_EXACT_ETH
:
estimate
=
routerContract
.
estimate
.
swapTokensForExactETH
estimate
=
routerContract
.
estimate
.
swapTokensForExactETH
method
=
routerContract
.
swapTokensForExactETH
method
=
routerContract
.
swapTokensForExactETH
args
=
[
args
=
[
slippageAdjustedAmounts
Raw
[
Field
.
OUTPUT
]
.
toString
(),
slippageAdjustedAmounts
[
Field
.
OUTPUT
].
raw
.
toString
(),
slippageAdjustedAmounts
Raw
[
Field
.
INPUT
]
.
toString
(),
slippageAdjustedAmounts
[
Field
.
INPUT
].
raw
.
toString
(),
path
,
path
,
account
,
account
,
deadline
deadline
FromNow
]
]
value
=
ethers
.
constants
.
Zero
value
=
ethers
.
constants
.
Zero
break
break
...
@@ -404,24 +472,22 @@ export default function ExchangePage() {
...
@@ -404,24 +472,22 @@ export default function ExchangePage() {
estimate
=
routerContract
.
estimate
.
swapExactTokensForETH
estimate
=
routerContract
.
estimate
.
swapExactTokensForETH
method
=
routerContract
.
swapExactTokensForETH
method
=
routerContract
.
swapExactTokensForETH
args
=
[
args
=
[
slippageAdjustedAmounts
Raw
[
Field
.
INPUT
]
.
toString
(),
slippageAdjustedAmounts
[
Field
.
INPUT
].
raw
.
toString
(),
slippageAdjustedAmounts
Raw
[
Field
.
OUTPUT
]
.
toString
(),
slippageAdjustedAmounts
[
Field
.
OUTPUT
].
raw
.
toString
(),
path
,
path
,
account
,
account
,
deadline
deadline
FromNow
]
]
value
=
ethers
.
constants
.
Zero
value
=
ethers
.
constants
.
Zero
break
break
case
SWAP_TYPE
.
ETH_FOR_EXACT_TOKENS
:
case
SWAP_TYPE
.
ETH_FOR_EXACT_TOKENS
:
estimate
=
routerContract
.
estimate
.
swapETHForExactTokens
estimate
=
routerContract
.
estimate
.
swapETHForExactTokens
method
=
routerContract
.
swapETHForExactTokens
method
=
routerContract
.
swapETHForExactTokens
args
=
[
slippageAdjustedAmounts
Raw
[
Field
.
OUTPUT
].
toString
(),
path
,
account
,
deadline
]
args
=
[
slippageAdjustedAmounts
[
Field
.
OUTPUT
].
raw
.
toString
(),
path
,
account
,
deadlineFromNow
]
value
=
hex
(
slippageAdjustedAmounts
Raw
[
Field
.
INPUT
]
)
value
=
hex
(
slippageAdjustedAmounts
[
Field
.
INPUT
].
raw
)
break
break
}
}
const
GAS_MARGIN
=
ethers
.
utils
.
bigNumberify
(
1000
)
const
estimatedGasLimit
=
await
estimate
(...
args
,
{
value
}).
catch
(
e
=>
{
const
estimatedGasLimit
=
await
estimate
(...
args
,
{
value
}).
catch
(
e
=>
{
console
.
log
(
'
error getting gas limit
'
)
console
.
log
(
'
error getting gas limit
'
)
})
})
...
@@ -433,71 +499,267 @@ export default function ExchangePage() {
...
@@ -433,71 +499,267 @@ export default function ExchangePage() {
.
then
(
response
=>
{
.
then
(
response
=>
{
setTxHash
(
response
)
setTxHash
(
response
)
addTransaction
(
response
)
addTransaction
(
response
)
toggel
PendingConfirmation
(
false
)
set
PendingConfirmation
(
false
)
})
})
.
catch
(
e
=>
{
.
catch
(
e
=>
{
console
.
log
(
'
error when trying transaction
'
)
addPopup
(
console
.
log
(
e
)
<
AutoColumn
gap=
"10px"
>
<
Text
>
Transaction Failed: try again.
</
Text
>
</
AutoColumn
>
)
resetModal
()
setShowConfirm
(
false
)
setShowConfirm
(
false
)
})
})
}
}
// errors
// errors
const
[
inputError
,
setInputError
]
=
useState
()
const
[
inputError
,
setInputError
]
=
useState
(
''
)
const
[
outputError
,
setOutputError
]
=
useState
()
const
[
outputError
,
setOutputError
]
=
useState
(
''
)
const
[
errorText
,
setErrorText
]
=
useState
(
'
'
)
const
[
isValid
,
setIsValid
]
=
useState
(
false
)
const
[
isError
,
setIsError
]
=
useState
(
false
)
// update errors live
useEffect
(()
=>
{
useEffect
(()
=>
{
// reset errors
// reset errors
setInputError
(
null
)
setInputError
(
null
)
setOutputError
(
null
)
setOutputError
(
null
)
setIsError
(
false
)
setTradeError
(
null
)
setIsValid
(
true
)
if
(
parsedAmounts
[
Field
.
INPUT
]
&&
exchange
&&
JSBI
.
greaterThan
(
parsedAmounts
[
Field
.
INPUT
].
raw
,
exchange
.
reserveOf
(
tokens
[
Field
.
INPUT
]).
raw
)
)
{
setTradeError
(
'
Low Liquidity Error
'
)
setIsValid
(
false
)
}
if
(
parsedAmounts
[
Field
.
OUTPUT
]
&&
exchange
&&
JSBI
.
greaterThan
(
parsedAmounts
[
Field
.
OUTPUT
].
raw
,
exchange
.
reserveOf
(
tokens
[
Field
.
OUTPUT
]).
raw
)
)
{
setTradeError
(
'
Low Liquidity Error
'
)
setIsValid
(
false
)
}
if
(
showInputUnlock
)
{
if
(
showInputUnlock
)
{
setInputError
(
'
Need to approve amount on input.
'
)
setInputError
(
'
Approval Needed
'
)
setIsValid
(
false
)
}
}
if
(
showOutputUnlock
)
{
setOutputError
(
'
Approval Needed
'
)
setIsValid
(
false
)
}
if
(
if
(
userBalances
[
Field
.
INPUT
]
&&
userBalances
[
Field
.
INPUT
]
&&
parsedAmounts
[
Field
.
INPUT
]
&&
parsedAmounts
[
Field
.
INPUT
]
&&
JSBI
.
lessThan
(
userBalances
[
Field
.
INPUT
].
raw
,
parsedAmounts
[
Field
.
INPUT
]?.
raw
)
JSBI
.
lessThan
(
userBalances
[
Field
.
INPUT
].
raw
,
parsedAmounts
[
Field
.
INPUT
]?.
raw
)
)
{
)
{
setInputError
(
'
Insufficient balance.
'
)
setInputError
(
'
Insufficient balance.
'
)
setIs
Error
(
tru
e
)
setIs
Valid
(
fals
e
)
}
}
},
[
parsedAmounts
,
showInputUnlock
,
userBalances
])
// set error text based on all errors
if
(
useEffect
(()
=>
{
userBalances
[
Field
.
OUTPUT
]
&&
setErrorText
(
null
)
parsedAmounts
[
Field
.
OUTPUT
]
&&
if
(
!
parsedAmounts
[
Field
.
INPUT
])
{
JSBI
.
lessThan
(
userBalances
[
Field
.
OUTPUT
].
raw
,
parsedAmounts
[
Field
.
OUTPUT
]?.
raw
)
setErrorText
(
'
Enter an amount to continue
'
)
)
{
}
else
if
(
outputError
)
{
setOutputError
(
'
Insufficient balance.
'
)
setErrorText
(
outputError
)
setIsValid
(
false
)
}
else
if
(
inputError
)
{
setErrorText
(
inputError
)
return
}
}
},
[
inputError
,
outputError
,
parsedAmount
s
])
},
[
exchange
,
parsedAmounts
,
showInputUnlock
,
showOutputUnlock
,
tokens
,
userBalance
s
])
// error state for button
const
warningMedium
=
slippageFromTrade
&&
parseFloat
(
slippageFromTrade
.
toFixed
(
4
))
>
ALLOWED_IMPACT_MEDIUM
/
100
const
isValid
=
!
errorText
const
warningHigh
=
slippageFromTrade
&&
parseFloat
(
slippageFromTrade
.
toFixed
(
4
))
>
ALLOWED_IMPACT_HIGH
/
100
function
resetModal
()
{
setPendingConfirmation
(
true
)
setAttemptingTxn
(
false
)
setShowAdvanced
(
false
)
}
function
modalHeader
()
{
return
(
return
(
<
AutoColumn
gap=
{
'
20px
'
}
style=
{
{
marginTop
:
'
40px
'
}
}
>
<
RowBetween
align=
"flex-end"
>
<
Text
fontSize=
{
36
}
fontWeight=
{
500
}
>
{
!!
slippageAdjustedAmounts
[
Field
.
INPUT
]
&&
slippageAdjustedAmounts
[
Field
.
INPUT
].
toSignificant
(
6
)
}
</
Text
>
<
RowFixed
gap=
"10px"
>
<
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=
"#888D9B"
/>
</
RowFixed
>
<
RowBetween
align=
"flex-end"
>
<
Text
fontSize=
{
36
}
fontWeight=
{
500
}
color=
{
warningHigh
?
'
#FF6871
'
:
'
#2172E5
'
}
>
{
!!
slippageAdjustedAmounts
[
Field
.
OUTPUT
]
&&
slippageAdjustedAmounts
[
Field
.
OUTPUT
].
toSignificant
(
6
)
}
</
Text
>
<
RowFixed
gap=
"10px"
>
<
TokenLogo
address=
{
tokens
[
Field
.
OUTPUT
]?.
address
}
size=
{
'
24px
'
}
/>
<
Text
fontSize=
{
24
}
fontWeight=
{
500
}
style=
{
{
marginLeft
:
'
10px
'
}
}
>
{
tokens
[
Field
.
OUTPUT
]?.
symbol
||
''
}
</
Text
>
</
RowFixed
>
</
RowBetween
>
</
AutoColumn
>
)
}
function
modalBottom
()
{
return
showAdvanced
?
(
<
AutoColumn
gap=
"20px"
>
<
Link
onClick=
{
()
=>
{
setShowAdvanced
(
false
)
}
}
>
back
</
Link
>
<
RowBetween
>
<
TYPE
.
main
>
Limit additional price slippage
</
TYPE
.
main
>
<
QuestionHelper
text=
""
/>
</
RowBetween
>
<
Row
>
<
ButtonRadio
active=
{
SLIPPAGE_INDEX
[
1
]
===
activeIndex
}
padding=
"4px 6px"
borderRadius=
"8px"
style=
{
{
marginRight
:
'
16px
'
}
}
width=
{
'
60px
'
}
onClick=
{
()
=>
{
setActiveIndex
(
SLIPPAGE_INDEX
[
1
])
setAllowedSlippage
(
10
)
}
}
>
0.1%
</
ButtonRadio
>
<
ButtonRadio
active=
{
SLIPPAGE_INDEX
[
2
]
===
activeIndex
}
padding=
"4px 6px"
borderRadius=
"8px"
style=
{
{
marginRight
:
'
16px
'
}
}
width=
{
'
60px
'
}
onClick=
{
()
=>
{
setActiveIndex
(
SLIPPAGE_INDEX
[
2
])
setAllowedSlippage
(
100
)
}
}
>
1%
</
ButtonRadio
>
<
ButtonRadio
active=
{
SLIPPAGE_INDEX
[
3
]
===
activeIndex
}
padding=
"4px"
borderRadius=
"8px"
width=
{
'
140px
'
}
onClick=
{
()
=>
{
setActiveIndex
(
SLIPPAGE_INDEX
[
3
])
setAllowedSlippage
(
200
)
}
}
>
2% (suggested)
</
ButtonRadio
>
</
Row
>
<
RowFixed
>
<
InputWrapper
active=
{
SLIPPAGE_INDEX
[
4
]
===
activeIndex
}
>
<
NumericalInput
align=
{
customSlippage
?
'
right
'
:
'
left
'
}
value=
{
customSlippage
||
''
}
onUserInput=
{
val
=>
{
parseCustomInput
(
val
)
setActiveIndex
(
SLIPPAGE_INDEX
[
4
])
}
}
placeHolder=
"Custom"
onClick=
{
()
=>
{
setActiveIndex
(
SLIPPAGE_INDEX
[
4
])
if
(
customSlippage
)
{
parseCustomInput
(
customSlippage
)
}
}
}
/>
%
</
InputWrapper
>
</
RowFixed
>
<
RowBetween
>
<
TYPE
.
main
>
Adjust deadline (minutes from now)
</
TYPE
.
main
>
</
RowBetween
>
<
RowFixed
>
<
NumericalInput
value=
{
customDeadline
}
onUserInput=
{
val
=>
{
parseCustomDeadline
(
val
)
}
}
/>
</
RowFixed
>
</
AutoColumn
>
)
:
(
<>
<>
<
RowBetween
>
<
Text
color=
"#565A69"
fontWeight=
{
500
}
fontSize=
{
16
}
>
Price
</
Text
>
<
Text
fontWeight=
{
500
}
fontSize=
{
16
}
>
{
`1 ${tokens[Field.INPUT]?.symbol} = ${route && route.midPrice && route.midPrice.adjusted.toFixed(8)} ${
tokens[Field.OUTPUT]?.symbol
}`
}
</
Text
>
</
RowBetween
>
<
RowBetween
>
<
Text
color=
"#565A69"
fontWeight=
{
500
}
fontSize=
{
16
}
>
Slippage
<
Link
onClick=
{
()
=>
setShowAdvanced
(
true
)
}
>
(edit limits)
</
Link
>
</
Text
>
<
ErrorText
warningHigh=
{
warningHigh
}
fontWeight=
{
500
}
>
{
slippageFromTrade
&&
slippageFromTrade
.
toFixed
(
4
)
}
%
</
ErrorText
>
</
RowBetween
>
<
ButtonError
onClick=
{
onSwap
}
error=
{
!!
warningHigh
}
style=
{
{
margin
:
'
10px 0
'
}
}
>
<
Text
fontSize=
{
20
}
fontWeight=
{
500
}
>
{
warningHigh
?
'
Swap Anyway
'
:
'
Swap
'
}
</
Text
>
</
ButtonError
>
<
Text
fontSize=
{
12
}
color=
"#565A69"
textAlign=
"center"
>
{
`Output is estimated. You will receive at least ${slippageAdjustedAmounts[Field.OUTPUT]?.toSignificant(6)} ${
tokens[Field.OUTPUT]?.symbol
} or the transaction will revert.`
}
</
Text
>
<
AutoColumn
justify=
"center"
>
<
Link
onClick=
{
()
=>
{
setShowAdvanced
(
true
)
}
}
>
Advanced Options
</
Link
>
</
AutoColumn
>
</>
)
}
const
pendingText
=
` Swapped
${
parsedAmounts
[
Field
.
INPUT
]?.
toSignificant
(
6
)}
$
{
tokens
[
Field
.
INPUT
]?.
symbol
}
for
$
{
parsedAmounts
[
Field
.
OUTPUT
]?.
toSignificant
(
6
)}
$
{
tokens
[
Field
.
OUTPUT
]?.
symbol
}
`
return (
<Wrapper>
<ConfirmationModal
<ConfirmationModal
isOpen={showConfirm}
isOpen={showConfirm}
onDismiss={() => {
onDismiss={() => {
setTxHash
(
null
)
resetModal(
)
setShowConfirm(false)
setShowConfirm(false)
}}
}}
amount0=
{
parsedAmounts
[
Field
.
INPUT
]
}
attemptingTxn={attemptingTxn}
amount1=
{
parsedAmounts
[
Field
.
OUTPUT
]
}
price=
{
route
?.
midPrice
}
transactionType=
{
TRANSACTION_TYPE
.
SWAP
}
contractCall=
{
onSwap
}
pendingConfirmation={pendingConfirmation}
pendingConfirmation={pendingConfirmation}
hash=
{
txHash
?
txHash
.
hash
:
''
}
hash={txHash ? txHash : ''}
topContent={() => modalHeader()}
bottomContent={modalBottom}
pendingText={pendingText}
title="Confirm Swap"
/>
/>
<AutoColumn gap={'20px'}>
<AutoColumn gap={'20px'}>
<CurrencyInputPanel
<CurrencyInputPanel
...
@@ -509,7 +771,7 @@ export default function ExchangePage() {
...
@@ -509,7 +771,7 @@ export default function ExchangePage() {
}}
}}
atMax={atMaxAmountInput}
atMax={atMaxAmountInput}
token={tokens[Field.INPUT]}
token={tokens[Field.INPUT]}
onTokenSelection=
{
onTokenSelection
}
onTokenSelection={
address => onTokenSelection(Field.INPUT, address)
}
title={'Input'}
title={'Input'}
error={inputError}
error={inputError}
exchange={exchange}
exchange={exchange}
...
@@ -530,36 +792,69 @@ export default function ExchangePage() {
...
@@ -530,36 +792,69 @@ export default function ExchangePage() {
}}
}}
atMax={atMaxAmountOutput}
atMax={atMaxAmountOutput}
token={tokens[Field.OUTPUT]}
token={tokens[Field.OUTPUT]}
onTokenSelection=
{
onTokenSelection
}
onTokenSelection={
address => onTokenSelection(Field.OUTPUT, address)
}
title={'Output'}
title={'Output'}
error={outputError}
error={outputError}
exchange={exchange}
exchange={exchange}
disableUnlock
showUnlock={showOutputUnlock}
/>
/>
<RowBetween>
<RowBetween>
Rate:
<Text fontWeight={500} color="#565A69">
<
div
>
Price
</Text>
<Text fontWeight={500} color="#565A69">
{exchange
{exchange
? `
1
$
{
tokens
[
Field
.
INPUT
].
symbol
}
=
$
{
route
?.
midPrice
.
toSignificant
(
6
)}
$
{
tokens
[
Field
.
OUTPUT
].
symbol
}
`
? `
1
$
{
tokens
[
Field
.
INPUT
].
symbol
}
=
$
{
route
?.
midPrice
.
toSignificant
(
6
)}
$
{
tokens
[
Field
.
OUTPUT
].
symbol
}
`
: '-'}
: '-'}
</
div
>
</
Text
>
</RowBetween>
</RowBetween>
<
ColumnCenter
style=
{
{
height
:
'
20px
'
}
}
>
{warningMedium && (
<
ErrorText
fontSize=
{
12
}
error=
{
isError
}
>
<RowBetween>
{
errorText
&&
errorText
}
<Text fontWeight={500} color="#565A69">
Slippage
</Text>
<ErrorText fontWeight={500} warningMedium={warningMedium} warningHigh={warningHigh}>
{slippageFromTrade.toFixed(4)}%
</ErrorText>
</ErrorText>
</
ColumnCenter
>
</RowBetween>
<
ButtonPrimary
)}
<ButtonError
onClick={() => {
onClick={() => {
setShowConfirm(true)
setShowConfirm(true)
}}
}}
disabled={!isValid}
disabled={!isValid}
error={!!warningHigh}
>
>
<Text fontSize={20} fontWeight={500}>
<Text fontSize={20} fontWeight={500}>
Swap
{inputError
? inputError
: outputError
? outputError
: tradeError
? tradeError
: warningHigh
? 'Swap Anyway'
: 'Swap'}
</Text>
</Text>
</
Button
Primary
>
</Button
Error
>
</AutoColumn>
</AutoColumn>
</>
{warningHigh && (
<FixedBottom>
<GreyCard>
<AutoColumn gap="12px">
<RowBetween>
<Text fontWeight={500}>Slippage Warning</Text>
<QuestionHelper text="" />
</RowBetween>
<Text color="#565A69" lineHeight="145.23%;">
This trade will move the price by {slippageFromTrade.toFixed(2)}%. This pool probably doesn’t have
enough liquidity. Are you sure you want to continue this trade?
</Text>
</AutoColumn>
</GreyCard>
</FixedBottom>
)}
</Wrapper>
)
)
}
}
src/components/Header/index.js
View file @
4e2c5c1e
...
@@ -17,6 +17,7 @@ import { isMobile } from 'react-device-detect'
...
@@ -17,6 +17,7 @@ import { isMobile } from 'react-device-detect'
import
{
useWeb3React
}
from
'
../../hooks
'
import
{
useWeb3React
}
from
'
../../hooks
'
import
{
useAddressBalance
}
from
'
../../contexts/Balances
'
import
{
useAddressBalance
}
from
'
../../contexts/Balances
'
import
{
useWalletModalToggle
,
usePopups
}
from
'
../../contexts/Application
'
import
{
useWalletModalToggle
,
usePopups
}
from
'
../../contexts/Application
'
import
{
AutoColumn
}
from
'
../Column
'
const
HeaderFrame
=
styled
.
div
`
const
HeaderFrame
=
styled
.
div
`
display: flex;
display: flex;
...
@@ -68,7 +69,7 @@ const AccountElement = styled.div`
...
@@ -68,7 +69,7 @@ const AccountElement = styled.div`
/* width: 100%; */
/* width: 100%; */
`
`
const
FixedPopupColumn
=
styled
.
div
`
const
FixedPopupColumn
=
styled
(
AutoColumn
)
`
position: absolute;
position: absolute;
top: 80px;
top: 80px;
right: 20px
right: 20px
...
@@ -84,6 +85,15 @@ const StyledClose = styled(X)`
...
@@ -84,6 +85,15 @@ const StyledClose = styled(X)`
}
}
`
`
const
Popup
=
styled
(
Card
)
`
box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.04), 0px 4px 8px rgba(0, 0, 0, 0.04), 0px 16px 24px rgba(0, 0, 0, 0.04),
0px 24px 32px rgba(0, 0, 0, 0.04);
z-index: 9999;
border-radius: 8px;
padding: 1rem;
background:
${
theme
=>
theme
.
white
}
;
`
export
default
function
Header
()
{
export
default
function
Header
()
{
const
{
account
,
chainId
}
=
useWeb3React
()
const
{
account
,
chainId
}
=
useWeb3React
()
...
@@ -117,13 +127,13 @@ export default function Header() {
...
@@ -117,13 +127,13 @@ export default function Header() {
<
/AccountElement
>
<
/AccountElement
>
<
Menu
/>
<
Menu
/>
<
/HeaderElement
>
<
/HeaderElement
>
<
FixedPopupColumn
>
<
FixedPopupColumn
gap
=
"
20px
"
>
{
activePopups
.
map
(
item
=>
{
{
activePopups
.
map
(
item
=>
{
return
(
return
(
<
Card
bg
=
"
white
"
padding
=
{
'
16px
'
}
key
=
{
item
.
key
}
borderRadius
=
{
'
8px
'
}
>
<
Popup
key
=
{
item
.
key
}
>
<
StyledClose
color
=
"
#888D9B
"
onClick
=
{()
=>
removePopup
(
item
.
key
)}
/
>
<
StyledClose
color
=
"
#888D9B
"
onClick
=
{()
=>
removePopup
(
item
.
key
)}
/
>
{
item
.
content
}
{
item
.
content
}
<
/
Card
>
<
/
Popup
>
)
)
})}
})}
<
/FixedPopupColumn
>
<
/FixedPopupColumn
>
...
...
src/components/Menu/index.js
View file @
4e2c5c1e
...
@@ -6,7 +6,6 @@ import { ReactComponent as MenuIcon } from '../../assets/images/menu.svg'
...
@@ -6,7 +6,6 @@ import { ReactComponent as MenuIcon } from '../../assets/images/menu.svg'
import
{
Link
}
from
'
../../theme
'
import
{
Link
}
from
'
../../theme
'
import
{
darken
,
transparentize
}
from
'
polished
'
import
{
darken
,
transparentize
}
from
'
polished
'
import
{
useAdvancedManager
}
from
'
../../contexts/LocalStorage
'
import
Toggle
from
'
react-switch
'
import
Toggle
from
'
react-switch
'
...
@@ -140,7 +139,7 @@ const EmojiToggle = styled.span`
...
@@ -140,7 +139,7 @@ const EmojiToggle = styled.span`
export
default
function
Menu
()
{
export
default
function
Menu
()
{
const
[
isDark
,
toggleDarkMode
]
=
useDarkModeManager
()
const
[
isDark
,
toggleDarkMode
]
=
useDarkModeManager
()
const
[
isAdvanced
,
toggleAdvanced
]
=
useState
()
const
[
isAdvanced
,
toggleAdvanced
]
=
useState
(
false
)
const
node
=
useRef
()
const
node
=
useRef
()
const
[
open
,
toggle
]
=
useToggle
(
false
)
const
[
open
,
toggle
]
=
useToggle
(
false
)
...
...
src/components/NumericalInput/index.tsx
View file @
4e2c5c1e
...
@@ -11,6 +11,8 @@ const StyledInput = styled.input`
...
@@ -11,6 +11,8 @@ const StyledInput = styled.input`
flex: 1 1 auto;
flex: 1 1 auto;
width: 0;
width: 0;
background-color:
${({
theme
})
=>
theme
.
inputBackground
}
;
background-color:
${({
theme
})
=>
theme
.
inputBackground
}
;
font-size:
${({
fontSize
})
=>
fontSize
&&
fontSize
}
;
text-align:
${({
align
})
=>
align
&&
align
}
;
[type='number'] {
[type='number'] {
-moz-appearance: textfield;
-moz-appearance: textfield;
...
@@ -32,10 +34,10 @@ function escapeRegExp(string: string): string {
...
@@ -32,10 +34,10 @@ function escapeRegExp(string: string): string {
return
string
.
replace
(
/
[
.*+?^${}()|[
\]\\]
/g
,
'
\\
$&
'
)
// $& means the whole matched string
return
string
.
replace
(
/
[
.*+?^${}()|[
\]\\]
/g
,
'
\\
$&
'
)
// $& means the whole matched string
}
}
export
const
Input
=
React
.
memo
(({
field
,
value
,
onUserInput
,
...
rest
}:
any
)
=>
{
export
const
Input
=
React
.
memo
(({
value
,
onUserInput
,
placeHolder
=
null
,
...
rest
}:
any
)
=>
{
function
enforcer
(
nextUserInput
:
string
)
{
function
enforcer
(
nextUserInput
:
string
)
{
if
(
nextUserInput
===
''
||
inputRegex
.
test
(
escapeRegExp
(
nextUserInput
)))
{
if
(
nextUserInput
===
''
||
inputRegex
.
test
(
escapeRegExp
(
nextUserInput
)))
{
onUserInput
(
field
,
nextUserInput
)
onUserInput
(
nextUserInput
)
}
}
}
}
...
@@ -53,7 +55,7 @@ export const Input = React.memo(({ field, value, onUserInput, ...rest }: any) =>
...
@@ -53,7 +55,7 @@ export const Input = React.memo(({ field, value, onUserInput, ...rest }: any) =>
autoCorrect=
"off"
autoCorrect=
"off"
// text-specific options
// text-specific options
type=
"text"
type=
"text"
placeholder=
"0.0"
placeholder=
{
placeHolder
||
'
0.0
'
}
minLength=
{
1
}
minLength=
{
1
}
maxLength=
{
79
}
maxLength=
{
79
}
spellCheck=
"false"
spellCheck=
"false"
...
...
src/components/PoolFinder/index.js
View file @
4e2c5c1e
...
@@ -16,7 +16,7 @@ import { Link } from '../../theme'
...
@@ -16,7 +16,7 @@ import { Link } from '../../theme'
import
{
Text
}
from
'
rebass
'
import
{
Text
}
from
'
rebass
'
import
{
Plus
}
from
'
react-feather
'
import
{
Plus
}
from
'
react-feather
'
import
{
LightCard
}
from
'
../Card
'
import
{
LightCard
}
from
'
../Card
'
import
{
AutoColumn
,
ColumnCenter
}
from
'
../Column
'
import
Column
,
{
AutoColumn
,
ColumnCenter
}
from
'
../Column
'
import
{
ButtonPrimary
,
ButtonDropwdown
,
ButtonDropwdownLight
}
from
'
../Button
'
import
{
ButtonPrimary
,
ButtonDropwdown
,
ButtonDropwdownLight
}
from
'
../Button
'
import
DoubleTokenLogo
from
'
../DoubleLogo
'
import
DoubleTokenLogo
from
'
../DoubleLogo
'
...
@@ -112,6 +112,13 @@ function PoolFinder({ history }) {
...
@@ -112,6 +112,13 @@ function PoolFinder({ history }) {
<
/Row
>
<
/Row
>
<
/ButtonDropwdownLight
>
<
/ButtonDropwdownLight
>
)}
)}
{
allowImport
&&
(
<
ColumnCenter
justify
=
"
center
"
style
=
{{
backgroundColor
:
'
#EBF4FF
'
,
padding
:
'
8px
'
,
borderRadius
:
'
12px
'
}}
>
<
Text
textAlign
=
"
center
"
fontWeight
=
{
500
}
color
=
"
#2172E5
"
>
Liquidity
Found
!
<
/Text
>
<
/ColumnCenter
>
)}
{
position
?
(
{
position
?
(
!
JSBI
.
equal
(
position
.
raw
,
JSBI
.
BigInt
(
0
))
?
(
!
JSBI
.
equal
(
position
.
raw
,
JSBI
.
BigInt
(
0
))
?
(
<
PositionCard
<
PositionCard
...
@@ -155,11 +162,7 @@ function PoolFinder({ history }) {
...
@@ -155,11 +162,7 @@ function PoolFinder({ history }) {
<
/Text
>
<
/Text
>
<
/LightCard
>
<
/LightCard
>
)}
)}
{
allowImport
&&
(
<
Text
textAlign
=
"
center
"
fontWeight
=
{
500
}
>
Liquidity
Found
!
<
/Text
>
)}
<
ButtonPrimary
disabled
=
{
!
allowImport
}
onClick
=
{
endSearch
}
>
<
ButtonPrimary
disabled
=
{
!
allowImport
}
onClick
=
{
endSearch
}
>
<
Text
fontWeight
=
{
500
}
fontSize
=
{
20
}
>
<
Text
fontWeight
=
{
500
}
fontSize
=
{
20
}
>
Import
Import
...
...
src/components/PositionCard/index.js
View file @
4e2c5c1e
...
@@ -61,11 +61,6 @@ function PositionCard({ exchangeAddress, token0, token1, history, minimal = fals
...
@@ -61,11 +61,6 @@ function PositionCard({ exchangeAddress, token0, token1, history, minimal = fals
return
(
return
(
<
DynamicCard
{...
rest
}
>
<
DynamicCard
{...
rest
}
>
<
AutoColumn
gap
=
"
20px
"
>
<
AutoColumn
gap
=
"
20px
"
>
<
FixedHeightRow
>
<
Text
fontWeight
=
{
500
}
fontSize
=
{
16
}
>
Current
Position
<
/Text
>
<
/FixedHeightRow
>
<
FixedHeightRow
>
<
FixedHeightRow
>
<
RowFixed
>
<
RowFixed
>
<
DoubleLogo
a0
=
{
token0
?.
address
||
''
}
a1
=
{
token1
?.
address
||
''
}
margin
=
{
true
}
size
=
{
24
}
/
>
<
DoubleLogo
a0
=
{
token0
?.
address
||
''
}
a1
=
{
token1
?.
address
||
''
}
margin
=
{
true
}
size
=
{
24
}
/
>
...
...
src/components/Row/index.js
View file @
4e2c5c1e
...
@@ -4,6 +4,7 @@ const Row = styled.div`
...
@@ -4,6 +4,7 @@ const Row = styled.div`
width: 100%;
width: 100%;
display: flex;
display: flex;
align-items: center;
align-items: center;
align-items:
${({
align
})
=>
align
&&
align
}
;
`
`
export
const
RowBetween
=
styled
(
Row
)
`
export
const
RowBetween
=
styled
(
Row
)
`
...
...
src/components/SearchModal/index.js
View file @
4e2c5c1e
...
@@ -411,6 +411,7 @@ function SearchModal({ history, isOpen, onDismiss, onTokenSelect, urlAddedTokens
...
@@ -411,6 +411,7 @@ function SearchModal({ history, isOpen, onDismiss, onTokenSelect, urlAddedTokens
/
>
/
>
<
RowBetween
>
<
RowBetween
>
<
div
>
<
div
>
{
filterType
!==
'
tokens
'
&&
(
<
Text
>
<
Text
>
Don
'
t see a pool?{
'
'
}
Don
'
t see a pool?{
'
'
}
<StyledLink
<StyledLink
...
@@ -421,6 +422,7 @@ function SearchModal({ history, isOpen, onDismiss, onTokenSelect, urlAddedTokens
...
@@ -421,6 +422,7 @@ function SearchModal({ history, isOpen, onDismiss, onTokenSelect, urlAddedTokens
Import it.
Import it.
</StyledLink>
</StyledLink>
</Text>
</Text>
)}
</div>
</div>
<div />
<div />
<Filter title="Your Balances" filter={FILTERS.BALANCES} />
<Filter title="Your Balances" filter={FILTERS.BALANCES} />
...
...
src/constants/index.ts
View file @
4e2c5c1e
...
@@ -19,13 +19,6 @@ export const SUPPORTED_THEMES = {
...
@@ -19,13 +19,6 @@ export const SUPPORTED_THEMES = {
LIGHT
:
'
LIGHT
'
LIGHT
:
'
LIGHT
'
}
}
export
enum
TRANSACTION_TYPE
{
SWAP
,
SEND
,
ADD
,
REMOVE
}
const
MAINNET_WALLETS
=
{
const
MAINNET_WALLETS
=
{
INJECTED
:
{
INJECTED
:
{
connector
:
injected
,
connector
:
injected
,
...
...
src/contexts/Exchanges.tsx
View file @
4e2c5c1e
...
@@ -9,14 +9,14 @@ import { ChainId, WETH, Token, TokenAmount, Exchange, JSBI } from '@uniswap/sdk'
...
@@ -9,14 +9,14 @@ import { ChainId, WETH, Token, TokenAmount, Exchange, JSBI } from '@uniswap/sdk'
const
UPDATE
=
'
UPDATE
'
const
UPDATE
=
'
UPDATE
'
const
ALL_EXCHANGES
:
[
Token
,
Token
][]
=
[
const
ALL_EXCHANGES
:
[
Token
,
Token
][]
=
[
//
[
[
//
INITIAL_TOKENS_CONTEXT[ChainId.RINKEBY][WETH[ChainId.RINKEBY].address],
INITIAL_TOKENS_CONTEXT
[
ChainId
.
RINKEBY
][
WETH
[
ChainId
.
RINKEBY
].
address
],
//
INITIAL_TOKENS_CONTEXT[ChainId.RINKEBY]['0xc7AD46e0b8a400Bb3C915120d284AafbA8fc4735']
INITIAL_TOKENS_CONTEXT
[
ChainId
.
RINKEBY
][
'
0xc7AD46e0b8a400Bb3C915120d284AafbA8fc4735
'
]
// ]
],
//
[
[
//
INITIAL_TOKENS_CONTEXT[ChainId.RINKEBY]['0xc7AD46e0b8a400Bb3C915120d284AafbA8fc4735'],
INITIAL_TOKENS_CONTEXT
[
ChainId
.
RINKEBY
][
'
0xc7AD46e0b8a400Bb3C915120d284AafbA8fc4735
'
],
//
INITIAL_TOKENS_CONTEXT[ChainId.RINKEBY]['0x8ab15C890E5C03B5F240f2D146e3DF54bEf3Df44']
INITIAL_TOKENS_CONTEXT
[
ChainId
.
RINKEBY
][
'
0x8ab15C890E5C03B5F240f2D146e3DF54bEf3Df44
'
]
//
]
]
]
]
const
EXCHANGE_MAP
:
{
const
EXCHANGE_MAP
:
{
...
...
src/pages/App.js
View file @
4e2c5c1e
...
@@ -27,11 +27,6 @@ const HeaderWrapper = styled.div`
...
@@ -27,11 +27,6 @@ const HeaderWrapper = styled.div`
width: 100%;
width: 100%;
justify-content: space-between;
justify-content: space-between;
`
`
const
FooterWrapper
=
styled
.
div
`
width: 100%;
min-height: 30px;
align-self: flex-end;
`
const
BodyWrapper
=
styled
.
div
`
const
BodyWrapper
=
styled
.
div
`
display: flex;
display: flex;
...
@@ -50,7 +45,7 @@ const Body = styled.div`
...
@@ -50,7 +45,7 @@ const Body = styled.div`
box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.01), 0px 4px 8px rgba(0, 0, 0, 0.04), 0px 16px 24px rgba(0, 0, 0, 0.04),
box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.01), 0px 4px 8px rgba(0, 0, 0, 0.04), 0px 16px 24px rgba(0, 0, 0, 0.04),
0px 24px 32px rgba(0, 0, 0, 0.01);
0px 24px 32px rgba(0, 0, 0, 0.01);
border-radius: 20px;
border-radius: 20px;
padding: 2rem 2rem;
padding: 2rem 2rem
1rem 2rem
;
`
`
export
default
function
App
()
{
export
default
function
App
()
{
...
...
src/pages/Supply/AddLiquidity.tsx
View file @
4e2c5c1e
...
@@ -5,26 +5,27 @@ import { parseUnits, parseEther } from '@ethersproject/units'
...
@@ -5,26 +5,27 @@ import { parseUnits, parseEther } from '@ethersproject/units'
import
{
WETH
,
TokenAmount
,
JSBI
,
Percent
,
Route
}
from
'
@uniswap/sdk
'
import
{
WETH
,
TokenAmount
,
JSBI
,
Percent
,
Route
}
from
'
@uniswap/sdk
'
import
DoubleLogo
from
'
../../components/DoubleLogo
'
import
DoubleLogo
from
'
../../components/DoubleLogo
'
import
TokenLogo
from
'
../../components/TokenLogo
'
import
SearchModal
from
'
../../components/SearchModal
'
import
SearchModal
from
'
../../components/SearchModal
'
import
PositionCard
from
'
../../components/PositionCard
'
import
PositionCard
from
'
../../components/PositionCard
'
import
ConfirmationModal
from
'
../../components/ConfirmationModal
'
import
ConfirmationModal
from
'
../../components/ConfirmationModal
'
import
CurrencyInputPanel
from
'
../../components/CurrencyInputPanel
'
import
CurrencyInputPanel
from
'
../../components/CurrencyInputPanel
'
import
{
Text
}
from
'
rebass
'
import
{
Text
}
from
'
rebass
'
import
{
Plus
}
from
'
react-feather
'
import
{
Plus
}
from
'
react-feather
'
import
{
RowBetween
}
from
'
../../components/Row
'
import
{
ButtonPrimary
}
from
'
../../components/Button
'
import
{
ChevronDown
}
from
'
react-feather
'
import
{
AutoColumn
,
ColumnCenter
}
from
'
../../components/Column
'
import
{
AutoColumn
,
ColumnCenter
}
from
'
../../components/Column
'
import
{
ButtonPrimary
,
ButtonEmpty
}
from
'
../../components/Button
'
import
Row
,
{
RowBetween
,
RowFlat
,
RowFixed
}
from
'
../../components/Row
'
import
{
useToken
}
from
'
../../contexts/Tokens
'
import
{
useToken
}
from
'
../../contexts/Tokens
'
import
{
useWeb3React
}
from
'
../../hooks
'
import
{
useWeb3React
}
from
'
../../hooks
'
import
{
usePopups
}
from
'
../../contexts/Application
'
import
{
useAddressBalance
}
from
'
../../contexts/Balances
'
import
{
useAddressBalance
}
from
'
../../contexts/Balances
'
import
{
useAddressAllowance
}
from
'
../../contexts/Allowances
'
import
{
useAddressAllowance
}
from
'
../../contexts/Allowances
'
import
{
useTransactionAdder
}
from
'
../../contexts/Transactions
'
import
{
useTransactionAdder
}
from
'
../../contexts/Transactions
'
import
{
useExchange
,
useTotalSupply
}
from
'
../../contexts/Exchanges
'
import
{
useExchange
,
useTotalSupply
}
from
'
../../contexts/Exchanges
'
import
{
BigNumber
}
from
'
ethers/utils
'
import
{
BigNumber
}
from
'
ethers/utils
'
import
{
TRANSACTION_TYPE
,
ROUTER_ADDRESSES
}
from
'
../../constants
'
import
{
ROUTER_ADDRESSES
}
from
'
../../constants
'
import
{
getRouterContract
,
calculateGasMargin
}
from
'
../../utils
'
import
{
getRouterContract
,
calculateGasMargin
}
from
'
../../utils
'
// denominated in bips
// denominated in bips
...
@@ -41,7 +42,7 @@ const Wrapper = styled.div`
...
@@ -41,7 +42,7 @@ const Wrapper = styled.div`
const
FixedBottom
=
styled
.
div
`
const
FixedBottom
=
styled
.
div
`
position: absolute;
position: absolute;
bottom: -2
4
0px;
bottom: -2
0
0px;
width: 100%;
width: 100%;
`
`
...
@@ -145,6 +146,7 @@ export default function AddLiquidity({ token0, token1 }) {
...
@@ -145,6 +146,7 @@ export default function AddLiquidity({ token0, token1 }) {
// modal states
// modal states
const
[
showSearch
,
setShowSearch
]
=
useState
<
boolean
>
(
false
)
const
[
showSearch
,
setShowSearch
]
=
useState
<
boolean
>
(
false
)
const
[
showConfirm
,
setShowConfirm
]
=
useState
<
boolean
>
(
false
)
const
[
showConfirm
,
setShowConfirm
]
=
useState
<
boolean
>
(
false
)
const
[
attemptingTxn
,
setAttemptingTxn
]
=
useState
<
boolean
>
(
false
)
// clicke confirm
const
[
pendingConfirmation
,
setPendingConfirmation
]
=
useState
<
boolean
>
(
true
)
const
[
pendingConfirmation
,
setPendingConfirmation
]
=
useState
<
boolean
>
(
true
)
// input state
// input state
...
@@ -369,7 +371,10 @@ export default function AddLiquidity({ token0, token1 }) {
...
@@ -369,7 +371,10 @@ export default function AddLiquidity({ token0, token1 }) {
return
null
return
null
}
}
const
[,
addPopup
]
=
usePopups
()
async
function
onAdd
()
{
async
function
onAdd
()
{
setAttemptingTxn
(
true
)
const
router
=
getRouterContract
(
chainId
,
library
,
account
)
const
router
=
getRouterContract
(
chainId
,
library
,
account
)
const
minTokenInput
=
calculateSlippageAmount
(
parsedAmounts
[
Field
.
INPUT
])[
0
]
const
minTokenInput
=
calculateSlippageAmount
(
parsedAmounts
[
Field
.
INPUT
])[
0
]
...
@@ -428,26 +433,112 @@ export default function AddLiquidity({ token0, token1 }) {
...
@@ -428,26 +433,112 @@ export default function AddLiquidity({ token0, token1 }) {
})
})
.
catch
((
e
:
Error
)
=>
{
.
catch
((
e
:
Error
)
=>
{
console
.
log
(
e
)
console
.
log
(
e
)
addPopup
(
<
AutoColumn
gap=
"10px"
>
<
Text
>
Transaction Failed: try again.
</
Text
>
</
AutoColumn
>
)
setPendingConfirmation
(
true
)
setAttemptingTxn
(
false
)
setShowConfirm
(
false
)
setShowConfirm
(
false
)
})
})
}
}
const
modalHeader
=
()
=>
{
return
(
<
AutoColumn
gap=
"20px"
>
<
RowFlat
style=
{
{
marginTop
:
'
60px
'
}
}
>
<
Text
fontSize=
"48px"
fontWeight=
{
500
}
lineHeight=
"32px"
marginRight=
{
10
}
>
{
liquidityMinted
?.
toFixed
(
6
)
}
</
Text
>
<
DoubleLogo
a0=
{
tokens
[
Field
.
INPUT
]?.
symbol
||
''
}
a1=
{
tokens
[
Field
.
OUTPUT
]?.
symbol
||
''
}
size=
{
30
}
/>
</
RowFlat
>
<
Row
>
<
Text
fontSize=
"24px"
>
{
tokens
[
Field
.
INPUT
]?.
symbol
+
'
:
'
+
tokens
[
Field
.
OUTPUT
]?.
symbol
+
'
Pool Tokens
'
}
</
Text
>
</
Row
>
</
AutoColumn
>
)
}
const
modalBottom
=
()
=>
{
return
(
<>
<
RowBetween
>
<
Text
color=
"#565A69"
fontWeight=
{
500
}
fontSize=
{
16
}
>
{
tokens
[
Field
.
INPUT
]?.
symbol
}
Deposited
</
Text
>
<
RowFixed
>
<
TokenLogo
address=
{
tokens
[
Field
.
INPUT
]?.
address
||
''
}
style=
{
{
marginRight
:
'
8px
'
}
}
/>
<
Text
fontWeight=
{
500
}
fontSize=
{
16
}
>
{
!!
parsedAmounts
[
Field
.
INPUT
]
&&
parsedAmounts
[
Field
.
INPUT
].
toSignificant
(
6
)
}
</
Text
>
</
RowFixed
>
</
RowBetween
>
<
RowBetween
>
<
Text
color=
"#565A69"
fontWeight=
{
500
}
fontSize=
{
16
}
>
{
tokens
[
Field
.
OUTPUT
]?.
symbol
}
Deposited
</
Text
>
<
RowFixed
>
<
TokenLogo
address=
{
tokens
[
Field
.
OUTPUT
]?.
address
||
''
}
style=
{
{
marginRight
:
'
8px
'
}
}
/>
<
Text
fontWeight=
{
500
}
fontSize=
{
16
}
>
{
!!
parsedAmounts
[
Field
.
OUTPUT
]
&&
parsedAmounts
[
Field
.
OUTPUT
].
toSignificant
(
6
)
}
</
Text
>
</
RowFixed
>
</
RowBetween
>
<
RowBetween
>
<
Text
color=
"#565A69"
fontWeight=
{
500
}
fontSize=
{
16
}
>
Rate
</
Text
>
<
Text
fontWeight=
{
500
}
fontSize=
{
16
}
>
{
`1 ${tokens[Field.INPUT]?.symbol} = ${route?.midPrice &&
route?.midPrice?.raw?.denominator &&
route.midPrice.adjusted.toFixed(8)} ${tokens[Field.OUTPUT]?.symbol}`
}
</
Text
>
</
RowBetween
>
<
RowBetween
>
<
Text
color=
"#565A69"
fontWeight=
{
500
}
fontSize=
{
16
}
>
Minted Pool Share:
</
Text
>
<
Text
fontWeight=
{
500
}
fontSize=
{
16
}
>
{
poolTokenPercentage
?.
toFixed
(
6
)
+
'
%
'
}
</
Text
>
</
RowBetween
>
<
ButtonPrimary
style=
{
{
margin
:
'
20px 0
'
}
}
onClick=
{
onAdd
}
>
<
Text
fontWeight=
{
500
}
fontSize=
{
20
}
>
Confirm Supply
</
Text
>
</
ButtonPrimary
>
<
Text
fontSize=
{
12
}
color=
"#565A69"
textAlign=
"center"
>
{
`Output is estimated. You will receive at least ${liquidityMinted?.toFixed(6)} UNI ${
tokens[Field.INPUT]?.symbol
}/${tokens[Field.OUTPUT]?.symbol} or the transaction will revert.`
}
</
Text
>
</>
)
}
const
pendingText
=
`Supplied
${
parsedAmounts
[
Field
.
INPUT
]?.
toSignificant
(
6
)}
$
{
tokens
[
Field
.
INPUT
]?.
symbol
}
$
{
'
and
'
}
$
{
parsedAmounts
[
Field
.
OUTPUT
]?.
toSignificant
(
6
)}
$
{
tokens
[
Field
.
OUTPUT
]?.
symbol
}
`
return (
return (
<Wrapper>
<Wrapper>
<ConfirmationModal
<ConfirmationModal
isOpen={showConfirm}
isOpen={showConfirm}
onDismiss={() => {
onDismiss={() => {
setPendingConfirmation(true)
setAttemptingTxn(false)
setShowConfirm(false)
setShowConfirm(false)
}}
}}
liquidityAmount=
{
liquidityMinted
}
attemptingTxn={attemptingTxn}
amount0=
{
parsedAmounts
[
Field
.
INPUT
]
}
amount1=
{
parsedAmounts
[
Field
.
OUTPUT
]
}
poolTokenPercentage=
{
poolTokenPercentage
}
price=
{
route
?.
midPrice
&&
route
?.
midPrice
?.
raw
?.
denominator
}
transactionType=
{
TRANSACTION_TYPE
.
ADD
}
contractCall=
{
onAdd
}
pendingConfirmation={pendingConfirmation}
pendingConfirmation={pendingConfirmation}
hash={txHash ? txHash : ''}
hash={txHash ? txHash : ''}
topContent={() => modalHeader()}
bottomContent={modalBottom}
pendingText={pendingText}
title="You will receive"
/>
/>
<SearchModal
<SearchModal
isOpen={showSearch}
isOpen={showSearch}
...
@@ -456,22 +547,6 @@ export default function AddLiquidity({ token0, token1 }) {
...
@@ -456,22 +547,6 @@ export default function AddLiquidity({ token0, token1 }) {
}}
}}
/>
/>
<AutoColumn gap="20px">
<AutoColumn gap="20px">
<
ButtonEmpty
padding=
{
'
1rem
'
}
onClick=
{
()
=>
{
setShowSearch
(
true
)
}
}
>
<
RowBetween
>
<
DoubleLogo
a0=
{
exchange
?.
token0
?.
address
||
''
}
a1=
{
exchange
?.
token1
?.
address
||
''
}
size=
{
24
}
/>
<
Text
fontSize=
{
20
}
>
{
exchange
?.
token0
&&
exchange
?.
token1
?
exchange
.
token0
.
symbol
+
'
/
'
+
exchange
.
token1
.
symbol
+
'
Pool
'
:
''
}
</
Text
>
<
ChevronDown
size=
{
24
}
/>
</
RowBetween
>
</
ButtonEmpty
>
{noLiquidity && (
{noLiquidity && (
<ColumnCenter>
<ColumnCenter>
<Text fontWeight={500} style={{ textAlign: 'center' }}>
<Text fontWeight={500} style={{ textAlign: 'center' }}>
...
...
src/pages/Supply/RemoveLiquidity.tsx
View file @
4e2c5c1e
...
@@ -6,15 +6,17 @@ import { TokenAmount, JSBI, Route, WETH, Percent } from '@uniswap/sdk'
...
@@ -6,15 +6,17 @@ import { TokenAmount, JSBI, Route, WETH, Percent } from '@uniswap/sdk'
import
Slider
from
'
../../components/Slider
'
import
Slider
from
'
../../components/Slider
'
import
TokenLogo
from
'
../../components/TokenLogo
'
import
TokenLogo
from
'
../../components/TokenLogo
'
import
DoubleLogo
from
'
../../components/DoubleLogo
'
import
PositionCard
from
'
../../components/PositionCard
'
import
PositionCard
from
'
../../components/PositionCard
'
import
ConfirmationModal
from
'
../../components/ConfirmationModal
'
import
ConfirmationModal
from
'
../../components/ConfirmationModal
'
import
CurrencyInputPanel
from
'
../../components/CurrencyInputPanel
'
import
CurrencyInputPanel
from
'
../../components/CurrencyInputPanel
'
import
{
Text
}
from
'
rebass
'
import
{
Text
}
from
'
rebass
'
import
{
LightCard
}
from
'
../../components/Card
'
import
{
LightCard
}
from
'
../../components/Card
'
import
{
ButtonPrimary
}
from
'
../../components/Button
'
import
{
ButtonPrimary
}
from
'
../../components/Button
'
import
{
ButtonConfirmed
}
from
'
../../components/Button
'
import
{
ArrowDown
,
Plus
}
from
'
react-feather
'
import
{
ArrowDown
,
Plus
}
from
'
react-feather
'
import
{
RowBetween
,
RowFixed
}
from
'
../../components/Row
'
import
{
AutoColumn
,
ColumnCenter
}
from
'
../../components/Column
'
import
{
AutoColumn
,
ColumnCenter
}
from
'
../../components/Column
'
import
Row
,
{
RowBetween
,
RowFixed
}
from
'
../../components/Row
'
import
{
useToken
}
from
'
../../contexts/Tokens
'
import
{
useToken
}
from
'
../../contexts/Tokens
'
import
{
useWeb3React
}
from
'
../../hooks
'
import
{
useWeb3React
}
from
'
../../hooks
'
...
@@ -25,7 +27,6 @@ import { useExchange, useTotalSupply } from '../../contexts/Exchanges'
...
@@ -25,7 +27,6 @@ import { useExchange, useTotalSupply } from '../../contexts/Exchanges'
import
{
BigNumber
}
from
'
ethers/utils
'
import
{
BigNumber
}
from
'
ethers/utils
'
import
{
splitSignature
}
from
'
@ethersproject/bytes
'
import
{
splitSignature
}
from
'
@ethersproject/bytes
'
import
{
TRANSACTION_TYPE
}
from
'
../../constants
'
import
{
ROUTER_ADDRESSES
}
from
'
../../constants
'
import
{
ROUTER_ADDRESSES
}
from
'
../../constants
'
import
{
getRouterContract
,
calculateGasMargin
}
from
'
../../utils
'
import
{
getRouterContract
,
calculateGasMargin
}
from
'
../../utils
'
...
@@ -138,6 +139,10 @@ function reducer(
...
@@ -138,6 +139,10 @@ function reducer(
}
}
}
}
const
ConfirmedText
=
styled
(
Text
)
`
color:
${({
theme
,
confirmed
})
=>
(
confirmed
?
theme
.
connectedGreen
:
theme
.
white
)}
;
`
export
default
function
RemoveLiquidity
({
token0
,
token1
})
{
export
default
function
RemoveLiquidity
({
token0
,
token1
})
{
const
{
account
,
chainId
,
library
}
=
useWeb3React
()
const
{
account
,
chainId
,
library
}
=
useWeb3React
()
const
routerAddress
=
ROUTER_ADDRESSES
[
chainId
]
const
routerAddress
=
ROUTER_ADDRESSES
[
chainId
]
...
@@ -302,19 +307,19 @@ export default function RemoveLiquidity({ token0, token1 }) {
...
@@ -302,19 +307,19 @@ export default function RemoveLiquidity({ token0, token1 }) {
:
false
:
false
// errors
// errors
const
[
generalError
,
setGeneralError
]
=
useState
()
const
[
generalError
,
setGeneralError
]
=
useState
(
''
)
const
[
inputError
,
setInputError
]
=
useState
()
const
[
inputError
,
setInputError
]
=
useState
(
''
)
const
[
outputError
,
setOutputError
]
=
useState
()
const
[
outputError
,
setOutputError
]
=
useState
(
''
)
const
[
poolTokenError
,
setPoolTokenError
]
=
useState
()
const
[
poolTokenError
,
setPoolTokenError
]
=
useState
(
''
)
const
[
isValid
,
setIsValid
]
=
useState
(
false
)
const
[
isValid
,
setIsValid
]
=
useState
(
false
)
// update errors live
// update errors live
useEffect
(()
=>
{
useEffect
(()
=>
{
// reset errors
// reset errors
setGeneralError
(
null
)
setGeneralError
(
''
)
setInputError
(
null
)
setInputError
(
''
)
setOutputError
(
null
)
setOutputError
(
''
)
setPoolTokenError
(
null
)
setPoolTokenError
(
''
)
setIsValid
(
true
)
setIsValid
(
true
)
if
(
formattedAmounts
[
Field
.
TOKEN0
]
===
''
)
{
if
(
formattedAmounts
[
Field
.
TOKEN0
]
===
''
)
{
...
@@ -480,28 +485,103 @@ export default function RemoveLiquidity({ token0, token1 }) {
...
@@ -480,28 +485,103 @@ export default function RemoveLiquidity({ token0, token1 }) {
setPendingConfirmation
(
true
)
setPendingConfirmation
(
true
)
}
}
function
modalHeader
()
{
return
(
<
AutoColumn
gap=
"16px"
>
<
Row
style=
{
{
marginTop
:
'
40px
'
}
}
>
<
TokenLogo
address=
{
tokens
[
Field
.
TOKEN0
]?.
symbol
}
size=
{
'
30px
'
}
/>
<
Text
fontSize=
"24px"
marginLeft=
{
10
}
>
{
tokens
[
Field
.
TOKEN0
]?.
symbol
}{
'
'
}
{
!!
parsedAmounts
[
Field
.
TOKEN0
]
&&
parsedAmounts
[
Field
.
TOKEN0
].
toSignificant
(
8
)
}
</
Text
>
</
Row
>
<
Row
>
<
TokenLogo
address=
{
tokens
[
Field
.
TOKEN1
]?.
symbol
}
size=
{
'
30px
'
}
/>
<
Text
fontSize=
"24px"
marginLeft=
{
10
}
>
{
tokens
[
Field
.
TOKEN1
]?.
symbol
}{
'
'
}
{
!!
parsedAmounts
[
Field
.
TOKEN1
]
&&
parsedAmounts
[
Field
.
TOKEN1
].
toSignificant
(
8
)
}
</
Text
>
</
Row
>
</
AutoColumn
>
)
}
function
modalBottom
()
{
return
(
<>
<
RowBetween
>
<
Text
color=
"#565A69"
fontWeight=
{
500
}
fontSize=
{
16
}
>
{
'
UNI
'
+
tokens
[
Field
.
TOKEN0
]?.
symbol
+
'
:
'
+
tokens
[
Field
.
TOKEN1
]?.
symbol
}
Burned
</
Text
>
<
RowFixed
>
<
DoubleLogo
a0=
{
tokens
[
Field
.
TOKEN0
]?.
address
||
''
}
a1=
{
tokens
[
Field
.
TOKEN1
]?.
address
||
''
}
margin=
{
true
}
/>
<
Text
fontWeight=
{
500
}
fontSize=
{
16
}
>
{
parsedAmounts
[
Field
.
LIQUIDITY
]?.
toSignificant
(
6
)
}
</
Text
>
</
RowFixed
>
</
RowBetween
>
<
RowBetween
>
<
Text
color=
"#565A69"
fontWeight=
{
500
}
fontSize=
{
16
}
>
Rate
</
Text
>
<
Text
fontWeight=
{
500
}
fontSize=
{
16
}
>
{
`1 ${tokens[Field.TOKEN0]?.symbol} = ${route?.midPrice && route.midPrice.adjusted.toFixed(8)} ${
tokens[Field.TOKEN1]?.symbol
}`
}
</
Text
>
</
RowBetween
>
<
RowBetween
gap=
"20px"
>
<
ButtonConfirmed
style=
{
{
margin
:
'
20px 0
'
}
}
width=
"48%"
onClick=
{
onSign
}
confirmed=
{
signed
}
disabled=
{
signed
}
>
<
ConfirmedText
fontWeight=
{
500
}
fontSize=
{
20
}
confirmed=
{
signed
}
>
{
signed
?
'
Signed
'
:
'
Sign
'
}
</
ConfirmedText
>
</
ButtonConfirmed
>
<
ButtonPrimary
width=
"48%"
disabled=
{
!
signed
}
style=
{
{
margin
:
'
20px 0
'
}
}
onClick=
{
onRemove
}
>
<
Text
fontWeight=
{
500
}
fontSize=
{
20
}
>
Confirm Remove
</
Text
>
</
ButtonPrimary
>
</
RowBetween
>
<
Text
fontSize=
{
12
}
color=
"#565A69"
textAlign=
"center"
>
{
`Output is estimated. You will receive at least ${parsedAmounts[Field.TOKEN0]?.toFixed(6)} ${
tokens[Field.TOKEN0]?.symbol
} and at least ${parsedAmounts[Field.TOKEN1]?.toFixed(6)} ${
tokens[Field.TOKEN1]?.symbol
} or the transaction will revert.`
}
</
Text
>
</>
)
}
const
pendingText
=
`Removed
${
parsedAmounts
[
Field
.
TOKEN0
]?.
toSignificant
(
6
)}
$
{
tokens
[
Field
.
TOKEN0
]?.
symbol
}
and
$
{
parsedAmounts
[
Field
.
TOKEN1
]?.
toSignificant
(
6
)}
$
{
tokens
[
Field
.
TOKEN1
]?.
symbol
}
`
return (
return (
<Wrapper>
<Wrapper>
{
!!
parsedAmounts
[
Field
.
TOKEN0
]
&&
!!
parsedAmounts
[
Field
.
TOKEN1
]
&&
!!
parsedAmounts
[
Field
.
LIQUIDITY
]
&&
(
<ConfirmationModal
<ConfirmationModal
isOpen={showConfirm}
isOpen={showConfirm}
onDismiss={() => {
onDismiss={() => {
resetModalState()
resetModalState()
setShowConfirm(false)
setShowConfirm(false)
}}
}}
amount0=
{
parsedAmounts
[
Field
.
TOKEN0
]
}
attemptingTxn={attemptedRemoval}
amount1=
{
parsedAmounts
[
Field
.
TOKEN1
]
}
price=
{
route
?.
midPrice
}
liquidityAmount=
{
parsedAmounts
[
Field
.
LIQUIDITY
]
}
transactionType=
{
TRANSACTION_TYPE
.
REMOVE
}
contractCall=
{
onRemove
}
extraCall=
{
onSign
}
signed=
{
signed
}
attemptedRemoval=
{
attemptedRemoval
}
pendingConfirmation={pendingConfirmation}
pendingConfirmation={pendingConfirmation}
hash={txHash ? txHash : ''}
hash={txHash ? txHash : ''}
topContent={modalHeader}
bottomContent={modalBottom}
pendingText={pendingText}
title="You will remove"
/>
/>
)
}
<AutoColumn gap="20px">
<AutoColumn gap="20px">
<LightCard>
<LightCard>
<AutoColumn gap="20px">
<AutoColumn gap="20px">
...
...
src/pages/Supply/index.js
View file @
4e2c5c1e
...
@@ -3,22 +3,22 @@ import styled from 'styled-components'
...
@@ -3,22 +3,22 @@ import styled from 'styled-components'
import
{
JSBI
}
from
'
@uniswap/sdk
'
import
{
JSBI
}
from
'
@uniswap/sdk
'
import
{
withRouter
}
from
'
react-router-dom
'
import
{
withRouter
}
from
'
react-router-dom
'
import
{
useWeb3React
}
from
'
@web3-react/core
'
import
Card
from
'
../../components/Card
'
import
{
useAllTokens
}
from
'
../../contexts/Tokens
'
import
{
useAllExchanges
}
from
'
../../contexts/Exchanges
'
import
{
useAllBalances
,
useAccountLPBalances
}
from
'
../../contexts/Balances
'
import
Question
from
'
../../components/Question
'
import
Question
from
'
../../components/Question
'
import
SearchModal
from
'
../../components/SearchModal
'
import
SearchModal
from
'
../../components/SearchModal
'
import
PositionCard
from
'
../../components/PositionCard
'
import
PositionCard
from
'
../../components/PositionCard
'
import
Row
,
{
RowBetween
}
from
'
../../components/Row
'
import
Row
,
{
RowBetween
}
from
'
../../components/Row
'
import
Card
,
{
LightCard
}
from
'
../../components/Card
'
import
{
Link
}
from
'
../../theme
'
import
{
Link
}
from
'
../../theme
'
import
{
Text
}
from
'
rebass
'
import
{
Text
}
from
'
rebass
'
import
{
AutoColumn
}
from
'
../../components/Column
'
import
{
AutoColumn
}
from
'
../../components/Column
'
import
{
ArrowRight
}
from
'
react-feather
'
import
{
ArrowRight
}
from
'
react-feather
'
import
{
ButtonPrimary
}
from
'
../../components/Button
'
import
{
ButtonPrimary
}
from
'
../../components/Button
'
import
{
useWeb3React
}
from
'
@web3-react/core
'
import
{
useAllTokens
}
from
'
../../contexts/Tokens
'
import
{
useAllExchanges
}
from
'
../../contexts/Exchanges
'
import
{
useAllBalances
,
useAccountLPBalances
}
from
'
../../contexts/Balances
'
const
Positions
=
styled
.
div
`
const
Positions
=
styled
.
div
`
position: relative;
position: relative;
margin-top: 38px;
margin-top: 38px;
...
@@ -71,19 +71,16 @@ function Supply({ history }) {
...
@@ -71,19 +71,16 @@ function Supply({ history }) {
<
/ButtonPrimary
>
<
/ButtonPrimary
>
<
Positions
>
<
Positions
>
<
AutoColumn
gap
=
"
20px
"
>
<
AutoColumn
gap
=
"
20px
"
>
{
filteredExchangeList
?.
length
!==
0
&&
(
<
RowBetween
>
<
RowBetween
>
<
Text
fontWeight
=
{
500
}
>
Your
Pooled
Liquidity
<
/Text
>
<
Text
fontWeight
=
{
500
}
>
Your
Pooled
Liquidity
<
/Text
>
<
Question
text
=
"
filler text
"
/>
<
Question
text
=
"
filler text
"
/>
<
/RowBetween
>
<
/RowBetween
>
{
filteredExchangeList
}
{
filteredExchangeList
?.
length
===
0
&&
(
<
LightCard
bg
=
"
rgba(255, 255, 255, 0.6)
"
padding
=
{
'
45px
'
}
>
<
Text
color
=
"
#C3C5CB
"
>
Add
liquidity
to
see
your
positions
<
/Text
>
<
/LightCard
>
)}
)}
{
filteredExchangeList
}
<
AutoColumn
justify
=
"
center
"
>
<
AutoColumn
justify
=
"
center
"
>
<
Text
color
=
"
#AEAEAE
"
>
<
Text
color
=
"
#AEAEAE
"
>
Already
have
liquidity
?{
'
'
}
{
filteredExchangeList
?.
length
!==
0
?
`Don't see your `
:
'
Already have
'
}
liquidity
?{
'
'
}
<
Link
<
Link
onClick
=
{()
=>
{
onClick
=
{()
=>
{
history
.
push
(
'
/find
'
)
history
.
push
(
'
/find
'
)
...
...
src/theme/components.js
View file @
4e2c5c1e
...
@@ -45,6 +45,7 @@ export const Link = styled.a.attrs({
...
@@ -45,6 +45,7 @@ export const Link = styled.a.attrs({
text-decoration: none;
text-decoration: none;
cursor: pointer;
cursor: pointer;
color:
${({
theme
})
=>
theme
.
royalBlue
}
;
color:
${({
theme
})
=>
theme
.
royalBlue
}
;
font-weight: 500;
:focus {
:focus {
outline: none;
outline: none;
...
...
src/theme/index.js
View file @
4e2c5c1e
...
@@ -3,6 +3,7 @@ import { ThemeProvider as StyledComponentsThemeProvider, createGlobalStyle, css
...
@@ -3,6 +3,7 @@ import { ThemeProvider as StyledComponentsThemeProvider, createGlobalStyle, css
import
{
getQueryParam
,
checkSupportedTheme
}
from
'
../utils
'
import
{
getQueryParam
,
checkSupportedTheme
}
from
'
../utils
'
import
{
SUPPORTED_THEMES
}
from
'
../constants
'
import
{
SUPPORTED_THEMES
}
from
'
../constants
'
import
{
useDarkModeManager
}
from
'
../contexts/LocalStorage
'
import
{
useDarkModeManager
}
from
'
../contexts/LocalStorage
'
import
{
Text
}
from
'
rebass
'
export
*
from
'
./components
'
export
*
from
'
./components
'
...
@@ -117,6 +118,19 @@ const theme = darkMode => ({
...
@@ -117,6 +118,19 @@ const theme = darkMode => ({
`
`
})
})
export
const
TYPE
=
{
main
:
({
children
,
...
rest
})
=>
(
<
Text
fontWeight
=
{
500
}
color
=
{
theme
().
mineshaftGray
}
{...
rest
}
>
{
children
}
<
/Text
>
),
blue
:
({
children
,
...
rest
})
=>
(
<
Text
fontWeight
=
{
500
}
color
=
{
theme
().
royalBlue
}
{...
rest
}
>
{
children
}
<
/Text
>
)
}
export
const
GlobalStyle
=
createGlobalStyle
`
export
const
GlobalStyle
=
createGlobalStyle
`
@import url('https://rsms.me/inter/inter.css');
@import url('https://rsms.me/inter/inter.css');
html { font-family: 'Inter', sans-serif; }
html { font-family: 'Inter', sans-serif; }
...
...
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