chore(governance): vesting balances (#5237)
Co-authored-by: Madalina Raicu <madalina@raygroup.uk>
This commit is contained in:
parent
3294c0cabe
commit
1a7682c3c9
@ -302,14 +302,17 @@ context(
|
|||||||
|
|
||||||
cy.getByTestId(vegaWalletCurrencyTitle)
|
cy.getByTestId(vegaWalletCurrencyTitle)
|
||||||
.contains(name)
|
.contains(name)
|
||||||
.parent()
|
.parent() // back to currency-title
|
||||||
.siblings(txTimeout)
|
.parent() // back to container
|
||||||
.should((elementAmount) => {
|
.within(() => {
|
||||||
const displayedAmount = parseFloat(elementAmount.text());
|
cy.get(
|
||||||
// @ts-ignore clash between jest and cypress
|
'[data-account-type="account_type_general"] [data-value]'
|
||||||
expect(displayedAmount).be.gte(expectedAmount);
|
).should((elementAmount) => {
|
||||||
|
const displayedAmount = parseFloat(elementAmount.text());
|
||||||
|
// @ts-ignore clash between jest and cypress
|
||||||
|
expect(displayedAmount).be.gte(expectedAmount);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.getByTestId(vegaWalletCurrencyTitle)
|
cy.getByTestId(vegaWalletCurrencyTitle)
|
||||||
.contains(name)
|
.contains(name)
|
||||||
.parent()
|
.parent()
|
||||||
|
@ -256,10 +256,7 @@ export function validateWalletCurrency(
|
|||||||
.parent()
|
.parent()
|
||||||
.parent()
|
.parent()
|
||||||
.within(() => {
|
.within(() => {
|
||||||
cy.getByTestId('currency-value', txTimeout).should(
|
cy.get('[data-value]', txTimeout).should('have.text', expectedAmount);
|
||||||
'have.text',
|
|
||||||
expectedAmount
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,6 +114,16 @@ export const usePollForDelegations = () => {
|
|||||||
isAssetTypeERC20(a.asset) &&
|
isAssetTypeERC20(a.asset) &&
|
||||||
a.asset.source.contractAddress === vegaToken.address;
|
a.asset.source.contractAddress === vegaToken.address;
|
||||||
|
|
||||||
|
const isVesting =
|
||||||
|
a.type === Schema.AccountType.ACCOUNT_TYPE_VESTED_REWARDS ||
|
||||||
|
a.type === Schema.AccountType.ACCOUNT_TYPE_VESTING_REWARDS;
|
||||||
|
|
||||||
|
let icon = noIcon;
|
||||||
|
if (isVega) {
|
||||||
|
if (isVesting) icon = vegaVesting;
|
||||||
|
else icon = vegaBlack;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isVega,
|
isVega,
|
||||||
name: a.asset.name,
|
name: a.asset.name,
|
||||||
@ -124,14 +134,7 @@ export const usePollForDelegations = () => {
|
|||||||
balance: new BigNumber(
|
balance: new BigNumber(
|
||||||
addDecimal(a.balance, a.asset.decimals)
|
addDecimal(a.balance, a.asset.decimals)
|
||||||
),
|
),
|
||||||
image: isVega
|
image: icon,
|
||||||
? vegaBlack
|
|
||||||
: a.type ===
|
|
||||||
Schema.AccountType.ACCOUNT_TYPE_VESTED_REWARDS ||
|
|
||||||
a.type ===
|
|
||||||
Schema.AccountType.ACCOUNT_TYPE_VESTING_REWARDS
|
|
||||||
? vegaVesting
|
|
||||||
: noIcon,
|
|
||||||
border: isVega,
|
border: isVega,
|
||||||
address: isAssetTypeERC20(a.asset)
|
address: isAssetTypeERC20(a.asset)
|
||||||
? a.asset.source.contractAddress
|
? a.asset.source.contractAddress
|
||||||
|
@ -11,7 +11,10 @@ import { BigNumber } from '../../lib/bignumber';
|
|||||||
import { truncateMiddle } from '../../lib/truncate-middle';
|
import { truncateMiddle } from '../../lib/truncate-middle';
|
||||||
import Routes from '../../routes/routes';
|
import Routes from '../../routes/routes';
|
||||||
import { BulletHeader } from '../bullet-header';
|
import { BulletHeader } from '../bullet-header';
|
||||||
import type { WalletCardAssetProps } from '../wallet-card';
|
import type {
|
||||||
|
WalletCardAssetProps,
|
||||||
|
WalletCardAssetWithMultipleBalancesProps,
|
||||||
|
} from '../wallet-card';
|
||||||
import {
|
import {
|
||||||
WalletCard,
|
WalletCard,
|
||||||
WalletCardActions,
|
WalletCardActions,
|
||||||
@ -27,6 +30,7 @@ import { Button, ButtonLink } from '@vegaprotocol/ui-toolkit';
|
|||||||
import { toBigNum } from '@vegaprotocol/utils';
|
import { toBigNum } from '@vegaprotocol/utils';
|
||||||
import { usePendingBalancesStore } from '../../hooks/use-pending-balances-manager';
|
import { usePendingBalancesStore } from '../../hooks/use-pending-balances-manager';
|
||||||
import { StakingEventType } from '../../hooks/use-get-association-breakdown';
|
import { StakingEventType } from '../../hooks/use-get-association-breakdown';
|
||||||
|
import omit from 'lodash/omit';
|
||||||
|
|
||||||
export const VegaWallet = () => {
|
export const VegaWallet = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -99,12 +103,29 @@ const VegaWalletAssetList = ({ accounts }: VegaWalletAssetsListProps) => {
|
|||||||
if (!accounts.length) {
|
if (!accounts.length) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const groupedByAsset = accounts.reduce((all, a) => {
|
||||||
|
const foundIndex = all.findIndex((acc) => acc.assetId === a.assetId);
|
||||||
|
if (foundIndex > -1) {
|
||||||
|
const found = all[foundIndex];
|
||||||
|
all[foundIndex] = {
|
||||||
|
...found,
|
||||||
|
balances: [...found.balances, { balance: a.balance, type: a.type }],
|
||||||
|
};
|
||||||
|
return all;
|
||||||
|
}
|
||||||
|
const acc = {
|
||||||
|
...omit(a, 'balance', 'type'),
|
||||||
|
balances: [{ balance: a.balance, type: a.type }],
|
||||||
|
};
|
||||||
|
return [...all, acc];
|
||||||
|
}, [] as WalletCardAssetWithMultipleBalancesProps[]);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<WalletCardHeader>
|
<WalletCardHeader>
|
||||||
<BulletHeader tag="h2">{t('assets')}</BulletHeader>
|
<BulletHeader tag="h2">{t('assets')}</BulletHeader>
|
||||||
</WalletCardHeader>
|
</WalletCardHeader>
|
||||||
{accounts.map((a, i) => (
|
{groupedByAsset.map((a, i) => (
|
||||||
<WalletCardAsset key={i} {...a} />
|
<WalletCardAsset key={i} {...a} />
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
@ -182,6 +203,7 @@ const VegaWalletConnected = ({ vegaKeys }: VegaWalletConnectedProps) => {
|
|||||||
subheading={t('Associated')}
|
subheading={t('Associated')}
|
||||||
symbol="VEGA"
|
symbol="VEGA"
|
||||||
balance={currentStakeAvailable}
|
balance={currentStakeAvailable}
|
||||||
|
allowZeroBalance={true}
|
||||||
/>
|
/>
|
||||||
{totalPending.eq(0) ? null : (
|
{totalPending.eq(0) ? null : (
|
||||||
<>
|
<>
|
||||||
@ -192,6 +214,7 @@ const VegaWalletConnected = ({ vegaKeys }: VegaWalletConnectedProps) => {
|
|||||||
subheading={t('Pending association')}
|
subheading={t('Pending association')}
|
||||||
symbol="VEGA"
|
symbol="VEGA"
|
||||||
balance={totalPending}
|
balance={totalPending}
|
||||||
|
allowZeroBalance={true}
|
||||||
/>
|
/>
|
||||||
<WalletCardAsset
|
<WalletCardAsset
|
||||||
image={vegaWhite}
|
image={vegaWhite}
|
||||||
@ -200,6 +223,7 @@ const VegaWalletConnected = ({ vegaKeys }: VegaWalletConnectedProps) => {
|
|||||||
subheading={t('Total associated after pending')}
|
subheading={t('Total associated after pending')}
|
||||||
symbol="VEGA"
|
symbol="VEGA"
|
||||||
balance={pendingStakeAmount}
|
balance={pendingStakeAmount}
|
||||||
|
allowZeroBalance={true}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
@ -103,7 +103,7 @@ export const WalletCardActions = ({
|
|||||||
return <div className="flex justify-end gap-2 mb-4">{children}</div>;
|
return <div className="flex justify-end gap-2 mb-4">{children}</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface WalletCardAssetProps {
|
export type WalletCardAssetProps = {
|
||||||
image: string;
|
image: string;
|
||||||
name: string;
|
name: string;
|
||||||
symbol: string;
|
symbol: string;
|
||||||
@ -113,42 +113,61 @@ export interface WalletCardAssetProps {
|
|||||||
border?: boolean;
|
border?: boolean;
|
||||||
subheading?: string;
|
subheading?: string;
|
||||||
type?: Schema.AccountType;
|
type?: Schema.AccountType;
|
||||||
}
|
allowZeroBalance?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WalletCardAssetWithMultipleBalancesProps = Omit<
|
||||||
|
WalletCardAssetProps,
|
||||||
|
'balance' | 'type'
|
||||||
|
> & {
|
||||||
|
balances: { balance: BigNumber; type?: Schema.AccountType }[];
|
||||||
|
};
|
||||||
|
|
||||||
export const WalletCardAsset = ({
|
export const WalletCardAsset = ({
|
||||||
image,
|
image,
|
||||||
name,
|
name,
|
||||||
symbol,
|
symbol,
|
||||||
balance,
|
|
||||||
decimals,
|
decimals,
|
||||||
assetId,
|
assetId,
|
||||||
border,
|
border,
|
||||||
subheading,
|
subheading,
|
||||||
type,
|
allowZeroBalance = false,
|
||||||
}: WalletCardAssetProps) => {
|
...props
|
||||||
const [integers, decimalsPlaces, separator] = useNumberParts(
|
}: WalletCardAssetProps | WalletCardAssetWithMultipleBalancesProps) => {
|
||||||
balance,
|
const balance = 'balance' in props ? props.balance : undefined;
|
||||||
decimals
|
const type = 'type' in props ? props.type : undefined;
|
||||||
);
|
const balances =
|
||||||
const { t } = useTranslation();
|
'balances' in props
|
||||||
const consoleLink = useLinks(DApp.Console);
|
? props.balances
|
||||||
const transferAssetLink = (assetId: string) =>
|
: balance
|
||||||
consoleLink(CONSOLE_TRANSFER_ASSET.replace(':assetId', assetId));
|
? [{ balance, type }]
|
||||||
const { param: baseRate } = useNetworkParam('rewards_vesting_baseRate');
|
: undefined;
|
||||||
|
|
||||||
const isRedeemable =
|
const values =
|
||||||
type === Schema.AccountType.ACCOUNT_TYPE_VESTED_REWARDS && assetId;
|
balances &&
|
||||||
|
balances.length > 0 &&
|
||||||
|
balances
|
||||||
|
.filter((b) => allowZeroBalance || !b.balance.isZero())
|
||||||
|
.sort((a, b) => {
|
||||||
|
const order = [
|
||||||
|
Schema.AccountType.ACCOUNT_TYPE_VESTING_REWARDS,
|
||||||
|
Schema.AccountType.ACCOUNT_TYPE_VESTED_REWARDS,
|
||||||
|
Schema.AccountType.ACCOUNT_TYPE_GENERAL,
|
||||||
|
undefined,
|
||||||
|
];
|
||||||
|
return order.indexOf(a.type) - order.indexOf(b.type);
|
||||||
|
})
|
||||||
|
.map(({ balance, type }, i) => (
|
||||||
|
<CurrencyValue
|
||||||
|
key={i}
|
||||||
|
balance={balance}
|
||||||
|
decimals={decimals}
|
||||||
|
type={type}
|
||||||
|
assetId={assetId}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
|
||||||
const accountTypeTooltip = useMemo(() => {
|
if (!values || values.length === 0) return;
|
||||||
if (type === Schema.AccountType.ACCOUNT_TYPE_VESTED_REWARDS) {
|
|
||||||
return t('VestedRewardsTooltip');
|
|
||||||
}
|
|
||||||
if (type === Schema.AccountType.ACCOUNT_TYPE_VESTING_REWARDS && baseRate) {
|
|
||||||
return t('VestingRewardsTooltip', { baseRate });
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}, [baseRate, t, type]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-nowrap gap-2 mt-2 mb-4">
|
<div className="flex flex-nowrap gap-2 mt-2 mb-4">
|
||||||
@ -169,35 +188,92 @@ export const WalletCardAsset = ({
|
|||||||
{subheading || symbol}
|
{subheading || symbol}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{type ? (
|
{values}
|
||||||
<div className="mb-[2px] flex gap-2 items-baseline">
|
</div>
|
||||||
<Tooltip description={accountTypeTooltip}>
|
</div>
|
||||||
<span className="px-2 py-1 leading-none text-xs bg-vega-cdark-700 rounded">
|
);
|
||||||
{Schema.AccountTypeMapping[type]}
|
};
|
||||||
</span>
|
|
||||||
</Tooltip>
|
const useAccountTypeTooltip = (type?: Schema.AccountType) => {
|
||||||
{isRedeemable ? (
|
const { t } = useTranslation();
|
||||||
<Tooltip description={t('RedeemRewardsTooltip')}>
|
const { param: baseRate } = useNetworkParam('rewards_vesting_baseRate');
|
||||||
<AnchorButton
|
const accountTypeTooltip = useMemo(() => {
|
||||||
variant="primary"
|
if (type === Schema.AccountType.ACCOUNT_TYPE_VESTED_REWARDS) {
|
||||||
size="xs"
|
return t('VestedRewardsTooltip');
|
||||||
href={transferAssetLink(assetId)}
|
}
|
||||||
target="_blank"
|
if (type === Schema.AccountType.ACCOUNT_TYPE_VESTING_REWARDS && baseRate) {
|
||||||
className="px-2 py-1 leading-none text-xs bg-vega-yellow text-black rounded"
|
return t('VestingRewardsTooltip', { baseRate });
|
||||||
>
|
}
|
||||||
{t('Redeem')}
|
|
||||||
</AnchorButton>
|
return null;
|
||||||
</Tooltip>
|
}, [baseRate, t, type]);
|
||||||
) : null}
|
|
||||||
</div>
|
return accountTypeTooltip;
|
||||||
) : null}
|
};
|
||||||
<div className="basis-full font-mono" data-testid="currency-value">
|
|
||||||
<span>
|
const CurrencyValue = ({
|
||||||
{integers}
|
balance,
|
||||||
{separator}
|
decimals,
|
||||||
</span>
|
type,
|
||||||
<span className="text-neutral-400">{decimalsPlaces}</span>
|
assetId,
|
||||||
</div>
|
}: {
|
||||||
|
balance: BigNumber;
|
||||||
|
decimals: number;
|
||||||
|
type?: Schema.AccountType;
|
||||||
|
assetId?: string;
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const consoleLink = useLinks(DApp.Console);
|
||||||
|
const transferAssetLink = (assetId: string) =>
|
||||||
|
consoleLink(CONSOLE_TRANSFER_ASSET.replace(':assetId', assetId));
|
||||||
|
|
||||||
|
const [integers, decimalsPlaces, separator] = useNumberParts(
|
||||||
|
balance,
|
||||||
|
decimals
|
||||||
|
);
|
||||||
|
const accountTypeTooltip = useAccountTypeTooltip(type);
|
||||||
|
|
||||||
|
const accountType = type && (
|
||||||
|
<Tooltip description={accountTypeTooltip}>
|
||||||
|
<span className="px-2 py-1 leading-none text-xs bg-vega-cdark-700 rounded">
|
||||||
|
{Schema.AccountTypeMapping[type]}
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
const isRedeemable =
|
||||||
|
type === Schema.AccountType.ACCOUNT_TYPE_VESTED_REWARDS && assetId;
|
||||||
|
const redeemBtn = isRedeemable ? (
|
||||||
|
<Tooltip description={t('RedeemRewardsTooltip')}>
|
||||||
|
<AnchorButton
|
||||||
|
variant="primary"
|
||||||
|
size="xs"
|
||||||
|
href={transferAssetLink(assetId)}
|
||||||
|
target="_blank"
|
||||||
|
className="px-2 py-1 leading-none text-xs bg-vega-yellow text-black rounded"
|
||||||
|
>
|
||||||
|
{t('Redeem')}
|
||||||
|
</AnchorButton>
|
||||||
|
</Tooltip>
|
||||||
|
) : null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="basis-full font-mono mb-1"
|
||||||
|
data-account-type={type?.toLowerCase() || 'unspecified'}
|
||||||
|
data-testid="currency-value"
|
||||||
|
>
|
||||||
|
{type && (
|
||||||
|
<div data-type className="flex gap-1">
|
||||||
|
{accountType}
|
||||||
|
{redeemBtn}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div data-value>
|
||||||
|
<span>
|
||||||
|
{integers}
|
||||||
|
{separator}
|
||||||
|
</span>
|
||||||
|
<span className="text-neutral-400">{decimalsPlaces}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user