Merge remote-tracking branch 'origin/develop' into feat/4387-market-terminate-banner

This commit is contained in:
maciek
2023-10-10 09:16:11 +02:00
40 changed files with 1239 additions and 238 deletions
@@ -82,3 +82,38 @@ jobs:
https://${{ env.IPFS_V1 }}.ipfs.dweb.link/
https://${{ env.IPFS_V1 }}.ipfs.cf-ipfs.com/
ipfs://${{ env.IPFS_V0 }}/
- name: Ensure 'Released' label exists
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
REPO="${{ github.repository }}"
LABEL_EXIST=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/$REPO/labels/Released")
if [[ "$LABEL_EXIST" == *"Not Found"* ]]; then
curl -s -H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
-X POST "https://api.github.com/repos/$REPO/labels" \
-d '{"name": "Released", "color": "FFFFFF"}'
fi
- name: Extract issues from release notes
id: extract-issues
run: |
ISSUES=$(echo "${{ github.event.release.body }}" | grep -o -E '#[0-9]+' | tr -d '#' | jq -R . | jq -cs .)
echo "Issues to label: $ISSUES"
echo "::set-output name=issue_numbers::$ISSUES"
- name: Add 'Released' label to issues
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
ISSUE_NUMBERS="${{ steps.extract-issues.outputs.issue_numbers }}"
REPO="${{ github.repository }}"
for ISSUE in $(echo "$ISSUE_NUMBERS" | jq -r '.[]'); do
curl -s -H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
-X POST "https://api.github.com/repos/$REPO/issues/$ISSUE/labels" \
-d '{"labels": ["Released"]}'
done
+9 -9
View File
@@ -170,15 +170,6 @@ jobs:
preview_explorer: ${{ env.PREVIEW_EXPLORER }}
preview_tools: ${{ env.PREVIEW_TOOLS }}
# console-e2e:
# needs: build-sources
# name: '(CI) console python'
# uses: ./.github/workflows/console-test-run.yml
# secrets: inherit
# if: ${{ contains(fromJSON(needs.build-sources.outputs.projects), 'trading') && github.event_name == 'pull_request' }}
# with:
# github-sha: ${{ github.event.pull_request.head.sha || github.sha }}
check-e2e-needed:
runs-on: ubuntu-latest
needs: build-sources
@@ -212,6 +203,15 @@ jobs:
projects: ${{ needs.build-sources.outputs.projects-e2e }}
tags: '@smoke'
console-e2e:
needs: [build-sources, check-e2e-needed]
name: '(CI) console python'
uses: ./.github/workflows/console-test-run.yml
secrets: inherit
if: ${{ needs.check-e2e-needed.outputs.run-tests == 'true' }} && ${{ contains(fromJSON(needs.build-sources.outputs.projects), 'trading') }}
with:
github-sha: ${{ github.event.pull_request.head.sha || github.sha }}
publish-dist:
needs: build-sources
name: '(CD) publish dist'
+119 -47
View File
@@ -1,8 +1,5 @@
name: (CI) Console tests
env:
VEGA_VERSION: v0.72.14
on:
workflow_call:
inputs:
@@ -19,9 +16,9 @@ on:
- develop
jobs:
run-tests:
name: run-tests
runs-on: 8-cores
create-docker-image:
name: Create docker image for console-test
runs-on: ubuntu-22.04
timeout-minutes: 20
steps:
#----------------------------------------------
@@ -58,23 +55,105 @@ jobs:
#----------------------------------------------
# build trading
#----------------------------------------------
- name: Build affected spec
- name: Build trading app
run: |
yarn env-cmd -f ./apps/trading/.env.stagnet1 yarn nx export trading
DIST_LOCATION=dist/apps/trading/exported
mv $DIST_LOCATION dist-result
tree dist-result
#----------------------------------------------
# run trading server
# export trading app docker image
#----------------------------------------------
- name: Run trading server
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and export to local Docker
id: docker_build
uses: docker/build-push-action@v5
with:
context: .
file: docker/node-outside-docker.Dockerfile
load: true
build-args: |
APP=trading
ENV_NAME=stagnet1
tags: ci/trading:local
outputs: type=docker,dest=/tmp/console-image.tar
- name: Verify docker image created
run: |
docker run -d -p 80:4200 -v $PWD/docker/nginx.conf:/etc/nginx/conf.d/default.conf -v $PWD/dist/apps/trading/exported:/usr/share/nginx/html nginx:1.23-alpine@sha256:6318314189b40e73145a48060bff4783a116c34cc7241532d0d94198fb2c9629
sleep 5
docker ps
#----------------------------------------------
# check if container persists between runs
#----------------------------------------------
- name: Check server
echo ${{ steps.docker_build.outputs.digest }}
echo ${{ steps.docker_build.outputs.imageid }}
- name: Upload docker image for console-test usage
uses: actions/upload-artifact@v3
with:
name: console-image
path: /tmp/console-image.tar
console-test-branch:
name: Choose console-test branch to run on
runs-on: ubuntu-22.04
timeout-minutes: 5
outputs:
console-branch: ${{ steps.output-step.outputs.branch }}
steps:
- name: Workflow dispatch input
id: dispatch-step
if: github.event_name == 'workflow_dispatch'
run: echo "branch=${{ inputs.console-test-branch }}" >> $GITHUB_OUTPUT
- name: Print Workflow dispatch input
if: github.event_name == 'workflow_dispatch'
run: echo ${{ steps.dispatch-step.outputs.branch }}
- name: Workflow_call input
id: workflow_call-step
if: github.event_name != 'workflow_dispatch'
run: |
docker ps
if [[ "${{ github.base_ref }}" == "main" ]]; then
echo "branch=main" >> $GITHUB_OUTPUT
elif [[ "${{ github.base_ref }}" == "develop" && "${{ github.ref_name }}" == "main" ]]; then
echo "branch=main" >> $GITHUB_OUTPUT
elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref_name }}" == *"release/mainnet"* ]]; then
echo "branch=main" >> $GITHUB_OUTPUT
else
echo "branch=develop" >> $GITHUB_OUTPUT
fi
- name: Print Workflow_call input
if: github.event_name != 'workflow_dispatch'
run: echo ${{ steps.workflow_call-step.outputs.branch }}
- name: Set output
id: output-step
run: echo "branch=${{ steps.dispatch-step.outputs.branch || steps.workflow_call-step.outputs.branch }}" >> $GITHUB_OUTPUT
- name: Print final output
run: echo ${{ steps.output-step.outputs.branch }}
run-tests:
name: run-tests
runs-on: 8-cores
needs: [create-docker-image, console-test-branch]
timeout-minutes: 20
steps:
#----------------------------------------------
# load docker image
#----------------------------------------------
- name: Download docker image from previous job
uses: actions/download-artifact@v3
with:
name: console-image
path: /tmp
- name: Load Docker image
run: |
docker load --input /tmp/console-image.tar
docker image ls -a
#----------------------------------------------
# check-out tests repo
#----------------------------------------------
@@ -82,62 +161,55 @@ jobs:
uses: actions/checkout@v3
with:
repository: vegaprotocol/console-test
ref: ${{ inputs.console-test-branch }}
path: './console-test'
ref: ${{ needs.console-test-branch.outputs.console-branch }}
- name: Load console test envs
id: console-test-env
uses: falti/dotenv-action@v1.0.4
with:
path: './console-test/.env.${{ inputs.console-test-branch }}'
path: '.env.${{ needs.console-test-branch.outputs.console-branch }}'
export-variables: true
keys-case: upper
log-variables: true
#----------------------------------------------
# install dependencies
# ----- Setup python -----
#----------------------------------------------
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
#----------------------------------------------
# ----- install & configure poetry -----
#----------------------------------------------
- name: Install Poetry
uses: snok/install-poetry@v1
with:
virtualenvs-create: true
virtualenvs-in-project: true
virtualenvs-path: .venv
#----------------------------------------------
# install python dependencies
#----------------------------------------------
- name: Install dependencies
working-directory: ./console-test
run: poetry install --no-interaction --no-root
#----------------------------------------------
# find vega binaries path
#----------------------------------------------
- name: Find vega binaries path
id: vega_bin_path
working-directory: ./console-test
run: echo path=$(poetry run python -c "import vega_sim; print(vega_sim.vega_bin_path)") >> $GITHUB_OUTPUT
#----------------------------------------------
# vega binaries cache
#----------------------------------------------
- name: Vega binaries cache
uses: actions/cache@v3
id: vega_binaries_cache
with:
path: ${{ steps.vega_bin_path.outputs.path }}
key: ${{ runner.os }}-vega-binaries-${{ env.VEGA_VERSION }}
#----------------------------------------------
# install vega binaries
# install vega binaries
#----------------------------------------------
- name: Install vega binaries
working-directory: ./console-test
run: poetry run python -m vega_sim.tools.load_binaries --force --version ${{ env.VEGA_VERSION }}
#----------------------------------------------
# install playwright
#----------------------------------------------
- name: install playwright
run: poetry run playwright install --with-deps chromium
working-directory: ./console-test
#----------------------------------------------
# run tests
#----------------------------------------------
- name: Run tests
working-directory: ./console-test
run: poetry run pytest -v -s --numprocesses 4 --dist loadfile --durations=15
- name: Check files
run: |
ls -al .
ls -al console-test
run: CONSOLE_IMAGE_NAME=ci/trading:local poetry run pytest -v -s --numprocesses 4 --dist loadfile --durations=15
#----------------------------------------------
# upload traces
#----------------------------------------------
@@ -36,7 +36,7 @@ context('Market page', { tags: '@regression' }, function () {
it('Able to go to market details page', function () {
cy.navigate_to('markets');
cy.get_element_by_col_id('actions').eq(1).click();
cy.contains('Test market 1').click();
cy.getByTestId(marketHeaders).should('have.text', 'Test market 1');
cy.validate_element_from_table('Name', 'Test market 1');
cy.validate_element_from_table('Market ID', this.createdMarketId);
@@ -90,7 +90,7 @@ context('Market page', { tags: '@regression' }, function () {
// Liquidity price range
cy.validate_element_from_table(
'Liquidity Price Range',
'1,000.00% of mid price'
'95.00% of mid price'
);
cy.validate_element_from_table('Lowest Price', '0.00 fUSDC');
cy.validate_element_from_table('Highest Price', '0.00 fUSDC');
@@ -433,9 +433,10 @@ describe(
'contain.text',
'0.3'
);
getProposalDetailsValue(
'Minimum Probability Of Trading LP Orders'
).should('contain.text', '1e-8');
getProposalDetailsValue('Min Probability Of Trading LP Orders').should(
'contain.text',
'1e-8'
);
});
it('Able to see suspended market proposal', function () {
@@ -424,7 +424,7 @@ context(
validateValidatorListTotalStakeAndShare('0', '3,002.00', '50.02%');
});
it('Associating wallet tokens - when some already staked - auto stakes tokens to staked validator', function () {
it.skip('Associating wallet tokens - when some already staked - auto stakes tokens to staked validator', function () {
// 1002-STKE-004
stakingPageAssociateTokens('3');
verifyUnstakedBalance(3.0);
@@ -438,7 +438,7 @@ context(
verifyStakedBalance(7.0);
});
it('Associating vesting contract tokens - when some already staked - auto stakes tokens to staked validator', function () {
it.skip('Associating vesting contract tokens - when some already staked - auto stakes tokens to staked validator', function () {
// 1002-STKE-004
stakingPageAssociateTokens('3', { type: 'contract' });
verifyUnstakedBalance(3.0);
@@ -452,7 +452,7 @@ context(
verifyStakedBalance(7.0);
});
it('Associating vesting contract tokens - when wallet tokens already staked - auto stakes tokens to staked validator', function () {
it.skip('Associating vesting contract tokens - when wallet tokens already staked - auto stakes tokens to staked validator', function () {
// 1002-STKE-004
stakingPageAssociateTokens('3', { type: 'wallet' });
verifyUnstakedBalance(3.0);
@@ -466,7 +466,7 @@ context(
verifyStakedBalance(7.0);
});
it('Associating tokens - with multiple validators already staked - auto stakes to staked validators - abiding by existing stake ratio', function () {
it.skip('Associating tokens - with multiple validators already staked - auto stakes to staked validators - abiding by existing stake ratio', function () {
// 1002-STKE-004
stakingPageAssociateTokens('6');
verifyUnstakedBalance(6.0);
@@ -74,25 +74,12 @@ context(
});
it('should be able to see a working link for - find out more about Vega governance', function () {
// 3001-VOTE-001
// 3001-VOTE-001 // 3002-PROP-001
cy.getByTestId(proposalDocumentationLink)
.should('be.visible')
.and('have.text', 'Find out more about Vega governance')
.and('have.attr', 'href')
.and('equal', governanceDocsUrl);
// 3002-PROP-001
cy.request(governanceDocsUrl)
.its('body')
.then((body) => {
if (!body.includes('Govern the network')) {
assert.include(
body,
'Govern the network',
`Checking that governance link destination includes 'Govern the network' text`
);
}
});
});
// 3007-PNE-021
@@ -1,127 +0,0 @@
import { checkSorting } from '@vegaprotocol/cypress';
const dialogClose = 'dialog-close';
describe('accounts', { tags: '@smoke' }, () => {
beforeEach(() => {
cy.mockTradingPage();
cy.mockWeb3Provider();
cy.mockSubscription();
cy.setVegaWallet();
cy.visit('/#/markets/market-0');
});
it('should open usage breakdown dialog when clicked on used', () => {
cy.getByTestId('Collateral').click();
// 7001-COLL-009
cy.get('[col-id="used"]').contains('1.01').click();
const headers = ['Market', 'Account type', 'Balance', 'Margin health'];
cy.getByTestId('usage-breakdown').within(($headers) => {
cy.wrap($headers)
.get('.ag-header-cell-text')
.each(($header, i) => {
cy.wrap($header).should('have.text', headers[i]);
});
});
cy.getByTestId(dialogClose).click();
});
describe('sorting by ag-grid columns should work well', () => {
before(() => {
const dialogs = Cypress.$('[data-testid="dialog-close"]:visible');
if (dialogs.length > 0) {
dialogs.each((btn) => {
cy.wrap(btn).click();
});
}
cy.contains('Loading...').should('not.exist');
});
// 7001-COLL-010
it('sorting by asset', () => {
cy.getByTestId('Collateral').click();
const marketsSortedDefault = ['tBTC', 'tEURO', 'tDAI', 'tBTC'];
const marketsSortedAsc = ['tBTC', 'tBTC', 'tDAI', 'tEURO'];
const marketsSortedDesc = Array.from(marketsSortedAsc).reverse();
checkSorting(
'asset.symbol',
marketsSortedDefault,
marketsSortedAsc,
marketsSortedDesc
);
});
it('sorting by total', () => {
cy.getByTestId('Collateral').click();
const marketsSortedDefault = [
'1,000.00002',
'1,000.01',
'1,000.00',
'1,000.00001',
];
const marketsSortedAsc = [
'1,000.00',
'1,000.00001',
'1,000.00002',
'1,000.01',
];
const marketsSortedDesc = Array.from(marketsSortedAsc).reverse();
checkSorting(
'total',
marketsSortedDefault,
marketsSortedAsc,
marketsSortedDesc
);
});
it('sorting by used', () => {
cy.getByTestId('Collateral').click();
// concat actual value with percentage value
// as cypress will pick up the entire cell contes
// textContent
const marketsSortedDefault = [
'0.00' + '0.00%',
'0.01' + '0.00%',
'0.00' + '0.00%',
'0.00' + '0.00%',
];
const marketsSortedAsc = [
'0.00' + '0.00%',
'0.00' + '0.00%',
'0.00' + '0.00%',
'0.01' + '0.00%',
];
const marketsSortedDesc = Array.from(marketsSortedAsc).reverse();
checkSorting(
'used',
marketsSortedDefault,
marketsSortedAsc,
marketsSortedDesc
);
});
it('sorting by available', () => {
cy.getByTestId('Collateral').click();
const marketsSortedDefault = [
'1,000.00002',
'1,000.00',
'1,000.00',
'1,000.00001',
];
const marketsSortedAsc = [
'1,000.00',
'1,000.00',
'1,000.00001',
'1,000.00002',
];
const marketsSortedDesc = Array.from(marketsSortedAsc).reverse();
checkSorting(
'available',
marketsSortedDefault,
marketsSortedAsc,
marketsSortedDesc
);
});
});
});
@@ -139,6 +139,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')}
@@ -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),
@@ -9,7 +9,9 @@ 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';
import { OrdersContainer } from '../../components/orders-container';
import { LedgerContainer } from '../../components/ledger-container';
@@ -68,7 +70,11 @@ export const Portfolio = () => {
<Tab id="account-history" name={t('Account history')}>
<AccountHistoryContainer />
</Tab>
<Tab id="positions" name={t('Positions')}>
<Tab
id="positions"
name={t('Positions')}
menu={<PositionsMenu />}
>
<PositionsContainer allKeys />
</Tab>
<Tab id="orders" name={t('Orders')}>
@@ -77,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>
@@ -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',
})
);
@@ -0,0 +1 @@
export * from './funding-payments-container';
@@ -3,6 +3,7 @@ import * as Types from '@vegaprotocol/types';
import type { AccountFields } from './accounts-data-provider';
import { getAccountData } from './accounts-data-provider';
import { AccountTable } from './accounts-table';
import userEvent from '@testing-library/user-event';
const singleRow = {
__typename: 'AccountBalance',
@@ -24,6 +25,26 @@ const singleRow = {
} as AccountFields;
const singleRowData = [singleRow];
const secondRow = {
__typename: 'AccountBalance',
type: Types.AccountType.ACCOUNT_TYPE_MARGIN,
balance: '125600002',
market: {
__typename: 'Market',
id: '10cd0a793ad2887b340940337fa6d97a212e0e517fe8e9eab2b5ef3a38633f35',
},
asset: {
__typename: 'Asset',
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
symbol: 'aBTC',
decimals: 5,
},
available: '125600001',
used: '125600001',
total: '251200002',
} as AccountFields;
const multiRowData = [singleRow, secondRow];
describe('AccountsTable', () => {
it('should render correct columns', async () => {
// 7001-COLL-001
@@ -68,6 +89,25 @@ describe('AccountsTable', () => {
expect(rows?.childElementCount).toBe(1);
});
it('should sort assets', async () => {
// 7001-COLL-010
const { container } = render(
<AccountTable
rowData={multiRowData}
onClickAsset={() => null}
isReadOnly={false}
/>
);
const headerCell = screen.getByText('Asset');
await userEvent.click(headerCell);
const rows = container.querySelectorAll(
'.ag-center-cols-container .ag-row'
);
expect(rows[0].textContent).toContain('aBTC');
expect(rows[1].textContent).toContain('tBTC');
});
it('should apply correct formatting in view as user mode', async () => {
const { container } = render(
<AccountTable
+1
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';
+13
View File
@@ -0,0 +1,13 @@
{
"sourceType": "unambiguous",
"presets": [
[
"@nx/react/babel",
{
"runtime": "automatic",
"useBuiltIns": "usage"
}
]
],
"plugins": []
}
+18
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": {}
}
]
}
+7
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).
+6
View File
@@ -0,0 +1,6 @@
function ReactMarkdown({ children }) {
// eslint-disable-next-line react/jsx-no-useless-fragment
return <>{children}</>;
}
export default ReactMarkdown;
+17
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'],
};
+10
View File
@@ -0,0 +1,10 @@
const { join } = require('path');
module.exports = {
plugins: {
tailwindcss: {
config: join(__dirname, 'tailwind.config.js'),
},
autoprefixer: {},
},
};
+37
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"
}
}
}
}
+3
View File
@@ -0,0 +1,3 @@
export * from './lib/funding-payments-manager';
export * from './lib/funding-payments-data-provider';
export * from './lib/__generated__/FundingPayments';
@@ -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
}
}
}
@@ -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>;
@@ -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
],
})
);
}
);
@@ -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}
/>
);
};
@@ -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');
});
});
@@ -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}
/>
);
}
);
@@ -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',
}),
];
@@ -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);
};
+4
View File
@@ -0,0 +1,4 @@
import '@testing-library/jest-dom';
import ResizeObserver from 'resize-observer-polyfill';
global.ResizeObserver = ResizeObserver;
+17
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],
};
+27
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"
}
]
}
+27
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"]
}
+20
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"
]
}
+141 -30
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 */
@@ -15,6 +15,7 @@ import { useCallback, useState } from 'react';
import type { WalletClientError } from '@vegaprotocol/wallet-client';
import { t } from '@vegaprotocol/i18n';
import type { Connectors, VegaConnector } from '../connectors';
import { DEFAULT_SNAP_VERSION } from '../connectors';
import {
DEFAULT_SNAP_ID,
InjectedConnector,
@@ -352,7 +353,9 @@ const ConnectorList = ({
</>
}
onClick={() => {
requestSnap(DEFAULT_SNAP_ID);
requestSnap(DEFAULT_SNAP_ID, {
version: DEFAULT_SNAP_VERSION,
});
}}
/>
{snapStatus === SnapStatus.NOT_SUPPORTED ? (
@@ -41,6 +41,7 @@ const ethereumRequest = <T>(args: RequestArguments): Promise<T> => {
export const LOCAL_SNAP_ID = 'local:http://localhost:8080';
export const DEFAULT_SNAP_ID = 'npm:@vegaprotocol/snap';
export const DEFAULT_SNAP_VERSION = '0.2.0';
type GetSnapsResponse = Record<string, Snap>;
+1
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"],