feat(trading): add funding payment history (#4989)

This commit is contained in:
Bartłomiej Głownia 2023-10-09 16:59:00 +02:00 committed by GitHub
parent 81ebefc329
commit da8e382454
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 1014 additions and 30 deletions

View File

@ -138,6 +138,9 @@ const MainGrid = memo(
<Tab id="fills" name={t('Fills')}>
<TradingViews.fills.component />
</Tab>
<Tab id="funding-payments" name={t('Funding payments')}>
<TradingViews.fundingPayments.component />
</Tab>
<Tab
id="accounts"
name={t('Collateral')}

View File

@ -14,6 +14,7 @@ import { PositionsContainer } from '../../components/positions-container';
import { AccountsContainer } from '../../components/accounts-container';
import { LiquidityContainer } from '../../components/liquidity-container';
import { FundingContainer } from '../../components/funding-container';
import { FundingPaymentsContainer } from '../../components/funding-payments-container';
import type { OrderContainerProps } from '../../components/orders-container';
import { OrdersContainer } from '../../components/orders-container';
import { StopOrdersContainer } from '../../components/stop-orders-container';
@ -55,6 +56,10 @@ export const TradingViews = {
label: 'Funding',
component: requiresMarket(FundingContainer),
},
fundingPayments: {
label: 'Funding Payments',
component: FundingPaymentsContainer,
},
orderbook: {
label: 'Orderbook',
component: requiresMarket(OrderbookContainer),

View File

@ -9,6 +9,7 @@ import { usePageTitleStore } from '../../stores';
import { AccountsContainer } from '../../components/accounts-container';
import { DepositsContainer } from '../../components/deposits-container';
import { FillsContainer } from '../../components/fills-container';
import { FundingPaymentsContainer } from '../../components/funding-payments-container';
import { PositionsContainer } from '../../components/positions-container';
import { PositionsMenu } from '../../components/positions-menu';
import { WithdrawalsContainer } from '../../components/withdrawals-container';
@ -82,6 +83,9 @@ export const Portfolio = () => {
<Tab id="fills" name={t('Fills')}>
<FillsContainer />
</Tab>
<Tab id="funding-payments" name={t('Funding payments')}>
<FundingPaymentsContainer />
</Tab>
<Tab id="ledger-entries" name={t('Ledger entries')}>
<LedgerContainer />
</Tab>

View File

@ -0,0 +1,46 @@
import { useVegaWallet } from '@vegaprotocol/wallet';
import { FundingPaymentsManager } from '@vegaprotocol/funding-payments';
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import { useDataGridEvents } from '@vegaprotocol/datagrid';
import { t } from '@vegaprotocol/i18n';
import { Splash } from '@vegaprotocol/ui-toolkit';
import type { DataGridSlice } from '../../stores/datagrid-store-slice';
import { createDataGridSlice } from '../../stores/datagrid-store-slice';
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
export const FundingPaymentsContainer = () => {
const onMarketClick = useMarketClickHandler(true);
const { pubKey } = useVegaWallet();
const gridStore = useFundingPaymentsStore((store) => store.gridStore);
const updateGridStore = useFundingPaymentsStore(
(store) => store.updateGridStore
);
const gridStoreCallbacks = useDataGridEvents(gridStore, (colState) => {
updateGridStore(colState);
});
if (!pubKey) {
return (
<Splash>
<p>{t('Please connect Vega wallet')}</p>
</Splash>
);
}
return (
<FundingPaymentsManager
partyId={pubKey}
onMarketClick={onMarketClick}
gridProps={gridStoreCallbacks}
/>
);
};
const useFundingPaymentsStore = create<DataGridSlice>()(
persist(createDataGridSlice, {
name: 'vega_funding_payments_store',
})
);

View File

@ -0,0 +1 @@
export * from './funding-payments-container';

View File

@ -10,6 +10,7 @@ export * from '../deposits/src/lib/deposit.mock';
export * from '../environment/src/utils/node.mock';
export * from '../environment/src/components/node-guard/node-guard.mock';
export * from '../fills/src/lib/fills.mock';
export * from '../funding-payments/src/lib/funding-payments.mock';
export * from '../proposals/src/lib/proposals-data-provider/proposals.mock';
export * from '../market-depth/src/lib/market-depth.mock';
export * from '../markets/src/lib/components/market-info/market-info.mock';

View File

@ -0,0 +1,13 @@
{
"sourceType": "unambiguous",
"presets": [
[
"@nx/react/babel",
{
"runtime": "automatic",
"useBuiltIns": "usage"
}
]
],
"plugins": []
}

View File

@ -0,0 +1,18 @@
{
"extends": ["plugin:@nx/react", "../../.eslintrc.json"],
"ignorePatterns": ["!**/*", "__generated__"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}

View File

@ -0,0 +1,7 @@
# funding-payments
This library was generated with [Nx](https://nx.dev).
## Running unit tests
Run `nx test funding-payments` to execute the unit tests via [Jest](https://jestjs.io).

View File

@ -0,0 +1,6 @@
function ReactMarkdown({ children }) {
// eslint-disable-next-line react/jsx-no-useless-fragment
return <>{children}</>;
}
export default ReactMarkdown;

View File

@ -0,0 +1,17 @@
/* eslint-disable */
export default {
displayName: 'funding-payments',
preset: '../../jest.preset.js',
globals: {},
transform: {
'^.+\\.[tj]sx?$': [
'ts-jest',
{
tsconfig: '<rootDir>/tsconfig.spec.json',
},
],
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: '../../coverage/libs/funding-payments',
setupFilesAfterEnv: ['./src/setup-tests.ts'],
};

View File

@ -0,0 +1,10 @@
const { join } = require('path');
module.exports = {
plugins: {
tailwindcss: {
config: join(__dirname, 'tailwind.config.js'),
},
autoprefixer: {},
},
};

View File

@ -0,0 +1,37 @@
{
"name": "funding-payments",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "libs/funding-payments/src",
"projectType": "library",
"tags": [],
"targets": {
"lint": {
"executor": "@nx/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["libs/funding-payments/**/*.{ts,tsx,js,jsx}"]
}
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/libs/funding-payments"],
"options": {
"jestConfig": "libs/funding-payments/jest.config.ts",
"passWithNoTests": true
},
"configurations": {
"ci": {
"ci": true,
"codeCoverage": true
}
}
},
"build-spec": {
"executor": "nx:run-commands",
"outputs": [],
"options": {
"command": "yarn tsc --project ./libs/funding-payments/tsconfig.spec.json"
}
}
}
}

View File

@ -0,0 +1,3 @@
export * from './lib/funding-payments-manager';
export * from './lib/funding-payments-data-provider';
export * from './lib/__generated__/FundingPayments';

View File

@ -0,0 +1,24 @@
fragment FundingPaymentFields on FundingPayment {
marketId
partyId
fundingPeriodSeq
amount
timestamp
}
query FundingPayments($partyId: ID!, $pagination: Pagination) {
fundingPayments(partyId: $partyId, pagination: $pagination) {
edges {
node {
...FundingPaymentFields
}
cursor
}
pageInfo {
startCursor
endCursor
hasNextPage
hasPreviousPage
}
}
}

View File

@ -0,0 +1,71 @@
import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type FundingPaymentFieldsFragment = { __typename?: 'FundingPayment', marketId: string, partyId: string, fundingPeriodSeq: number, amount?: string | null, timestamp: any };
export type FundingPaymentsQueryVariables = Types.Exact<{
partyId: Types.Scalars['ID'];
pagination?: Types.InputMaybe<Types.Pagination>;
}>;
export type FundingPaymentsQuery = { __typename?: 'Query', fundingPayments: { __typename?: 'FundingPaymentConnection', edges: Array<{ __typename?: 'FundingPaymentEdge', cursor: string, node: { __typename?: 'FundingPayment', marketId: string, partyId: string, fundingPeriodSeq: number, amount?: string | null, timestamp: any } }>, pageInfo: { __typename?: 'PageInfo', startCursor: string, endCursor: string, hasNextPage: boolean, hasPreviousPage: boolean } } };
export const FundingPaymentFieldsFragmentDoc = gql`
fragment FundingPaymentFields on FundingPayment {
marketId
partyId
fundingPeriodSeq
amount
timestamp
}
`;
export const FundingPaymentsDocument = gql`
query FundingPayments($partyId: ID!, $pagination: Pagination) {
fundingPayments(partyId: $partyId, pagination: $pagination) {
edges {
node {
...FundingPaymentFields
}
cursor
}
pageInfo {
startCursor
endCursor
hasNextPage
hasPreviousPage
}
}
}
${FundingPaymentFieldsFragmentDoc}`;
/**
* __useFundingPaymentsQuery__
*
* To run a query within a React component, call `useFundingPaymentsQuery` and pass it any options that fit your needs.
* When your component renders, `useFundingPaymentsQuery` 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 } = useFundingPaymentsQuery({
* variables: {
* partyId: // value for 'partyId'
* pagination: // value for 'pagination'
* },
* });
*/
export function useFundingPaymentsQuery(baseOptions: Apollo.QueryHookOptions<FundingPaymentsQuery, FundingPaymentsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<FundingPaymentsQuery, FundingPaymentsQueryVariables>(FundingPaymentsDocument, options);
}
export function useFundingPaymentsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<FundingPaymentsQuery, FundingPaymentsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<FundingPaymentsQuery, FundingPaymentsQueryVariables>(FundingPaymentsDocument, options);
}
export type FundingPaymentsQueryHookResult = ReturnType<typeof useFundingPaymentsQuery>;
export type FundingPaymentsLazyQueryHookResult = ReturnType<typeof useFundingPaymentsLazyQuery>;
export type FundingPaymentsQueryResult = Apollo.QueryResult<FundingPaymentsQuery, FundingPaymentsQueryVariables>;

View File

@ -0,0 +1,69 @@
import type { PageInfo, Cursor } from '@vegaprotocol/data-provider';
import {
makeDataProvider,
makeDerivedDataProvider,
defaultAppend as append,
} from '@vegaprotocol/data-provider';
import type { Market } from '@vegaprotocol/markets';
import { marketsMapProvider } from '@vegaprotocol/markets';
import { FundingPaymentsDocument } from './__generated__/FundingPayments';
import type {
FundingPaymentsQuery,
FundingPaymentsQueryVariables,
FundingPaymentFieldsFragment,
} from './__generated__/FundingPayments';
export type FundingPayment = Omit<FundingPaymentFieldsFragment, 'market'> & {
market?: Market;
};
const getData = (
responseData: FundingPaymentsQuery | null
): (FundingPaymentFieldsFragment & Cursor)[] =>
responseData?.fundingPayments?.edges.map<
FundingPaymentFieldsFragment & Cursor
>((edge) => ({
...edge.node,
cursor: edge.cursor,
})) || [];
const getPageInfo = (
responseData: FundingPaymentsQuery | null
): PageInfo | null => responseData?.fundingPayments?.pageInfo || null;
export const fundingPaymentsProvider = makeDataProvider<
Parameters<typeof getData>['0'],
ReturnType<typeof getData>,
never,
never,
FundingPaymentsQueryVariables
>({
query: FundingPaymentsDocument,
getData,
pagination: {
getPageInfo,
append,
first: 100,
},
});
export const fundingPaymentsWithMarketProvider = makeDerivedDataProvider<
FundingPayment[],
never,
FundingPaymentsQueryVariables
>(
[
fundingPaymentsProvider,
(callback, client) => marketsMapProvider(callback, client, undefined),
],
(partsData): FundingPayment[] | null => {
return ((partsData[0] as ReturnType<typeof getData>) || []).map(
(fundingPayment) => ({
...fundingPayment,
market: (partsData[1] as Record<string, Market>)[
fundingPayment.marketId
],
})
);
}
);

View File

@ -0,0 +1,42 @@
import type { AgGridReact } from 'ag-grid-react';
import { useRef } from 'react';
import { t } from '@vegaprotocol/i18n';
import { FundingPaymentsTable } from './funding-payments-table';
import type { useDataGridEvents } from '@vegaprotocol/datagrid';
import { useDataProvider } from '@vegaprotocol/data-provider';
import { fundingPaymentsWithMarketProvider } from './funding-payments-data-provider';
interface FundingPaymentsManagerProps {
partyId: string;
onMarketClick?: (marketId: string, metaKey?: boolean) => void;
gridProps: ReturnType<typeof useDataGridEvents>;
}
export const FundingPaymentsManager = ({
partyId,
onMarketClick,
gridProps,
}: FundingPaymentsManagerProps) => {
const gridRef = useRef<AgGridReact | null>(null);
const { data, error } = useDataProvider({
dataProvider: fundingPaymentsWithMarketProvider,
update: ({ data }) => {
if (data?.length && gridRef.current?.api) {
gridRef.current?.api.setRowData(data);
return true;
}
return false;
},
variables: { partyId },
});
return (
<FundingPaymentsTable
ref={gridRef}
rowData={data}
onMarketClick={onMarketClick}
overlayNoRowsTemplate={error ? error.message : t('No funding payments')}
{...gridProps}
/>
);
};

View File

@ -0,0 +1,92 @@
import { act, render, screen } from '@testing-library/react';
import { getDateTimeFormat } from '@vegaprotocol/utils';
import type { PartialDeep } from 'type-fest';
import type { FundingPayment } from './funding-payments-data-provider';
import { FundingPaymentsTable } from './funding-payments-table';
import { generateFundingPayment } from './test-helpers';
describe('FundingPaymentsTable', () => {
let defaultFundingPayment: PartialDeep<FundingPayment>;
beforeEach(() => {
defaultFundingPayment = {
marketId:
'69abf5c456c20f4d189cea79a11dfd6b0958ead58ab34bd66f73eea48aee600c',
partyId:
'02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65',
fundingPeriodSeq: 84,
amount: '100',
timestamp: '2023-10-06T07:06:43.020994Z',
market: {
decimalPlaces: 2,
positionDecimalPlaces: 5,
tradableInstrument: {
instrument: {
code: 'test market',
product: {
__typename: 'Future',
settlementAsset: {
decimals: 2,
symbol: 'BTC',
},
},
},
},
},
};
});
it('correct columns are rendered', async () => {
await act(async () => {
render(<FundingPaymentsTable rowData={[generateFundingPayment()]} />);
});
const headers = screen.getAllByRole('columnheader');
const expectedHeaders = ['Market', 'Amount', 'Date'];
expect(headers).toHaveLength(expectedHeaders.length);
expect(headers.map((h) => h.textContent?.trim())).toEqual(expectedHeaders);
});
it('formats positive cells', async () => {
const fundingPayment = generateFundingPayment({
...defaultFundingPayment,
});
render(<FundingPaymentsTable rowData={[fundingPayment]} />);
const cells = screen.getAllByRole('gridcell');
const expectedValues = [
fundingPayment.market?.tradableInstrument.instrument.code || '',
'1.00 BTC',
getDateTimeFormat().format(new Date(fundingPayment.timestamp)),
];
cells.forEach((cell, i) => {
expect(cell).toHaveTextContent(expectedValues[i]);
});
const amountCell = cells.find((c) => c.getAttribute('col-id') === 'amount');
expect(
amountCell?.querySelector('.ag-cell-value')?.firstElementChild
).toHaveClass('text-market-green-600');
});
it('formats negative cells', async () => {
const fundingPayment = generateFundingPayment({
...defaultFundingPayment,
amount: `-${defaultFundingPayment.amount}`,
});
render(<FundingPaymentsTable rowData={[fundingPayment]} />);
const cells = screen.getAllByRole('gridcell');
const expectedValues = [
fundingPayment.market?.tradableInstrument.instrument.code || '',
'-1.00 BTC',
getDateTimeFormat().format(new Date(fundingPayment.timestamp)),
];
cells.forEach((cell, i) => {
expect(cell).toHaveTextContent(expectedValues[i]);
});
const amountCell = cells.find((c) => c.getAttribute('col-id') === 'amount');
expect(
amountCell?.querySelector('.ag-cell-value')?.firstElementChild
).toHaveClass('text-market-red dark:text-market-red');
});
});

View File

@ -0,0 +1,132 @@
import { useMemo } from 'react';
import type {
AgGridReact,
AgGridReactProps,
AgReactUiProps,
} from 'ag-grid-react';
import type { ColDef } from 'ag-grid-community';
import {
addDecimalsFormatNumber,
getDateTimeFormat,
isNumeric,
toBigNum,
} from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import {
AgGrid,
DateRangeFilter,
MarketNameCell,
negativeClassNames,
positiveClassNames,
} from '@vegaprotocol/datagrid';
import type {
VegaValueFormatterParams,
VegaValueGetterParams,
} from '@vegaprotocol/datagrid';
import { forwardRef } from 'react';
import type { FundingPayment } from './funding-payments-data-provider';
import { getAsset } from '@vegaprotocol/markets';
import classNames from 'classnames';
const defaultColDef = {
resizable: true,
sortable: true,
};
export type Props = (AgGridReactProps | AgReactUiProps) & {
onMarketClick?: (marketId: string, metaKey?: boolean) => void;
};
const formatAmount = ({
value,
data,
}: VegaValueFormatterParams<FundingPayment, 'amount'>) => {
if (!data?.market || !isNumeric(value)) {
return '-';
}
const { symbol: assetSymbol, decimals: assetDecimals } = getAsset(
data.market
);
const valueFormatted = addDecimalsFormatNumber(value, assetDecimals);
return `${valueFormatted} ${assetSymbol}`;
};
export const FundingPaymentsTable = forwardRef<AgGridReact, Props>(
({ onMarketClick, ...props }, ref) => {
const columnDefs = useMemo<ColDef[]>(
() => [
{
headerName: t('Market'),
field: 'market.tradableInstrument.instrument.code',
cellRenderer: 'MarketNameCell',
filter: true,
cellRendererParams: { idPath: 'market.id', onMarketClick },
},
{
headerName: t('Amount'),
field: 'amount',
valueFormatter: formatAmount,
type: 'rightAligned',
filter: 'agNumberColumnFilter',
valueGetter: ({ data }: VegaValueGetterParams<FundingPayment>) =>
data?.amount && data?.market
? toBigNum(data.amount, getAsset(data.market).decimals).toNumber()
: 0,
cellRenderer: ({ data }: { data: FundingPayment }) => {
if (!data?.market || !isNumeric(data.amount)) {
return '-';
}
const { symbol: assetSymbol, decimals: assetDecimals } = getAsset(
data.market
);
const valueFormatted = addDecimalsFormatNumber(
data.amount,
assetDecimals
);
return (
<>
<span
className={classNames({
[positiveClassNames]: !data?.amount?.startsWith('-'),
[negativeClassNames]: !!data?.amount?.startsWith('-'),
})}
>
{valueFormatted}
</span>
{` ${assetSymbol}`}
</>
);
},
},
{
headerName: t('Date'),
field: 'timestamp',
type: 'rightAligned',
filter: DateRangeFilter,
valueFormatter: ({
value,
}: VegaValueFormatterParams<FundingPayment, 'timestamp'>) => {
return value ? getDateTimeFormat().format(new Date(value)) : '';
},
},
],
[onMarketClick]
);
return (
<AgGrid
ref={ref}
defaultColDef={defaultColDef}
columnDefs={columnDefs}
overlayNoRowsTemplate={t('No funding payments')}
getRowId={({ data }: { data?: FundingPayment }) =>
`${data?.marketId}-${data?.fundingPeriodSeq}`
}
components={{ MarketNameCell }}
{...props}
/>
);
}
);

View File

@ -0,0 +1,74 @@
import type {
FundingPaymentsQuery,
FundingPaymentFieldsFragment,
} from './__generated__/FundingPayments';
import merge from 'lodash/merge';
import type { PartialDeep } from 'type-fest';
export const fundingPaymentsQuery = (
override?: PartialDeep<FundingPaymentsQuery>,
vegaPublicKey?: string
): FundingPaymentsQuery => {
const defaultResult: FundingPaymentsQuery = {
fundingPayments: {
__typename: 'FundingPaymentConnection',
edges: fundingPayments(vegaPublicKey).map((node) => ({
__typename: 'FundingPaymentEdge',
cursor: '3',
node,
})),
pageInfo: {
__typename: 'PageInfo',
startCursor: '1',
endCursor: '2',
hasNextPage: false,
hasPreviousPage: false,
},
},
};
return merge(defaultResult, override);
};
export const generateFundingPayment = (
override?: PartialDeep<FundingPaymentFieldsFragment>
) => {
const defaultFundingPayment: FundingPaymentFieldsFragment = {
marketId: 'market-0',
partyId: 'partyId',
fundingPeriodSeq: 84,
amount: '126973',
timestamp: '2023-10-06T07:06:43.020994Z',
};
return merge(defaultFundingPayment, override);
};
const fundingPayments = (
partyId = 'partyId'
): FundingPaymentFieldsFragment[] => [
generateFundingPayment({
partyId,
fundingPeriodSeq: 78,
amount: '92503',
timestamp: '2023-10-06T04:06:43.652759Z',
}),
generateFundingPayment({
partyId,
fundingPeriodSeq: 77,
amount: '-37841',
timestamp: '2023-10-06T03:36:43.437139Z',
}),
generateFundingPayment({
partyId,
fundingPeriodSeq: 76,
amount: '32838',
timestamp: '2023-10-06T03:06:43.430384Z',
}),
generateFundingPayment({
partyId,
fundingPeriodSeq: 75,
amount: '-298259',
timestamp: '2023-10-06T02:36:43.51153Z',
}),
];

View File

@ -0,0 +1,102 @@
import merge from 'lodash/merge';
import type { PartialDeep } from 'type-fest';
import * as Schema from '@vegaprotocol/types';
import type { FundingPayment } from './funding-payments-data-provider';
const { MarketState, MarketTradingMode } = Schema;
export const generateFundingPayment = (
override?: PartialDeep<FundingPayment>
) => {
const defaultFundingPayment: FundingPayment = {
marketId:
'69abf5c456c20f4d189cea79a11dfd6b0958ead58ab34bd66f73eea48aee600c',
partyId: '02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65',
fundingPeriodSeq: 84,
amount: '126973',
timestamp: '2023-10-06T07:06:43.020994Z',
market: {
__typename: 'Market',
id: 'market-id',
positionDecimalPlaces: 0,
decimalPlaces: 5,
state: MarketState.STATE_ACTIVE,
tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS,
liquidityMonitoringParameters: {
triggeringRatio: '1',
},
fees: {
__typename: 'Fees',
factors: {
__typename: 'FeeFactors',
infrastructureFee: '0.1',
liquidityFee: '0.1',
makerFee: '0.1',
},
},
marketTimestamps: {
__typename: 'MarketTimestamps',
open: '2005-04-02T19:37:00.000Z',
close: '2005-04-02T19:37:00.000Z',
},
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
id: 'instrument-id',
code: 'instrument-code',
name: 'UNIDAI Monthly (30 Jun 2022)',
metadata: {
__typename: 'InstrumentMetadata',
tags: ['tag-a'],
},
product: {
__typename: 'Future',
settlementAsset: {
__typename: 'Asset',
id: 'asset-id',
name: 'asset-id',
symbol: 'SYM',
decimals: 18,
quantum: '1',
},
quoteName: '',
dataSourceSpecForTradingTermination: {
__typename: 'DataSourceSpec',
id: 'oracleId',
data: {
__typename: 'DataSourceDefinition',
sourceType: {
__typename: 'DataSourceDefinitionExternal',
sourceType: {
__typename: 'DataSourceSpecConfiguration',
},
},
},
},
dataSourceSpecForSettlementData: {
__typename: 'DataSourceSpec',
id: 'oracleId',
data: {
__typename: 'DataSourceDefinition',
sourceType: {
__typename: 'DataSourceDefinitionExternal',
sourceType: {
__typename: 'DataSourceSpecConfiguration',
},
},
},
},
dataSourceSpecBinding: {
__typename: 'DataSourceSpecToFutureBinding',
tradingTerminationProperty: 'trading-termination-property',
settlementDataProperty: 'settlement-data-property',
},
},
},
},
},
};
return merge(defaultFundingPayment, override);
};

View File

@ -0,0 +1,4 @@
import '@testing-library/jest-dom';
import ResizeObserver from 'resize-observer-polyfill';
global.ResizeObserver = ResizeObserver;

View File

@ -0,0 +1,17 @@
const { join } = require('path');
const { createGlobPatternsForDependencies } = require('@nx/react/tailwind');
const theme = require('../tailwindcss-config/src/theme');
const vegaCustomClasses = require('../tailwindcss-config/src/vega-custom-classes');
module.exports = {
content: [
join(__dirname, 'src/**/*.{ts,tsx,html,mdx}'),
join(__dirname, '.storybook/preview.js'),
...createGlobPatternsForDependencies(__dirname),
],
darkMode: 'class',
theme: {
extend: theme,
},
plugins: [vegaCustomClasses],
};

View File

@ -0,0 +1,27 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"jsx": "react-jsx",
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
},
{
"path": "./.storybook/tsconfig.json"
}
]
}

View File

@ -0,0 +1,27 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"types": ["node"]
},
"files": [
"../../node_modules/@nx/react/typings/cssmodule.d.ts",
"../../node_modules/@nx/react/typings/image.d.ts"
],
"exclude": [
"**/*.spec.ts",
"**/*.test.ts",
"**/*.spec.tsx",
"**/*.test.tsx",
"**/*.spec.js",
"**/*.test.js",
"**/*.spec.jsx",
"**/*.test.jsx",
"**/*.stories.ts",
"**/*.stories.js",
"**/*.stories.jsx",
"**/*.stories.tsx",
"jest.config.ts"
],
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
}

