feat(trading): add liquidity provision new SLA parameters to liquidity tables (#5032)

Co-authored-by: asiaznik <artur@vegaprotocol.io>
This commit is contained in:
m.ray 2023-10-24 12:32:07 +03:00 committed by GitHub
parent 43cd170c77
commit 82fb29d541
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 406 additions and 361 deletions

View File

@ -128,9 +128,7 @@ describe('<ProposalReferralProgramDetails />', () => {
it('should not render if there are no relevant fields', () => {
const incompleteProposal = generateProposal({
terms: {
change: {
__typename: 'UpdateReferralProgram',
},
change: {},
},
});

View File

@ -69,7 +69,7 @@ describe(
cy.contains('Something went wrong').should('not.exist');
cy.contains('Application error').should('not.exist');
cy.getByTestId('tab-liquidity').within(() => {
cy.get('[col-id="party.id"]').eq(1).should('not.be.empty');
cy.get('[col-id="partyId"]').eq(1).should('not.be.empty');
});
});
}

View File

@ -12,8 +12,7 @@ const marketSummaryBlock = 'header-summary';
const itemValue = 'item-value';
const itemHeader = 'item-header';
const colCommitmentAmount = '[col-id="commitmentAmount"]';
const colAverageEntryValuation = '[col-id="averageEntryValuation"]';
const colEquityLikeShare = '[col-id="equityLikeShare"]';
const colEquityLikeShare = '[col-id="feeShare.equityLikeShare"]';
const colFee = '[col-id="fee"]';
const colCommitmentAmount_1 = '[col-id="commitmentAmount_1"]';
const colBalance = '[col-id="balance"]';
@ -24,11 +23,16 @@ const colUpdatedAt = '[col-id="updatedAt"] button';
const headers = [
'Party',
'Commitment (tDAI)',
'Share',
'Proposed fee',
'Market valuation at entry',
'Obligation',
'Supplied',
'Fee',
'Adjusted stake share',
'Share',
'Live supplied liquidity',
'Live time fraction on book',
'Live liquidity quality score (%)',
'Last time fraction on the book',
'Last fee penalty',
'Last bond penalty',
'Status',
'Created',
'Updated',
@ -64,11 +68,8 @@ describe('liquidity table - trading', { tags: '@smoke' }, () => {
// 5002-LIQP-002
cy.get(rowSelector)
.first()
.find('[col-id="party.id"]')
.should(
'have.text',
'69464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6f'
);
.find('[col-id="partyId"]')
.should('have.text', '69464e…dc6f');
cy.get(rowSelector)
.first()
@ -82,12 +83,6 @@ describe('liquidity table - trading', { tags: '@smoke' }, () => {
cy.get(rowSelector).first().find(colFee).should('have.text', '0.09%');
// 5002-LIQP-013
cy.get(rowSelector)
.first()
.find(colAverageEntryValuation)
.should('have.text', '685,852.93692');
cy.get(rowSelector)
.first()
.find(colCommitmentAmount_1)
@ -104,7 +99,8 @@ describe('liquidity table - trading', { tags: '@smoke' }, () => {
cy.get(rowSelector).first().find(colCreatedAt).should('not.be.empty');
cy.get(rowSelector).first().find(colUpdatedAt).should('not.be.empty');
});
it.skip('liquidity status column should be sorted properly', () => {
it('liquidity status column should be sorted properly', () => {
// 5002-LIQP-003
const liquidityColDefault = ['Active', 'Pending'];
const liquidityColAsc = ['Active', 'Pending'];
@ -220,11 +216,8 @@ describe('liquidity table view', { tags: '@smoke' }, () => {
// 5002-LIQP-011
cy.get(rowSelectorLiquidityActive)
.first()
.find('[col-id="party.id"]')
.should(
'have.text',
'69464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6f'
);
.find('[col-id="partyId"]')
.should('have.text', '69464e…dc6f');
cy.get(rowSelectorLiquidityActive)
.first()
@ -241,12 +234,6 @@ describe('liquidity table view', { tags: '@smoke' }, () => {
.find(colFee)
.should('have.text', '0.09%');
// 5002-LIQP-013
cy.get(rowSelectorLiquidityActive)
.first()
.find(colAverageEntryValuation)
.should('have.text', '685,852.93692');
cy.get(rowSelectorLiquidityActive)
.first()
.find(colCommitmentAmount_1)
@ -277,11 +264,8 @@ describe('liquidity table view', { tags: '@smoke' }, () => {
cy.getByTestId('Inactive').click();
cy.get(rowSelectorLiquidityInactive)
.first()
.find('[col-id="party.id"]')
.should(
'have.text',
'cc464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6f'
);
.find('[col-id="partyId"]')
.should('have.text', 'cc464e…dc6f');
cy.get(rowSelectorLiquidityInactive)
.first()
@ -298,11 +282,6 @@ describe('liquidity table view', { tags: '@smoke' }, () => {
.find(colFee)
.should('have.text', '0.40%');
cy.get(rowSelectorLiquidityInactive)
.first()
.find(colAverageEntryValuation)
.should('have.text', '685,852.93692');
cy.get(rowSelectorLiquidityInactive)
.first()
.find(colCommitmentAmount_1)

View File

@ -30,11 +30,11 @@ import {
blockStatisticsQuery,
networkParamQuery,
liquidityProvisionsQuery,
liquidityProviderFeeShareQuery,
successorMarketQuery,
parentMarketIdQuery,
successorMarketIdsQuery,
successorMarketProposalDetailsQuery,
liquidityProvidersQuery,
} from '@vegaprotocol/mock';
import type { PartialDeep } from 'type-fest';
import type { MarketDataQuery, MarketsQuery } from '@vegaprotocol/markets';
@ -162,11 +162,7 @@ const mockTradingPage = (
aliasGQLQuery(req, 'Trades', tradesQuery());
aliasGQLQuery(req, 'Chart', chartQuery());
aliasGQLQuery(req, 'LiquidityProvisions', liquidityProvisionsQuery());
aliasGQLQuery(
req,
'LiquidityProviderFeeShare',
liquidityProviderFeeShareQuery
);
aliasGQLQuery(req, 'LiquidityProviders', liquidityProvidersQuery());
aliasGQLQuery(req, 'Candles', candlesQuery());
aliasGQLQuery(req, 'Withdrawals', withdrawalsQuery());
aliasGQLQuery(req, 'NetworkParams', networkParamsQuery());

View File

@ -3,21 +3,21 @@ NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_SENTRY_DSN=https://2ffce43721964aafa78277c50654ece4@o286262.ingest.sentry.io/6300613
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet1/vegawallet-stagnet1.toml
NX_VEGA_ENV=STAGNET1
NX_VEGA_EXPLORER_URL=https://explorer.stagnet1.vega.rocks
NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/fairground/vegawallet-fairground.toml
NX_VEGA_ENV=TESTNET
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
NX_VEGA_NETWORKS={\"MAINNET\":\"https://console.vega.xyz\",\"TESTNET\":\"https://console.fairground.wtf\",\"STAGNET1\":\"https://trading.stagnet1.vega.rocks\"}
NX_VEGA_TOKEN_URL=https://governance.stagnet1.vega.rocks
NX_VEGA_TOKEN_URL=https://governance.fairground.wtf
NX_VEGA_WALLET_URL=http://localhost:1789
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases
NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports
NX_VEGA_CONSOLE_URL=https://console.fairground.wtf
NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn
NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground
NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json
NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72
# Cosmic elevator flags
NX_SUCCESSOR_MARKETS=true

View File

@ -32,39 +32,43 @@ query LiquidityProvisions($marketId: ID!) {
}
}
subscription LiquidityProvisionsUpdate($partyId: ID, $marketId: ID) {
liquidityProvisions(partyId: $partyId, marketId: $marketId) {
id
partyID
createdAt
updatedAt
marketID
commitmentAmount
fee
status
}
}
# Liquidity Provider Share Fee
fragment LiquidityProviderFeeShareFields on LiquidityProviderFeeShare {
party {
id
}
equityLikeShare
averageEntryValuation
averageScore
virtualStake
}
query LiquidityProviderFeeShare($marketId: ID!) {
market(id: $marketId) {
id
data {
market {
id
fragment LiquidityProviderSLAFields on LiquidityProviderSLA {
currentEpochFractionOfTimeOnBook
lastEpochFractionOfTimeOnBook
lastEpochFeePenalty
lastEpochBondPenalty
hysteresisPeriodFeePenalties
requiredLiquidity
notionalVolumeBuys
notionalVolumeSells
}
liquidityProviderFeeShare {
query LiquidityProviders($marketId: ID!) {
liquidityProviders(marketId: $marketId) {
edges {
node {
...LiquidityProviderFields
}
}
}
}
fragment LiquidityProviderFields on LiquidityProvider {
partyId
marketId
feeShare {
...LiquidityProviderFeeShareFields
}
}
sla {
...LiquidityProviderSLAFields
}
}

View File

@ -12,22 +12,18 @@ export type LiquidityProvisionsQueryVariables = Types.Exact<{
export type LiquidityProvisionsQuery = { __typename?: 'Query', market?: { __typename?: 'Market', liquidityProvisionsConnection?: { __typename?: 'LiquidityProvisionsConnection', edges?: Array<{ __typename?: 'LiquidityProvisionsEdge', node: { __typename?: 'LiquidityProvision', id: string, createdAt: any, updatedAt?: any | null, commitmentAmount: string, fee: string, status: Types.LiquidityProvisionStatus, party: { __typename?: 'Party', id: string, accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', type: Types.AccountType, balance: string } } | null> | null } | null } } } | null> | null } | null } | null };
export type LiquidityProvisionsUpdateSubscriptionVariables = Types.Exact<{
partyId?: Types.InputMaybe<Types.Scalars['ID']>;
marketId?: Types.InputMaybe<Types.Scalars['ID']>;
}>;
export type LiquidityProviderFeeShareFieldsFragment = { __typename?: 'LiquidityProviderFeeShare', equityLikeShare: string, averageEntryValuation: string, averageScore: string, virtualStake: string };
export type LiquidityProviderSLAFieldsFragment = { __typename?: 'LiquidityProviderSLA', currentEpochFractionOfTimeOnBook: string, lastEpochFractionOfTimeOnBook: string, lastEpochFeePenalty: string, lastEpochBondPenalty: string, hysteresisPeriodFeePenalties?: Array<string> | null, requiredLiquidity: string, notionalVolumeBuys: string, notionalVolumeSells: string };
export type LiquidityProvisionsUpdateSubscription = { __typename?: 'Subscription', liquidityProvisions?: Array<{ __typename?: 'LiquidityProvisionUpdate', id: string, partyID: string, createdAt: any, updatedAt?: any | null, marketID: string, commitmentAmount: string, fee: string, status: Types.LiquidityProvisionStatus }> | null };
export type LiquidityProviderFeeShareFieldsFragment = { __typename?: 'LiquidityProviderFeeShare', equityLikeShare: string, averageEntryValuation: string, party: { __typename?: 'Party', id: string } };
export type LiquidityProviderFeeShareQueryVariables = Types.Exact<{
export type LiquidityProvidersQueryVariables = Types.Exact<{
marketId: Types.Scalars['ID'];
}>;
export type LiquidityProviderFeeShareQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, data?: { __typename?: 'MarketData', market: { __typename?: 'Market', id: string }, liquidityProviderFeeShare?: Array<{ __typename?: 'LiquidityProviderFeeShare', equityLikeShare: string, averageEntryValuation: string, party: { __typename?: 'Party', id: string } }> | null } | null } | null };
export type LiquidityProvidersQuery = { __typename?: 'Query', liquidityProviders?: { __typename?: 'LiquidityProviderConnection', edges: Array<{ __typename?: 'LiquidityProviderEdge', node: { __typename?: 'LiquidityProvider', partyId: string, marketId: string, feeShare?: { __typename?: 'LiquidityProviderFeeShare', equityLikeShare: string, averageEntryValuation: string, averageScore: string, virtualStake: string } | null, sla?: { __typename?: 'LiquidityProviderSLA', currentEpochFractionOfTimeOnBook: string, lastEpochFractionOfTimeOnBook: string, lastEpochFeePenalty: string, lastEpochBondPenalty: string, hysteresisPeriodFeePenalties?: Array<string> | null, requiredLiquidity: string, notionalVolumeBuys: string, notionalVolumeSells: string } | null } }> } | null };
export type LiquidityProviderFieldsFragment = { __typename?: 'LiquidityProvider', partyId: string, marketId: string, feeShare?: { __typename?: 'LiquidityProviderFeeShare', equityLikeShare: string, averageEntryValuation: string, averageScore: string, virtualStake: string } | null, sla?: { __typename?: 'LiquidityProviderSLA', currentEpochFractionOfTimeOnBook: string, lastEpochFractionOfTimeOnBook: string, lastEpochFeePenalty: string, lastEpochBondPenalty: string, hysteresisPeriodFeePenalties?: Array<string> | null, requiredLiquidity: string, notionalVolumeBuys: string, notionalVolumeSells: string } | null };
export const LiquidityProvisionFieldsFragmentDoc = gql`
fragment LiquidityProvisionFields on LiquidityProvision {
@ -52,13 +48,37 @@ export const LiquidityProvisionFieldsFragmentDoc = gql`
`;
export const LiquidityProviderFeeShareFieldsFragmentDoc = gql`
fragment LiquidityProviderFeeShareFields on LiquidityProviderFeeShare {
party {
id
}
equityLikeShare
averageEntryValuation
averageScore
virtualStake
}
`;
export const LiquidityProviderSLAFieldsFragmentDoc = gql`
fragment LiquidityProviderSLAFields on LiquidityProviderSLA {
currentEpochFractionOfTimeOnBook
lastEpochFractionOfTimeOnBook
lastEpochFeePenalty
lastEpochBondPenalty
hysteresisPeriodFeePenalties
requiredLiquidity
notionalVolumeBuys
notionalVolumeSells
}
`;
export const LiquidityProviderFieldsFragmentDoc = gql`
fragment LiquidityProviderFields on LiquidityProvider {
partyId
marketId
feeShare {
...LiquidityProviderFeeShareFields
}
sla {
...LiquidityProviderSLAFields
}
}
${LiquidityProviderFeeShareFieldsFragmentDoc}
${LiquidityProviderSLAFieldsFragmentDoc}`;
export const LiquidityProvisionsDocument = gql`
query LiquidityProvisions($marketId: ID!) {
market(id: $marketId) {
@ -100,84 +120,42 @@ export function useLiquidityProvisionsLazyQuery(baseOptions?: Apollo.LazyQueryHo
export type LiquidityProvisionsQueryHookResult = ReturnType<typeof useLiquidityProvisionsQuery>;
export type LiquidityProvisionsLazyQueryHookResult = ReturnType<typeof useLiquidityProvisionsLazyQuery>;
export type LiquidityProvisionsQueryResult = Apollo.QueryResult<LiquidityProvisionsQuery, LiquidityProvisionsQueryVariables>;
export const LiquidityProvisionsUpdateDocument = gql`
subscription LiquidityProvisionsUpdate($partyId: ID, $marketId: ID) {
liquidityProvisions(partyId: $partyId, marketId: $marketId) {
id
partyID
createdAt
updatedAt
marketID
commitmentAmount
fee
status
export const LiquidityProvidersDocument = gql`
query LiquidityProviders($marketId: ID!) {
liquidityProviders(marketId: $marketId) {
edges {
node {
...LiquidityProviderFields
}
}
`;
}
}
${LiquidityProviderFieldsFragmentDoc}`;
/**
* __useLiquidityProvisionsUpdateSubscription__
* __useLiquidityProvidersQuery__
*
* To run a query within a React component, call `useLiquidityProvisionsUpdateSubscription` and pass it any options that fit your needs.
* When your component renders, `useLiquidityProvisionsUpdateSubscription` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the subscription, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useLiquidityProvisionsUpdateSubscription({
* variables: {
* partyId: // value for 'partyId'
* marketId: // value for 'marketId'
* },
* });
*/
export function useLiquidityProvisionsUpdateSubscription(baseOptions?: Apollo.SubscriptionHookOptions<LiquidityProvisionsUpdateSubscription, LiquidityProvisionsUpdateSubscriptionVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useSubscription<LiquidityProvisionsUpdateSubscription, LiquidityProvisionsUpdateSubscriptionVariables>(LiquidityProvisionsUpdateDocument, options);
}
export type LiquidityProvisionsUpdateSubscriptionHookResult = ReturnType<typeof useLiquidityProvisionsUpdateSubscription>;
export type LiquidityProvisionsUpdateSubscriptionResult = Apollo.SubscriptionResult<LiquidityProvisionsUpdateSubscription>;
export const LiquidityProviderFeeShareDocument = gql`
query LiquidityProviderFeeShare($marketId: ID!) {
market(id: $marketId) {
id
data {
market {
id
}
liquidityProviderFeeShare {
...LiquidityProviderFeeShareFields
}
}
}
}
${LiquidityProviderFeeShareFieldsFragmentDoc}`;
/**
* __useLiquidityProviderFeeShareQuery__
*
* To run a query within a React component, call `useLiquidityProviderFeeShareQuery` and pass it any options that fit your needs.
* When your component renders, `useLiquidityProviderFeeShareQuery` returns an object from Apollo Client that contains loading, error, and data properties
* To run a query within a React component, call `useLiquidityProvidersQuery` and pass it any options that fit your needs.
* When your component renders, `useLiquidityProvidersQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useLiquidityProviderFeeShareQuery({
* const { data, loading, error } = useLiquidityProvidersQuery({
* variables: {
* marketId: // value for 'marketId'
* },
* });
*/
export function useLiquidityProviderFeeShareQuery(baseOptions: Apollo.QueryHookOptions<LiquidityProviderFeeShareQuery, LiquidityProviderFeeShareQueryVariables>) {
export function useLiquidityProvidersQuery(baseOptions: Apollo.QueryHookOptions<LiquidityProvidersQuery, LiquidityProvidersQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<LiquidityProviderFeeShareQuery, LiquidityProviderFeeShareQueryVariables>(LiquidityProviderFeeShareDocument, options);
return Apollo.useQuery<LiquidityProvidersQuery, LiquidityProvidersQueryVariables>(LiquidityProvidersDocument, options);
}
export function useLiquidityProviderFeeShareLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<LiquidityProviderFeeShareQuery, LiquidityProviderFeeShareQueryVariables>) {
export function useLiquidityProvidersLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<LiquidityProvidersQuery, LiquidityProvidersQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<LiquidityProviderFeeShareQuery, LiquidityProviderFeeShareQueryVariables>(LiquidityProviderFeeShareDocument, options);
return Apollo.useLazyQuery<LiquidityProvidersQuery, LiquidityProvidersQueryVariables>(LiquidityProvidersDocument, options);
}
export type LiquidityProviderFeeShareQueryHookResult = ReturnType<typeof useLiquidityProviderFeeShareQuery>;
export type LiquidityProviderFeeShareLazyQueryHookResult = ReturnType<typeof useLiquidityProviderFeeShareLazyQuery>;
export type LiquidityProviderFeeShareQueryResult = Apollo.QueryResult<LiquidityProviderFeeShareQuery, LiquidityProviderFeeShareQueryVariables>;
export type LiquidityProvidersQueryHookResult = ReturnType<typeof useLiquidityProvidersQuery>;
export type LiquidityProvidersLazyQueryHookResult = ReturnType<typeof useLiquidityProvidersLazyQuery>;
export type LiquidityProvidersQueryResult = Apollo.QueryResult<LiquidityProvidersQuery, LiquidityProvidersQueryVariables>;

View File

@ -1,7 +1,9 @@
import type { LiquidityProviderFeeShare } from '@vegaprotocol/types';
import { AccountType } from '@vegaprotocol/types';
import { getLiquidityProvision } from './liquidity-data-provider';
import type { LiquidityProvisionFieldsFragment } from './__generated__/MarketLiquidity';
import type {
LiquidityProviderFieldsFragment,
LiquidityProvisionFieldsFragment,
} from './__generated__/MarketLiquidity';
const input = {
liquidityProvisions: [
@ -31,28 +33,32 @@ const input = {
__typename: 'LiquidityProvision',
} as LiquidityProvisionFieldsFragment,
],
liquidityFeeShare: [
liquidityProviders: [
{
party: {
id: 'dde288688af2aeb5feb349dd72d3679a7a9be34c7375f6a4a48ef2f6140e7e59',
__typename: 'Party',
},
partyId:
'dde288688af2aeb5feb349dd72d3679a7a9be34c7375f6a4a48ef2f6140e7e59',
feeShare: {
equityLikeShare: '1',
averageEntryValuation: '12064118310408958216220.7224556301338111',
__typename: 'LiquidityProviderFeeShare',
} as LiquidityProviderFeeShare,
},
} as LiquidityProviderFieldsFragment,
],
};
const result = [
{
__typename: 'LiquidityProvision',
averageEntryValuation: '12064118310408958216220.7224556301338111',
__typename: undefined,
balance: '1.8003328918633596575e+22',
commitmentAmount: '18003328918633596575000',
createdAt: '2022-12-16T09:28:29.071781Z',
feeShare: {
equityLikeShare: '1',
__typename: 'LiquidityProviderFeeShare',
averageEntryValuation: '12064118310408958216220.7224556301338111',
},
fee: '0.001',
partyId: 'dde288688af2aeb5feb349dd72d3679a7a9be34c7375f6a4a48ef2f6140e7e59',
party: {
__typename: 'Party',
accountsConnection: {
@ -84,13 +90,13 @@ describe('getLiquidityProvision', () => {
it('should return correct array when correct liquidity provision parameters are provided', () => {
const data = getLiquidityProvision(
input.liquidityProvisions,
input.liquidityFeeShare
input.liquidityProviders
);
expect(data).toStrictEqual(result);
});
it('should return empty array when no liquidity provision parameters are provided', () => {
const data = getLiquidityProvision([], input.liquidityFeeShare);
const data = getLiquidityProvision([], input.liquidityProviders);
expect(data).toStrictEqual([]);
});

View File

@ -5,86 +5,50 @@ import {
} from '@vegaprotocol/data-provider';
import * as Schema from '@vegaprotocol/types';
import BigNumber from 'bignumber.js';
import produce from 'immer';
import {
LiquidityProviderFeeShareDocument,
LiquidityProvidersDocument,
LiquidityProvisionsDocument,
LiquidityProvisionsUpdateDocument,
} from './__generated__/MarketLiquidity';
import type {
LiquidityProviderFeeShareFieldsFragment,
LiquidityProviderFeeShareQuery,
LiquidityProviderFeeShareQueryVariables,
LiquidityProviderFieldsFragment,
LiquidityProvidersQuery,
LiquidityProvidersQueryVariables,
LiquidityProvisionFieldsFragment,
LiquidityProvisionsQuery,
LiquidityProvisionsQueryVariables,
LiquidityProvisionsUpdateSubscription,
} from './__generated__/MarketLiquidity';
export const liquidityProvisionsDataProvider = makeDataProvider<
LiquidityProvisionsQuery,
LiquidityProvisionFieldsFragment[],
LiquidityProvisionsUpdateSubscription,
LiquidityProvisionsUpdateSubscription['liquidityProvisions'],
never,
never,
LiquidityProvisionsQueryVariables
>({
query: LiquidityProvisionsDocument,
subscriptionQuery: LiquidityProvisionsUpdateDocument,
update: (
data: LiquidityProvisionFieldsFragment[] | null,
deltas: LiquidityProvisionsUpdateSubscription['liquidityProvisions']
) => {
return produce(data || [], (draft) => {
deltas?.forEach((delta) => {
const index = draft.findIndex((a) => delta.id === a.id);
if (index !== -1) {
draft[index].commitmentAmount = delta.commitmentAmount;
draft[index].fee = delta.fee;
draft[index].updatedAt = delta.updatedAt;
draft[index].status = delta.status;
} else {
draft.unshift({
id: delta.id,
commitmentAmount: delta.commitmentAmount,
fee: delta.fee,
status: delta.status,
updatedAt: delta.updatedAt,
createdAt: delta.createdAt,
party: {
id: delta.partyID,
},
// TODO add accounts connection to the subscription
});
}
});
});
},
getData: (responseData: LiquidityProvisionsQuery | null) => {
return (
responseData?.market?.liquidityProvisionsConnection?.edges?.map(
(e) => e?.node
) ?? []
).filter((e) => !!e) as LiquidityProvisionFieldsFragment[];
},
getDelta: (
subscriptionData: LiquidityProvisionsUpdateSubscription
): LiquidityProvisionsUpdateSubscription['liquidityProvisions'] => {
return subscriptionData.liquidityProvisions;
).filter((n) => !!n) as LiquidityProvisionFieldsFragment[];
},
});
export const liquidityFeeShareDataProvider = makeDataProvider<
LiquidityProviderFeeShareQuery,
LiquidityProviderFeeShareFieldsFragment[],
export const lpDataProvider = makeDataProvider<
LiquidityProvidersQuery,
LiquidityProviderFieldsFragment[],
never,
never,
LiquidityProviderFeeShareQueryVariables
LiquidityProvidersQueryVariables
>({
query: LiquidityProviderFeeShareDocument,
query: LiquidityProvidersDocument,
getData: (data) => {
return data?.market?.data?.liquidityProviderFeeShare || [];
return (
data?.liquidityProviders?.edges.filter(Boolean).map((e) => e.node) ?? []
);
},
});
@ -101,17 +65,17 @@ export const lpAggregatedDataProvider = makeDerivedDataProvider<
marketId: variables.marketId,
}),
(callback, client, variables) =>
liquidityFeeShareDataProvider(callback, client, {
lpDataProvider(callback, client, {
marketId: variables.marketId,
}),
],
(
[liquidityProvisions, liquidityFeeShare],
[liquidityProvisions, liquidityProvider],
{ filter }
): LiquidityProvisionData[] => {
return getLiquidityProvision(
liquidityProvisions,
liquidityFeeShare,
liquidityProvider,
filter
);
}
@ -139,9 +103,17 @@ export const matchFilter = (
return true;
};
export interface LiquidityProvisionData
extends Omit<LiquidityProvisionFieldsFragment, '__typename'> {
assetDecimalPlaces?: number;
balance?: string;
averageEntryValuation?: string;
equityLikeShare?: string;
}
export const getLiquidityProvision = (
liquidityProvisions: LiquidityProvisionFieldsFragment[],
liquidityFeeShare: LiquidityProviderFeeShareFieldsFragment[],
liquidityProvider: LiquidityProviderFieldsFragment[],
filter?: Filter
): LiquidityProvisionData[] => {
return liquidityProvisions
@ -161,10 +133,8 @@ export const getLiquidityProvision = (
return true;
})
.map((lp) => {
const feeShare = liquidityFeeShare.find(
(f) => f.party.id === lp.party.id
);
if (!feeShare) return lp;
const lpObj = liquidityProvider.find((f) => lp.party.id === f.partyId);
if (!lpObj) return lp;
const accounts = compact(lp.party.accountsConnection?.edges).map(
(e) => e.node
);
@ -180,17 +150,9 @@ export const getLiquidityProvision = (
.toString() || '0';
return {
...lp,
averageEntryValuation: feeShare?.averageEntryValuation,
equityLikeShare: feeShare?.equityLikeShare,
...lpObj,
balance,
__typename: undefined,
};
});
};
export interface LiquidityProvisionData
extends LiquidityProvisionFieldsFragment {
assetDecimalPlaces?: number;
balance?: string;
averageEntryValuation?: string;
equityLikeShare?: string;
}

View File

@ -10,8 +10,10 @@ const singleRow = {
commitmentAmount: '56298653179',
fee: '0.001',
status: Schema.LiquidityProvisionStatus.STATUS_ACTIVE,
feeShare: {
equityLikeShare: '0.5',
averageEntryValuation: '0.5',
},
supplied: '67895',
obligation: '56785',
} as unknown as LiquidityProvisionData;
@ -41,13 +43,23 @@ describe('LiquidityTable', () => {
h.querySelector('[ref="eText"]')?.textContent?.trim()
);
const expectedHeaders = [
undefined,
undefined,
undefined,
undefined,
undefined,
'Party',
'Commitment ()',
'Share',
'Proposed fee',
'Market valuation at entry',
'Obligation',
'Supplied',
'Fee',
'Adjusted stake share',
'Share',
'Live supplied liquidity',
'Live time fraction on book',
'Live liquidity quality score (%)',
'Last time fraction on the book',
'Last fee penalty',
'Last bond penalty',
'Status',
'Created',
'Updated',

View File

@ -8,9 +8,16 @@ import {
import { t } from '@vegaprotocol/i18n';
import type { TypedDataAgGrid } from '@vegaprotocol/datagrid';
import { AgGrid } from '@vegaprotocol/datagrid';
import { TooltipCellComponent } from '@vegaprotocol/ui-toolkit';
import {
CopyWithTooltip,
Tooltip,
TooltipCellComponent,
VegaIcon,
VegaIconNames,
truncateMiddle,
} from '@vegaprotocol/ui-toolkit';
import type {
ColDef,
ColGroupDef,
ITooltipParams,
ValueFormatterParams,
} from 'ag-grid-community';
@ -24,6 +31,20 @@ const percentageFormatter = ({ value }: ValueFormatterParams) => {
return formatNumberPercentage(new BigNumber(value).times(100), 2) || '-';
};
const copyCellRenderer = ({ value }: { value?: string | null }) => {
if (!value) return '-';
return (
<CopyWithTooltip data-testid="copy-to-clipboard" text={value}>
<button className="flex gap-1">
<Tooltip description={value}>
<span className="break-words">{truncateMiddle(value)}</span>
</Tooltip>
<VegaIcon name={VegaIconNames.COPY} size={12} />
</button>
</CopyWithTooltip>
);
};
const dateValueFormatter = ({ value }: { value?: string | null }) => {
if (!value) {
return '-';
@ -89,12 +110,24 @@ export const LiquidityTable = ({
)}`;
};
const defs: ColDef[] = [
const defs: ColGroupDef[] = [
{
headerName: '',
children: [
{
headerName: t('Party'),
field: 'party.id',
headerTooltip: t('The public key of the party making this commitment.'),
field: 'partyId',
headerTooltip: t(
'The public key of the party making this commitment.'
),
cellRenderer: copyCellRenderer,
},
],
},
{
headerName: t('Commitment details'),
marryChildren: true,
children: [
{
headerName: t(`Commitment (${symbol})`),
field: 'commitmentAmount',
@ -105,34 +138,6 @@ export const LiquidityTable = ({
valueFormatter: assetDecimalsQuantumFormatter,
tooltipValueGetter: assetDecimalsFormatter,
},
{
headerName: t(`Share`),
field: 'equityLikeShare',
type: 'rightAligned',
headerTooltip: t(
'The equity-like share of liquidity of the market used to determine allocation of LP fees. Calculated based on share of total liquidity, with a premium added for length of commitment.'
),
valueFormatter: percentageFormatter,
},
{
headerName: t('Proposed fee'),
headerTooltip: t(
'The fee percentage (per trade) proposed by each liquidity provider.'
),
field: 'fee',
type: 'rightAligned',
valueFormatter: percentageFormatter,
},
{
headerName: t('Market valuation at entry'),
field: 'averageEntryValuation',
type: 'rightAligned',
headerTooltip: t(
'The valuation of the market at the time the liquidity commitment was made. Commitments made at a lower valuation earlier in the lifetime of the market would be expected to have a higher equity-like share if the market has grown. If a commitment is amended, value will reflect the average of the market valuations across the lifetime of the commitment.'
),
valueFormatter: assetDecimalsQuantumFormatter,
tooltipValueGetter: assetDecimalsFormatter,
},
{
headerName: t('Obligation'),
field: 'commitmentAmount',
@ -144,7 +149,40 @@ export const LiquidityTable = ({
tooltipValueGetter: stakeToCcyVolumeFormatter,
},
{
headerName: t('Supplied'),
headerName: t('Fee'),
headerTooltip: t(
'The fee percentage (per trade) proposed by each liquidity provider.'
),
field: 'fee',
type: 'rightAligned',
valueFormatter: percentageFormatter,
},
{
headerName: t('Adjusted stake share'),
field: 'feeShare.virtualStake',
type: 'rightAligned',
headerTooltip: t('The virtual stake of the liquidity provider.'),
valueFormatter: assetDecimalsQuantumFormatter,
tooltipValueGetter: assetDecimalsFormatter,
},
{
headerName: t(`Share`),
field: 'feeShare.equityLikeShare',
type: 'rightAligned',
headerTooltip: t(
'The equity-like share of liquidity of the market used to determine allocation of LP fees. Calculated based on share of total liquidity, with a premium added for length of commitment.'
),
valueFormatter: percentageFormatter,
},
],
},
{
headerName: t('Live liquidity details'),
marryChildren: true,
children: [
{
headerName: t('Live supplied liquidity'),
field: 'balance',
type: 'rightAligned',
headerTooltip: t(
@ -153,6 +191,53 @@ export const LiquidityTable = ({
valueFormatter: stakeToCcyVolumeQuantumFormatter,
tooltipValueGetter: stakeToCcyVolumeFormatter,
},
{
headerName: t(`Live time fraction on book`),
field: 'sla.currentEpochFractionOfTimeOnBook',
type: 'rightAligned',
headerTooltip: t('Current epoch fraction of time on the book.'),
valueFormatter: percentageFormatter,
},
{
headerName: t('Live liquidity quality score (%)'),
field: 'feeShare.averageScore',
type: 'rightAligned',
headerTooltip: t('The average score of the liquidity provider.'),
valueFormatter: percentageFormatter,
},
],
},
{
headerName: t('Last epoch SLA details'),
marryChildren: true,
children: [
{
headerName: t(`Last time fraction on the book`),
field: 'sla.lastEpochFractionOfTimeOnBook',
type: 'rightAligned',
headerTooltip: t('Last epoch fraction of time on the book.'),
valueFormatter: percentageFormatter,
},
{
headerName: t(`Last fee penalty`),
field: 'sla.lastEpochFeePenalty',
type: 'rightAligned',
headerTooltip: t('Last epoch fee penalty.'),
valueFormatter: percentageFormatter,
},
{
headerName: t(`Last bond penalty`),
field: 'sla.lastEpochBondPenalty',
type: 'rightAligned',
headerTooltip: t('Last epoch bond penalty.'),
valueFormatter: percentageFormatter,
},
],
},
{
headerName: '',
marryChildren: true,
children: [
{
headerName: t('Status'),
headerTooltip: t('The current status of this liquidity provision.'),
@ -182,10 +267,11 @@ export const LiquidityTable = ({
type: 'rightAligned',
valueFormatter: dateValueFormatter,
},
],
},
];
return defs;
}, [assetDecimalPlaces, quantum, stakeToCcyVolume, symbol]);
return (
<AgGrid
overlayNoRowsTemplate={t('No liquidity provisions')}

View File

@ -2,7 +2,7 @@ import merge from 'lodash/merge';
import * as Schema from '@vegaprotocol/types';
import type { PartialDeep } from 'type-fest';
import type {
LiquidityProviderFeeShareQuery,
LiquidityProvidersQuery,
LiquidityProvisionsQuery,
} from './__generated__/MarketLiquidity';
import type { LiquidityProvisionFieldsFragment } from './__generated__/MarketLiquidity';
@ -26,40 +26,61 @@ export const liquidityProvisionsQuery = (
return merge(defaultResult, override);
};
export const liquidityProviderFeeShareQuery = (
override?: PartialDeep<LiquidityProviderFeeShareQuery>
): LiquidityProviderFeeShareQuery => {
const defaultResult: LiquidityProviderFeeShareQuery = {
market: {
id: 'market-0',
data: {
market: {
id: 'market-0',
__typename: 'Market',
},
liquidityProviderFeeShare: [
export const liquidityProvidersQuery = (
override?: PartialDeep<LiquidityProvidersQuery>
): LiquidityProvidersQuery => {
const defaultResult: LiquidityProvidersQuery = {
liquidityProviders: {
edges: [
{
party: {
id: '69464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6f',
__typename: 'Party',
},
node: {
partyId:
'69464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6f',
marketId:
'5ddb6f1570c0ef7aea41ebfef234dbded4ce2c11722cf033954459c45c30c057',
feeShare: {
equityLikeShare: '1',
averageEntryValuation: '68585293691.5598054356207737',
__typename: 'LiquidityProviderFeeShare',
averageEntryValuation: '3570452966575.2571864668476351',
averageScore: '0',
virtualStake: '296386536856.9999884883855020',
},
sla: {
currentEpochFractionOfTimeOnBook: '0',
lastEpochFractionOfTimeOnBook: '0',
lastEpochFeePenalty: '1',
lastEpochBondPenalty: '0.05',
hysteresisPeriodFeePenalties: ['1'],
requiredLiquidity: '',
notionalVolumeBuys: '',
notionalVolumeSells: '',
},
},
},
{
party: {
id: 'cc464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6f',
__typename: 'Party',
},
node: {
partyId:
'cc464e35bcb8e8a2900ca0f87acaf252d50cf2ab2fc73694845a16b7c8a0dc6f',
marketId:
'5ddb6f1570c0ef7aea41ebfef234dbded4ce2c11722cf033954459c45c30c057',
feeShare: {
equityLikeShare: '1',
averageEntryValuation: '68585293691.5598054356207737',
__typename: 'LiquidityProviderFeeShare',
averageEntryValuation: '3570452966575.2571864668476351',
averageScore: '0',
virtualStake: '296386536856.9999884883855020',
},
sla: {
currentEpochFractionOfTimeOnBook: '0',
lastEpochFractionOfTimeOnBook: '0',
lastEpochFeePenalty: '1',
lastEpochBondPenalty: '0.05',
hysteresisPeriodFeePenalties: ['1'],
requiredLiquidity: '',
notionalVolumeBuys: '',
notionalVolumeSells: '',
},
},
},
],
__typename: 'MarketData',
},
__typename: 'Market',
},
};
return merge(defaultResult, override);

View File

@ -53,7 +53,10 @@ export const Tooltip = ({
className={tooltipContentClasses}
sideOffset={sideOffset}
>
<div className="relative z-0" data-testid="tooltip-content">
<div
className="relative z-0 break-words"
data-testid="tooltip-content"
>
{description}
</div>
</Content>