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
8ffe4e99
Unverified
Commit
8ffe4e99
authored
Aug 11, 2023
by
cartcrom
Committed by
GitHub
Aug 11, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: properly display FOT swaps (#7146)
parent
2b85852a
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
129 additions
and
89 deletions
+129
-89
parseRemote.tsx
...ents/AccountDrawer/MiniPortfolio/Activity/parseRemote.tsx
+19
-8
PortfolioLogo.tsx
src/components/AccountDrawer/MiniPortfolio/PortfolioLogo.tsx
+110
-81
No files found.
src/components/AccountDrawer/MiniPortfolio/Activity/parseRemote.tsx
View file @
8ffe4e99
import
{
t
}
from
'
@lingui/macro
'
import
{
ChainId
,
NONFUNGIBLE_POSITION_MANAGER_ADDRESSES
,
UNI_ADDRESSES
}
from
'
@uniswap/sdk-core
'
import
{
ChainId
,
Currency
,
NONFUNGIBLE_POSITION_MANAGER_ADDRESSES
,
UNI_ADDRESSES
}
from
'
@uniswap/sdk-core
'
import
UniswapXBolt
from
'
assets/svg/bolt.svg
'
import
moonpayLogoSrc
from
'
assets/svg/moonpay.svg
'
import
{
nativeOnChain
}
from
'
constants/tokens
'
import
{
ActivityType
,
AssetActivityPartsFragment
,
Currency
,
Currency
as
GQLCurrency
,
NftApprovalPartsFragment
,
NftApproveForAllPartsFragment
,
NftTransferPartsFragment
,
...
...
@@ -17,7 +17,7 @@ import {
TokenTransferPartsFragment
,
TransactionDetailsPartsFragment
,
}
from
'
graphql/data/__generated__/types-and-hooks
'
import
{
logSentryErrorForUnsupportedChain
,
supportedChainIdFromGQLChain
}
from
'
graphql/data/util
'
import
{
gqlToCurrency
,
logSentryErrorForUnsupportedChain
,
supportedChainIdFromGQLChain
}
from
'
graphql/data/util
'
import
ms
from
'
ms
'
import
{
useEffect
,
useState
}
from
'
react
'
import
{
isAddress
}
from
'
utils
'
...
...
@@ -142,7 +142,7 @@ function getSwapDescriptor({
*/
function
formatTransactedValue
(
transactedValue
:
TokenTransferPartsFragment
[
'
transactedValue
'
]):
string
{
if
(
!
transactedValue
)
return
'
-
'
const
price
=
transactedValue
?.
currency
===
Currency
.
Usd
?
transactedValue
.
value
??
undefined
:
undefined
const
price
=
transactedValue
?.
currency
===
GQL
Currency
.
Usd
?
transactedValue
.
value
??
undefined
:
undefined
return
formatFiatPrice
(
price
)
}
...
...
@@ -156,7 +156,9 @@ function parseSwap(changes: TransactionChanges) {
.
join
()
return
{
title
,
descriptor
}
}
else
if
(
changes
.
TokenTransfer
.
length
===
2
)
{
}
// Some swaps may have more than 2 transfers, e.g. swaps with fees on tranfer
if
(
changes
.
TokenTransfer
.
length
>=
2
)
{
const
sent
=
changes
.
TokenTransfer
.
find
((
t
)
=>
t
?.
__typename
===
'
TokenTransfer
'
&&
t
.
direction
===
'
OUT
'
)
const
received
=
changes
.
TokenTransfer
.
find
((
t
)
=>
t
?.
__typename
===
'
TokenTransfer
'
&&
t
.
direction
===
'
IN
'
)
if
(
sent
&&
received
)
{
...
...
@@ -165,6 +167,7 @@ function parseSwap(changes: TransactionChanges) {
return
{
title
:
getSwapTitle
(
sent
,
received
),
descriptor
:
getSwapDescriptor
({
tokenIn
:
sent
.
asset
,
inputAmount
,
tokenOut
:
received
.
asset
,
outputAmount
}),
currencies
:
[
gqlToCurrency
(
sent
.
asset
),
gqlToCurrency
(
received
.
asset
)],
}
}
}
...
...
@@ -179,7 +182,8 @@ function parseApprove(changes: TransactionChanges) {
if
(
changes
.
TokenApproval
.
length
===
1
)
{
const
title
=
parseInt
(
changes
.
TokenApproval
[
0
].
quantity
)
===
0
?
t
`Revoked Approval`
:
t
`Approved`
const
descriptor
=
`
${
changes
.
TokenApproval
[
0
].
asset
.
symbol
}
`
return
{
title
,
descriptor
}
const
currencies
=
[
gqlToCurrency
(
changes
.
TokenApproval
[
0
].
asset
)]
return
{
title
,
descriptor
,
currencies
}
}
return
{
title
:
t
`Unknown Approval`
}
}
...
...
@@ -194,6 +198,7 @@ function parseLPTransfers(changes: TransactionChanges) {
return
{
descriptor
:
`
${
tokenAQuanitity
}
${
poolTokenA
.
asset
.
symbol
}
and
${
tokenBQuantity
}
${
poolTokenB
.
asset
.
symbol
}
`
,
logos
:
[
poolTokenA
.
asset
.
project
?.
logo
?.
url
,
poolTokenB
.
asset
.
project
?.
logo
?.
url
],
currencies
:
[
gqlToCurrency
(
poolTokenA
.
asset
),
gqlToCurrency
(
poolTokenB
.
asset
)],
}
}
...
...
@@ -210,6 +215,7 @@ function parseSendReceive(changes: TransactionChanges, assetActivity: Transactio
let
transfer
:
NftTransferPartsFragment
|
TokenTransferPartsFragment
|
undefined
let
assetName
:
string
|
undefined
let
amount
:
string
|
undefined
let
currencies
:
(
Currency
|
undefined
)[]
|
undefined
if
(
changes
.
NftTransfer
.
length
===
1
)
{
transfer
=
changes
.
NftTransfer
[
0
]
...
...
@@ -219,6 +225,7 @@ function parseSendReceive(changes: TransactionChanges, assetActivity: Transactio
transfer
=
changes
.
TokenTransfer
[
0
]
assetName
=
transfer
.
asset
.
symbol
amount
=
formatNumberOrString
(
transfer
.
quantity
,
NumberType
.
TokenNonTx
)
currencies
=
[
gqlToCurrency
(
transfer
.
asset
)]
}
if
(
transfer
&&
assetName
&&
amount
)
{
...
...
@@ -230,17 +237,20 @@ function parseSendReceive(changes: TransactionChanges, assetActivity: Transactio
title
:
t
`Purchased`
,
descriptor
:
`
${
amount
}
${
assetName
}
${
t
`for`
}
${
formatTransactedValue
(
transfer
.
transactedValue
)}
`
,
logos
:
[
moonpayLogoSrc
],
currencies
,
}
:
{
title
:
t
`Received`
,
descriptor
:
`
${
amount
}
${
assetName
}
${
t
`from`
}
`
,
otherAccount
:
isAddress
(
transfer
.
sender
)
||
undefined
,
currencies
,
}
}
else
{
return
{
title
:
t
`Sent`
,
descriptor
:
`
${
amount
}
${
assetName
}
${
t
`to`
}
`
,
otherAccount
:
isAddress
(
transfer
.
recipient
)
||
undefined
,
currencies
,
}
}
}
...
...
@@ -276,7 +286,7 @@ const ActivityParserByType: { [key: string]: ActivityTypeParser | undefined } =
[
ActivityType
.
Unknown
]:
parseUnknown
,
}
function
getLogoSrcs
(
changes
:
TransactionChanges
):
string
[]
{
function
getLogoSrcs
(
changes
:
TransactionChanges
):
Array
<
string
|
undefined
>
{
// Uses set to avoid duplicate logos (e.g. nft's w/ same image url)
const
logoSet
=
new
Set
<
string
|
undefined
>
()
// Uses only NFT logos if they are present (will not combine nft image w/ token image)
...
...
@@ -286,7 +296,7 @@ function getLogoSrcs(changes: TransactionChanges): string[] {
changes
.
TokenTransfer
.
forEach
((
tokenChange
)
=>
logoSet
.
add
(
tokenChange
.
asset
.
project
?.
logo
?.
url
))
changes
.
TokenApproval
.
forEach
((
tokenChange
)
=>
logoSet
.
add
(
tokenChange
.
asset
.
project
?.
logo
?.
url
))
}
return
Array
.
from
(
logoSet
)
.
filter
(
Boolean
)
as
string
[]
return
Array
.
from
(
logoSet
)
}
function
parseUniswapXOrder
({
details
,
chain
,
timestamp
}:
OrderActivity
):
Activity
|
undefined
{
...
...
@@ -321,6 +331,7 @@ function parseUniswapXOrder({ details, chain, timestamp }: OrderActivity): Activ
offchainOrderStatus
:
uniswapXOrderStatus
,
timestamp
,
logos
:
[
inputToken
.
project
?.
logo
?.
url
,
outputToken
.
project
?.
logo
?.
url
],
currencies
:
[
gqlToCurrency
(
inputToken
),
gqlToCurrency
(
outputToken
)],
title
,
descriptor
,
from
:
details
.
offerer
,
...
...
src/components/AccountDrawer/MiniPortfolio/PortfolioLogo.tsx
View file @
8ffe4e99
...
...
@@ -2,14 +2,14 @@ import { ChainId, Currency } from '@uniswap/sdk-core'
import
blankTokenUrl
from
'
assets/svg/blank_token.svg
'
import
{
ReactComponent
as
UnknownStatus
}
from
'
assets/svg/contract-interaction.svg
'
import
{
MissingImageLogo
}
from
'
components/Logo/AssetLogo
'
import
CurrencyLogo
from
'
components/Logo/CurrencyLogo
'
import
{
Unicon
}
from
'
components/Unicon
'
import
{
getChainInfo
}
from
'
constants/chainInfo
'
import
useTokenLogoSource
from
'
hooks/useAssetLogoSource
'
import
useENSAvatar
from
'
hooks/useENSAvatar
'
import
React
from
'
react
'
import
{
Loader
}
from
'
react-feather
'
import
styled
,
{
useTheme
}
from
'
styled-components
'
import
styled
from
'
styled-components
'
const
UnknownContract
=
styled
(
UnknownStatus
)
`
color:
${({
theme
})
=>
theme
.
textSecondary
}
;
`
...
...
@@ -36,15 +36,6 @@ const DoubleLogoContainer = styled.div`
}
`
type
MultiLogoProps
=
{
chainId
:
ChainId
accountAddress
?:
string
currencies
?:
Array
<
Currency
|
undefined
>
images
?:
(
string
|
undefined
)[]
size
?:
string
style
?:
React
.
CSSProperties
}
const
StyledLogoParentContainer
=
styled
.
div
`
position: relative;
top: 0;
...
...
@@ -73,8 +64,8 @@ const CircleLogoImage = styled.img<{ size: string }>`
border-radius: 50%;
`
const
L2LogoContainer
=
styled
.
div
<
{
$backgroundColor
?:
string
}
>
`
background-color:
${({
$backgroundColor
})
=>
$backgroundColor
}
;
const
L2LogoContainer
=
styled
.
div
<
{
hasSquareLogo
?:
boolean
}
>
`
background-color:
${({
theme
,
hasSquareLogo
})
=>
(
hasSquareLogo
?
theme
.
backgroundSurface
:
theme
.
textPrimary
)
}
;
border-radius: 2px;
height: 16px;
left: 60%;
...
...
@@ -87,81 +78,119 @@ const L2LogoContainer = styled.div<{ $backgroundColor?: string }>`
justify-content: center;
`
/**
* Renders an image by prioritizing a list of sources, and then eventually a fallback triangle alert
*/
export
function
PortfolioLogo
({
chainId
=
ChainId
.
MAINNET
,
accountAddress
,
currencies
,
images
,
size
=
'
40px
'
,
style
,
}:
MultiLogoProps
)
{
const
chainInfo
=
getChainInfo
(
chainId
)
const
squareLogoUrl
=
chainInfo
?.
squareLogoUrl
const
logoUrl
=
chainInfo
?.
logoUrl
const
chainLogo
=
squareLogoUrl
??
logoUrl
const
{
avatar
,
loading
}
=
useENSAvatar
(
accountAddress
,
false
)
const
theme
=
useTheme
()
interface
DoubleLogoProps
{
logo1
?:
string
logo2
?:
string
size
:
string
onError1
?:
()
=>
void
onError2
?:
()
=>
void
}
const
[
src
,
nextSrc
]
=
useTokenLogoSource
(
currencies
?.[
0
]?.
wrapped
.
address
,
chainId
,
currencies
?.[
0
]?.
isNative
)
const
[
src2
,
nextSrc2
]
=
useTokenLogoSource
(
currencies
?.[
1
]?.
wrapped
.
address
,
chainId
,
currencies
?.[
1
]?.
isNative
)
function
DoubleLogo
({
logo1
,
onError1
,
logo2
,
onError2
,
size
}:
DoubleLogoProps
)
{
return
(
<
DoubleLogoContainer
>
<
CircleLogoImage
size=
{
size
}
src=
{
logo1
??
blankTokenUrl
}
onError=
{
onError1
}
/>
<
CircleLogoImage
size=
{
size
}
src=
{
logo2
??
blankTokenUrl
}
onError=
{
onError2
}
/>
</
DoubleLogoContainer
>
)
}
let
component
if
(
accountAddress
)
{
component
=
loading
?
(
<
Loader
size=
{
size
}
/>
)
:
avatar
?
(
<
ENSAvatarImg
src=
{
avatar
}
alt=
"avatar"
/>
)
:
(
<
Unicon
size=
{
40
}
address=
{
accountAddress
}
/>
)
}
else
if
(
currencies
&&
currencies
.
length
)
{
const
logo1
=
<
CircleLogoImage
size=
{
size
}
src=
{
src
??
blankTokenUrl
}
onError=
{
nextSrc
}
/>
const
logo2
=
<
CircleLogoImage
size=
{
size
}
src=
{
src2
??
blankTokenUrl
}
onError=
{
nextSrc2
}
/>
component
=
currencies
.
length
>
1
?
(
<
DoubleLogoContainer
style=
{
style
}
>
{
logo1
}
{
logo2
}
</
DoubleLogoContainer
>
)
:
currencies
.
length
===
1
?
(
<
CurrencyLogo
currency=
{
currencies
[
0
]
}
size=
{
size
}
/>
)
:
(
<
MissingImageLogo
size=
{
size
}
>
{
currencies
[
0
]?.
symbol
?.
toUpperCase
().
replace
(
'
$
'
,
''
).
replace
(
/
\s
+/g
,
''
).
slice
(
0
,
3
)
}
</
MissingImageLogo
>
)
}
else
if
(
images
&&
images
.
length
)
{
component
=
images
.
length
>
1
?
(
<
DoubleLogoContainer
style=
{
style
}
>
<
CircleLogoImage
size=
{
size
}
src=
{
images
[
0
]
}
/>
<
CircleLogoImage
size=
{
size
}
src=
{
images
[
images
.
length
-
1
]
}
/>
</
DoubleLogoContainer
>
)
:
(
<
CircleLogoImage
size=
{
size
}
src=
{
images
[
0
]
}
/>
)
}
else
{
return
<
UnknownContract
width=
{
size
}
height=
{
size
}
/>
interface
DoubleCurrencyLogoProps
{
chainId
:
ChainId
currencies
:
Array
<
Currency
|
undefined
>
backupImages
?:
Array
<
string
|
undefined
>
size
:
string
}
function
DoubleCurrencyLogo
({
chainId
,
currencies
,
backupImages
,
size
}:
DoubleCurrencyLogoProps
)
{
const
[
src
,
nextSrc
]
=
useTokenLogoSource
(
currencies
?.[
0
]?.
wrapped
.
address
,
chainId
,
currencies
?.[
0
]?.
isNative
,
backupImages
?.[
0
]
)
const
[
src2
,
nextSrc2
]
=
useTokenLogoSource
(
currencies
?.[
1
]?.
wrapped
.
address
,
chainId
,
currencies
?.[
1
]?.
isNative
,
backupImages
?.[
1
]
)
if
(
currencies
.
length
===
1
&&
src
)
{
return
<
CircleLogoImage
size=
{
size
}
src=
{
src
}
onError=
{
nextSrc
}
/>
}
if
(
currencies
.
length
>
1
)
{
return
<
DoubleLogo
logo1=
{
src
}
onError1=
{
nextSrc
}
logo2=
{
src2
}
onError2=
{
nextSrc2
}
size=
{
size
}
/>
}
return
(
<
MissingImageLogo
size=
{
size
}
>
{
currencies
[
0
]?.
symbol
?.
toUpperCase
().
replace
(
'
$
'
,
''
).
replace
(
/
\s
+/g
,
''
).
slice
(
0
,
3
)
}
</
MissingImageLogo
>
)
}
function
PortfolioAvatar
({
accountAddress
,
size
}:
{
accountAddress
:
string
;
size
:
string
})
{
const
{
avatar
,
loading
}
=
useENSAvatar
(
accountAddress
,
false
)
if
(
loading
)
{
return
<
Loader
size=
{
size
}
/>
}
if
(
avatar
)
{
return
<
ENSAvatarImg
src=
{
avatar
}
alt=
"avatar"
/>
}
return
<
Unicon
size=
{
40
}
address=
{
accountAddress
}
/>
}
const
L2Logo
=
chainId
!==
ChainId
.
MAINNET
&&
chainLogo
?
(
<
L2LogoContainer
$backgroundColor=
{
squareLogoUrl
?
theme
.
backgroundSurface
:
theme
.
textPrimary
}
>
{
squareLogoUrl
?
(
<
SquareChainLogo
src=
{
chainLogo
}
alt=
"chainLogo"
/>
)
:
(
<
StyledChainLogo
src=
{
chainLogo
}
alt=
"chainLogo"
/>
)
}
</
L2LogoContainer
>
)
:
null
interface
PortfolioLogoProps
{
chainId
:
ChainId
accountAddress
?:
string
currencies
?:
Array
<
Currency
|
undefined
>
images
?:
Array
<
string
|
undefined
>
size
?:
string
style
?:
React
.
CSSProperties
}
function
SquareL2Logo
({
chainId
}:
{
chainId
:
ChainId
})
{
if
(
chainId
===
ChainId
.
MAINNET
)
return
null
const
{
squareLogoUrl
,
logoUrl
}
=
getChainInfo
(
chainId
)
const
chainLogo
=
squareLogoUrl
??
logoUrl
return
(
<
L2LogoContainer
hasSquareLogo=
{
!!
squareLogoUrl
}
>
{
squareLogoUrl
?
(
<
SquareChainLogo
src=
{
chainLogo
}
alt=
"chainLogo"
/>
)
:
(
<
StyledChainLogo
src=
{
chainLogo
}
alt=
"chainLogo"
/>
)
}
</
L2LogoContainer
>
)
}
/**
* Renders an image by prioritizing a list of sources, and then eventually a fallback contract icon
*/
export
function
PortfolioLogo
(
props
:
PortfolioLogoProps
)
{
return
(
<
StyledLogoParentContainer
>
{
component
}
{
L2Logo
}
{
getLogo
(
props
)
}
<
SquareL2Logo
chainId=
{
props
.
chainId
}
/>
</
StyledLogoParentContainer
>
)
}
function
getLogo
({
chainId
,
accountAddress
,
currencies
,
images
,
size
=
'
40px
'
}:
PortfolioLogoProps
)
{
if
(
accountAddress
)
{
return
<
PortfolioAvatar
accountAddress=
{
accountAddress
}
size=
{
size
}
/>
}
if
(
currencies
&&
currencies
.
length
)
{
return
<
DoubleCurrencyLogo
chainId=
{
chainId
}
currencies=
{
currencies
}
backupImages=
{
images
}
size=
{
size
}
/>
}
if
(
images
?.
length
===
1
)
{
return
<
CircleLogoImage
size=
{
size
}
src=
{
images
[
0
]
??
blankTokenUrl
}
/>
}
if
(
images
&&
images
?.
length
>=
2
)
{
return
<
DoubleLogo
logo1=
{
images
[
0
]
}
logo2=
{
images
[
images
.
length
-
1
]
}
size=
{
size
}
/>
}
return
<
UnknownContract
width=
{
size
}
height=
{
size
}
/>
}
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