Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43c2c4f9fa | ||
|
|
12b1f005ba | ||
|
|
72f8499fc4 | ||
|
|
5e5ec0e470 | ||
|
|
9233778e85 | ||
|
|
7a91f48bcb |
@@ -8,6 +8,7 @@ import { ENV } from '../../config';
|
||||
|
||||
import noIcon from '../../images/token-no-icon.png';
|
||||
import vegaBlack from '../../images/vega_black.png';
|
||||
import vegaVesting from '../../images/vega_vesting.png';
|
||||
import { BigNumber } from '../../lib/bignumber';
|
||||
import type { WalletCardAssetProps } from '../wallet-card';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
@@ -102,7 +103,10 @@ export const usePollForDelegations = () => {
|
||||
setAccounts(
|
||||
accounts
|
||||
.filter(
|
||||
(a) => a.type === Schema.AccountType.ACCOUNT_TYPE_GENERAL
|
||||
(a) =>
|
||||
a.type === Schema.AccountType.ACCOUNT_TYPE_GENERAL ||
|
||||
a.type === Schema.AccountType.ACCOUNT_TYPE_VESTED_REWARDS ||
|
||||
a.type === Schema.AccountType.ACCOUNT_TYPE_VESTING_REWARDS
|
||||
)
|
||||
.map((a) => {
|
||||
const isVega =
|
||||
@@ -115,14 +119,23 @@ export const usePollForDelegations = () => {
|
||||
subheading: isVega ? t('collateral') : a.asset.symbol,
|
||||
symbol: a.asset.symbol,
|
||||
decimals: a.asset.decimals,
|
||||
assetId: a.asset.id,
|
||||
balance: new BigNumber(
|
||||
addDecimal(a.balance, a.asset.decimals)
|
||||
),
|
||||
image: isVega ? vegaBlack : noIcon,
|
||||
image: isVega
|
||||
? vegaBlack
|
||||
: a.type ===
|
||||
Schema.AccountType.ACCOUNT_TYPE_VESTED_REWARDS ||
|
||||
a.type ===
|
||||
Schema.AccountType.ACCOUNT_TYPE_VESTING_REWARDS
|
||||
? vegaVesting
|
||||
: noIcon,
|
||||
border: isVega,
|
||||
address: isAssetTypeERC20(a.asset)
|
||||
? a.asset.source.contractAddress
|
||||
: undefined,
|
||||
type: a.type,
|
||||
};
|
||||
})
|
||||
.sort((a, b) => {
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { useAnimateValue } from '../../hooks/use-animate-value';
|
||||
import type { BigNumber } from '../../lib/bignumber';
|
||||
import { useNumberParts } from '@vegaprotocol/react-helpers';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { AnchorButton, Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
CONSOLE_TRANSFER_ASSET,
|
||||
DApp,
|
||||
useLinks,
|
||||
} from '@vegaprotocol/environment';
|
||||
import { useNetworkParam } from '@vegaprotocol/network-parameters';
|
||||
|
||||
interface WalletCardProps {
|
||||
children: React.ReactNode;
|
||||
@@ -100,8 +109,10 @@ export interface WalletCardAssetProps {
|
||||
symbol: string;
|
||||
balance: BigNumber;
|
||||
decimals: number;
|
||||
assetId?: string;
|
||||
border?: boolean;
|
||||
subheading?: string;
|
||||
type?: Schema.AccountType;
|
||||
}
|
||||
|
||||
export const WalletCardAsset = ({
|
||||
@@ -110,16 +121,37 @@ export const WalletCardAsset = ({
|
||||
symbol,
|
||||
balance,
|
||||
decimals,
|
||||
assetId,
|
||||
border,
|
||||
subheading,
|
||||
type,
|
||||
}: WalletCardAssetProps) => {
|
||||
const [integers, decimalsPlaces, separator] = useNumberParts(
|
||||
balance,
|
||||
decimals
|
||||
);
|
||||
const { t } = useTranslation();
|
||||
const consoleLink = useLinks(DApp.Console);
|
||||
const transferAssetLink = (assetId: string) =>
|
||||
consoleLink(CONSOLE_TRANSFER_ASSET.replace(':assetId', assetId));
|
||||
const { param: baseRate } = useNetworkParam('rewards_vesting_baseRate');
|
||||
|
||||
const isRedeemable =
|
||||
type === Schema.AccountType.ACCOUNT_TYPE_VESTED_REWARDS && assetId;
|
||||
|
||||
const accountTypeTooltip = useMemo(() => {
|
||||
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 (
|
||||
<div className="flex flex-nowrap mt-2 mb-4">
|
||||
<div className="flex flex-nowrap gap-2 mt-2 mb-4">
|
||||
<img
|
||||
alt="Vega"
|
||||
src={image}
|
||||
@@ -129,15 +161,37 @@ export const WalletCardAsset = ({
|
||||
/>
|
||||
<div>
|
||||
<div
|
||||
className="flex align-center text-base"
|
||||
className="flex align-center items-baseline text-base gap-2"
|
||||
data-testid="currency-title"
|
||||
>
|
||||
<div className="mb-0 px-2 uppercase">{name}</div>
|
||||
<div className="mb-0 uppercase">{name}</div>
|
||||
<div className="mb-0 uppercase text-neutral-400">
|
||||
{subheading || symbol}
|
||||
</div>
|
||||
</div>
|
||||
<div className="px-2 basis-full font-mono" data-testid="currency-value">
|
||||
{type ? (
|
||||
<div className="mb-[2px] flex gap-2 items-baseline">
|
||||
<Tooltip description={accountTypeTooltip}>
|
||||
<span className="px-2 py-1 leading-none text-xs bg-vega-cdark-700 rounded">
|
||||
{Schema.AccountTypeMapping[type]}
|
||||
</span>
|
||||
</Tooltip>
|
||||
{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}
|
||||
</div>
|
||||
) : null}
|
||||
<div className="basis-full font-mono" data-testid="currency-value">
|
||||
<span>
|
||||
{integers}
|
||||
{separator}
|
||||
|
||||
@@ -953,5 +953,8 @@
|
||||
"ACCOUNT_TYPE_REWARD_RELATIVE_RETURN": "Relative return reward account",
|
||||
"ACCOUNT_TYPE_REWARD_RETURN_VOLATILITY": "Return volatility reward account",
|
||||
"ACCOUNT_TYPE_REWARD_VALIDATOR_RANKING": "Validator ranking reward account",
|
||||
"ACCOUNT_TYPE_PENDING_FEE_REFERRAL_REWARD": "Pending fee referral reward account"
|
||||
"ACCOUNT_TYPE_PENDING_FEE_REFERRAL_REWARD": "Pending fee referral reward account",
|
||||
"VestingRewardsTooltip": "Vesting rewards will be moved to vested account at a rate of {{baseRate}} per epoch.",
|
||||
"VestedRewardsTooltip": "Vested rewards can be redeemed using Console",
|
||||
"RedeemRewardsTooltip": "Click to redeem vested rewards in Console"
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ const colUpdatedAt = '[col-id="updatedAt"] button';
|
||||
|
||||
const headers = [
|
||||
'Party',
|
||||
'Status',
|
||||
'Commitment (tDAI)',
|
||||
'Obligation',
|
||||
'Fee',
|
||||
@@ -34,7 +35,6 @@ const headers = [
|
||||
'Last time on the book',
|
||||
'Last fee penalty',
|
||||
'Last bond penalty',
|
||||
'Status',
|
||||
'Created',
|
||||
'Updated',
|
||||
];
|
||||
|
||||
@@ -1,11 +1,28 @@
|
||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { AddressField, TransferFee, TransferForm } from './transfer-form';
|
||||
import {
|
||||
AddressField,
|
||||
TransferFee,
|
||||
TransferForm,
|
||||
type TransferFormProps,
|
||||
} from './transfer-form';
|
||||
import { AccountType } from '@vegaprotocol/types';
|
||||
import { removeDecimal } from '@vegaprotocol/utils';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
|
||||
describe('TransferForm', () => {
|
||||
const renderComponent = (props: TransferFormProps) => {
|
||||
return render(
|
||||
// Wrap with mock provider as the form will make queries to fetch the selected
|
||||
// toVegaKey accounts. We don't test this for now but we need to wrap so that
|
||||
// the component has access to the client
|
||||
<MockedProvider>
|
||||
<TransferForm {...props} />
|
||||
</MockedProvider>
|
||||
);
|
||||
};
|
||||
|
||||
const submit = async () => {
|
||||
await userEvent.click(
|
||||
screen.getByRole('button', { name: 'Confirm transfer' })
|
||||
@@ -66,7 +83,7 @@ describe('TransferForm', () => {
|
||||
// 1003-TRAN-017
|
||||
// 1003-TRAN-018
|
||||
// 1003-TRAN-019
|
||||
render(<TransferForm {...props} />);
|
||||
renderComponent(props);
|
||||
// Select a pubkey
|
||||
await userEvent.selectOptions(
|
||||
screen.getByLabelText('To Vega key'),
|
||||
@@ -113,7 +130,7 @@ describe('TransferForm', () => {
|
||||
// 1003-TRAN-012
|
||||
// 1003-TRAN-013
|
||||
// 1003-TRAN-004
|
||||
render(<TransferForm {...props} />);
|
||||
renderComponent(props);
|
||||
await submit();
|
||||
expect(await screen.findAllByText('Required')).toHaveLength(3); // pubkey is set as default value
|
||||
const toggle = screen.getByText('Enter manually');
|
||||
@@ -139,7 +156,7 @@ describe('TransferForm', () => {
|
||||
// 1002-WITH-010
|
||||
// 1003-TRAN-011
|
||||
// 1003-TRAN-014
|
||||
render(<TransferForm {...props} />);
|
||||
renderComponent(props);
|
||||
|
||||
// check current pubkey not shown
|
||||
const keySelect = screen.getByLabelText<HTMLSelectElement>('To Vega key');
|
||||
@@ -206,7 +223,7 @@ describe('TransferForm', () => {
|
||||
describe('IncludeFeesCheckbox', () => {
|
||||
it('validates fields and submits when checkbox is checked', async () => {
|
||||
const mockSubmit = jest.fn();
|
||||
render(<TransferForm {...props} submitTransfer={mockSubmit} />);
|
||||
renderComponent({ ...props, submitTransfer: mockSubmit });
|
||||
|
||||
// check current pubkey not shown
|
||||
const keySelect = screen.getByLabelText<HTMLSelectElement>('To Vega key');
|
||||
@@ -275,7 +292,7 @@ describe('TransferForm', () => {
|
||||
});
|
||||
|
||||
it('validates fields when checkbox is not checked', async () => {
|
||||
render(<TransferForm {...props} />);
|
||||
renderComponent(props);
|
||||
|
||||
// check current pubkey not shown
|
||||
const keySelect: HTMLSelectElement = screen.getByLabelText('To Vega key');
|
||||
|
||||
@@ -27,6 +27,8 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import { AssetOption, Balance } from '@vegaprotocol/assets';
|
||||
import { AccountType, AccountTypeMapping } from '@vegaprotocol/types';
|
||||
import { useDataProvider } from '@vegaprotocol/data-provider';
|
||||
import { accountsDataProvider } from './accounts-data-provider';
|
||||
|
||||
interface FormFields {
|
||||
toVegaKey: string;
|
||||
@@ -35,7 +37,7 @@ interface FormFields {
|
||||
fromAccount: AccountType;
|
||||
}
|
||||
|
||||
interface TransferFormProps {
|
||||
export interface TransferFormProps {
|
||||
pubKey: string | null;
|
||||
pubKeys: string[] | null;
|
||||
accounts: Array<{
|
||||
@@ -72,8 +74,28 @@ export const TransferForm = ({
|
||||
|
||||
const assets = sortBy(
|
||||
accounts
|
||||
.filter((a) => a.type === AccountType.ACCOUNT_TYPE_GENERAL)
|
||||
.filter(
|
||||
(a) =>
|
||||
a.type === AccountType.ACCOUNT_TYPE_GENERAL ||
|
||||
a.type === AccountType.ACCOUNT_TYPE_VESTED_REWARDS
|
||||
)
|
||||
// Sum the general and vested account balances so the value shown in the asset
|
||||
// dropdown is correct for all transferable accounts
|
||||
.reduce((merged, account) => {
|
||||
const existing = merged.findIndex(
|
||||
(m) => m.asset.id === account.asset.id
|
||||
);
|
||||
if (existing > -1) {
|
||||
const balance = new BigNumber(merged[existing].balance)
|
||||
.plus(new BigNumber(account.balance))
|
||||
.toString();
|
||||
merged[existing] = { ...merged[existing], balance };
|
||||
return merged;
|
||||
}
|
||||
return [...merged, account];
|
||||
}, [] as typeof accounts)
|
||||
.map((account) => ({
|
||||
key: account.asset.id,
|
||||
...account.asset,
|
||||
balance: addDecimal(account.balance, account.asset.decimals),
|
||||
})),
|
||||
@@ -87,18 +109,30 @@ export const TransferForm = ({
|
||||
|
||||
const asset = assets.find((a) => a.id === assetId);
|
||||
|
||||
const { data: toAccounts } = useDataProvider({
|
||||
dataProvider: accountsDataProvider,
|
||||
variables: {
|
||||
partyId: selectedPubKey,
|
||||
},
|
||||
skip: !selectedPubKey,
|
||||
});
|
||||
|
||||
const account = accounts.find(
|
||||
(a) => a.asset.id === assetId && a.type === fromAccount
|
||||
);
|
||||
const accountBalance =
|
||||
account && addDecimal(account.balance, account.asset.decimals);
|
||||
|
||||
// General account for the selected asset
|
||||
const generalAccount = accounts.find((a) => {
|
||||
return (
|
||||
a.asset.id === assetId && a.type === AccountType.ACCOUNT_TYPE_GENERAL
|
||||
);
|
||||
});
|
||||
// The general account of the selected pubkey. You can only transfer
|
||||
// to general accounts, either when redeeming vested rewards or just
|
||||
// during normal general -> general transfers
|
||||
const toGeneralAccount =
|
||||
toAccounts &&
|
||||
toAccounts.find((a) => {
|
||||
return (
|
||||
a.asset.id === assetId && a.type === AccountType.ACCOUNT_TYPE_GENERAL
|
||||
);
|
||||
});
|
||||
|
||||
const [includeFee, setIncludeFee] = useState(false);
|
||||
|
||||
@@ -226,7 +260,7 @@ export const TransferForm = ({
|
||||
>
|
||||
{assets.map((a) => (
|
||||
<AssetOption
|
||||
key={a.id}
|
||||
key={a.key}
|
||||
asset={a}
|
||||
balance={
|
||||
<Balance
|
||||
@@ -296,14 +330,16 @@ export const TransferForm = ({
|
||||
defaultValue={AccountType.ACCOUNT_TYPE_GENERAL}
|
||||
>
|
||||
<option value={AccountType.ACCOUNT_TYPE_GENERAL}>
|
||||
{generalAccount
|
||||
{toGeneralAccount
|
||||
? `${
|
||||
AccountTypeMapping[AccountType.ACCOUNT_TYPE_GENERAL]
|
||||
} (${addDecimalsFormatNumber(
|
||||
generalAccount.balance,
|
||||
generalAccount.asset.decimals
|
||||
)} ${generalAccount.asset.symbol})`
|
||||
: AccountTypeMapping[AccountType.ACCOUNT_TYPE_GENERAL]}
|
||||
toGeneralAccount.balance,
|
||||
toGeneralAccount.asset.decimals
|
||||
)} ${toGeneralAccount.asset.symbol})`
|
||||
: `${AccountTypeMapping[AccountType.ACCOUNT_TYPE_GENERAL]} ${
|
||||
asset ? `(0 ${asset.symbol})` : ''
|
||||
}`}
|
||||
</option>
|
||||
</TradingSelect>
|
||||
</TradingFormGroup>
|
||||
|
||||
@@ -685,7 +685,7 @@ export const DealTicket = ({
|
||||
subLabel={`${formatValue(
|
||||
normalizedOrder.size,
|
||||
market.positionDecimalPlaces
|
||||
)} ${baseQuote} @ ${
|
||||
)} ${baseQuote || ''} @ ${
|
||||
type === Schema.OrderType.TYPE_MARKET
|
||||
? 'market'
|
||||
: `${formatValue(
|
||||
|
||||
@@ -126,6 +126,11 @@ export const useEtherscanLink = () => {
|
||||
return link;
|
||||
};
|
||||
|
||||
// Console pages
|
||||
export const CONSOLE_TRANSFER = '#/portfolio/assets/transfer';
|
||||
export const CONSOLE_TRANSFER_ASSET =
|
||||
'#/portfolio/assets/transfer?assetId=:assetId';
|
||||
|
||||
// Governance pages
|
||||
export const TOKEN_NEW_MARKET_PROPOSAL = '/proposals/propose/new-market';
|
||||
export const TOKEN_NEW_NETWORK_PARAM_PROPOSAL =
|
||||
|
||||
@@ -49,6 +49,7 @@ describe('LiquidityTable', () => {
|
||||
undefined,
|
||||
undefined,
|
||||
'Party',
|
||||
'Status',
|
||||
'Commitment ()',
|
||||
'Obligation',
|
||||
'Fee',
|
||||
@@ -61,7 +62,6 @@ describe('LiquidityTable', () => {
|
||||
'Last time on the book',
|
||||
'Last fee penalty',
|
||||
'Last bond penalty',
|
||||
'Status',
|
||||
'Created',
|
||||
'Updated',
|
||||
];
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import type {
|
||||
TypedDataAgGrid,
|
||||
VegaValueFormatterParams,
|
||||
VegaICellRendererParams,
|
||||
} from '@vegaprotocol/datagrid';
|
||||
import { AgGrid } from '@vegaprotocol/datagrid';
|
||||
import {
|
||||
@@ -183,6 +183,36 @@ export const LiquidityTable = ({
|
||||
headerName: t('Commitment details'),
|
||||
marryChildren: true,
|
||||
children: [
|
||||
{
|
||||
headerName: t('Status'),
|
||||
headerTooltip: t('The current status of this liquidity provision.'),
|
||||
field: 'status',
|
||||
cellRenderer: ({
|
||||
data,
|
||||
value,
|
||||
}: VegaICellRendererParams<LiquidityProvisionData, 'status'>) => {
|
||||
if (!value) return value;
|
||||
if (
|
||||
data?.status === LiquidityProvisionStatus.STATUS_PENDING &&
|
||||
(data?.currentCommitmentAmount || data?.currentFee)
|
||||
) {
|
||||
return (
|
||||
<span className="text-warning">
|
||||
{t('Updating next epoch')}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<span>
|
||||
{
|
||||
LiquidityProvisionStatusMapping[
|
||||
value as LiquidityProvisionStatus
|
||||
]
|
||||
}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
headerName: t(`Commitment (${symbol})`),
|
||||
field: 'commitmentAmount',
|
||||
@@ -190,30 +220,46 @@ export const LiquidityTable = ({
|
||||
headerTooltip: t(
|
||||
'The amount committed to the market by this liquidity provider.'
|
||||
),
|
||||
valueFormatter: ({
|
||||
cellRenderer: ({
|
||||
data,
|
||||
value,
|
||||
}: VegaValueFormatterParams<
|
||||
}: VegaICellRendererParams<
|
||||
LiquidityProvisionData,
|
||||
'commitmentAmount'
|
||||
>) => {
|
||||
if (!value) return '-';
|
||||
const formattedCommitmentAmount = addDecimalsFormatNumberQuantum(
|
||||
value,
|
||||
assetDecimalPlaces ?? 0,
|
||||
quantum ?? 0
|
||||
);
|
||||
if (
|
||||
data?.currentCommitmentAmount &&
|
||||
data?.currentCommitmentAmount !== value
|
||||
) {
|
||||
return `${addDecimalsFormatNumberQuantum(
|
||||
data.currentCommitmentAmount,
|
||||
const currentCommitmentAmount = data?.currentCommitmentAmount;
|
||||
const pendingCommitmentAmount = value;
|
||||
|
||||
const formattedPendingCommitmentAmount =
|
||||
addDecimalsFormatNumberQuantum(
|
||||
pendingCommitmentAmount,
|
||||
assetDecimalPlaces ?? 0,
|
||||
quantum ?? 0
|
||||
)}/${formattedCommitmentAmount}`;
|
||||
);
|
||||
|
||||
if (
|
||||
currentCommitmentAmount &&
|
||||
currentCommitmentAmount !== pendingCommitmentAmount
|
||||
) {
|
||||
const formattedCurrentCommitmentAmount =
|
||||
addDecimalsFormatNumberQuantum(
|
||||
currentCommitmentAmount,
|
||||
assetDecimalPlaces ?? 0,
|
||||
quantum ?? 0
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<span>{formattedCurrentCommitmentAmount}</span> (
|
||||
<span className="text-warning">
|
||||
{formattedPendingCommitmentAmount}
|
||||
</span>
|
||||
)
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
return formattedCommitmentAmount;
|
||||
return formattedPendingCommitmentAmount;
|
||||
}
|
||||
},
|
||||
tooltipValueGetter: assetDecimalsFormatter,
|
||||
@@ -223,9 +269,58 @@ export const LiquidityTable = ({
|
||||
field: 'commitmentAmount',
|
||||
type: 'rightAligned',
|
||||
headerTooltip: t(
|
||||
`The liquidity provider's obligation to the market, calculated as the liquidity commitment amount multiplied by the value of the stake_to_ccy_volume network parameter to convert into units of liquidity volume. The obligation can be met by a combination of LP orders and limit orders on the order book.`
|
||||
`The liquidity provider's obligation to the market, calculated as the liquidity commitment amount multiplied by the value of the stake_to_ccy_volume network parameter to convert into units of liquidity volume.`
|
||||
),
|
||||
valueFormatter: stakeToCcyVolumeQuantumFormatter,
|
||||
cellRenderer: ({
|
||||
data,
|
||||
value,
|
||||
}: VegaICellRendererParams<
|
||||
LiquidityProvisionData,
|
||||
'commitmentAmount'
|
||||
>) => {
|
||||
if (!value) return '-';
|
||||
|
||||
const currentCommitmentAmount = data?.currentCommitmentAmount
|
||||
? new BigNumber(data?.currentCommitmentAmount)
|
||||
.times(Number(stakeToCcyVolume) || 1)
|
||||
.toString()
|
||||
: undefined;
|
||||
|
||||
const pendingCommitmentAmount = new BigNumber(value)
|
||||
.times(Number(stakeToCcyVolume) || 1)
|
||||
.toString();
|
||||
|
||||
const formattedPendingCommitmentAmount =
|
||||
addDecimalsFormatNumberQuantum(
|
||||
pendingCommitmentAmount,
|
||||
assetDecimalPlaces ?? 0,
|
||||
quantum ?? 0
|
||||
);
|
||||
|
||||
if (
|
||||
currentCommitmentAmount &&
|
||||
currentCommitmentAmount !== pendingCommitmentAmount
|
||||
) {
|
||||
const formattedCurrentCommitmentAmount =
|
||||
addDecimalsFormatNumberQuantum(
|
||||
currentCommitmentAmount,
|
||||
assetDecimalPlaces ?? 0,
|
||||
quantum ?? 0
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<span>{formattedCurrentCommitmentAmount}</span> (
|
||||
<span className="text-warning">
|
||||
{formattedPendingCommitmentAmount}
|
||||
</span>
|
||||
)
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
return formattedPendingCommitmentAmount;
|
||||
}
|
||||
},
|
||||
tooltipValueGetter: stakeToCcyVolumeFormatter,
|
||||
},
|
||||
{
|
||||
@@ -235,21 +330,27 @@ export const LiquidityTable = ({
|
||||
),
|
||||
field: 'fee',
|
||||
type: 'rightAligned',
|
||||
valueFormatter: ({
|
||||
cellRenderer: ({
|
||||
data,
|
||||
value,
|
||||
}: ValueFormatterParams<LiquidityProvisionData, 'fee'>) => {
|
||||
}: VegaICellRendererParams<LiquidityProvisionData, 'fee'>) => {
|
||||
if (!value) return '-';
|
||||
const formattedValue =
|
||||
const formattedPendingFee =
|
||||
formatNumberPercentage(new BigNumber(value).times(100), 2) ||
|
||||
'-';
|
||||
if (data?.currentFee && data?.currentFee !== value) {
|
||||
return `${formatNumberPercentage(
|
||||
const formattedCurrentFee = formatNumberPercentage(
|
||||
new BigNumber(data.currentFee).times(100),
|
||||
2
|
||||
)}/${formattedValue}`;
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<span>{formattedCurrentFee}</span> (
|
||||
<span className="text-warning">{formattedPendingFee}</span>)
|
||||
</>
|
||||
);
|
||||
}
|
||||
return formattedValue;
|
||||
return formattedPendingFee;
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -367,26 +468,6 @@ export const LiquidityTable = ({
|
||||
headerName: '',
|
||||
marryChildren: true,
|
||||
children: [
|
||||
{
|
||||
headerName: t('Status'),
|
||||
headerTooltip: t('The current status of this liquidity provision.'),
|
||||
field: 'status',
|
||||
valueFormatter: ({
|
||||
data,
|
||||
value,
|
||||
}: ValueFormatterParams<LiquidityProvisionData, 'status'>) => {
|
||||
if (!value) return value;
|
||||
if (
|
||||
data?.status === LiquidityProvisionStatus.STATUS_PENDING &&
|
||||
(data?.currentCommitmentAmount || data?.currentFee)
|
||||
) {
|
||||
return t('Updating next epoch');
|
||||
}
|
||||
return LiquidityProvisionStatusMapping[
|
||||
value as LiquidityProvisionStatus
|
||||
];
|
||||
},
|
||||
},
|
||||
{
|
||||
headerName: t('Created'),
|
||||
headerTooltip: t(
|
||||
|
||||
@@ -12,6 +12,7 @@ export const NetworkParams = {
|
||||
'rewards_marketCreationQuantumMultiple',
|
||||
reward_staking_delegation_payoutDelay:
|
||||
'reward_staking_delegation_payoutDelay',
|
||||
rewards_vesting_baseRate: 'rewards_vesting_baseRate',
|
||||
governance_proposal_market_minVoterBalance:
|
||||
'governance_proposal_market_minVoterBalance',
|
||||
governance_proposal_market_minClose: 'governance_proposal_market_minClose',
|
||||
|
||||
@@ -148,6 +148,7 @@ export const OrderListManager = ({
|
||||
expiresAt: editOrder.expiresAt,
|
||||
side: editOrder.side,
|
||||
marketId: editOrder.market.id,
|
||||
remaining: editOrder.remaining,
|
||||
};
|
||||
create({ orderAmendment }, originalOrder);
|
||||
setEditOrder(null);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
MAXGOINT64,
|
||||
addDecimalsFormatNumber,
|
||||
getDateTimeFormat,
|
||||
isNumeric,
|
||||
@@ -144,11 +145,22 @@ export const OrderListTable = memo<
|
||||
if (!data?.market || !isNumeric(data.size)) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
const prefix = data
|
||||
? data.side === Schema.Side.SIDE_BUY
|
||||
? '+'
|
||||
: '-'
|
||||
: '';
|
||||
|
||||
if (
|
||||
data.size === MAXGOINT64 &&
|
||||
data.timeInForce ===
|
||||
Schema.OrderTimeInForce.TIME_IN_FORCE_IOC &&
|
||||
data.reduceOnly
|
||||
) {
|
||||
return t('MAX');
|
||||
}
|
||||
|
||||
return (
|
||||
prefix +
|
||||
addDecimalsFormatNumber(
|
||||
|
||||
@@ -65,6 +65,7 @@ fragment OrderTxUpdateFields on OrderUpdate {
|
||||
expiresAt
|
||||
side
|
||||
marketId
|
||||
remaining
|
||||
}
|
||||
|
||||
subscription OrderTxUpdate($partyId: ID!) {
|
||||
|
||||
+3
-2
@@ -21,14 +21,14 @@ export type WithdrawalBusEventSubscriptionVariables = Types.Exact<{
|
||||
|
||||
export type WithdrawalBusEventSubscription = { __typename?: 'Subscription', busEvents?: Array<{ __typename?: 'BusEvent', event: { __typename?: 'Deposit' } | { __typename?: 'TimeUpdate' } | { __typename?: 'TransactionResult' } | { __typename?: 'Withdrawal', id: string, status: Types.WithdrawalStatus, amount: string, createdTimestamp: any, withdrawnTimestamp?: any | null, txHash?: string | null, pendingOnForeignChain: boolean, asset: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, status: Types.AssetStatus, source: { __typename?: 'BuiltinAsset' } | { __typename?: 'ERC20', contractAddress: string } }, details?: { __typename?: 'Erc20WithdrawalDetails', receiverAddress: string } | null } }> | null };
|
||||
|
||||
export type OrderTxUpdateFieldsFragment = { __typename?: 'OrderUpdate', type?: Types.OrderType | null, id: string, status: Types.OrderStatus, rejectionReason?: Types.OrderRejectionReason | null, createdAt: any, size: string, price: string, timeInForce: Types.OrderTimeInForce, expiresAt?: any | null, side: Types.Side, marketId: string };
|
||||
export type OrderTxUpdateFieldsFragment = { __typename?: 'OrderUpdate', type?: Types.OrderType | null, id: string, status: Types.OrderStatus, rejectionReason?: Types.OrderRejectionReason | null, createdAt: any, size: string, price: string, timeInForce: Types.OrderTimeInForce, expiresAt?: any | null, side: Types.Side, marketId: string, remaining: string };
|
||||
|
||||
export type OrderTxUpdateSubscriptionVariables = Types.Exact<{
|
||||
partyId: Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type OrderTxUpdateSubscription = { __typename?: 'Subscription', orders?: Array<{ __typename?: 'OrderUpdate', type?: Types.OrderType | null, id: string, status: Types.OrderStatus, rejectionReason?: Types.OrderRejectionReason | null, createdAt: any, size: string, price: string, timeInForce: Types.OrderTimeInForce, expiresAt?: any | null, side: Types.Side, marketId: string }> | null };
|
||||
export type OrderTxUpdateSubscription = { __typename?: 'Subscription', orders?: Array<{ __typename?: 'OrderUpdate', type?: Types.OrderType | null, id: string, status: Types.OrderStatus, rejectionReason?: Types.OrderRejectionReason | null, createdAt: any, size: string, price: string, timeInForce: Types.OrderTimeInForce, expiresAt?: any | null, side: Types.Side, marketId: string, remaining: string }> | null };
|
||||
|
||||
export type DepositBusEventFieldsFragment = { __typename?: 'Deposit', id: string, status: Types.DepositStatus, amount: string, createdTimestamp: any, creditedTimestamp?: any | null, txHash?: string | null, asset: { __typename?: 'Asset', id: string, symbol: string, decimals: number } };
|
||||
|
||||
@@ -88,6 +88,7 @@ export const OrderTxUpdateFieldsFragmentDoc = gql`
|
||||
expiresAt
|
||||
side
|
||||
marketId
|
||||
remaining
|
||||
}
|
||||
`;
|
||||
export const DepositBusEventFieldsFragmentDoc = gql`
|
||||
|
||||
@@ -56,6 +56,7 @@ describe('useVegaTransactionStore', () => {
|
||||
side: Side.SIDE_BUY,
|
||||
marketId:
|
||||
'3aa2a828687cc3d59e92445d294891cbbd40e2165bbfb15674158ef5d4e8848d',
|
||||
remaining: '12',
|
||||
};
|
||||
|
||||
const processedTransactionUpdate = {
|
||||
|
||||
@@ -193,6 +193,7 @@ const submitOrder: VegaStoredTxState = {
|
||||
createdAt: new Date(),
|
||||
marketId: 'market-1',
|
||||
status: OrderStatus.STATUS_ACTIVE,
|
||||
remaining: '10',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -249,6 +250,7 @@ const editOrder: VegaStoredTxState = {
|
||||
createdAt: new Date(),
|
||||
marketId: 'market-1',
|
||||
status: OrderStatus.STATUS_ACTIVE,
|
||||
remaining: '10',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -489,6 +491,7 @@ describe('getRejectionReason', () => {
|
||||
timeInForce: Types.OrderTimeInForce.TIME_IN_FORCE_FOK,
|
||||
side: Types.Side.SIDE_BUY,
|
||||
marketId: '',
|
||||
remaining: '',
|
||||
})
|
||||
).toBe('Insufficient asset balance');
|
||||
});
|
||||
@@ -505,6 +508,7 @@ describe('getRejectionReason', () => {
|
||||
timeInForce: Types.OrderTimeInForce.TIME_IN_FORCE_FOK,
|
||||
side: Types.Side.SIDE_BUY,
|
||||
marketId: '',
|
||||
remaining: '',
|
||||
})
|
||||
).toBe(
|
||||
'Your Fill or Kill (FOK) order was not filled and it has been stopped'
|
||||
|
||||
@@ -41,6 +41,7 @@ import {
|
||||
toBigNum,
|
||||
truncateByChars,
|
||||
formatTrigger,
|
||||
MAXGOINT64,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useAssetsMapProvider } from '@vegaprotocol/assets';
|
||||
@@ -585,6 +586,23 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => {
|
||||
<Panel>
|
||||
{t('Close position for')}{' '}
|
||||
<strong>{market.tradableInstrument.instrument.code}</strong>
|
||||
{tx.order?.remaining && (
|
||||
<p>
|
||||
{t('Filled')}{' '}
|
||||
<SizeAtPrice
|
||||
meta={{
|
||||
positionDecimalPlaces: market.positionDecimalPlaces,
|
||||
decimalPlaces: market.decimalPlaces,
|
||||
asset: getAsset(market).symbol,
|
||||
}}
|
||||
side={tx.order.side}
|
||||
size={(
|
||||
BigInt(tx.order.size) - BigInt(tx.order.remaining)
|
||||
).toString()}
|
||||
price={tx.order.price}
|
||||
/>
|
||||
</p>
|
||||
)}
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
@@ -953,7 +971,19 @@ export const getVegaTransactionContentIntent = (tx: VegaStoredTxState) => {
|
||||
isWithdrawTransaction(tx.body) &&
|
||||
Intent.Warning;
|
||||
|
||||
// Toast for an IOC should go green when it is stopped,
|
||||
// because stopping an IOC once all available volume has filled is the correct behaviour (it is immediate or cancel),
|
||||
// this behaviour should apply to all IOC, not just those created due to "Close position"
|
||||
const intentForClosedPosition =
|
||||
tx.order &&
|
||||
tx.order.status === Schema.OrderStatus.STATUS_STOPPED &&
|
||||
tx.order.timeInForce === Schema.OrderTimeInForce.TIME_IN_FORCE_IOC &&
|
||||
tx.order.size === MAXGOINT64 &&
|
||||
// isClosePositionTransaction(tx) &&
|
||||
Intent.Success;
|
||||
|
||||
const intent =
|
||||
intentForClosedPosition ||
|
||||
intentForRejectedOrder ||
|
||||
intentForCompletedWithdrawal ||
|
||||
intentMap[tx.status];
|
||||
|
||||
@@ -76,6 +76,7 @@ const orderUpdate: OrderTxUpdateFieldsFragment = {
|
||||
createdAt: '2022-07-05T14:25:47.815283706Z',
|
||||
expiresAt: '2022-07-05T14:25:47.815283706Z',
|
||||
size: '10',
|
||||
remaining: '10',
|
||||
price: '300000',
|
||||
timeInForce: OrderTimeInForce.TIME_IN_FORCE_GTC,
|
||||
side: Side.SIDE_BUY,
|
||||
|
||||
Reference in New Issue
Block a user