Skip to content

Feat/umbrella #2321

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 137 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
137 commits
Select commit Hold shift + click to select a range
04c51de
feat: init umbrella
foodaka Jan 9, 2025
7a101b5
feat: separate sections
foodaka Jan 9, 2025
0242e76
feat: init data provider service
grothem Jan 9, 2025
3a3d959
Merge branch 'feat/umbrella' into feat/data-provider-service
grothem Jan 9, 2025
f47be93
fix: addresses
grothem Jan 9, 2025
3c37253
fix: package json
grothem Jan 9, 2025
2a21c6a
feat: updated provider
grothem Jan 10, 2025
fe0dd11
chore: org folders
foodaka Jan 10, 2025
06e18fa
fix: latest provider
grothem Jan 10, 2025
8397972
feat: udated provider
grothem Jan 10, 2025
dc8b0ba
chore: user stake list vars
foodaka Jan 13, 2025
99d8e26
fix: underlying decimals
grothem Jan 13, 2025
59064ae
feat: lint
JoaquinBattilana Jan 15, 2025
74e3c09
feat: added basic selectors
JoaquinBattilana Jan 16, 2025
c020cd7
feat: added new interfaces + types
JoaquinBattilana Jan 16, 2025
4cb9eb4
feat: balance breakdown
foodaka Jan 16, 2025
c2f23c1
feat: basic stake list
JoaquinBattilana Jan 16, 2025
a83d4e1
Feat: merged with main
JoaquinBattilana Jan 16, 2025
26197e6
feat: useUmbrellaSummary
JoaquinBattilana Jan 16, 2025
621d9e5
feat: integrate apy
foodaka Jan 16, 2025
b2304e8
feat: sync conflicts
foodaka Jan 16, 2025
0330be0
chore: fix conflict
foodaka Jan 16, 2025
62a0a1a
feat: basic modal content umbrella
JoaquinBattilana Jan 16, 2025
5734646
Merge branch 'feat/umbrella' of github.com:aave/interface into feat/u…
JoaquinBattilana Jan 16, 2025
3f7ecc2
feat: basic stake tx
JoaquinBattilana Jan 17, 2025
b3fb0fe
chore: fix sort
foodaka Jan 17, 2025
c280955
chore: fix sort
foodaka Jan 17, 2025
94f8bdf
chore: some cleanup
foodaka Jan 17, 2025
43ef57e
feat: multi tokens
grothem Jan 17, 2025
86f5871
feat: list item components
grothem Jan 17, 2025
6cd8c71
fix: cleanup
grothem Jan 17, 2025
fe62df0
feat: underlying stake token info
grothem Jan 17, 2025
f4d5a84
feat: available to claim item
grothem Jan 17, 2025
c073249
feat: updated provider
grothem Jan 17, 2025
d660d46
Merge branch 'feat/umbrella' of github.com:aave/interface into feat/u…
foodaka Jan 20, 2025
251c47d
chore: some cleanup
foodaka Jan 20, 2025
28e2d9e
chore: fix mobile layout
foodaka Jan 20, 2025
81d1a22
chore: some cleanup
foodaka Jan 20, 2025
2fc6b35
chore: cleanup files
foodaka Jan 20, 2025
040d053
feat: action buttons
grothem Jan 21, 2025
62003de
feat: amount staked, token price
grothem Jan 21, 2025
32a2140
feat: net umbrella balance
foodaka Jan 22, 2025
6a9ec3f
chore: sync changes
foodaka Jan 22, 2025
eea55b3
feat: apys
foodaka Jan 22, 2025
500bae0
fix: apy
foodaka Jan 22, 2025
5356bb3
feat: cooldown
grothem Jan 22, 2025
7ff0402
fix: build
grothem Jan 22, 2025
1665de7
feat: basic permit functions
JoaquinBattilana Jan 23, 2025
b1ad21a
feat: eslint
JoaquinBattilana Jan 23, 2025
2a13c79
Feat: merge with base
JoaquinBattilana Jan 23, 2025
18dddb3
feat: dropdown actions
foodaka Jan 23, 2025
65ae2b2
feat: sync cooldown
foodaka Jan 23, 2025
932096e
feat: cleanup
foodaka Jan 23, 2025
f35226d
chore: type fixes
foodaka Jan 23, 2025
1648017
fix: mobile views
foodaka Jan 23, 2025
861f7cc
fix: loading states
foodaka Jan 24, 2025
a3dcdad
feat: basic umbrella claim modal
JoaquinBattilana Jan 24, 2025
e0d19b1
Merge branch 'feat/umbrella' of github.com:aave/interface into feat/u…
JoaquinBattilana Jan 24, 2025
6b34886
feat: unstake, stake token service
grothem Jan 24, 2025
c10ec97
Merge branch 'feat/umbrella' of github.com:aave/interface into feat/u…
foodaka Jan 27, 2025
3c8078d
fix: search umbrella assets
foodaka Jan 27, 2025
8d4cf4e
feat: cooldown and unstake time
grothem Jan 28, 2025
e7ff5e6
fix: cooldown timers
grothem Jan 28, 2025
3a4a24f
fix: apy tooltips
grothem Jan 28, 2025
ec99536
feat: claim txs
JoaquinBattilana Jan 28, 2025
d985926
feat: merged with main
JoaquinBattilana Jan 28, 2025
698dfdb
feat: lint fix
JoaquinBattilana Jan 28, 2025
ef77f3b
fix: claim tooltip
grothem Jan 28, 2025
dabc5be
fix: cooldown buttons
grothem Jan 28, 2025
970e91d
feat: ui cleanup
grothem Jan 29, 2025
63bcd7a
Merge branch 'feat/umbrella' of github.com:aave/interface into feat/u…
foodaka Jan 29, 2025
d60ef98
fix: sorting
foodaka Jan 29, 2025
6e781f7
feat: preview redeem
grothem Jan 30, 2025
af05fe3
Merge branch 'feat/umbrella' of github.com:aave/interface into feat/u…
foodaka Jan 30, 2025
c631b52
fix: token icons
foodaka Jan 30, 2025
9e235d9
feat: check balance on aTokens (#2327)
foodaka Jan 30, 2025
5d7ee7e
Merge branch 'feat/umbrella' of github.com:aave/interface into feat/u…
foodaka Jan 30, 2025
5d32ba0
fix: token symbol
grothem Jan 30, 2025
62bde3b
feat: show hf change on stake
grothem Jan 31, 2025
f9f1c56
fix: token spacing
grothem Jan 31, 2025
1a5d504
fix: icon color
grothem Jan 31, 2025
b5cdc7d
fix: cooldown
grothem Jan 31, 2025
1e6405d
fix: cleanup
grothem Jan 31, 2025
cb9037d
fix: non waToken stake
grothem Jan 31, 2025
0b57a41
fix: cleanup
grothem Feb 3, 2025
37b41ec
Feat: updated stake gateway
JoaquinBattilana Feb 3, 2025
85ae8c6
fix: cursor
grothem Feb 3, 2025
5c1c33a
fix: mobile, cleanup
grothem Feb 3, 2025
9ab4a39
fix: column width
grothem Feb 3, 2025
e18457e
fix: timers
grothem Feb 3, 2025
7d08dc3
feat: no connected account view
grothem Feb 5, 2025
e233198
Merge branch 'feat/umbrella' of github.com:aave/interface into feat/u…
foodaka Feb 5, 2025
a54ed31
feat: mobile default view
grothem Feb 5, 2025
3ccca89
feat: default header
grothem Feb 5, 2025
bcd6675
Merge branch 'feat/umbrella' of github.com:aave/interface into feat/u…
foodaka Feb 5, 2025
be0d489
feat: no assets configured message
grothem Feb 5, 2025
e8e04fa
fix: skeleton loaders
grothem Feb 5, 2025
8c8efb5
Feat/deployment sep umbrella (#2337)
foodaka Feb 5, 2025
27e0f92
fix: lint
grothem Feb 5, 2025
a0205aa
fix: cleanup
grothem Feb 6, 2025
163e48b
Merge branch 'feat/umbrella' of github.com:aave/interface into feat/u…
foodaka Feb 6, 2025
71f7b3a
fix: adds whitespace
foodaka Feb 6, 2025
37ffbc0
fix: approval amounts
grothem Feb 6, 2025
dfb5f35
Merge branch 'feat/umbrella' of github.com:aave/interface into feat/u…
foodaka Feb 6, 2025
9c30490
fix: summary calc cleanup
grothem Feb 6, 2025
cfe4f03
fix: allow claim if unclaimed rewards
grothem Feb 6, 2025
2b048c3
fix: aToken balance available to stake
grothem Feb 6, 2025
8c92735
Merge branch 'feat/umbrella' of github.com:aave/interface into feat/u…
foodaka Feb 7, 2025
70236f6
Feat/umbrella utils (#2366)
JoaquinBattilana Feb 18, 2025
8f6eb54
fix: helpers
grothem Feb 17, 2025
a20993d
fix: waToken rename
grothem Feb 18, 2025
ee0907d
Merge branch 'main' into feat/umbrella
grothem Feb 18, 2025
5b15bae
fix: wa token naming
grothem Feb 18, 2025
91c2bba
feat: stake native tokens
JoaquinBattilana Feb 19, 2025
8929d64
Merge branch 'feat/umbrella' of github.com:aave/interface into feat/u…
foodaka Feb 19, 2025
43cc586
feat: redeem as eth
JoaquinBattilana Feb 19, 2025
2e868e2
feat: usePoolOracles and claim usd amount
JoaquinBattilana Feb 19, 2025
4425c2a
feat: order stake assets in modal by balance + naming underlying no s…
JoaquinBattilana Feb 19, 2025
91d2ad1
feat: preview stake amount
grothem Feb 19, 2025
6a4a2c6
Merge branch 'feat/umbrella' of github.com:aave/interface into feat/u…
foodaka Feb 20, 2025
f0249ed
chore: move rewards umbrella to stake config
foodaka Feb 20, 2025
d520e6e
Merge branch 'feat/umbrella' of github.com:aave/interface into feat/u…
JoaquinBattilana Feb 27, 2025
ce65881
feat: icons
JoaquinBattilana Feb 27, 2025
0f633bd
feat: updated data provider
grothem Mar 3, 2025
af9b3ba
Merge branch 'feat/umbrella' of github.com:aave/interface into feat/u…
JoaquinBattilana Mar 3, 2025
0b1c6bb
feat: added new batch contract
JoaquinBattilana Mar 3, 2025
3580c34
fix: preview
grothem Mar 3, 2025
b24d1c4
fix: reward prices
grothem Mar 4, 2025
c63d9b7
feat: merged with main
JoaquinBattilana Mar 24, 2025
a740a73
Feat/umbrella final (#2406)
JoaquinBattilana Apr 2, 2025
f024bfb
Merge branch 'main' into feat/umbrella
grothem Apr 2, 2025
f9e0a72
fix: package json
grothem Apr 2, 2025
9d217b5
fix: updated provider
grothem Apr 2, 2025
6bac5ee
fix: removed add to wallet action
grothem Apr 3, 2025
f4549d8
fix: search
grothem Apr 3, 2025
ade38f1
fix: gas estimation
grothem Apr 3, 2025
7624fdd
feat: claim all
grothem Apr 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
"test:coverage": "jest --coverage"
},
"dependencies": {
"@aave/contract-helpers": "1.33.1",
"@aave/math-utils": "1.33.1",
"@aave/contract-helpers": "1.33.2-5d41c2b71aef3dc0142968e2c61bb997a1daef78.0+bbfe1c8",
"@aave/math-utils": "1.33.2-5d41c2b71aef3dc0142968e2c61bb997a1daef78.0+bbfe1c8",
"@bgd-labs/aave-address-book": "^4.17.1",
"@emotion/cache": "11.10.3",
"@emotion/react": "11.10.4",
Expand Down
60 changes: 60 additions & 0 deletions pages/umbrella.page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import dynamic from 'next/dynamic';
import { ContentContainer } from 'src/components/ContentContainer';
import { MainLayout } from 'src/layouts/MainLayout';
import { UmbrellaAssetsListContainer } from 'src/modules/umbrella/StakeAssets/UmbrellaAssetsListContainer';
import { UmrellaAssetsDefaultListContainer } from 'src/modules/umbrella/UmbrellaAssetsDefault';
import { UmbrellaHeader } from 'src/modules/umbrella/UmbrellaHeader';

import { useWeb3Context } from '../src/libs/hooks/useWeb3Context';

const UmbrellaStakeModal = dynamic(() =>
import('../src/modules/umbrella/UmbrellaModal').then((module) => module.UmbrellaModal)
);
const StakeCooldownModal = dynamic(() =>
import('../src/modules/umbrella/StakeCooldownModal').then((module) => module.StakeCooldownModal)
);
const StakeRewardClaimModal = dynamic(() =>
import('../src/components/transactions/StakeRewardClaim/StakeRewardClaimModal').then(
(module) => module.StakeRewardClaimModal
)
);
const StakeRewardClaimRestakeModal = dynamic(() =>
import(
'../src/components/transactions/StakeRewardClaimRestake/StakeRewardClaimRestakeModal'
).then((module) => module.StakeRewardClaimRestakeModal)
);
const UnStakeModal = dynamic(() =>
import('../src/modules/umbrella/UnstakeModal').then((module) => module.UnStakeModal)
);
const UmbrellaClaimModal = dynamic(() =>
import('../src/modules/umbrella/UmbrellaClaimModal').then((module) => module.UmbrellaClaimModal)
);

export default function UmbrellaStaking() {
const { currentAccount } = useWeb3Context();

return (
<>
<UmbrellaHeader />
<ContentContainer>
{currentAccount ? <UmbrellaAssetsListContainer /> : <UmrellaAssetsDefaultListContainer />}
</ContentContainer>
</>
);
}

UmbrellaStaking.getLayout = function getLayout(page: React.ReactElement) {
return (
<MainLayout>
{page}
{/** Modals */}
<UmbrellaStakeModal />
<StakeCooldownModal />
<UnStakeModal />
<StakeRewardClaimModal />
<StakeRewardClaimRestakeModal />
<UmbrellaClaimModal />
{/** End of modals */}
</MainLayout>
);
};
14 changes: 10 additions & 4 deletions src/components/Warnings/CooldownWarning.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { Trans } from '@lingui/macro';
import { Typography } from '@mui/material';
import { SecondsToString } from 'src/modules/staking/StakingPanel';
import { useRootStore } from 'src/store/root';
import { GENERAL } from 'src/utils/mixPanelEvents';

import { Link } from '../primitives/Link';
import { Warning } from '../primitives/Warning';

export const CooldownWarning = () => {
const TWENTY_DAYS = 20 * 24 * 60 * 60;

export const CooldownWarning = ({ cooldownSeconds }: { cooldownSeconds?: number }) => {
const cooldownTime = cooldownSeconds || TWENTY_DAYS;

const trackEvent = useRootStore((store) => store.trackEvent);
return (
<Warning severity="warning" sx={{ '.MuiAlert-message': { p: 0 }, mb: 6 }}>
Expand All @@ -15,9 +20,10 @@ export const CooldownWarning = () => {
</Typography>
<Typography variant="caption">
<Trans>
The cooldown period is the time required prior to unstaking your tokens (20 days). You can
only withdraw your assets from the Security Module after the cooldown period and within
the unstake window.
The cooldown period is the time required prior to unstaking your tokens (
<SecondsToString seconds={cooldownTime} />
). You can only withdraw your assets from the Security Module after the cooldown period
and within the unstake window.{' '}
<Link
href="https://docs.aave.com/faq/migration-and-staking"
fontWeight={500}
Expand Down
15 changes: 15 additions & 0 deletions src/components/infoTooltips/TokenContractTooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { ExternalLinkIcon } from '@heroicons/react/outline';
import { IconButton, SvgIcon } from '@mui/material';

import { Link } from '../primitives/Link';
import { DarkTooltip } from './DarkTooltip';

export const TokenContractTooltip = ({ explorerUrl }: { explorerUrl: string }) => (
<DarkTooltip title="View token contract" sx={{ display: { xsm: 'none' } }}>
<IconButton LinkComponent={Link} href={explorerUrl} sx={{ height: '24px', width: '24px' }}>
<SvgIcon sx={{ fontSize: '14px' }}>
<ExternalLinkIcon />
</SvgIcon>
</IconButton>
</DarkTooltip>
);
1 change: 1 addition & 0 deletions src/components/primitives/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,5 @@ export const ROUTES = {
`/reserve-overview/?underlyingAsset=${underlyingAsset}&marketName=${marketName}`,
history: '/history',
bridge: '/bridge',
umbrella: '/umbrella',
};
110 changes: 77 additions & 33 deletions src/components/primitives/TokenIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@ import { Badge, Box, Icon, IconProps } from '@mui/material';
import { forwardRef, useEffect, useRef, useState } from 'react';
import LazyLoad from 'react-lazy-load';

interface ATokenIconProps {
symbol?: string;
}

/**
* To save some bundle size we stopped base64 encoding & inlining svgs as base encoding increases size by up to 30%
* and most users will never need all token icons.
Expand All @@ -21,22 +17,30 @@ interface ATokenIconProps {
* This component is probably hugely over engineered & unnecessary.
* I'm looking forward for the pr which evicts it.
*/
interface ATokenIconProps {
symbol?: string;
waToken?: boolean; // Add waToken prop
}

// Modified Base64Token to support waToken
export function Base64Token({
symbol,
onImageGenerated,
aToken,
waToken,
}: {
symbol: string;
aToken?: boolean;
waToken?: boolean;
onImageGenerated: (base64: string) => void;
}) {
const ref = useRef<HTMLObjectElement>(null);
const aRef = useRef<SVGSVGElement>(null);
const tokenRef = useRef<SVGSVGElement>(null);

const [loading, setLoading] = useState(true);
useEffect(() => {
if (!loading && ref.current && ref.current?.contentDocument) {
if (aToken) {
if (aToken || waToken) {
// eslint-disable-next-line
const inner = ref.current?.contentDocument?.childNodes?.[0] as any;
const oldWidth = inner.getAttribute('width');
Expand All @@ -50,8 +54,8 @@ export function Base64Token({
inner.setAttribute('viewBox', `0 0 ${oldWidth} ${oldHeight}`);
}

aRef.current?.appendChild(inner);
const s = new XMLSerializer().serializeToString(aRef.current as unknown as Node);
tokenRef.current?.appendChild(inner);
const s = new XMLSerializer().serializeToString(tokenRef.current as unknown as Node);

onImageGenerated(
`data:image/svg+xml;base64,${window.btoa(unescape(encodeURIComponent(s)))}`
Expand All @@ -63,7 +67,7 @@ export function Base64Token({
);
}
}
}, [loading, aToken]);
}, [loading, aToken, waToken]);
return (
<div
style={{
Expand All @@ -80,12 +84,13 @@ export function Base64Token({
data={`/icons/tokens/${symbol.toLowerCase()}.svg`}
onLoad={() => setLoading(false)}
/>
{aToken && <ATokenIcon ref={aRef} />}
{(aToken || waToken) && <TokenRing ref={tokenRef} waToken={waToken} />}
</div>
);
}

export const ATokenIcon = forwardRef<SVGSVGElement, ATokenIconProps>(({ symbol }, ref) => {
// Renamed from ATokenIcon to TokenRing to better reflect its purpose
export const TokenRing = forwardRef<SVGSVGElement, ATokenIconProps>(({ symbol, waToken }, ref) => {
return (
<svg
style={{
Expand Down Expand Up @@ -113,14 +118,26 @@ export const ATokenIcon = forwardRef<SVGSVGElement, ATokenIconProps>(({ symbol }
<stop offset="0" stopColor="#b6509e" id="stop2" />
<stop offset="1" stopColor="#2ebac6" id="stop4" />
</linearGradient>
<linearGradient id="linear-gradient-2" x1=".907" x2=".163" y1=".227" y2=".853" />
</defs>
<g id="Group_29109">
<path
id="Subtraction_108"
fill="url(#linear-gradient)"
d="M128 256a128.976 128.976 0 0 1-25.8-2.6 127.309 127.309 0 0 1-45.77-19.261 128.366 128.366 0 0 1-46.375-56.315A127.357 127.357 0 0 1 2.6 153.8a129.251 129.251 0 0 1 0-51.593 127.31 127.31 0 0 1 19.26-45.77 128.372 128.372 0 0 1 56.317-46.378A127.33 127.33 0 0 1 102.2 2.6a129.244 129.244 0 0 1 51.593 0 127.308 127.308 0 0 1 45.77 19.26 128.367 128.367 0 0 1 46.375 56.316A127.343 127.343 0 0 1 253.4 102.2a129.248 129.248 0 0 1 0 51.593 127.3 127.3 0 0 1-19.26 45.77 128.382 128.382 0 0 1-56.316 46.375A127.4 127.4 0 0 1 153.8 253.4 128.977 128.977 0 0 1 128 256zm0-242.287a115.145 115.145 0 0 0-23.033 2.322A113.657 113.657 0 0 0 64.1 33.232a114.622 114.622 0 0 0-41.4 50.283 113.7 113.7 0 0 0-6.659 21.452 115.4 115.4 0 0 0 0 46.065 113.66 113.66 0 0 0 17.2 40.866 114.627 114.627 0 0 0 50.282 41.407 113.75 113.75 0 0 0 21.453 6.658 115.381 115.381 0 0 0 46.065 0 113.609 113.609 0 0 0 40.866-17.2 114.622 114.622 0 0 0 41.393-50.278 113.741 113.741 0 0 0 6.659-21.453 115.4 115.4 0 0 0 0-46.065 113.662 113.662 0 0 0-17.2-40.865A114.619 114.619 0 0 0 172.485 22.7a113.74 113.74 0 0 0-21.453-6.659A115.145 115.145 0 0 0 128 13.714z"
/>
{waToken ? (
// Dotted border path for waToken
<path
id="Subtraction_108"
fill="none"
stroke="url(#linear-gradient)"
strokeWidth="13.713"
strokeDasharray="8,8"
d="M128 256a128.976 128.976 0 0 1-25.8-2.6 127.309 127.309 0 0 1-45.77-19.261 128.366 128.366 0 0 1-46.375-56.315A127.357 127.357 0 0 1 2.6 153.8a129.251 129.251 0 0 1 0-51.593 127.31 127.31 0 0 1 19.26-45.77 128.372 128.372 0 0 1 56.317-46.378A127.33 127.33 0 0 1 102.2 2.6a129.244 129.244 0 0 1 51.593 0 127.308 127.308 0 0 1 45.77 19.26 128.367 128.367 0 0 1 46.375 56.316A127.343 127.343 0 0 1 253.4 102.2a129.248 129.248 0 0 1 0 51.593 127.3 127.3 0 0 1-19.26 45.77 128.382 128.382 0 0 1-56.316 46.375A127.4 127.4 0 0 1 153.8 253.4 128.977 128.977 0 0 1 128 256z"
/>
) : (
// Original filled path for aToken
<path
id="Subtraction_108"
fill="url(#linear-gradient)"
d="M128 256a128.976 128.976 0 0 1-25.8-2.6 127.309 127.309 0 0 1-45.77-19.261 128.366 128.366 0 0 1-46.375-56.315A127.357 127.357 0 0 1 2.6 153.8a129.251 129.251 0 0 1 0-51.593 127.31 127.31 0 0 1 19.26-45.77 128.372 128.372 0 0 1 56.317-46.378A127.33 127.33 0 0 1 102.2 2.6a129.244 129.244 0 0 1 51.593 0 127.308 127.308 0 0 1 45.77 19.26 128.367 128.367 0 0 1 46.375 56.316A127.343 127.343 0 0 1 253.4 102.2a129.248 129.248 0 0 1 0 51.593 127.3 127.3 0 0 1-19.26 45.77 128.382 128.382 0 0 1-56.316 46.375A127.4 127.4 0 0 1 153.8 253.4 128.977 128.977 0 0 1 128 256zm0-242.287a115.145 115.145 0 0 0-23.033 2.322A113.657 113.657 0 0 0 64.1 33.232a114.622 114.622 0 0 0-41.4 50.283 113.7 113.7 0 0 0-6.659 21.452 115.4 115.4 0 0 0 0 46.065 113.66 113.66 0 0 0 17.2 40.866 114.627 114.627 0 0 0 50.282 41.407 113.75 113.75 0 0 0 21.453 6.658 115.381 115.381 0 0 0 46.065 0 113.609 113.609 0 0 0 40.866-17.2 114.622 114.622 0 0 0 41.393-50.278 113.741 113.741 0 0 0 6.659-21.453 115.4 115.4 0 0 0 0-46.065 113.662 113.662 0 0 0-17.2-40.865A114.619 114.619 0 0 0 172.485 22.7a113.74 113.74 0 0 0-21.453-6.659A115.145 115.145 0 0 0 128 13.714z"
/>
)}
{symbol && (
<image
x="25"
Expand All @@ -134,20 +151,17 @@ export const ATokenIcon = forwardRef<SVGSVGElement, ATokenIconProps>(({ symbol }
</svg>
);
});
ATokenIcon.displayName = 'ATokenIcon';
TokenRing.displayName = 'TokenRing';

interface TokenIconProps extends IconProps {
symbol: string;
aToken?: boolean;
waToken?: boolean;
aTokens?: boolean[];
waTokens?: boolean[];
}

/**
* Renders a tokenIcon specified by symbol.
* TokenIcons are expected to be located at /public/icons/tokens and lowercase named <symbol>.svg
* @param param0
* @returns
*/
function SingleTokenIcon({ symbol, aToken, ...rest }: TokenIconProps) {
function SingleTokenIcon({ symbol, aToken, waToken, ...rest }: TokenIconProps) {
const [tokenSymbol, setTokenSymbol] = useState(symbol.toLowerCase());

useEffect(() => {
Expand All @@ -156,10 +170,9 @@ function SingleTokenIcon({ symbol, aToken, ...rest }: TokenIconProps) {

return (
<Icon {...rest} sx={{ display: 'flex', position: 'relative', borderRadius: '50%', ...rest.sx }}>
{aToken ? (
<ATokenIcon symbol={tokenSymbol} />
{aToken || waToken ? (
<TokenRing symbol={tokenSymbol} waToken={waToken} />
) : (
// eslint-disable-next-line
<img
src={`/icons/tokens/${tokenSymbol}.svg`}
onError={() => setTokenSymbol('default')}
Expand Down Expand Up @@ -205,9 +218,23 @@ interface MultiTokenIconProps extends IconProps {
symbols: string[];
badgeSymbol?: string;
aToken?: boolean;
waToken?: boolean;
aTokens?: boolean[];
waTokens?: boolean[];
}

export function MultiTokenIcon({ symbols, badgeSymbol, ...rest }: MultiTokenIconProps) {
export function MultiTokenIcon({
symbols,
badgeSymbol,
aToken = false,
waToken = false,
aTokens: providedATokens,
waTokens: providedWaTokens,
...rest
}: MultiTokenIconProps) {
const aTokens = providedATokens || symbols.map((_, index) => (index === 0 ? aToken : false));
const waTokens = providedWaTokens || symbols.map((_, index) => (index === 0 ? waToken : false));

if (!badgeSymbol)
return (
<Box sx={{ display: 'inline-flex', position: 'relative' }}>
Expand All @@ -216,6 +243,8 @@ export function MultiTokenIcon({ symbols, badgeSymbol, ...rest }: MultiTokenIcon
{...rest}
key={symbol}
symbol={symbol}
aToken={aTokens[ix]}
waToken={waTokens[ix]}
sx={{ ml: ix === 0 ? 0 : `calc(-1 * 0.5em)`, ...rest.sx }}
/>
))}
Expand All @@ -233,18 +262,33 @@ export function MultiTokenIcon({ symbols, badgeSymbol, ...rest }: MultiTokenIcon
{...rest}
key={symbol}
symbol={symbol}
aToken={aTokens[ix]}
waToken={waTokens[ix]}
sx={{ ml: ix === 0 ? 0 : 'calc(-1 * 0.5em)', ...rest.sx }}
/>
))}
</Badge>
);
}

export function TokenIcon({ symbol, ...rest }: TokenIconProps) {
export function TokenIcon({ symbol, aToken, waToken, aTokens, waTokens, ...rest }: TokenIconProps) {
const symbolChunks = symbol.split('_');
if (symbolChunks.length > 1) {
const [badge, ...symbols] = symbolChunks;
return <MultiTokenIcon {...rest} symbols={symbols} badgeSymbol={'/pools/' + badge} />;
if (symbolChunks[0].startsWith('pools/')) {
const [badge, ...symbols] = symbolChunks;
return <MultiTokenIcon {...rest} symbols={symbols} badgeSymbol={'/pools/' + badge} />;
}
return (
<MultiTokenIcon
{...rest}
symbols={symbolChunks}
aToken={aToken}
waToken={waToken}
aTokens={aTokens}
waTokens={waTokens}
/>
);
}
return <SingleTokenIcon symbol={symbol} {...rest} />;

return <SingleTokenIcon symbol={symbol} aToken={aToken} waToken={waToken} {...rest} />;
}
4 changes: 3 additions & 1 deletion src/components/transactions/ClaimRewards/RewardsSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import { Reward } from 'src/helpers/types';
import { FormattedNumber } from '../../primitives/FormattedNumber';
import { TokenIcon } from '../../primitives/TokenIcon';

export type RewardSelect = Pick<Reward, 'symbol' | 'balanceUsd'>;

export type RewardsSelectProps = {
rewards: Reward[];
rewards: RewardSelect[];
setSelectedReward: (key: string) => void;
selectedReward: string;
};
Expand Down
Loading
Loading