View File

@ -0,0 +1,20 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node", "@testing-library/jest-dom"]
},
"include": [
"**/*.test.ts",
"**/*.spec.ts",
"**/*.test.tsx",
"**/*.spec.tsx",
"**/*.test.js",
"**/*.spec.js",
"**/*.test.jsx",
"**/*.spec.jsx",
"**/*.d.ts",
"jest.config.ts"
]
}

View File

@ -1287,6 +1287,39 @@ export type Filter = {
key: PropertyKey;
};
/** The funding payment from a perpetual market. */
export type FundingPayment = {
__typename?: 'FundingPayment';
/** Amount transferred */
amount?: Maybe<Scalars['String']>;
/** Sequence number of the funding period the funding payment belongs to. */
fundingPeriodSeq: Scalars['Int'];
/** Market the funding payment applies to. */
marketId: Scalars['ID'];
/** Party the funding payment applies to. */
partyId: Scalars['ID'];
/** RFC3339Nano timestamp when the data point was received. */
timestamp: Scalars['Timestamp'];
};
/** Connection type for funding payment */
export type FundingPaymentConnection = {
__typename?: 'FundingPaymentConnection';
/** List of funding payments */
edges: Array<FundingPaymentEdge>;
/** Pagination information */
pageInfo: PageInfo;
};
/** Edge type for funding payment */
export type FundingPaymentEdge = {
__typename?: 'FundingPaymentEdge';
/** Cursor identifying the funding payment */
cursor: Scalars['String'];
/** The funding payment */
node: FundingPayment;
};
/** Details of a funding interval for a perpetual market. */
export type FundingPeriod = {
__typename?: 'FundingPeriod';
@ -4097,6 +4130,8 @@ export type Query = {
coreSnapshots?: Maybe<CoreSnapshotConnection>;
/** Get the current referral program */
currentReferralProgram?: Maybe<CurrentReferralProgram>;
/** Get the current volume discount program */
currentVolumeDiscountProgram?: Maybe<VolumeDiscountProgram>;
/** Find a deposit using its ID */
deposit?: Maybe<Deposit>;
/** Fetch all deposits */
@ -4128,6 +4163,8 @@ export type Query = {
estimatePosition?: Maybe<PositionEstimate>;
/** Query for historic ethereum key rotations */
ethereumKeyRotations: EthereumKeyRotationsConnection;
/** Funding payment for perpetual markets. */
fundingPayments: FundingPaymentConnection;
/**
* Funding period data points for a perpetual market. The data points within a funding period are used to calculate the
* time-weighted average price (TWAP), funding rate and funding payments for each funding period.
@ -4196,6 +4233,8 @@ export type Query = {
/** Get referrer fee and discount stats */
referralFeeStats?: Maybe<ReferralSetFeeStats>;
referralSetReferees: ReferralSetRefereeConnection;
/** Get referral set statistics */
referralSetStats: ReferralSetStatsConnection;
/** List referral sets */
referralSets: ReferralSetConnection;
/** Get statistics about the Vega node */
@ -4224,6 +4263,8 @@ export type Query = {
transfer?: Maybe<Transfer>;
/** Get a list of all transfers for a public key */
transfersConnection?: Maybe<TransferConnection>;
/** Get volume discount statistics */
volumeDiscountStats: VolumeDiscountStatsConnection;
/** Find a withdrawal using its ID */
withdrawal?: Maybe<Withdrawal>;
/** Fetch all withdrawals */
@ -4369,6 +4410,14 @@ export type QueryethereumKeyRotationsArgs = {
};
/** Queries allow a caller to read data and filter data via GraphQL. */
export type QueryfundingPaymentsArgs = {
marketId?: InputMaybe<Scalars['ID']>;
pagination?: InputMaybe<Pagination>;
partyId: Scalars['ID'];
};
/** Queries allow a caller to read data and filter data via GraphQL. */
export type QueryfundingPeriodDataPointsArgs = {
dateRange?: InputMaybe<DateRange>;
@ -4568,6 +4617,15 @@ export type QueryreferralSetRefereesArgs = {
};
/** Queries allow a caller to read data and filter data via GraphQL. */
export type QueryreferralSetStatsArgs = {
epoch?: InputMaybe<Scalars['Int']>;
id: Scalars['ID'];
pagination?: InputMaybe<Pagination>;
partyId?: InputMaybe<Scalars['ID']>;
};
/** Queries allow a caller to read data and filter data via GraphQL. */
export type QueryreferralSetsArgs = {
id?: InputMaybe<Scalars['ID']>;
@ -4642,6 +4700,14 @@ export type QuerytransfersConnectionArgs = {
};
/** Queries allow a caller to read data and filter data via GraphQL. */
export type QueryvolumeDiscountStatsArgs = {
epoch?: InputMaybe<Scalars['Int']>;
pagination?: InputMaybe<Pagination>;
partyId?: InputMaybe<Scalars['ID']>;
};
/** Queries allow a caller to read data and filter data via GraphQL. */
export type QuerywithdrawalArgs = {
id: Scalars['ID'];
@ -4700,18 +4766,6 @@ export type RecurringTransfer = {
startEpoch: Scalars['Int'];
};
export type RefereeStats = {
__typename?: 'RefereeStats';
/** Discount factor applied to the party. */
discountFactor: Scalars['String'];
/** Current referee notional taker volume */
epochNotionalTakerVolume: Scalars['String'];
/** Unique ID of the party. */
partyId: Scalars['ID'];
/** Reward factor applied to the party. */
rewardFactor: Scalars['String'];
};
/** Referral program information */
export type ReferralProgram = {
__typename?: 'ReferralProgram';
@ -4742,22 +4796,10 @@ export type ReferralSet = {
id: Scalars['ID'];
/** Party that created the set. */
referrer: Scalars['ID'];
/**
* Referral set statistics for the latest or specific epoch.
* If provided the results can be filtered for a specific referee
*/
stats?: Maybe<ReferralSetStats>;
/** Timestamp as RFC3339Nano when the referral set was updated. */
updatedAt: Scalars['Timestamp'];
};
/** Data relating to a referral set. */
export type ReferralSetstatsArgs = {
epoch?: InputMaybe<Scalars['Int']>;
referee?: InputMaybe<Scalars['ID']>;
};
/** Connection type for retrieving cursor-based paginated referral set information */
export type ReferralSetConnection = {
__typename?: 'ReferralSetConnection';
@ -4828,14 +4870,36 @@ export type ReferralSetRefereeEdge = {
export type ReferralSetStats = {
__typename?: 'ReferralSetStats';
/** Epoch at which the set's statistics are updated. */
atEpoch?: Maybe<Scalars['Int']>;
/** Referees' statistics for that epoch. */
referees_stats: Array<RefereeStats>;
/** Epoch at which the statistics are updated. */
atEpoch: Scalars['Int'];
/** Discount factor applied to the party. */
discountFactor: Scalars['String'];
/** Current referee notional taker volume */
epochNotionalTakerVolume: Scalars['String'];
/** Unique ID of the party. */
partyId: Scalars['ID'];
/** Running volume for the set based on the window length of the current referral program. */
referralSetRunningNotionalTakerVolume: Scalars['String'];
/** Unique ID of the set */
setId: Scalars['ID'];
/** Reward factor applied to the party. */
rewardFactor: Scalars['String'];
};
/** Connection type for retrieving cursor-based paginated referral set statistics information */
export type ReferralSetStatsConnection = {
__typename?: 'ReferralSetStatsConnection';
/** The referral set statistics in this connection */
edges: Array<Maybe<ReferralSetStatsEdge>>;
/** The pagination information */
pageInfo: PageInfo;
};
/** Edge type containing the referral set statistics and cursor information returned by a ReferralSetStatsConnection */
export type ReferralSetStatsEdge = {
__typename?: 'ReferralSetStatsEdge';
/** The cursor for this referral set statistics */
cursor: Scalars['String'];
/** The referral set statistics */
node: ReferralSetStats;
};
/** Rewards generated for referrers by each of their referees */
@ -6137,6 +6201,53 @@ export type VolumeBenefitTier = {
volumeDiscountFactor: Scalars['String'];
};
/** Volume discount program information */
export type VolumeDiscountProgram = {
__typename?: 'VolumeDiscountProgram';
/** Defined tiers in increasing order. First element will give Tier 1, second element will give Tier 2, etc. */
benefitTiers: Array<VolumeBenefitTier>;
/** Timestamp as Unix time in nanoseconds, after which when the current epoch ends, the programs will end and benefits will be disabled. */
endOfProgramTimestamp: Scalars['Timestamp'];
/** Timestamp as RFC3339Nano when the program ended. If present, the current program has ended and no program is currently running. */
endedAt?: Maybe<Scalars['Timestamp']>;
/** Unique ID generated from the proposal that created this program. */
id: Scalars['ID'];
/** Incremental version of the program. It is incremented each time the volume discount program is edited. */
version: Scalars['Int'];
/** Number of epochs over which to evaluate parties' running volume. */
windowLength: Scalars['Int'];
};
export type VolumeDiscountStats = {
__typename?: 'VolumeDiscountStats';
/** Epoch at which the statistics are updated. */
atEpoch: Scalars['Int'];
/** Discount factor applied to the party. */
discountFactor: Scalars['String'];
/** Unique ID of the party. */
partyId: Scalars['ID'];
/** Party's running volume. */
runningVolume: Scalars['String'];
};
/** Connection type for retrieving cursor-based paginated volume discount statistics information */
export type VolumeDiscountStatsConnection = {
__typename?: 'VolumeDiscountStatsConnection';
/** The volume discount statistics in this connection */
edges: Array<Maybe<VolumeDiscountStatsEdge>>;
/** The pagination information */
pageInfo: PageInfo;
};
/** Edge type containing the volume discount statistics and cursor information returned by a VolumeDiscountStatsConnection */
export type VolumeDiscountStatsEdge = {
__typename?: 'VolumeDiscountStatsEdge';
/** The cursor for this volume discount statistics */
cursor: Scalars['String'];
/** The volume discount statistics */
node: VolumeDiscountStats;
};
export type Vote = {
__typename?: 'Vote';
/** RFC3339Nano time and date when the vote reached Vega network */

View File

@ -28,6 +28,7 @@
"@vegaprotocol/deposits": ["libs/deposits/src/index.ts"],
"@vegaprotocol/environment": ["libs/environment/src/index.ts"],
"@vegaprotocol/fills": ["libs/fills/src/index.ts"],
"@vegaprotocol/funding-payments": ["libs/funding-payments/src/index.ts"],
"@vegaprotocol/i18n": ["libs/i18n/src/index.ts"],
"@vegaprotocol/ledger": ["libs/ledger/src/index.ts"],
"@vegaprotocol/liquidity": ["libs/liquidity/src/index.ts"],