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
29e46455
Unverified
Commit
29e46455
authored
Aug 03, 2023
by
eddie
Committed by
GitHub
Aug 03, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: use submitted icon on mainnet (#7055)
* fix: use submitted icon on mainnet * fix: e2e test * fix: some cleanup
parent
cfc97480
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
180 additions
and
87 deletions
+180
-87
permit2.test.ts
cypress/e2e/permit2.test.ts
+8
-7
Logos.tsx
src/components/swap/PendingModalContent/Logos.tsx
+32
-1
PendingModalContent.test.tsx
...nts/swap/PendingModalContent/PendingModalContent.test.tsx
+32
-0
index.tsx
src/components/swap/PendingModalContent/index.tsx
+108
-79
No files found.
cypress/e2e/permit2.test.ts
View file @
29e46455
...
...
@@ -75,8 +75,9 @@ describe('Permit2', () => {
cy
.
contains
(
'
Allow DAI to be used for swapping
'
)
cy
.
wait
(
'
@eth_signTypedData_v4
'
)
cy
.
wait
(
'
@eth_sendRawTransaction
'
)
cy
.
contains
(
'
Swap submitted
'
)
cy
.
hardhat
().
then
((
hardhat
)
=>
hardhat
.
mine
())
cy
.
contains
(
'
S
uccess
'
)
cy
.
contains
(
'
S
wap success!
'
)
cy
.
get
(
getTestSelector
(
'
popups
'
)).
contains
(
'
Swapped
'
)
expectPermit2AllowanceForUniversalRouterToBeMax
(
DAI
)
})
...
...
@@ -99,7 +100,7 @@ describe('Permit2', () => {
// Verify transaction
cy
.
wait
(
'
@eth_sendRawTransaction
'
)
cy
.
hardhat
().
then
((
hardhat
)
=>
hardhat
.
mine
())
cy
.
contains
(
'
S
uccess
'
)
cy
.
contains
(
'
S
wap success!
'
)
cy
.
get
(
getTestSelector
(
'
popups
'
)).
contains
(
'
Swapped
'
)
})
...
...
@@ -142,7 +143,7 @@ describe('Permit2', () => {
// Verify transaction
cy
.
wait
(
'
@eth_sendRawTransaction
'
)
cy
.
hardhat
().
then
((
hardhat
)
=>
hardhat
.
mine
())
cy
.
contains
(
'
S
uccess
'
)
cy
.
contains
(
'
S
wap success!
'
)
cy
.
get
(
getTestSelector
(
'
popups
'
)).
contains
(
'
Swapped
'
)
})
})
...
...
@@ -158,7 +159,7 @@ describe('Permit2', () => {
initiateSwap
()
// Verify transaction
cy
.
contains
(
'
S
uccess
'
)
cy
.
contains
(
'
S
wap success!
'
)
cy
.
get
(
getTestSelector
(
'
popups
'
)).
contains
(
'
Swapped
'
)
})
...
...
@@ -197,7 +198,7 @@ describe('Permit2', () => {
cy
.
contains
(
'
Confirm swap
'
).
click
()
// Verify permit2 approval
cy
.
contains
(
'
S
uccess
'
)
cy
.
contains
(
'
S
wap success!
'
)
cy
.
get
(
getTestSelector
(
'
popups
'
)).
contains
(
'
Swapped
'
)
expectPermit2AllowanceForUniversalRouterToBeMax
(
DAI
)
})
...
...
@@ -231,7 +232,7 @@ describe('Permit2', () => {
// Verify permit2 approval
cy
.
wait
(
'
@eth_signTypedData_v4
'
)
cy
.
contains
(
'
S
uccess
'
)
cy
.
contains
(
'
S
wap success!
'
)
cy
.
get
(
getTestSelector
(
'
popups
'
)).
contains
(
'
Swapped
'
)
expectPermit2AllowanceForUniversalRouterToBeMax
(
DAI
)
})
...
...
@@ -249,7 +250,7 @@ describe('Permit2', () => {
// Verify permit2 approval
cy
.
wait
(
'
@eth_signTypedData_v4
'
)
cy
.
contains
(
'
S
uccess
'
)
cy
.
contains
(
'
S
wap success!
'
)
cy
.
get
(
getTestSelector
(
'
popups
'
)).
contains
(
'
Swapped
'
)
expectPermit2AllowanceForUniversalRouterToBeMax
(
DAI
)
})
...
...
src/components/swap/PendingModalContent/Logos.tsx
View file @
29e46455
...
...
@@ -162,7 +162,38 @@ function ConfirmedIcon({ className }: { className?: string }) {
)
}
export
const
AnimatedEntranceConfirmationIcon
=
styled
(
ConfirmedIcon
)
`
function
SubmittedIcon
({
className
}:
{
className
?:
string
})
{
const
theme
=
useTheme
()
return
(
<
FadePresence
$scale
>
<
svg
data
-
testid=
"submitted-icon"
width=
"54"
height=
"54"
viewBox=
"0 0 54 54"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
className=
{
className
}
>
<
path
d=
"M26.9997 0.333496C12.2717 0.333496 0.333008 12.2722 0.333008 27.0002C0.333008 41.7282 12.2717 53.6668 26.9997 53.6668C41.7277 53.6668 53.6663 41.7282 53.6663 27.0002C53.6663 12.2722 41.7277 0.333496 26.9997 0.333496ZM36.4131 25.7469C36.0238 26.1362 35.5117 26.3335 34.9997 26.3335C34.4877 26.3335 33.9756 26.1389 33.5863 25.7469L28.9997 21.1603V37.6668C28.9997 38.7708 28.1037 39.6668 26.9997 39.6668C25.8957 39.6668 24.9997 38.7708 24.9997 37.6668V21.1629L20.4131 25.7495C19.6318 26.5308 18.365 26.5308 17.5837 25.7495C16.8023 24.9682 16.8023 23.7014 17.5837 22.9201L25.5837 14.9201C25.7677 14.7361 25.9887 14.5898 26.2341 14.4884C26.722 14.2858 27.274 14.2858 27.762 14.4884C28.0074 14.5898 28.2291 14.7361 28.4131 14.9201L36.4131 22.9201C37.1944 23.7014 37.1944 24.9656 36.4131 25.7469Z"
fill=
{
theme
.
accentActive
}
/>
</
svg
>
</
FadePresence
>
)
}
const
IconCss
=
css
`
position: absolute;
height: 48px;
width: 48px;
`
export
const
AnimatedEntranceConfirmationIcon
=
styled
(
ConfirmedIcon
)
`
${
IconCss
}
`
export
const
AnimatedEntranceSubmittedIcon
=
styled
(
SubmittedIcon
)
`
${
IconCss
}
`
src/components/swap/PendingModalContent/PendingModalContent.test.tsx
View file @
29e46455
...
...
@@ -128,6 +128,38 @@ describe('PendingModalContent', () => {
expect
(
screen
.
queryByTestId
(
'
pending-modal-currency-logo-loader
'
)).
toBeNull
()
})
it
(
'
renders the submitted icon instead of the given logo on mainnet when the transaction is submitted
'
,
()
=>
{
mocked
(
useSwapTransactionStatus
).
mockReturnValue
(
TransactionStatus
.
Pending
)
render
(
<
PendingModalContent
steps=
{
[
ConfirmModalState
.
APPROVING_TOKEN
,
ConfirmModalState
.
PERMITTING
,
ConfirmModalState
.
PENDING_CONFIRMATION
,
]
}
currentStep=
{
ConfirmModalState
.
PENDING_CONFIRMATION
}
swapResult=
{
{
type
:
TradeFillType
.
Classic
,
response
:
{
hash
:
''
,
confirmations
:
0
,
from
:
''
,
wait
:
jest
.
fn
(),
nonce
:
0
,
gasLimit
:
BigNumber
.
from
(
0
),
data
:
''
,
value
:
BigNumber
.
from
(
0
),
chainId
:
0
,
},
}
}
/>
)
expect
(
screen
.
queryByTestId
(
'
pending-modal-failure-icon
'
)).
toBeNull
()
expect
(
screen
.
queryByTestId
(
'
pending-modal-currency-logo-loader
'
)).
toBeNull
()
expect
(
screen
.
getByTestId
(
'
submitted-icon
'
)).
toBeInTheDocument
()
})
it
(
'
renders the success icon instead of the given logo when confirmed and successful
'
,
()
=>
{
mocked
(
useSwapTransactionStatus
).
mockReturnValue
(
TransactionStatus
.
Confirmed
)
...
...
src/components/swap/PendingModalContent/index.tsx
View file @
29e46455
...
...
@@ -9,7 +9,7 @@ import { TransactionStatus } from 'graphql/data/__generated__/types-and-hooks'
import
{
SwapResult
}
from
'
hooks/useSwapCallback
'
import
{
useUnmountingAnimation
}
from
'
hooks/useUnmountingAnimation
'
import
{
UniswapXOrderStatus
}
from
'
lib/hooks/orders/types
'
import
{
ReactNode
,
useRef
}
from
'
react
'
import
{
ReactNode
,
use
Memo
,
use
Ref
}
from
'
react
'
import
{
InterfaceTrade
,
TradeFillType
}
from
'
state/routing/types
'
import
{
useOrder
}
from
'
state/signatures/hooks
'
import
{
UniswapXOrderDetails
}
from
'
state/signatures/types
'
...
...
@@ -23,6 +23,7 @@ import { ExplorerDataType } from 'utils/getExplorerLink'
import
{
ConfirmModalState
}
from
'
../ConfirmSwapModal
'
import
{
AnimatedEntranceConfirmationIcon
,
AnimatedEntranceSubmittedIcon
,
AnimationType
,
CurrencyLoader
,
LoadingIndicatorOverlay
,
...
...
@@ -102,7 +103,7 @@ export type PendingConfirmModalState = Extract<
interface
PendingModalStep
{
title
:
ReactNode
subtitle
?:
ReactNode
l
abel
?:
ReactNode
bottomL
abel
?:
ReactNode
logo
?:
ReactNode
button
?:
ReactNode
}
...
...
@@ -119,7 +120,6 @@ interface PendingModalContentProps {
}
interface
ContentArgs
{
step
:
PendingConfirmModalState
approvalCurrency
?:
Currency
trade
?:
InterfaceTrade
swapConfirmed
:
boolean
...
...
@@ -132,9 +132,59 @@ interface ContentArgs {
order
?:
UniswapXOrderDetails
}
function
getContent
(
args
:
ContentArgs
):
PendingModalStep
{
function
getPendingConfirmationContent
({
swapConfirmed
,
swapPending
,
trade
,
chainId
,
swapResult
,
}:
Pick
<
ContentArgs
,
'
swapConfirmed
'
|
'
swapPending
'
|
'
trade
'
|
'
chainId
'
|
'
swapResult
'
>
):
PendingModalStep
{
const
title
=
swapPending
?
t
`Swap submitted`
:
swapConfirmed
?
t
`Swap success!`
:
t
`Confirm Swap`
const
tradeSummary
=
trade
?
<
TradeSummary
trade=
{
trade
}
/>
:
null
if
(
swapPending
&&
trade
?.
fillType
===
TradeFillType
.
UniswapX
)
{
return
{
title
,
subtitle
:
tradeSummary
,
bottomLabel
:
(
<
ExternalLink
href=
"https://support.uniswap.org/hc/en-us/articles/17515415311501"
color=
"textSecondary"
>
<
Trans
>
Learn more about swapping with UniswapX
</
Trans
>
</
ExternalLink
>
),
}
}
else
if
((
swapPending
||
swapConfirmed
)
&&
chainId
&&
swapResult
?.
type
===
TradeFillType
.
Classic
)
{
const
explorerLink
=
(
<
ExternalLink
href=
{
getExplorerLink
(
chainId
,
swapResult
.
response
.
hash
,
ExplorerDataType
.
TRANSACTION
)
}
color=
"textSecondary"
>
<
Trans
>
View on Explorer
</
Trans
>
</
ExternalLink
>
)
if
(
swapPending
)
{
// On Mainnet, we show a "submitted" state while the transaction is pending confirmation.
return
{
title
,
subtitle
:
chainId
===
ChainId
.
MAINNET
?
explorerLink
:
tradeSummary
,
bottomLabel
:
chainId
===
ChainId
.
MAINNET
?
t
`Transaction pending...`
:
explorerLink
,
}
}
else
{
return
{
title
,
subtitle
:
explorerLink
,
bottomLabel
:
null
,
}
}
}
else
{
return
{
title
,
subtitle
:
tradeSummary
,
bottomLabel
:
t
`Proceed in your wallet`
,
}
}
}
function
useStepContents
(
args
:
ContentArgs
):
Record
<
PendingConfirmModalState
,
PendingModalStep
>
{
const
{
step
,
wrapPending
,
approvalCurrency
,
swapConfirmed
,
...
...
@@ -146,70 +196,60 @@ function getContent(args: ContentArgs): PendingModalStep {
chainId
,
}
=
args
switch
(
step
)
{
case
ConfirmModalState
.
WRAPPING
:
return
{
return
useMemo
(
()
=>
({
[
ConfirmModalState
.
WRAPPING
]:
{
title
:
t
`Wrap ETH`
,
subtitle
:
(
<
ExternalLink
href=
"https://support.uniswap.org/hc/en-us/articles/16015852009997"
>
<
Trans
>
Why is this required?
</
Trans
>
</
ExternalLink
>
),
label
:
wrapPending
?
t
`Pending...`
:
t
`Proceed in your wallet`
,
}
case
ConfirmModalState
.
RESETTING_USDT
:
return
{
bottomLabel
:
wrapPending
?
t
`Pending...`
:
t
`Proceed in your wallet`
,
},
[
ConfirmModalState
.
RESETTING_USDT
]:
{
title
:
t
`Reset USDT`
,
subtitle
:
t
`USDT requires resetting approval when spending limits are too low.`
,
label
:
revocationPending
?
t
`Pending...`
:
t
`Proceed in your wallet`
,
}
case
ConfirmModalState
.
APPROVING_TOKEN
:
return
{
bottomLabel
:
revocationPending
?
t
`Pending...`
:
t
`Proceed in your wallet`
,
},
[
ConfirmModalState
.
APPROVING_TOKEN
]:
{
title
:
t
`Enable spending
${
approvalCurrency
?.
symbol
??
'
this token
'
}
on
Uniswap
`,
subtitle: (
<ExternalLink href="https://support.uniswap.org/hc/en-us/articles/8120520483085">
<Trans>Why is this required?</Trans>
</ExternalLink>
),
label: tokenApprovalPending ? t`
Pending
...
` : t`
Proceed
in
your
wallet
`,
}
case ConfirmModalState.PERMITTING:
return {
bottomLabel: tokenApprovalPending ? t`
Pending
...
` : t`
Proceed
in
your
wallet
`,
},
[ConfirmModalState.PERMITTING]: {
title: t`
Allow
$
{
approvalCurrency
?.
symbol
??
'
this token
'
}
to
be
used
for
swapping
`,
subtitle: (
<ExternalLink href="https://support.uniswap.org/hc/en-us/articles/8120520483085">
<Trans>Why is this required?</Trans>
</ExternalLink>
),
label: t`
Proceed
in
your
wallet
`,
}
case ConfirmModalState.PENDING_CONFIRMATION: {
let labelText: string | null = null
let href: string | null = null
if (swapPending && trade?.fillType === TradeFillType.UniswapX) {
labelText = t`
Learn
more
about
swapping
with
UniswapX
`
href = 'https://support.uniswap.org/hc/en-us/articles/17515415311501'
} else if (chainId && (swapConfirmed || swapPending) && swapResult && swapResult.type === TradeFillType.Classic) {
labelText = t`
View
on
Explorer
`
href = getExplorerLink(chainId, swapResult.response.hash, ExplorerDataType.TRANSACTION)
} else {
labelText = t`
Proceed
in
your
wallet
`
}
return {
title: swapPending ? t`
Swap
submitted
` : swapConfirmed ? t`
Success
` : t`
Confirm
Swap
`,
subtitle: trade ? <TradeSummary trade={trade} /> : null,
label: href ? (
<ExternalLink href={href} color="textSecondary">
{labelText}
</ExternalLink>
) : (
labelText
),
}
}
}
bottomLabel: t`
Proceed
in
your
wallet
`,
},
[ConfirmModalState.PENDING_CONFIRMATION]: getPendingConfirmationContent({
chainId,
swapConfirmed,
swapPending,
swapResult,
trade,
}),
}),
[
approvalCurrency?.symbol,
chainId,
revocationPending,
swapConfirmed,
swapPending,
swapResult,
tokenApprovalPending,
trade,
wrapPending,
]
)
}
export function PendingModalContent({
...
...
@@ -236,8 +276,7 @@ export function PendingModalContent({
const swapPending = swapResult !== undefined && !swapConfirmed
const wrapPending = wrapTxHash != undefined && !wrapConfirmed
const { label, button } = getContent({
step: currentStep,
const stepContents = useStepContents({
approvalCurrency: trade?.inputAmount.currency,
swapConfirmed,
swapPending,
...
...
@@ -263,8 +302,11 @@ export function PendingModalContent({
return <OrderContent order={{ status: order.status, orderHash: order.orderHash, details: order }} />
}
// On mainnet, we show the success icon once the tx is sent, since it takes longer to confirm than on L2s.
const showSuccess = swapConfirmed || (swapPending && chainId === ChainId.MAINNET)
// On mainnet, we show a different icon when the transaction is submitted but pending confirmation.
const showSubmitted = swapPending && !swapConfirmed && chainId === ChainId.MAINNET
const showSuccess = swapConfirmed || (chainId !== ChainId.MAINNET && swapPending)
const transactionPending = revocationPending || tokenApprovalPending || wrapPending || swapPending
return (
<PendingModalContainer gap="lg">
...
...
@@ -282,31 +324,18 @@ export function PendingModalContent({
)}
{/* Shown only during the final step under "success" conditions, and scales in. */}
{currentStep === ConfirmModalState.PENDING_CONFIRMATION && showSuccess && <AnimatedEntranceConfirmationIcon />}
{/* Scales in for the USDT revoke allowance step if the revoke is pending onchain confirmation. */}
{/* Scales in for the setup approval step if the approval is pending onchain confirmation. */}
{/* Scales in for the final step if the swap is pending user signature or onchain confirmation. */}
{((currentStep === ConfirmModalState.PENDING_CONFIRMATION && !showSuccess) ||
tokenApprovalPending ||
wrapPending ||
revocationPending) && <LoadingIndicatorOverlay />}
{/* Shown only during the final step on mainnet, when the transaction is sent but pending confirmation. */}
{currentStep === ConfirmModalState.PENDING_CONFIRMATION && showSubmitted && <AnimatedEntranceSubmittedIcon />}
{/* Scales in for any step that waits for an onchain transaction, while the transaction is pending. */}
{/* On the last step, appears while waiting for the transaction to be signed too. */}
{((currentStep !== ConfirmModalState.PENDING_CONFIRMATION && transactionPending) ||
(currentStep === ConfirmModalState.PENDING_CONFIRMATION && !showSuccess && !showSubmitted)) && (
<LoadingIndicatorOverlay />
)}
</LogoContainer>
<HeaderContainer
gap="md"
$disabled={revocationPending || tokenApprovalPending || wrapPending || (swapPending && !showSuccess)}
>
<HeaderContainer gap="md" $disabled={transactionPending}>
<AnimationWrapper>
{steps.map((step) => {
const { title, subtitle } = getContent({
step,
approvalCurrency: trade?.inputAmount.currency,
swapConfirmed,
swapPending,
wrapPending,
revocationPending,
tokenApprovalPending,
swapResult,
trade,
})
// We only render one step at a time, but looping through the array allows us to keep
// the exiting step in the DOM during its animation.
return (
...
...
@@ -318,19 +347,19 @@ export function PendingModalContent({
ref={step === currentStep ? currentStepContainerRef : undefined}
>
<ThemedText.SubHeaderLarge textAlign="center" data-testid="pending-modal-content-title">
{title}
{
stepContents[step].
title}
</ThemedText.SubHeaderLarge>
<ThemedText.LabelSmall textAlign="center">{subtitle}</ThemedText.LabelSmall>
<ThemedText.LabelSmall textAlign="center">{s
tepContents[step].s
ubtitle}</ThemedText.LabelSmall>
</StepTitleAnimationContainer>
)
)
})}
</AnimationWrapper>
<Row justify="center" marginTop="32px" minHeight="24px">
<ThemedText.Caption color="textSecondary">{
l
abel}</ThemedText.Caption>
<ThemedText.Caption color="textSecondary">{
stepContents[currentStep].bottomL
abel}</ThemedText.Caption>
</Row>
</HeaderContainer>
{
button && <Row justify="center">{
button}</Row>}
{
stepContents[currentStep].button && <Row justify="center">{stepContents[currentStep].
button}</Row>}
{!hideStepIndicators && !showSuccess && (
<Row gap="14px" justify="center">
{steps.map((_, i) => {
...
...
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