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
8404c607
Unverified
Commit
8404c607
authored
Feb 10, 2022
by
Zach Pomerantz
Committed by
GitHub
Feb 10, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: confirm price impact (#3288)
* refactor: action button naming * feat: high price impact acknowledgement
parent
b4aac94c
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
52 additions
and
47 deletions
+52
-47
ActionButton.tsx
src/lib/components/ActionButton.tsx
+16
-24
ErrorBoundary.tsx
src/lib/components/Error/ErrorBoundary.tsx
+1
-1
ErrorDialog.tsx
src/lib/components/Error/ErrorDialog.tsx
+3
-3
StatusDialog.tsx
src/lib/components/Swap/Status/StatusDialog.tsx
+1
-1
index.tsx
src/lib/components/Swap/Summary/index.tsx
+26
-15
SwapButton.tsx
src/lib/components/Swap/SwapButton.tsx
+3
-3
index.tsx
src/lib/icons/index.tsx
+2
-0
No files found.
src/lib/components/ActionButton.tsx
View file @
8404c607
...
@@ -15,7 +15,7 @@ const StyledButton = styled(Button)`
...
@@ -15,7 +15,7 @@ const StyledButton = styled(Button)`
}
}
`
`
const
Update
Row
=
styled
(
Row
)
``
const
Action
Row
=
styled
(
Row
)
``
const
grow
=
keyframes
`
const
grow
=
keyframes
`
from {
from {
...
@@ -28,12 +28,12 @@ const grow = keyframes`
...
@@ -28,12 +28,12 @@ const grow = keyframes`
}
}
`
`
const
update
Css
=
css
`
const
action
Css
=
css
`
border: 1px solid
${({
theme
})
=>
theme
.
outline
}
;
border: 1px solid
${({
theme
})
=>
theme
.
outline
}
;
padding: calc(0.25em - 1px);
padding: calc(0.25em - 1px);
padding-left: calc(0.75em - 1px);
padding-left: calc(0.75em - 1px);
${
Update
Row
}
{
${
Action
Row
}
{
animation:
${
grow
}
0.25s ease-in;
animation:
${
grow
}
0.25s ease-in;
white-space: nowrap;
white-space: nowrap;
}
}
...
@@ -45,45 +45,37 @@ const updateCss = css`
...
@@ -45,45 +45,37 @@ const updateCss = css`
}
}
`
`
export
const
Overlay
=
styled
(
Row
)
<
{
update
?:
boolean
}
>
`
export
const
Overlay
=
styled
(
Row
)
<
{
action
?:
boolean
}
>
`
border-radius:
${({
theme
})
=>
theme
.
borderRadius
}
em;
border-radius:
${({
theme
})
=>
theme
.
borderRadius
}
em;
flex-direction: row-reverse;
flex-direction: row-reverse;
min-height: 3.5em;
min-height: 3.5em;
transition: padding 0.25s ease-out;
transition: padding 0.25s ease-out;
${({
update
})
=>
update
&&
update
Css
}
${({
action
})
=>
action
&&
action
Css
}
`
`
export
interface
ActionButtonProps
{
export
interface
ActionButtonProps
{
color
?:
Color
color
?:
Color
disabled
?:
boolean
disabled
?:
boolean
update
?:
{
message
:
ReactNode
;
action
:
ReactNode
;
icon
?:
Icon
}
action
?:
{
message
:
ReactNode
;
icon
?:
Icon
;
onClick
:
()
=>
void
;
children
:
ReactNode
}
onClick
:
()
=>
void
onClick
:
()
=>
void
onUpdate
?:
()
=>
void
children
:
ReactNode
children
:
ReactNode
}
}
export
default
function
ActionButton
({
export
default
function
ActionButton
({
color
=
'
accent
'
,
disabled
,
action
,
onClick
,
children
}:
ActionButtonProps
)
{
color
=
'
accent
'
,
disabled
,
update
,
onClick
,
onUpdate
,
children
,
}:
ActionButtonProps
)
{
const
textColor
=
useMemo
(()
=>
(
color
===
'
accent
'
&&
!
disabled
?
'
onAccent
'
:
'
currentColor
'
),
[
color
,
disabled
])
const
textColor
=
useMemo
(()
=>
(
color
===
'
accent
'
&&
!
disabled
?
'
onAccent
'
:
'
currentColor
'
),
[
color
,
disabled
])
return
(
return
(
<
Overlay
update=
{
Boolean
(
update
)
}
flex
align=
"stretch"
>
<
Overlay
action=
{
Boolean
(
action
)
}
flex
align=
"stretch"
>
<
StyledButton
color=
{
color
}
disabled=
{
disabled
}
onClick=
{
update
?
onUpdate
:
onClick
}
>
<
StyledButton
color=
{
color
}
disabled=
{
disabled
}
onClick=
{
action
?
action
.
onClick
:
onClick
}
>
<
ThemedText
.
TransitionButton
buttonSize=
{
update
?
'
medium
'
:
'
large
'
}
color=
{
textColor
}
>
<
ThemedText
.
TransitionButton
buttonSize=
{
action
?
'
medium
'
:
'
large
'
}
color=
{
textColor
}
>
{
update
?
update
.
actio
n
:
children
}
{
action
?
action
.
childre
n
:
children
}
</
ThemedText
.
TransitionButton
>
</
ThemedText
.
TransitionButton
>
</
StyledButton
>
</
StyledButton
>
{
update
&&
(
{
action
&&
(
<
Update
Row
gap=
{
0.5
}
>
<
Action
Row
gap=
{
0.5
}
>
<
LargeIcon
color=
"currentColor"
icon=
{
update
.
icon
||
AlertTriangle
}
/>
<
LargeIcon
color=
"currentColor"
icon=
{
action
.
icon
||
AlertTriangle
}
/>
<
ThemedText
.
Subhead2
>
{
update
?.
message
}
</
ThemedText
.
Subhead2
>
<
ThemedText
.
Subhead2
>
{
action
?.
message
}
</
ThemedText
.
Subhead2
>
</
Update
Row
>
</
Action
Row
>
)
}
)
}
</
Overlay
>
</
Overlay
>
)
)
...
...
src/lib/components/Error/ErrorBoundary.tsx
View file @
8404c607
...
@@ -36,7 +36,7 @@ export default class ErrorBoundary extends React.Component<ErrorBoundaryProps, E
...
@@ -36,7 +36,7 @@ export default class ErrorBoundary extends React.Component<ErrorBoundaryProps, E
error=
{
this
.
state
.
error
}
error=
{
this
.
state
.
error
}
header=
{
<
Trans
>
Something went wrong.
</
Trans
>
}
header=
{
<
Trans
>
Something went wrong.
</
Trans
>
}
action=
{
<
Trans
>
Reload the page
</
Trans
>
}
action=
{
<
Trans
>
Reload the page
</
Trans
>
}
on
Action
=
{
()
=>
window
.
location
.
reload
()
}
on
Click
=
{
()
=>
window
.
location
.
reload
()
}
/>
/>
</
Dialog
>
</
Dialog
>
)
)
...
...
src/lib/components/Error/ErrorDialog.tsx
View file @
8404c607
...
@@ -87,10 +87,10 @@ interface ErrorDialogProps {
...
@@ -87,10 +87,10 @@ interface ErrorDialogProps {
header
?:
ReactNode
header
?:
ReactNode
error
:
Error
error
:
Error
action
:
ReactNode
action
:
ReactNode
on
Action
:
()
=>
void
on
Click
:
()
=>
void
}
}
export
default
function
ErrorDialog
({
header
,
error
,
action
,
on
Action
}:
ErrorDialogProps
)
{
export
default
function
ErrorDialog
({
header
,
error
,
action
,
on
Click
}:
ErrorDialogProps
)
{
const
[
open
,
setOpen
]
=
useState
(
false
)
const
[
open
,
setOpen
]
=
useState
(
false
)
const
[
details
,
setDetails
]
=
useState
<
HTMLDivElement
|
null
>
(
null
)
const
[
details
,
setDetails
]
=
useState
<
HTMLDivElement
|
null
>
(
null
)
const
scrollbar
=
useScrollbar
(
details
)
const
scrollbar
=
useScrollbar
(
details
)
...
@@ -123,7 +123,7 @@ export default function ErrorDialog({ header, error, action, onAction }: ErrorDi
...
@@ -123,7 +123,7 @@ export default function ErrorDialog({ header, error, action, onAction }: ErrorDi
</
ThemedText
.
Code
>
</
ThemedText
.
Code
>
</
Column
>
</
Column
>
</
ErrorColumn
>
</
ErrorColumn
>
<
ActionButton
onClick=
{
on
Action
}
>
{
action
}
</
ActionButton
>
<
ActionButton
onClick=
{
on
Click
}
>
{
action
}
</
ActionButton
>
</
ExpandoColumn
>
</
ExpandoColumn
>
</
Column
>
</
Column
>
)
)
...
...
src/lib/components/Swap/Status/StatusDialog.tsx
View file @
8404c607
...
@@ -93,7 +93,7 @@ export default function TransactionStatusDialog({ tx, onClose }: TransactionStat
...
@@ -93,7 +93,7 @@ export default function TransactionStatusDialog({ tx, onClose }: TransactionStat
header=
{
errorMessage
}
header=
{
errorMessage
}
error=
{
new
Error
(
'
TODO(zzmp)
'
)
}
error=
{
new
Error
(
'
TODO(zzmp)
'
)
}
action=
{
<
Trans
>
Dismiss
</
Trans
>
}
action=
{
<
Trans
>
Dismiss
</
Trans
>
}
on
Action
=
{
onClose
}
on
Click
=
{
onClose
}
/>
/>
)
:
(
)
:
(
<
TransactionStatus
tx=
{
tx
}
onClose=
{
onClose
}
/>
<
TransactionStatus
tx=
{
tx
}
onClose=
{
onClose
}
/>
...
...
src/lib/components/Swap/Summary/index.tsx
View file @
8404c607
...
@@ -6,7 +6,7 @@ import { ALLOWED_PRICE_IMPACT_HIGH, ALLOWED_PRICE_IMPACT_MEDIUM } from 'constant
...
@@ -6,7 +6,7 @@ import { ALLOWED_PRICE_IMPACT_HIGH, ALLOWED_PRICE_IMPACT_MEDIUM } from 'constant
import
{
useAtomValue
}
from
'
jotai/utils
'
import
{
useAtomValue
}
from
'
jotai/utils
'
import
{
IconButton
}
from
'
lib/components/Button
'
import
{
IconButton
}
from
'
lib/components/Button
'
import
useScrollbar
from
'
lib/hooks/useScrollbar
'
import
useScrollbar
from
'
lib/hooks/useScrollbar
'
import
{
AlertTriangle
,
Expando
,
Info
}
from
'
lib/icons
'
import
{
AlertTriangle
,
BarChart
,
Expando
,
Info
}
from
'
lib/icons
'
import
{
MIN_HIGH_SLIPPAGE
}
from
'
lib/state/settings
'
import
{
MIN_HIGH_SLIPPAGE
}
from
'
lib/state/settings
'
import
{
Field
,
independentFieldAtom
}
from
'
lib/state/swap
'
import
{
Field
,
independentFieldAtom
}
from
'
lib/state/swap
'
import
styled
,
{
ThemedText
}
from
'
lib/theme
'
import
styled
,
{
ThemedText
}
from
'
lib/theme
'
...
@@ -79,8 +79,6 @@ const Body = styled(Column)<{ open: boolean }>`
...
@@ -79,8 +79,6 @@ const Body = styled(Column)<{ open: boolean }>`
}
}
`
`
const
priceUpdate
=
{
message
:
<
Trans
>
Price updated
</
Trans
>,
action
:
<
Trans
>
Accept
</
Trans
>
}
interface
SummaryDialogProps
{
interface
SummaryDialogProps
{
trade
:
Trade
<
Currency
,
Currency
,
TradeType
>
trade
:
Trade
<
Currency
,
Currency
,
TradeType
>
allowedSlippage
:
Percent
allowedSlippage
:
Percent
...
@@ -92,8 +90,12 @@ export function SummaryDialog({ trade, allowedSlippage, onConfirm }: SummaryDial
...
@@ -92,8 +90,12 @@ export function SummaryDialog({ trade, allowedSlippage, onConfirm }: SummaryDial
const
inputCurrency
=
inputAmount
.
currency
const
inputCurrency
=
inputAmount
.
currency
const
outputCurrency
=
outputAmount
.
currency
const
outputCurrency
=
outputAmount
.
currency
const
priceImpact
=
useMemo
(()
=>
computeRealizedPriceImpact
(
trade
),
[
trade
])
const
priceImpact
=
useMemo
(()
=>
computeRealizedPriceImpact
(
trade
),
[
trade
])
const
independentField
=
useAtomValue
(
independentFieldAtom
)
const
independentField
=
useAtomValue
(
independentFieldAtom
)
const
{
i18n
}
=
useLingui
()
const
[
open
,
setOpen
]
=
useState
(
false
)
const
[
details
,
setDetails
]
=
useState
<
HTMLDivElement
|
null
>
(
null
)
const
scrollbar
=
useScrollbar
(
details
)
const
warning
=
useMemo
(()
=>
{
const
warning
=
useMemo
(()
=>
{
if
(
priceImpact
.
greaterThan
(
ALLOWED_PRICE_IMPACT_HIGH
))
return
'
error
'
if
(
priceImpact
.
greaterThan
(
ALLOWED_PRICE_IMPACT_HIGH
))
return
'
error
'
...
@@ -102,18 +104,31 @@ export function SummaryDialog({ trade, allowedSlippage, onConfirm }: SummaryDial
...
@@ -102,18 +104,31 @@ export function SummaryDialog({ trade, allowedSlippage, onConfirm }: SummaryDial
return
return
},
[
allowedSlippage
,
priceImpact
])
},
[
allowedSlippage
,
priceImpact
])
const
[
ackPriceImpact
,
setAckPriceImpact
]
=
useState
(
false
)
const
[
confirmedTrade
,
setConfirmedTrade
]
=
useState
(
trade
)
const
[
confirmedTrade
,
setConfirmedTrade
]
=
useState
(
trade
)
const
doesTradeDiffer
=
useMemo
(
const
doesTradeDiffer
=
useMemo
(
()
=>
Boolean
(
trade
&&
confirmedTrade
&&
tradeMeaningfullyDiffers
(
trade
,
confirmedTrade
)),
()
=>
Boolean
(
trade
&&
confirmedTrade
&&
tradeMeaningfullyDiffers
(
trade
,
confirmedTrade
)),
[
confirmedTrade
,
trade
]
[
confirmedTrade
,
trade
]
)
)
const
[
open
,
setOpen
]
=
useState
(
false
)
const
[
details
,
setDetails
]
=
useState
<
HTMLDivElement
|
null
>
(
null
)
const
action
=
useMemo
(()
=>
{
if
(
doesTradeDiffer
)
{
const
scrollbar
=
useScrollbar
(
details
)
return
{
message
:
<
Trans
>
Price updated
</
Trans
>,
const
{
i18n
}
=
useLingui
()
icon
:
BarChart
,
onClick
:
()
=>
setConfirmedTrade
(
trade
),
children
:
<
Trans
>
Accept
</
Trans
>,
}
}
else
if
(
priceImpact
.
greaterThan
(
ALLOWED_PRICE_IMPACT_HIGH
)
&&
!
ackPriceImpact
)
{
return
{
message
:
<
Trans
>
High price impact
</
Trans
>,
onClick
:
()
=>
setAckPriceImpact
(
true
),
children
:
<
Trans
>
Acknowledge
</
Trans
>,
}
}
return
},
[
ackPriceImpact
,
doesTradeDiffer
,
priceImpact
,
trade
])
if
(
!
(
inputAmount
&&
outputAmount
&&
inputCurrency
&&
outputCurrency
))
{
if
(
!
(
inputAmount
&&
outputAmount
&&
inputCurrency
&&
outputCurrency
))
{
return
null
return
null
...
@@ -163,11 +178,7 @@ export function SummaryDialog({ trade, allowedSlippage, onConfirm }: SummaryDial
...
@@ -163,11 +178,7 @@ export function SummaryDialog({ trade, allowedSlippage, onConfirm }: SummaryDial
</
Trans
>
</
Trans
>
)
}
)
}
</
Estimate
>
</
Estimate
>
<
ActionButton
<
ActionButton
onClick=
{
onConfirm
}
action=
{
action
}
>
onClick=
{
onConfirm
}
onUpdate=
{
()
=>
setConfirmedTrade
(
trade
)
}
update=
{
doesTradeDiffer
?
priceUpdate
:
undefined
}
>
<
Trans
>
Confirm swap
</
Trans
>
<
Trans
>
Confirm swap
</
Trans
>
</
ActionButton
>
</
ActionButton
>
</
ExpandoColumn
>
</
ExpandoColumn
>
...
...
src/lib/components/Swap/SwapButton.tsx
View file @
8404c607
...
@@ -95,8 +95,9 @@ export default function SwapButton({ disabled }: SwapButtonProps) {
...
@@ -95,8 +95,9 @@ export default function SwapButton({ disabled }: SwapButtonProps) {
</
Row
>
</
Row
>
</
EtherscanLink
>
</
EtherscanLink
>
),
),
action
:
<
Trans
>
Approve
</
Trans
>,
icon
:
Spinner
,
icon
:
Spinner
,
onClick
:
addApprovalTransaction
,
children
:
<
Trans
>
Approve
</
Trans
>,
},
},
}
}
}
else
if
(
approval
===
ApprovalState
.
NOT_APPROVED
)
{
}
else
if
(
approval
===
ApprovalState
.
NOT_APPROVED
)
{
...
@@ -111,7 +112,7 @@ export default function SwapButton({ disabled }: SwapButtonProps) {
...
@@ -111,7 +112,7 @@ export default function SwapButton({ disabled }: SwapButtonProps) {
}
}
return
{
disabled
:
true
}
return
{
disabled
:
true
}
},
[
approval
,
approvalHash
,
chainId
,
disabled
,
inputCurrencyAmount
,
inputCurrencyBalance
])
},
[
a
ddApprovalTransaction
,
a
pproval
,
approvalHash
,
chainId
,
disabled
,
inputCurrencyAmount
,
inputCurrencyBalance
])
const
deadline
=
useTransactionDeadline
()
const
deadline
=
useTransactionDeadline
()
const
{
signatureData
}
=
useERC20PermitFromTrade
(
optimizedTrade
,
allowedSlippage
,
deadline
)
const
{
signatureData
}
=
useERC20PermitFromTrade
(
optimizedTrade
,
allowedSlippage
,
deadline
)
...
@@ -156,7 +157,6 @@ export default function SwapButton({ disabled }: SwapButtonProps) {
...
@@ -156,7 +157,6 @@ export default function SwapButton({ disabled }: SwapButtonProps) {
<
ActionButton
<
ActionButton
color=
{
tokenColorExtraction
?
'
interactive
'
:
'
accent
'
}
color=
{
tokenColorExtraction
?
'
interactive
'
:
'
accent
'
}
onClick=
{
()
=>
setActiveTrade
(
trade
.
trade
)
}
onClick=
{
()
=>
setActiveTrade
(
trade
.
trade
)
}
onUpdate=
{
addApprovalTransaction
}
{
...
actionProps
}
{
...
actionProps
}
>
>
<
Trans
>
Review swap
</
Trans
>
<
Trans
>
Review swap
</
Trans
>
...
...
src/lib/icons/index.tsx
View file @
8404c607
...
@@ -12,6 +12,7 @@ import {
...
@@ -12,6 +12,7 @@ import {
ArrowDown
as
ArrowDownIcon
,
ArrowDown
as
ArrowDownIcon
,
ArrowRight
as
ArrowRightIcon
,
ArrowRight
as
ArrowRightIcon
,
ArrowUp
as
ArrowUpIcon
,
ArrowUp
as
ArrowUpIcon
,
BarChart2
as
BarChart2Icon
,
CheckCircle
as
CheckCircleIcon
,
CheckCircle
as
CheckCircleIcon
,
ChevronDown
as
ChevronDownIcon
,
ChevronDown
as
ChevronDownIcon
,
Clock
as
ClockIcon
,
Clock
as
ClockIcon
,
...
@@ -75,6 +76,7 @@ export const ArrowDown = icon(ArrowDownIcon)
...
@@ -75,6 +76,7 @@ export const ArrowDown = icon(ArrowDownIcon)
export
const
ArrowRight
=
icon
(
ArrowRightIcon
)
export
const
ArrowRight
=
icon
(
ArrowRightIcon
)
export
const
ArrowUp
=
icon
(
ArrowUpIcon
)
export
const
ArrowUp
=
icon
(
ArrowUpIcon
)
export
const
CheckCircle
=
icon
(
CheckCircleIcon
)
export
const
CheckCircle
=
icon
(
CheckCircleIcon
)
export
const
BarChart
=
icon
(
BarChart2Icon
)
export
const
ChevronDown
=
icon
(
ChevronDownIcon
)
export
const
ChevronDown
=
icon
(
ChevronDownIcon
)
export
const
Clock
=
icon
(
ClockIcon
)
export
const
Clock
=
icon
(
ClockIcon
)
export
const
HelpCircle
=
icon
(
HelpCircleIcon
)
export
const
HelpCircle
=
icon
(
HelpCircleIcon
)
...
...
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