Compare commits

..
Author SHA1 Message Date
maciek 01f2b04e7b chore: fix failling int test 2023-02-28 15:13:31 +01:00
maciek 6d6258e39e Merge remote-tracking branch 'origin/develop' into chore/570-loader-component-css-animation-only 2023-02-28 14:43:02 +01:00
Sam Keen d87adfd7d5 fix(governance): vote state update fix (#3023) 2023-02-28 12:43:20 +00:00
dexturr 7364abbbf2 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-28 12:10:21 +00:00
maciek 14b9c23701 Merge remote-tracking branch 'origin/develop' into chore/570-loader-component-css-animation-only 2023-02-28 11:58:36 +01:00
maciek ec89883dec chore: loader no rerender version only, early resolving choosen theme 2023-02-28 11:50:13 +01:00
Ciaran McGhie 1bd56c9bdb chore(ci): bump ui-toolkit version to 0.7.0 (#2961) 2023-02-28 10:13:51 +00:00
Sam Keen a985bc7317 fix(governance): some fixes and tweaks for the rewards tables (#3009) 2023-02-28 10:07:51 +00:00
dexturr 1cab9abfd5 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-28 06:08:01 +00:00
dexturr 26a82ab2ab chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-28 00:17:25 +00:00
Matthew Russell 69a0830e80 fix(ui-toolkit): remove calt from nav and toasts (#3020) 2023-02-27 15:21:17 -08:00
m.ray 4eb6e09bd4 fix(trading): condense deal ticket & market info price range snags (#3012) 2023-02-27 18:04:13 +00:00
Maciek a02100b079 chore(ui-toolkit): revert: loader no rerender version only 2023-02-27 07:51:50 -08:00
Maciek 4bb78e9891 chore(ui-toolkit): loader no rerender version only (#3011) 2023-02-27 16:44:48 +01:00
dexturr 79f360dc24 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-27 12:10:43 +00:00
maciek e3b2ee12e6 chore: loader no rerender version only 2023-02-27 12:13:37 +01:00
Art a3fcd6b7dc feat(explorer): validators page (#2982) 2023-02-27 09:17:23 +00:00
Matthew Russell 23ce480daa feat(trading): show block height (#3010) 2023-02-27 09:16:19 +00:00
Matthew Russell da209d96b0 fix(tailwindcss-config): fix calt for firefox, make calt opt in when using font-alpha (#3007) 2023-02-27 09:13:19 +00:00
Matthew Russell 9166a85a55 chore(trading): update tooltip text for 24h volume (#3005) 2023-02-27 09:12:50 +00:00
dexturr a5ec1f708f chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-27 06:09:54 +00:00
dexturr 3afdc0c8da chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-27 00:17:20 +00:00
dexturr 757d545d97 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-26 18:09:19 +00:00
dexturr fc4d40f3cf chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-26 12:07:31 +00:00
dexturr ff47eda692 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-26 06:08:17 +00:00
dexturr 7483d9ce1d chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-26 00:15:56 +00:00
dexturr f9209cf327 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-25 18:07:08 +00:00
dexturr 420a29680d chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-25 12:09:08 +00:00
dexturr 19c9e79647 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-25 06:07:29 +00:00
dexturr 4cd856fcb8 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-25 00:16:11 +00:00
Matthew Russell 649cc61280 chore(trading): fix formatting for volume cells in book (#3006) 2023-02-24 16:31:42 -05:00
dexturr 35f47b75ac chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-24 18:07:20 +00:00
Dexter Edwards 0697acdac9 fix(token): mainnet tranches (#3001) 2023-02-24 15:20:30 +00:00
Dexter Edwards 92ec7166bc feat(token): 1823 tranches service (#2742) 2023-02-24 14:53:30 +00:00
Matthew Russell 56b5214dbf chore(trading): grid cell fixes (#2986) 2023-02-24 14:38:45 +00:00
Maciek 94509a29c5 chore(ui-toolkit): add pseudo random instead Math.random (#2997) 2023-02-24 14:38:34 +00:00
mattrussell36 4e2b6b2d04 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-24 12:08:16 +00:00
MaciekandMatthew Russell c29087cc96 chore(trading): filtering and sorting for ledger entries (#2944)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-02-24 08:40:31 +01:00
mattrussell36 5bde096977 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-24 06:07:21 +00:00
mattrussell36 923dc09eb6 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-24 00:10:31 +00:00
mattrussell36 4fbdb337dd chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-23 18:08:00 +00:00
Maciek 6f4a5b9097 chore(trading): make markets in dropdown unique (#2979) 2023-02-23 17:14:41 +01:00
m.ray 0c26d99ce2 fix(trading): fees breakdown layout and condense tabs (#2976) 2023-02-23 14:27:11 +00:00
daro-maj 5aedeba4ff test(trading): added rerun mechanism for cypress tests (#2977) 2023-02-23 15:23:19 +01:00
mattrussell36 5789d3496b chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-23 12:06:42 +00:00
m.ray d95fdca0d4 fix(trading): update step on market dp (#2972) 2023-02-23 11:10:56 +00:00
Maciek e4bf61c2e2 chore(trading): add market dropdown to account history (#2971) 2023-02-23 11:02:13 +00:00
Edd 0ba54cd8a4 fix(explorer): incorrect destination in market link components (#2968) 2023-02-23 10:46:55 +00:00
daro-maj eee85c231b test(trading): improved a dropdown verification test (#2969) 2023-02-23 10:16:22 +00:00
mattrussell36 afdb387742 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-23 06:08:36 +00:00
Matthew Russell 63698fbb80 feat(trading,deposits): improve ethereum connection and approve step (#2926) 2023-02-22 16:27:17 -08:00
mattrussell36 58d8f7857e chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-23 00:13:13 +00:00
mattrussell36 0931730582 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-22 18:06:22 +00:00
m.ray 3aefa10a4f feat(trading): quote unit and settlement asset relation (#2953) 2023-02-22 17:05:31 +00:00
Edd efeccc7972 feat(explorer): add transfers tx view (#2902) 2023-02-22 16:31:06 +00:00
Sam Keen 95f4e489b2 feat(governance): no delay on tooltip for validators table column headers (#2963) 2023-02-22 15:04:52 +00:00
Sam Keen 0033f3c5f5 feat(governance): tooltips for the validator details page (#2960) 2023-02-22 14:52:05 +00:00
Ciaran McGhie abf69786ba feat(ci): publish monorepo libs to npm (#2951) 2023-02-22 12:11:35 +00:00
daro-maj 0a5fb9d917 test(trading): deposit flow from collateral window e2e tests (#2959) 2023-02-22 12:04:47 +00:00
mattrussell36 8e82bf43fb chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-22 06:08:43 +00:00
Bartłomiej Głownia 4bb57e9c47 fix(market-depth): fix order book priceInCenter calculation and scroll to price (#2901) 2023-02-21 18:01:48 -08:00
mattrussell36 ce6d4cb35d chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-22 00:10:23 +00:00
mattrussell36 647f04656f chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-21 18:06:17 +00:00
daro-maj 67186bf4c0 test(trading): node version update for live workflow (#2954) 2023-02-21 17:46:00 +00:00
mattrussell36 96007bd230 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-21 12:06:41 +00:00
219 changed files with 6035 additions and 4349 deletions
+6
View File
@@ -18,6 +18,12 @@ jobs:
- name: Checkout
uses: actions/checkout@v2
- name: Use Node.js 16
id: Node
uses: actions/setup-node@v2
with:
node-version: 16.15.1
- name: Run Cypress tests
uses: cypress-io/github-action@v4
with:
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
id: Node
uses: actions/setup-node@v2
with:
node-version: 16.14.0
node-version: 16.15.1
- name: Install root dependencies
run: yarn install
- name: Generate queries
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
id: Node
uses: actions/setup-node@v2
with:
node-version: 16.14.0
node-version: 16.15.1
- name: Install root dependencies
run: yarn install
- name: Check PR title
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
id: Node
uses: actions/setup-node@v2
with:
node-version: 16.14.0
node-version: 16.15.1
- name: Install root dependencies
run: yarn install
- name: Generate queries
+47
View File
@@ -0,0 +1,47 @@
name: Publish libs to npm
on:
workflow_dispatch:
inputs:
project:
description: 'Monorepo project to publish'
required: true
type: choice
options:
- ui-toolkit
- react-helpers
- tailwindcss-config
- types
jobs:
publish:
name: Build & Publish - Tag
runs-on: ubuntu-latest
permissions:
contents: 'read'
actions: 'read'
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: User Node.js 16
id: Node
uses: actions/setup-node@v3
with:
node-version: 16.15.1
- name: Restore node_modules from cache
uses: actions/cache@v3
with:
path: '**/node_modules'
key: node_modules-${{ hashFiles('**/yarn.lock') }}
- name: Install root dependencies
run: yarn install --frozen-lockfile
- name: Build project
run: yarn nx build ${{inputs.project}}
- name: Publish project to @vegaprotocol
uses: JS-DevTools/npm-publish@v1
with:
token: ${{ secrets.NPM_TOKEN }}
package: dist/libs/${{inputs.project}}/package.json
access: public
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
id: Node
uses: actions/setup-node@v3
with:
node-version: 16.14.0
node-version: 16.15.1
- name: Restore node_modules from cache
uses: actions/cache@v3
with:
+1 -1
View File
@@ -1 +1 @@
16.14.0
16.15.1
@@ -8,7 +8,7 @@ context('Asset page', { tags: '@regression' }, () => {
it('should be able to see full assets list', () => {
cy.getAssets().then((assets) => {
Object.values(assets).forEach((asset) => {
assets.forEach((asset) => {
cy.get(`[row-id="${asset.id}"]`).should('be.visible');
});
});
@@ -25,7 +25,7 @@ context('Asset page', { tags: '@regression' }, () => {
});
cy.getAssets().then((assets) => {
Object.values(assets).forEach((asset) => {
assets.forEach((asset) => {
cy.get(`[row-id="${asset.id}"]`).should('be.visible');
});
});
@@ -33,7 +33,7 @@ context('Asset page', { tags: '@regression' }, () => {
it('should open details page when clicked on "View details"', () => {
cy.getAssets().then((assets) => {
Object.values(assets).forEach((asset) => {
assets.forEach((asset) => {
cy.get(`[row-id="${asset.id}"] [col-id="actions"] button`)
.eq(0)
.should('contain.text', 'View details');
@@ -1,303 +1,15 @@
context('Validator page', { tags: '@smoke' }, function () {
const validatorMenuHeading = 'a[href="/validators"]';
const tendermintDataHeader = '[data-testid="tendermint-header"]';
const vegaDataHeader = '[data-testid="vega-header"]';
const jsonSection = '.language-json';
before('Visit validators page and obtain data', function () {
cy.visit('/');
cy.get(validatorMenuHeading).click();
cy.get_validators().as('validators');
cy.get_nodes().as('nodes');
cy.visit('/validators');
});
describe('Verify elements on page', function () {
before('Ensure at least two validators are present', function () {
assert.isAtLeast(
this.validators.length,
2,
'Ensuring at least two validators exist'
);
});
it('should be able to see validator page sections', function () {
cy.get(vegaDataHeader)
.contains('Vega data')
.and('is.visible')
.next()
.within(() => {
cy.get(jsonSection).should('not.be.empty');
});
cy.get(tendermintDataHeader)
.contains('Tendermint data')
.and('is.visible')
.next()
.within(() => {
cy.get(jsonSection).should('not.be.empty');
});
});
it('should be able to see relevant validator information in tendermint section', function () {
cy.get(tendermintDataHeader)
.contains('Tendermint data')
.next()
.within(() => {
cy.get(jsonSection)
.invoke('text')
.convert_string_json_to_js_object()
.then((validatorsInJson) => {
this.validators.forEach((validator, index) => {
const validatorInJson =
validatorsInJson.result.validators[index];
assert.equal(
validatorInJson.address,
validator.address,
`Checking that validator address shown in json matches system data`
);
cy.contains(validator.address).should('be.visible');
assert.equal(
validatorInJson.pub_key.type,
validator.pub_key.type,
`Checking that validator public key type shown in json matches system data`
);
cy.contains(validator.pub_key.type).should('be.visible');
assert.equal(
validatorInJson.pub_key.value,
validator.pub_key.value,
`Checking that validator public key value shown in json matches system data`
);
cy.contains(validator.pub_key.value).should('be.visible');
assert.equal(
validatorInJson.voting_power,
validator.voting_power,
`Checking that validator voting power in json matches system data`
);
cy.contains(validator.voting_power).should('be.visible');
// Proposer priority can change frequently mid test
// Therefore only checking the field name is present.
cy.contains('proposer_priority').should('be.visible');
});
});
});
});
// Test disabled 2022/11/15 during the 0.62.1 upgrade. The JSON structure changed, and
// this test failed. Rather than fix it, it will be replaced when the validator view displays
// something useful rather than just dumping out the JSON.
xit('should be able to see relevant node information in vega data section', function () {
cy.get(vegaDataHeader)
.contains('Vega data')
.next()
.within(() => {
cy.get(jsonSection)
.invoke('text')
.convert_string_json_to_js_object()
.then((nodesInJson) => {
this.nodes.forEach((node, index) => {
const nodeInJson = nodesInJson.edges[index].node;
// Vegacapsule shows no info or null for following fields:
// name, infoURL, avatarUrl, location, epoch data
// Therefore, these values remain unchecked.
assert.equal(
nodeInJson.__typename,
node.__typename,
`Checking that node __typename shown in json matches system data`
);
cy.contains(node.__typename).should('be.visible');
assert.equal(
nodeInJson.id,
node.id,
`Checking that node id shown in json matches system data`
);
cy.contains(node.id).should('be.visible');
assert.equal(
nodeInJson.pubkey,
node.pubkey,
`Checking that node pubkey shown in json matches system data`
);
cy.contains(node.pubkey).should('be.visible');
assert.equal(
nodeInJson.tmPubkey,
node.tmPubkey,
`Checking that node tmPubkey shown in json matches system data`
);
cy.contains(node.tmPubkey).should('be.visible');
assert.equal(
nodeInJson.ethereumAddress,
node.ethereumAddress,
`Checking that node ethereumAddress shown in json matches system data`
);
cy.contains(node.ethereumAddress).should('be.visible');
assert.equal(
nodeInJson.stakedByOperator,
node.stakedByOperator,
`Checking that node stakedByOperator value shown in json matches system data`
);
cy.contains(node.stakedByOperator).should('be.visible');
assert.equal(
nodeInJson.stakedByDelegates,
node.stakedByDelegates,
`Checking that node stakedByDelegates value shown in json matches system data`
);
cy.contains(node.stakedByDelegates).should('be.visible');
assert.equal(
nodeInJson.stakedTotal,
node.stakedTotal,
`Checking that node stakedTotal shown in json matches system data`
);
cy.contains(node.stakedTotal).should('be.visible');
assert.equal(
nodeInJson.pendingStake,
node.pendingStake,
`Checking that node pendingStake shown in json matches system data`
);
cy.contains(node.pendingStake).should('be.visible');
assert.equal(
nodeInJson.status,
node.status,
`Checking that node status shown in json matches system data`
);
cy.contains(node.status).should('be.visible');
});
});
});
});
it('should be able to see validator page displayed on mobile', function () {
cy.common_switch_to_mobile_and_click_toggle();
cy.get(validatorMenuHeading).click();
cy.get(vegaDataHeader)
.contains('Vega data')
.and('is.visible')
.next()
.within(() => {
cy.get(jsonSection).should('not.be.empty');
});
cy.get(tendermintDataHeader)
.contains('Tendermint data')
.and('is.visible')
.next()
.within(() => {
cy.get(jsonSection).should('not.be.empty');
});
cy.get(tendermintDataHeader)
.contains('Tendermint data')
.next()
.within(() => {
this.validators.forEach((validator) => {
cy.contains(validator.address).should('be.visible');
cy.contains(validator.pub_key.type).should('be.visible');
cy.contains(validator.pub_key.value).should('be.visible');
cy.contains(validator.voting_power).should('be.visible');
// Proposer priority can change frequently mid test
// Therefore only checking the field name is present.
cy.contains('proposer_priority').should('be.visible');
});
});
});
it('should be able to switch validator page between light and dark mode', function () {
const whiteThemeSelectedMenuOptionColor = 'rgb(255, 7, 127)';
const whiteThemeJsonFieldBackColor = 'rgb(255, 255, 255)';
const whiteThemeSideMenuBackgroundColor = 'rgb(255, 255, 255)';
const darkThemeSelectedMenuOptionColor = 'rgb(215, 251, 80)';
const darkThemeJsonFieldBackColor = 'rgb(38, 38, 38)';
const darkThemeSideMenuBackgroundColor = 'rgb(0, 0, 0)';
const themeSwitcher = '[data-testid="theme-switcher"]';
const jsonFields = '.hljs';
const sideMenuBackground = '.absolute';
// Engage dark mode if not allready set
cy.get(sideMenuBackground)
.should('have.css', 'background-color')
.then((background_color) => {
if (background_color.includes(whiteThemeSideMenuBackgroundColor))
cy.get(themeSwitcher).click();
});
// Engage white mode
cy.get(themeSwitcher).click();
// White Mode
cy.get(validatorMenuHeading)
.should('have.css', 'background-color')
.and('include', whiteThemeSelectedMenuOptionColor);
cy.get(jsonFields)
.should('have.css', 'background-color')
.and('include', whiteThemeJsonFieldBackColor);
cy.get(sideMenuBackground)
.should('have.css', 'background-color')
.and('include', whiteThemeSideMenuBackgroundColor);
// Dark Mode
cy.get(themeSwitcher).click();
cy.get(validatorMenuHeading)
.should('have.css', 'background-color')
.and('include', darkThemeSelectedMenuOptionColor);
cy.get(jsonFields)
.should('have.css', 'background-color')
.and('include', darkThemeJsonFieldBackColor);
cy.get(sideMenuBackground)
.should('have.css', 'background-color')
.and('include', darkThemeSideMenuBackgroundColor);
});
Cypress.Commands.add('get_validators', () => {
cy.request({
method: 'GET',
url: `http://localhost:26617/validators`,
headers: { 'content-type': 'application/json' },
})
.its(`body.result.validators`)
.then(function (response) {
let validators = [];
response.forEach((account, index) => {
validators[index] = account;
});
return validators;
});
});
Cypress.Commands.add('get_nodes', () => {
const mutation =
'{nodesConnection { edges { node { id name infoUrl avatarUrl pubkey tmPubkey ethereumAddress \
location stakedByOperator stakedByDelegates stakedTotal pendingStake \
epochData { total offline online __typename } status name __typename}}}}';
cy.request({
method: 'POST',
url: `http://localhost:3028/query`,
body: {
query: mutation,
},
headers: { 'content-type': 'application/json' },
})
.its(`body.data.nodesConnection.edges`)
.then(function (response) {
let nodes = [];
response.forEach((node) => {
nodes.push(node);
});
return nodes;
it('should be able to see validator tiles', function () {
cy.getNodes().then((nodes) => {
nodes.forEach((node) => {
cy.get(`[validator-id="${node.id}"]`).should('be.visible');
});
});
});
});
});
@@ -19,12 +19,12 @@ const EmptyList = ({ heading, label }: EmptyListProps) => {
<div className="mt-4">
{heading ? (
<h1 className="font-alpha text-xl uppercase text-center leading-relaxed">
<h1 className="font-alpha calt text-xl uppercase text-center leading-relaxed">
{heading}
</h1>
) : null}
{label ? (
<p className="font-alpha text-gray-500 text-center">{label}</p>
<p className="font-alpha calt text-gray-500 text-center">{label}</p>
) : null}
</div>
</div>
@@ -48,7 +48,7 @@ const MarketLink = ({
<Link
className="underline"
{...props}
to={`/${Routes.MARKETS}#${id}`}
to={`/${Routes.MARKETS}/${id}`}
title={id}
>
{label}
@@ -56,7 +56,7 @@ const MarketLink = ({
);
} else {
return (
<Link className="underline" {...props} to={`/${Routes.MARKETS}#${id}`}>
<Link className="underline" {...props} to={`/${Routes.MARKETS}/${id}`}>
<Hash text={id} />
</Link>
);
@@ -22,8 +22,7 @@ export const MarketDetails = ({
}: {
market: MarketInfoNoCandlesQuery['market'];
}) => {
const assetSymbol =
market?.tradableInstrument.instrument.product?.settlementAsset.symbol;
const quoteUnit = market?.tradableInstrument.instrument.product.quoteName;
const assetId = useMemo(
() => market?.tradableInstrument.instrument.product?.settlementAsset.id,
[market]
@@ -39,6 +38,10 @@ export const MarketDetails = ({
const assetDecimals =
market.tradableInstrument.instrument.product.settlementAsset.decimals;
const liquidityPriceRange = formatNumberPercentage(
new BigNumber(market.lpPriceRange).times(100)
);
const panels = [
{
title: t('Key details'),
@@ -179,32 +182,40 @@ export const MarketDetails = ({
{
title: t('Liquidity price range'),
content: (
<MarketInfoTable
noBorder={false}
data={{
liquidityPriceRange: formatNumberPercentage(
new BigNumber(market.lpPriceRange).times(100)
),
LPVolumeMin:
market.data?.midPrice &&
`${addDecimalsFormatNumber(
new BigNumber(1)
.minus(market.lpPriceRange)
.times(market.data.midPrice)
.toString(),
market.decimalPlaces
)} ${assetSymbol}`,
LPVolumeMax:
market.data?.midPrice &&
`${addDecimalsFormatNumber(
new BigNumber(1)
.plus(market.lpPriceRange)
.times(market.data.midPrice)
.toString(),
market.decimalPlaces
)} ${assetSymbol}`,
}}
></MarketInfoTable>
<>
<p className="text-xs mb-4">
{`For liquidity orders to count towards a commitment, they must be
within the liquidity monitoring bounds.`}
</p>
<p className="text-xs mb-4">
{`The liquidity price range is a ${liquidityPriceRange} difference from the mid
price.`}
</p>
<MarketInfoTable
noBorder={false}
data={{
liquidityPriceRange: `${liquidityPriceRange} of mid price`,
lowestPrice:
market.data?.midPrice &&
`${addDecimalsFormatNumber(
new BigNumber(1)
.minus(market.lpPriceRange)
.times(market.data.midPrice)
.toString(),
market.decimalPlaces
)} ${quoteUnit}`,
highestPrice:
market.data?.midPrice &&
`${addDecimalsFormatNumber(
new BigNumber(1)
.plus(market.lpPriceRange)
.times(market.data.midPrice)
.toString(),
market.decimalPlaces
)} ${quoteUnit}`,
}}
></MarketInfoTable>
</>
),
},
{
@@ -237,7 +248,7 @@ export const MarketDetails = ({
<>
{panels.map((p) => (
<div className="mb-3">
<h2 className="font-alpha text-xl">{p.title}</h2>
<h2 className="font-alpha calt text-xl">{p.title}</h2>
{p.content}
</div>
))}
@@ -83,7 +83,7 @@ const NestedDataListItem = ({
});
const titleClasses = classNames({
'text-xl pl-4 border-l-4 font-alpha': hasChildren,
'text-xl pl-4 border-l-4 font-alpha calt': hasChildren,
'text-base font-medium whitespace-nowrap': !hasChildren,
});
@@ -20,7 +20,7 @@ export const PageHeader = ({
copy = false,
className,
}: PageHeaderProps) => {
const titleClasses = 'text-4xl xl:text-5xl uppercase font-alpha';
const titleClasses = 'text-4xl xl:text-5xl uppercase font-alpha calt';
return (
<header className={className}>
<span className={`${titleClasses} block`}>{prefix}</span>
@@ -0,0 +1 @@
export * from './page-actions';
@@ -0,0 +1,10 @@
import type { HTMLAttributes } from 'react';
export const PageActions = ({
children,
...props
}: HTMLAttributes<HTMLDivElement>) => (
<div className="flex flex-row items-start gap-1" {...props}>
{children}
</div>
);
@@ -0,0 +1,45 @@
import classNames from 'classnames';
import type { HTMLAttributes, ReactNode } from 'react';
import { useDocumentTitle } from '../../hooks/use-document-title';
import { RouteTitle } from '../route-title';
import { PageActions } from './page-actions';
type PageTitleProps = {
/**
* The page title
* (also sets the document title unless overwritten by
* `documentTitle` property)
*/
title: string;
/**
* The react node that consists of CTA buttons, links, etc.
*/
actions?: ReactNode;
/**
* Overwrites the document title
*/
documentTitle?: Parameters<typeof useDocumentTitle>[0];
} & Omit<HTMLAttributes<HTMLHeadingElement>, 'children'>;
export const PageTitle = ({
title,
actions,
documentTitle,
className,
...props
}: PageTitleProps) => {
useDocumentTitle(
documentTitle && documentTitle.length > 0 ? documentTitle : [title]
);
return (
<div
className="flex flex-col md:flex-row gap-1 justify-between content-start mb-8"
data-testid="page-title"
>
<RouteTitle className={classNames('mb-1', className)} {...props}>
{title}
</RouteTitle>
{actions && <PageActions>{actions}</PageActions>}
</div>
);
};
@@ -13,7 +13,7 @@ export const RouteTitle = ({
...props
}: RouteTitleProps) => {
const classes = classnames(
'font-alpha',
'font-alpha calt',
'text-4xl',
'uppercase',
'mb-8',
@@ -11,7 +11,7 @@ export const StatusMessage = ({
className,
...props
}: StatusMessageProps) => {
const classes = classnames('font-alpha text-2xl mb-28', className);
const classes = classnames('font-alpha calt text-2xl mb-28', className);
return (
<h3 className={classes} {...props}>
{children}
@@ -12,7 +12,7 @@ export const SubHeading = ({
...props
}: SubHeadingProps) => {
const classes = classnames(
'font-alpha',
'font-alpha calt',
'text-2xl',
'uppercase',
'mt-8 mb-2',
@@ -9,7 +9,7 @@ export type Metric = components['schemas']['vegaDispatchMetric'];
export const wrapperClasses =
'border border-vega-light-150 dark:border-vega-dark-200 rounded-md pv-2 mb-5 w-full sm:w-1/4 min-w-[200px] ';
export const headerClasses =
'bg-solid bg-vega-light-150 dark:bg-vega-dark-150 border-vega-light-150 text-center text-xl py-2 font-alpha';
'bg-solid bg-vega-light-150 dark:bg-vega-dark-150 border-vega-light-150 text-center text-xl py-2 font-alpha calt';
export type Transfer = components['schemas']['commandsv1Transfer'];
@@ -0,0 +1,55 @@
import { useFetch } from '@vegaprotocol/react-helpers';
import { useEffect, useRef } from 'react';
import { DATA_SOURCES } from '../config';
type PubKey = {
type: string;
value: string;
};
type Validator = {
address: string;
pub_key: PubKey;
voting_power: string;
proposer_priority: string;
};
type Result = {
block_height: string;
validators: Validator[];
count: string;
total: string;
};
type TendermintValidatorsResponse = {
jsonrpc: string;
id: number;
result: Result;
};
export const useTendermintValidators = (pollInterval?: number) => {
const {
state: { data, loading, error },
refetch,
} = useFetch<TendermintValidatorsResponse>(
`${DATA_SOURCES.tendermintUrl}/validators`
);
const ref = useRef<TendermintValidatorsResponse | undefined>(undefined);
useEffect(() => {
if (data) ref.current = data;
}, [data]);
useEffect(() => {
const interval =
pollInterval &&
setInterval(() => {
refetch();
}, pollInterval);
return () => {
clearInterval(interval);
};
}, [pollInterval, refetch]);
return { data: ref.current, loading, error, refetch };
};
@@ -1,5 +1,4 @@
import { t } from '@vegaprotocol/react-helpers';
import { RouteTitle } from '../../components/route-title';
import { AsyncRenderer, Button } from '@vegaprotocol/ui-toolkit';
import { useScrollToLocation } from '../../hooks/scroll-to-location';
import { useDocumentTitle } from '../../hooks/use-document-title';
@@ -8,6 +7,7 @@ import { AssetDetailsTable, useAssetDataProvider } from '@vegaprotocol/assets';
import { useParams } from 'react-router-dom';
import { JsonViewerDialog } from '../../components/dialogs/json-viewer-dialog';
import { useState } from 'react';
import { PageTitle } from '../../components/page-helpers/page-title';
export const AssetPage = () => {
useDocumentTitle(['Assets']);
@@ -22,18 +22,25 @@ export const AssetPage = () => {
return (
<>
<section className="relative">
<RouteTitle data-testid="asset-header">{title}</RouteTitle>
<PageTitle
data-testid="asset-header"
title={title}
actions={
<Button
disabled={!data}
size="xs"
onClick={() => setDialogOpen(true)}
>
{t('View JSON')}
</Button>
}
/>
<AsyncRenderer
noDataMessage={t('Asset not found')}
data={data}
loading={loading}
error={error}
>
<div className="absolute top-0 right-0">
<Button size="xs" onClick={() => setDialogOpen(true)}>
{t('View JSON')}
</Button>
</div>
<div className="h-full relative">
<AssetDetailsTable asset={data as AssetFieldsFragment} />
</div>
@@ -3,12 +3,12 @@ import { AsyncRenderer, Button } from '@vegaprotocol/ui-toolkit';
import { useMemo, useState } from 'react';
import { useParams } from 'react-router-dom';
import { MarketDetails } from '../../components/markets/market-details';
import { RouteTitle } from '../../components/route-title';
import { useScrollToLocation } from '../../hooks/scroll-to-location';
import { useDocumentTitle } from '../../hooks/use-document-title';
import compact from 'lodash/compact';
import { JsonViewerDialog } from '../../components/dialogs/json-viewer-dialog';
import { marketInfoNoCandlesDataProvider } from '@vegaprotocol/market-info';
import { PageTitle } from '../../components/page-helpers/page-title';
export const MarketPage = () => {
useScrollToLocation();
@@ -40,20 +40,25 @@ export const MarketPage = () => {
return (
<>
<section className="relative">
<RouteTitle data-testid="markets-heading">
{data?.market?.tradableInstrument.instrument.name}
</RouteTitle>
<PageTitle
data-testid="markets-heading"
title={data?.market?.tradableInstrument.instrument.name || ''}
actions={
<Button
disabled={!data?.market}
size="xs"
onClick={() => setDialogOpen(true)}
>
{t('View JSON')}
</Button>
}
/>
<AsyncRenderer
noDataMessage={t('This chain has no markets')}
data={data}
loading={loading}
error={error}
>
<div className="absolute top-0 right-0">
<Button size="xs" onClick={() => setDialogOpen(true)}>
{t('View JSON')}
</Button>
</div>
<MarketDetails market={data?.market} />
</AsyncRenderer>
</section>
@@ -68,7 +68,7 @@ const Party = () => {
return (
<section>
<h1
className="font-alpha uppercase font-xl mb-4 text-vega-dark-100 dark:text-vega-light-100"
className="font-alpha calt uppercase font-xl mb-4 text-vega-dark-100 dark:text-vega-light-100"
data-testid="parties-header"
>
{t('Public key')}
@@ -9,7 +9,7 @@ import Party from './parties';
import { Parties } from './parties/home';
import { Party as PartySingle } from './parties/id';
import Txs from './txs';
import Validators from './validators';
import { ValidatorsPage } from './validators';
import Genesis from './genesis';
import { Block } from './blocks/id';
import { Blocks } from './blocks/home';
@@ -125,7 +125,7 @@ const validators: Route[] = flags.validators
path: Routes.VALIDATORS,
name: 'Validators',
text: t('Validators'),
element: <Validators />,
element: <ValidatorsPage />,
},
]
: [];
@@ -1,47 +1 @@
import { t } from '@vegaprotocol/react-helpers';
import { RouteTitle } from '../../components/route-title';
import { SubHeading } from '../../components/sub-heading';
import { Loader, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { DATA_SOURCES } from '../../config';
import { useFetch } from '@vegaprotocol/react-helpers';
import type { TendermintValidatorsResponse } from './tendermint-validator-response';
import { useExplorerNodesQuery } from './__generated__/Nodes';
import { useDocumentTitle } from '../../hooks/use-document-title';
const Validators = () => {
const {
state: { data: validators },
} = useFetch<TendermintValidatorsResponse>(
`${DATA_SOURCES.tendermintUrl}/validators`
);
useDocumentTitle(['Validators']);
const { data } = useExplorerNodesQuery();
return (
<section>
<RouteTitle data-testid="validators-header">{t('Validators')}</RouteTitle>
{data ? (
<>
<SubHeading data-testid="vega-header">{t('Vega data')}</SubHeading>
<SyntaxHighlighter data-testid="vega-data" data={data} />
</>
) : (
<Loader />
)}
{validators ? (
<>
<SubHeading data-testid="tendermint-header">
{t('Tendermint data')}
</SubHeading>
<SyntaxHighlighter data-testid="tendermint-data" data={validators} />
</>
) : (
<Loader />
)}
</section>
);
};
export default Validators;
export * from './validators-page';
@@ -1,24 +0,0 @@
export interface PubKey {
type: string;
value: string;
}
export interface Validator {
address: string;
pub_key: PubKey;
voting_power: string;
proposer_priority: string;
}
export interface Result {
block_height: string;
validators: Validator[];
count: string;
total: string;
}
export interface TendermintValidatorsResponse {
jsonrpc: string;
id: number;
result: Result;
}
@@ -0,0 +1,340 @@
import { countryCodeToFlagEmoji, t } from '@vegaprotocol/react-helpers';
import {
AsyncRenderer,
Button,
CopyWithTooltip,
ExternalLink,
Icon,
KeyValueTable,
KeyValueTableRow,
Tooltip,
truncateMiddle,
} from '@vegaprotocol/ui-toolkit';
import { useExplorerNodesQuery } from './__generated__/Nodes';
import { useDocumentTitle } from '../../hooks/use-document-title';
import compact from 'lodash/compact';
import { useTendermintValidators } from '../../hooks/use-tendermint-validators';
import { useMemo, useState } from 'react';
import { JsonViewerDialog } from '../../components/dialogs/json-viewer-dialog';
import { PageTitle } from '../../components/page-helpers/page-title';
import BigNumber from 'bignumber.js';
import {
ContractAddressLink,
DApp,
TOKEN_VALIDATOR,
useLinks,
} from '@vegaprotocol/environment';
import classNames from 'classnames';
import { NodeStatus, NodeStatusMapping } from '@vegaprotocol/types';
type RateProps = {
value: BigNumber | number | undefined;
className?: string;
colour?: 'green' | 'blue' | 'pink' | 'orange';
asPoint?: boolean;
zero?: boolean;
};
const Rate = ({
value,
className,
colour = 'blue',
asPoint = false,
}: RateProps) => {
const val =
typeof value === 'undefined'
? new BigNumber(0)
: typeof value === 'number'
? new BigNumber(value)
: value;
const bar = asPoint
? {
right: `${val.times(100).toFixed(2)}%`,
}
: { width: `${val.times(100).toFixed(2)}%` };
return (
<div
className={classNames(
'overflow-hidden rounded h-[9px] flex w-full bg-vega-light-100 dark:bg-vega-dark-150',
{ 'pl-[9px]': asPoint },
{
'bg-gradient-to-l to-vega-orange-500 dark:to-vega-orange-550 from-vega-light-100 dark:from-vega-dark-150':
asPoint && colour === 'orange',
}
)}
>
<div className="relative w-full">
<div
className={classNames(
'w-[9px] h-[9px] absolute top-0 right-0 transition-all rounded',
{
'bg-vega-green-550 dark:bg-vega-green-500': colour === 'green',
'bg-vega-blue-550 dark:bg-vega-blue-500': colour === 'blue',
'bg-vega-pink-550 dark:bg-vega-pink-500': colour === 'pink',
'bg-vega-orange-550 dark:bg-vega-orange-500': colour === 'orange',
},
'bg-vega',
className
)}
style={bar}
></div>
</div>
</div>
);
};
export const ValidatorsPage = () => {
useDocumentTitle(['Validators']);
const { data: tmData } = useTendermintValidators(5000);
const { data, loading, error, refetch } = useExplorerNodesQuery();
const validators = compact(data?.nodesConnection.edges?.map((e) => e?.node));
// voting power
const powers = compact(tmData?.result.validators).map(
(v) => new BigNumber(v.voting_power)
);
const totalVotingPower = BigNumber.sum(...powers);
// proposer priority
const priorities = compact(tmData?.result.validators).map(
(v) => new BigNumber(v.proposer_priority)
);
const absoluteProposerPriority = BigNumber.max(
...priorities.map((p) => p.abs())
);
const tmValidators = useMemo(() => {
return tmData?.result.validators.map((v) => {
const data = {
key: v.pub_key.value,
votingPower: new BigNumber(v.voting_power),
proposerPriority: new BigNumber(v.proposer_priority),
};
return {
...data,
votingPowerRatio: data.votingPower.dividedBy(totalVotingPower),
proposerPriorityRatio: absoluteProposerPriority
.plus(data.proposerPriority)
.dividedBy(absoluteProposerPriority.times(2)),
};
});
}, [tmData?.result.validators, totalVotingPower, absoluteProposerPriority]);
const totalStaked = BigNumber.sum(
...validators.map((v) => new BigNumber(v.stakedTotal))
);
const [vegaDialog, setVegaDialog] = useState<boolean>(false);
const [tmDialog, setTmDialog] = useState<boolean>(false);
const tokenLink = useLinks(DApp.Token);
return (
<>
<section>
<PageTitle
title={t('Validators')}
actions={
<>
<Button
disabled={Boolean(!data)}
size="xs"
onClick={() => setVegaDialog(true)}
>
{t('View JSON')}
</Button>
{
<Button
disabled={Boolean(!tmData)}
size="xs"
onClick={() => setTmDialog(true)}
>
{t('View tendermint as JSON')}
</Button>
}
</>
}
/>
<AsyncRenderer
data={validators}
loading={loading}
error={error}
reload={refetch}
>
<ul className="md:columns-2">
{validators.map((v) => {
const tm = tmValidators?.find((tmv) => tmv.key === v.tmPubkey);
const stakedRatio = new BigNumber(v.stakedTotal).dividedBy(
totalStaked
);
const validatorPage = tokenLink(
TOKEN_VALIDATOR.replace(':id', v.id)
);
const validatorName =
v.name && v.name.length > 0 ? v.name : truncateMiddle(v.id);
return (
<li className="mb-5" key={v.id}>
<div
data-testid="validator-tile"
validator-id={v.id}
className="border border-vega-light-200 dark:border-vega-dark-200 rounded p-2 overflow-hidden relative flex gap-2 items-start justify-between"
>
{v.avatarUrl && (
<div className="w-20">
<ExternalLink href={validatorPage}>
<img
className="w-full"
src={v.avatarUrl}
alt={validatorName}
/>
</ExternalLink>
</div>
)}
<div className="w-full">
<h2 className="font-alpha text-2xl">
<ExternalLink href={validatorPage}>
{validatorName}
</ExternalLink>
</h2>
<KeyValueTable>
<KeyValueTableRow>
<div>{t('ID')}</div>
<div className="break-all text-xs">{v.id}</div>
</KeyValueTableRow>
<KeyValueTableRow>
<div>{t('Status')}</div>
<div className="break-all text-xs">
<span
className={classNames('mr-1', {
'text-vega-green-550 dark:vega-green-500':
v.status === NodeStatus.NODE_STATUS_VALIDATOR,
'text-vega-pink-550 dark:vega-pink-500':
v.status ===
NodeStatus.NODE_STATUS_NON_VALIDATOR,
})}
>
<Icon name="tick-circle" size={3} />
</span>
{NodeStatusMapping[v.status]}
</div>
</KeyValueTableRow>
<KeyValueTableRow>
<div>{t('Location')}</div>
<div>
{countryCodeToFlagEmoji(v.location)}{' '}
<span className="text-[10px]">{v.location}</span>
</div>
</KeyValueTableRow>
<KeyValueTableRow>
<div>{t('Public key')}</div>
<div className="break-all text-xs">{v.pubkey}</div>
</KeyValueTableRow>
<KeyValueTableRow>
<div>{t('Ethereum address')}</div>
<div className="break-all text-xs">
<ContractAddressLink address={v.ethereumAddress} />{' '}
<CopyWithTooltip text={v.ethereumAddress}>
<button title={t('Copy address to clipboard')}>
<Icon size={3} name="duplicate" />
</button>
</CopyWithTooltip>
</div>
</KeyValueTableRow>
<KeyValueTableRow>
<div>{t('Tendermint public key')}</div>
<div className="break-all text-xs">{v.tmPubkey}</div>
</KeyValueTableRow>
<KeyValueTableRow>
<div>{t('Voting power')}</div>
<div className="w-44 text-right">
<Rate value={tm?.votingPowerRatio} />
<div className="text-[10px] leading-3">
{tm?.votingPowerRatio.times(100).toFixed(2)}
{'% '}({tm?.votingPower.toString()})
</div>
</div>
</KeyValueTableRow>
<KeyValueTableRow>
<div>{t('Proposer priority')}</div>
<div className="w-44 text-right">
<Rate
value={tm?.proposerPriorityRatio}
colour="orange"
asPoint={true}
zero={true}
/>
<div className="text-[10px] leading-3">
{tm?.proposerPriority.toString()}
</div>
</div>
</KeyValueTableRow>
<KeyValueTableRow>
<div>{t('Stake share')}</div>
<div className="w-44 text-right">
<Rate value={stakedRatio} colour="green" />
<div className="text-[10px] leading-3">
<Tooltip
description={
<KeyValueTable
numerical={true}
className="mb-1"
>
<KeyValueTableRow
className="text-xs"
noBorder={true}
>
<div>{t('Staked by operator')}</div>
<div>{v.stakedByOperator}</div>
</KeyValueTableRow>
<KeyValueTableRow
className="text-xs"
noBorder={true}
>
<div>{t('Staked by delegates')}</div>
<div>{v.stakedByDelegates}</div>
</KeyValueTableRow>
<KeyValueTableRow
className="text-xs"
noBorder={true}
>
<div>{t('Staked (total)')}</div>
<div>{v.stakedTotal}</div>
</KeyValueTableRow>
</KeyValueTable>
}
>
<span>
{stakedRatio.times(100).toFixed(2)}%
</span>
</Tooltip>
</div>
</div>
</KeyValueTableRow>
</KeyValueTable>
</div>
</div>
</li>
);
})}
</ul>
</AsyncRenderer>
</section>
<JsonViewerDialog
open={vegaDialog}
onChange={(isOpen) => setVegaDialog(isOpen)}
title={t('Vega Validators')}
content={data}
/>
<JsonViewerDialog
open={tmDialog}
onChange={(isOpen) => setTmDialog(isOpen)}
title={t('Tendermint Validators')}
content={tmData}
/>
</>
);
};
@@ -8,7 +8,7 @@ export function Dashboard() {
<>
<div className="px-16 pt-20 pb-12 bg-greys-light-100">
<div className="max-w-screen-xl mx-auto">
<h1 className="font-alpha uppercase text-5xl mb-8">
<h1 className="font-alpha calt uppercase text-5xl mb-8">
{t('Top liquidity opportunities')}
</h1>
@@ -30,7 +30,7 @@ type Network = 'testnet' | 'mainnet';
export const Intro = ({ network = 'testnet' }: { network?: Network }) => {
return (
<div>
<p className="font-alpha text-2xl font-medium mb-2">
<p className="font-alpha calt text-2xl font-medium mb-2">
{t(
'Become a liquidity provider and earn a cut of the fees paid during trading.'
)}
@@ -92,7 +92,7 @@ export const Detail = () => {
)}
</div>
<div>
<h2 className="font-alpha text-2xl mb-4">
<h2 className="font-alpha calt text-2xl mb-4">
{t('Current Liquidity Provision')}
</h2>
<LPProvidersGrid
@@ -14,13 +14,13 @@ export const Header = ({
<div className="mb-6">
<Link to="/">
<Icon name="chevron-left" className="mr-2" />
<span className="underline font-alpha text-lg font-medium">
<span className="underline font-alpha calt text-lg font-medium">
{t('Liquidity opportunities')}
</span>
</Link>
</div>
<h1 className="font-alpha text-5xl mb-6">{name}</h1>
<p className="font-alpha text-4xl">{symbol}</p>
<h1 className="font-alpha calt text-5xl mb-6">{name}</h1>
<p className="font-alpha calt text-4xl">{symbol}</p>
</div>
);
};
@@ -44,7 +44,7 @@ export const Market = ({
<table className="w-full">
<thead>
<tr
className="text-sm text-greys-light-400 text-left font-alpha"
className="text-sm text-greys-light-400 text-left font-alpha calt"
style={{ fontFeatureSettings: "'liga' off, 'calt' off" }}
>
<th className="font-medium px-4">{t('Volume (24h)')}</th>
@@ -36,7 +36,7 @@ export const Grid = ({ isRowClickable, children, ...props }: Props) => {
return (
<AgGridReact
className={classNames('ag-theme-alpine h-full font-alpha', {
className={classNames('ag-theme-alpine h-full font-alpha calt', {
'row-hover': isRowClickable,
})}
rowHeight={92}
@@ -13,7 +13,7 @@ const Remainder = () => (
);
const COPY_CLASS =
'text-sm font-medium whitespace-nowrap text-white font-alpha';
'text-sm font-medium whitespace-nowrap text-white font-alpha calt';
const Tooltip = ({
children,
@@ -59,10 +59,10 @@ const ROWS = [
export const HealthDialog = ({ onChange, isOpen }: HealthDialogProps) => {
return (
<Dialog size="medium" open={isOpen} onChange={onChange}>
<h1 className="text-2xl mb-5 pr-2 font-medium font-alpha uppercase liga-0-calt-0">
<h1 className="text-2xl mb-5 pr-2 font-medium font-alpha uppercase">
{t('Health')}
</h1>
<p className="text-lg font-medium font-alpha mb-8 liga-0-calt-0">
<p className="text-lg font-medium font-alpha mb-8">
{t(
'Market health is a representation of market and liquidity status and how close that market is to moving from one fee level to another.'
)}
@@ -70,10 +70,10 @@ export const HealthDialog = ({ onChange, isOpen }: HealthDialogProps) => {
<table className="table-fixed">
<thead className="border-b border-greys-light-300">
<th className="w-1/2 text-left font-medium font-alpha text-base pb-4 uppercase liga-0-calt-0">
<th className="w-1/2 text-left font-medium font-alpha text-base pb-4 uppercase">
{t('Market status')}
</th>
<th className="w-1/2 text-lef font-medium font-alpha text-base pb-4 uppercase liga-0-calt-0">
<th className="w-1/2 text-lef font-medium font-alpha text-base pb-4 uppercase">
{t('Liquidity status')}
</th>
</thead>
@@ -85,12 +85,10 @@ export const HealthDialog = ({ onChange, isOpen }: HealthDialogProps) => {
<td
className={classNames('pr-4 pb-10', { 'pt-8': isFirstRow })}
>
<h2 className="font-medium font-alpha uppercase text-base liga-0-calt-0">
<h2 className="font-medium font-alpha uppercase text-base">
{t(r.title)}
</h2>
<p className="font-medium font-alpha text-lg liga-0-calt-0">
{t(r.copy)}
</p>
<p className="font-medium font-alpha text-lg">{t(r.copy)}</p>
</td>
<td
className={classNames('pl-4 pb-10', { 'pt-8': isFirstRow })}
@@ -1 +0,0 @@
[]
File diff suppressed because it is too large Load Diff
@@ -1 +0,0 @@
[]
+111
View File
@@ -0,0 +1,111 @@
.pre-loader {
display: flex;
width: 100%;
min-height: 100vh;
justify-content: center;
align-items: center;
}
.pre-loader .loader-item {
width: 10px;
height: 10px;
background: #000;
}
.pre-loader .pre-loader-center {
align-items: center;
display: flex;
flex-direction: column;
}
.pre-loader .pre-loader-wrapper {
width: 50px;
height: 50px;
display: flex;
flex-wrap: wrap;
}
.pre-loader .loader-item:nth-child(0) {
animation-delay: 0ms;
animation-direction: reverse;
}
.pre-loader .loader-item:first-child {
animation-delay: -50ms;
animation-direction: alternate;
}
.pre-loader .loader-item:nth-child(2) {
animation-delay: 0.2s;
animation-direction: reverse;
}
.pre-loader .loader-item:nth-child(3) {
animation-delay: -0.6s;
animation-direction: alternate;
}
.pre-loader .loader-item:nth-child(4) {
animation-delay: 0.4s;
animation-direction: reverse;
}
.pre-loader .loader-item:nth-child(5) {
animation-delay: -0.5s;
animation-direction: alternate;
}
.pre-loader .loader-item:nth-child(6) {
animation-delay: 0.3s;
animation-direction: reverse;
}
.pre-loader .loader-item:nth-child(7) {
animation-delay: -1.4s;
animation-direction: alternate;
}
.pre-loader .loader-item:nth-child(8) {
animation-delay: 2s;
animation-direction: reverse;
}
.pre-loader .loader-item:nth-child(9) {
animation-delay: -0.9s;
animation-direction: alternate;
}
.pre-loader .loader-item:nth-child(10) {
animation-delay: 1.5s;
animation-direction: reverse;
}
.pre-loader .loader-item:nth-child(11) {
animation-delay: -0.55s;
animation-direction: alternate;
}
.pre-loader .loader-item:nth-child(12) {
animation-delay: 1.2s;
animation-direction: reverse;
}
.pre-loader .loader-item:nth-child(13) {
animation-delay: -0.65s;
animation-direction: alternate;
}
.pre-loader .loader-item:nth-child(14) {
animation-delay: 0.7s;
animation-direction: reverse;
}
.pre-loader .loader-item:nth-child(15) {
animation-delay: -3.75s;
animation-direction: alternate;
}
.pre-loader .loader-item:nth-child(16) {
animation-delay: 1.6s;
animation-direction: reverse;
}
.pre-loader .loader-item {
animation: flickering 0.4s linear infinite alternate;
}
@keyframes flickering {
0% {
opacity: 1;
}
25% {
opacity: 1;
}
26% {
opacity: 0;
}
to {
opacity: 0;
}
}
html.dark .pre-loader .loader-item {
background: #fff;
}
@@ -1 +0,0 @@
[]
@@ -1 +0,0 @@
[]
@@ -1 +0,0 @@
[]
@@ -1 +0,0 @@
[]
+9
View File
@@ -0,0 +1,9 @@
(function () {
var storedTheme = window.localStorage.getItem('theme');
if (
storedTheme === 'dark' ||
(!storedTheme && window.matchMedia('(prefers-color-scheme: dark)').matches)
) {
document.documentElement.classList.add('dark');
}
})();
+1
View File
@@ -12,6 +12,7 @@ NX_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit suppl
NX_LOCAL_PROVIDER_URL=http://localhost:8545/
NX_VEGA_WALLET_URL=http://localhost:1789
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet3-k8s.ops.vega.xyz
#Test configuration variables
CYPRESS_FAIRGROUND=false
@@ -201,12 +201,21 @@ context('Staking Page - verify elements on page', function () {
cy.get(stakeShare)
.invoke('text')
.then(($stakePercentage) => {
if ($stakePercentage != '-') {
cy.wrap($stakePercentage).should(
'match',
/\b(?<!\.)(?!0+(?:\.0+)?%)(?:\d|[1-9]\d|100)(?:(?<!100)\.\d+)?%/
);
}
// The pattern must start at a word boundary (\b).
// The pattern cannot be immediately preceded by a dot ((?<!\.)).
// The pattern can be one of the following:
// A percentage value of zero (0%), or
// A non-zero percentage value that can be:
// A single digit (\d) between 0 and 9, or
// A two-digit number between 0 and 99 (\d{1,2}), or
// The number 100.
// The pattern can optionally include a decimal point and one or more digits after the decimal point ((?:(?<!100)\.\d+)?). However, if the number is 100, it cannot have a decimal point.
// The pattern must end with a percentage sign (%).
cy.wrap($stakePercentage).should(
'match',
/\b(?<!\.)(?:0+(?:\.0+)?%|(?:\d|\d{1,2}|100)(?:(?<!100)\.\d+)?)%/
);
});
});
@@ -1,4 +1,3 @@
const connectPrompt = '[data-testid="eth-connect-prompt"]';
const connectButton = '[data-testid="connect-to-eth-btn"]';
context(
@@ -18,7 +17,7 @@ context(
});
it('should have connect Eth wallet info', function () {
cy.get(connectPrompt).should('be.visible');
cy.get(connectButton).should('be.visible');
});
it('should have connect Eth wallet button', function () {
+1 -1
View File
@@ -13,4 +13,4 @@ last 2 Edge major versions
last 2 Safari major version
last 2 iOS major versions
Firefox ESR
not IE 9-11 # For IE 9-11 support, remove 'not'.
not IE 9-11 # For IE 9-11 support, remove 'not'.
+1
View File
@@ -12,6 +12,7 @@ NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet3-k8s.ops.vega.xyz
#Test configuration variables
CYPRESS_FAIRGROUND=false
+1
View File
@@ -15,6 +15,7 @@ NX_LOCAL_PROVIDER_URL=http://localhost:8545/
NX_VEGA_WALLET_URL=http://localhost:1789
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet3-k8s.ops.vega.xyz
#Test configuration variables
CYPRESS_FAIRGROUND=false
+1
View File
@@ -9,3 +9,4 @@ NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_VEGA_EXPLORER_URL=https://dev.explorer.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-devnet1-k8s.ops.vega.xyz
+1
View File
@@ -10,3 +10,4 @@ NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40:87edc2605e544f888305d7fc4a9141bd@o286262.ingest.sentry.io/5882996
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-mainnet-k8s.ops.vega.xyz
+1
View File
@@ -6,3 +6,4 @@ NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/stagnet1-network.json
NX_VEGA_EXPLORER_URL=https://stagnet1.explorer.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz
+1
View File
@@ -7,3 +7,4 @@ NX_VEGA_EXPLORER_URL=https://stagnet3.explorer.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-stagnet3-k8s.ops.vega.xyz
+1
View File
@@ -10,3 +10,4 @@ NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz
NX_DELEGATIONS_PAGINATION=50
NX_TRANCHES_SERVICE_URL=https://tranches-testnet-k8s.ops.vega.xyz
@@ -1,17 +1,17 @@
import * as Sentry from '@sentry/react';
import { toBigNum } from '@vegaprotocol/react-helpers';
import { useEthereumConfig } from '@vegaprotocol/web3';
import { useWeb3React } from '@web3-react/core';
import { useEffect } from 'react';
import { useAppState } from '../../contexts/app-state/app-state-context';
import { useContracts } from '../../contexts/contracts/contracts-context';
import { useGetAssociationBreakdown } from '../../hooks/use-get-association-breakdown';
import { useGetUserTrancheBalances } from '../../hooks/use-get-user-tranche-balances';
import { useGetUserBalances } from '../../hooks/use-get-user-balances';
import { useBalances } from '../../lib/balances/balances-store';
import type { ReactElement } from 'react';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { useListenForStakingEvents as useListenForAssociationEvents } from '../../hooks/use-listen-for-staking-events';
import { useTranches } from '../../lib/tranches/tranches-store';
import { useUserTrancheBalances } from '../../routes/redemption/hooks';
import { useEthereumConfig } from '@vegaprotocol/web3';
interface BalanceManagerProps {
children: ReactElement;
@@ -24,7 +24,13 @@ export const BalanceManager = ({ children }: BalanceManagerProps) => {
const {
appState: { decimals },
} = useAppState();
const { updateBalances: updateStoreBalances } = useBalances();
const updateStoreBalances = useBalances((state) => state.updateBalances);
const setTranchesBalances = useBalances((state) => state.setTranchesBalances);
const getUserBalances = useGetUserBalances(account);
const userTrancheBalances = useUserTrancheBalances(account);
useEffect(() => {
setTranchesBalances(userTrancheBalances);
}, [setTranchesBalances, userTrancheBalances]);
const { config } = useEthereumConfig();
const numberOfConfirmations = config?.confirmations || 0;
@@ -41,10 +47,10 @@ export const BalanceManager = ({ children }: BalanceManagerProps) => {
numberOfConfirmations
);
const getUserTrancheBalances = useGetUserTrancheBalances(
account || '',
contracts?.vesting
);
const getTranches = useTranches((state) => state.getTranches);
useEffect(() => {
getTranches(decimals);
}, [decimals, getTranches]);
const getAssociationBreakdown = useGetAssociationBreakdown(
account || '',
contracts?.staking,
@@ -54,50 +60,14 @@ export const BalanceManager = ({ children }: BalanceManagerProps) => {
// update balances on connect to Ethereum
useEffect(() => {
const updateBalances = async () => {
if (!account || !config) return;
try {
const [b, w, stats, a] = await Promise.all([
contracts.vesting.user_total_all_tranches(account),
contracts.token.balanceOf(account),
contracts.vesting.user_stats(account),
contracts.token.allowance(
account,
config.staking_bridge_contract.address
),
]);
const balance = toBigNum(b, decimals);
const walletBalance = toBigNum(w, decimals);
const lien = toBigNum(stats.lien, decimals);
const allowance = toBigNum(a, decimals);
updateStoreBalances({
balanceFormatted: balance,
walletBalance,
lien,
allowance,
});
} catch (err) {
Sentry.captureException(err);
const balances = await getUserBalances();
if (balances) {
updateStoreBalances(balances);
}
};
updateBalances();
}, [
decimals,
contracts.token,
contracts.vesting,
account,
config,
updateStoreBalances,
]);
// This use effect hook is very expensive and is kept separate to prevent expensive reloading of data.
useEffect(() => {
if (account) {
getUserTrancheBalances();
}
}, [account, getUserTrancheBalances]);
}, [getUserBalances, updateStoreBalances]);
useEffect(() => {
if (account) {
@@ -6,27 +6,22 @@ import {
useAppState,
} from '../../contexts/app-state/app-state-context';
interface EthConnectPrompProps {
children?: React.ReactNode;
}
export const EthConnectPrompt = ({ children }: EthConnectPrompProps) => {
export const EthConnectPrompt = () => {
const { t } = useTranslation();
const { appDispatch } = useAppState();
return (
<>
{children}
<Button
onClick={() =>
appDispatch({
type: AppStateActionType.SET_ETH_WALLET_OVERLAY,
isOpen: true,
})
}
data-testid="connect-to-eth-btn"
>
{t('connectEthWallet')}
</Button>
</>
<Button
variant="primary"
onClick={() =>
appDispatch({
type: AppStateActionType.SET_ETH_WALLET_OVERLAY,
isOpen: true,
})
}
fill={true}
data-testid="connect-to-eth-btn"
>
{t('connectEthWallet')}
</Button>
);
};
+1
View File
@@ -58,6 +58,7 @@ const envName = windowOrDefault('NX_VEGA_ENV') ?? 'local';
export const ENV = {
// Environment
tranchesServiceUrl: windowOrDefault('NX_TRANCHES_SERVICE_URL'),
dsn: windowOrDefault('NX_SENTRY_DSN'),
urlConnect: TRUTHY.includes(windowOrDefault('NX_ETH_URL_CONNECT')),
explorerUrl: windowOrDefault('NX_VEGA_EXPLORER'),
@@ -1,4 +1,3 @@
import type { Tranche } from '@vegaprotocol/smart-contracts';
import React from 'react';
import type { BigNumber } from '../../lib/bignumber';
@@ -19,21 +18,7 @@ export interface VegaKey {
meta: Array<{ key: string; value: string }> | null;
}
export interface UserTrancheBalance {
/** ID of tranche */
id: number;
/** Users vesting tokens on tranche */
locked: BigNumber;
/** Users vested tokens on tranche */
vested: BigNumber;
}
export interface AppState {
/** Array of tranche objects */
tranches: Tranche[] | null;
/** Number of decimal places of the VEGA token (18 on Mainnet, 5 on Testnet) */
decimals: number;
@@ -52,9 +37,6 @@ export interface AppState {
/** Whether or not the connect to Ethereum wallet overlay is open */
ethConnectOverlay: boolean;
/** The error if one was thrown during retrieval of tranche data */
trancheError: Error | null;
/** Whether or not the mobile drawer is open. Only relevant on screens smaller than 960 */
drawerOpen: boolean;
@@ -71,12 +53,10 @@ export enum AppStateActionType {
SET_TOKEN,
SET_ALLOWANCE,
REFRESH_BALANCES,
SET_TRANCHE_DATA,
SET_VEGA_WALLET_OVERLAY,
SET_VEGA_WALLET_MANAGE_OVERLAY,
SET_ETH_WALLET_OVERLAY,
SET_DRAWER,
SET_TRANCHE_ERROR,
REFRESH_ASSOCIATED_BALANCES,
SET_ASSOCIATION_BREAKDOWN,
SET_TRANSACTION_OVERLAY,
@@ -90,14 +70,6 @@ export type AppStateAction =
totalSupply: BigNumber;
totalAssociated: BigNumber;
}
| {
type: AppStateActionType.SET_TRANCHE_DATA;
tranches: Tranche[];
}
| {
type: AppStateActionType.SET_TRANCHE_ERROR;
error: Error | null;
}
| {
type: AppStateActionType.SET_VEGA_WALLET_OVERLAY;
isOpen: boolean;
@@ -14,11 +14,9 @@ const initialAppState: AppState = {
totalAssociated: new BigNumber(0),
decimals: 0,
totalSupply: new BigNumber(0),
tranches: null,
vegaWalletOverlay: false,
vegaWalletManageOverlay: false,
ethConnectOverlay: false,
trancheError: null,
drawerOpen: false,
transactionOverlay: false,
bannerMessage: '',
@@ -34,17 +32,6 @@ function appStateReducer(state: AppState, action: AppStateAction): AppState {
totalAssociated: action.totalAssociated,
};
}
case AppStateActionType.SET_TRANCHE_DATA:
return {
...state,
tranches: action.tranches,
};
case AppStateActionType.SET_TRANCHE_ERROR: {
return {
...state,
trancheError: action.error,
};
}
case AppStateActionType.SET_VEGA_WALLET_OVERLAY: {
return {
...state,
@@ -1,666 +0,0 @@
import parseJSON from 'date-fns/parseJSON';
import { BigNumber } from '../../lib/bignumber';
import type { Tranche } from '@vegaprotocol/smart-contracts';
const json: Tranche[] = [
{
tranche_id: 1,
tranche_start: parseJSON('2022-03-05T00:00:00.000Z'),
tranche_end: parseJSON('2023-06-05T00:00:00.000Z'),
total_added: new BigNumber('3505372.53445'),
total_removed: new BigNumber('0'),
locked_amount: new BigNumber('3505372.53445'),
deposits: [
{
amount: new BigNumber('187637.95'),
user: '0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0',
tx: '0xc4491908e3347b05f2394ac7e1006f573fe8cbc490a57cd1dadad70785e95024',
},
{
amount: new BigNumber('200000'),
user: '0x93b478148FF792B00076B7EdC89Db1FdE7772079',
tx: '0xcc8fba855a0d965044d4cc587701fe9ee9f5863852cede017382ffe02963d9b8',
},
{
amount: new BigNumber('21666.5743'),
user: '0xB523235B6c7C74DDB26b10E78bFb2d0Cb63Ae289',
tx: '0x8cc5159f3d665dd33a2bdac6e990cf1b65dc18b6b5e37a07b37dd54495a8d33c',
},
{
amount: new BigNumber('200000'),
user: '0x7227e17101E6C70F4dAfC7DDB77BB7D83DdfC1C8',
tx: '0x0cdef6868bd6b977362396fd06525e1e757e827659c5d75cd512db121947e6f7',
},
{
amount: new BigNumber('137998.56'),
user: '0x69eFc5642CfcCB1777bc663433640531F044D1F5',
tx: '0xaa9b3b39836a69f760f5d1d2fdba44ad348b27c8f31eb094ad6f779b39d7949c',
},
{
amount: new BigNumber('16249.93'),
user: '0x006B59DD3bC838A74476c0F4a33C1565831dA0DD',
tx: '0xda9bdc846300600c0d360edcaf4a5ed40fa2586ba7872f2bf68251a669adff0e',
},
],
withdrawals: [],
users: [
{
address: '0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0',
deposits: [
{
amount: new BigNumber('187637.95'),
user: '0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0',
tranche_id: 1,
tx: '0xc4491908e3347b05f2394ac7e1006f573fe8cbc490a57cd1dadad70785e95024',
},
],
withdrawals: [],
total_tokens: new BigNumber('187637.95'),
withdrawn_tokens: new BigNumber('0'),
remaining_tokens: new BigNumber('187637.95'),
},
{
address: '0x1A71e3ED1996CAbB91bB043f880CE963D601707e',
deposits: [
{
amount: new BigNumber('112323.67'),
user: '0x1A71e3ED1996CAbB91bB043f880CE963D601707e',
tranche_id: 1,
tx: '0xaa378d2d0d4d7b964a675bb19f19c4f7401deec6ce66b1bd98ad5b812026e53e',
},
],
withdrawals: [],
total_tokens: new BigNumber('112323.67'),
withdrawn_tokens: new BigNumber('0'),
remaining_tokens: new BigNumber('112323.67'),
},
],
},
{
tranche_id: 2,
tranche_start: parseJSON('2022-06-05T00:00:00.000Z'),
tranche_end: parseJSON('2023-12-05T00:00:00.000Z'),
total_added: new BigNumber('15464357.550320999700000001'),
total_removed: new BigNumber('0'),
locked_amount: new BigNumber('15464357.550320999700000001'),
deposits: [
{
amount: new BigNumber('1'),
user: '0x7fff551249D223f723557a96a0e1a469C79cC934',
tx: '0x55fa59d71aac37428a5804442c48da677a4426a4e92447919a8199520ce20f53',
},
{
amount: new BigNumber('100000'),
user: '0xe20D4d4fFb165e4b9926467d82d03c0e9ab66D89',
tx: '0xabf2cc96c41c8b4f0cff8d8ff7448e241ff83e296a7b7dea79d9d9868f33b7ad',
},
{
amount: new BigNumber('500000'),
user: '0x5f01A497e4033E4812ba5D494bCBc2220cd510Ed',
tx: '0xe3a1a74378a42eace12c21c24889d8b0da6a3736ca7987720e70f59886caa5a3',
},
{
amount: new BigNumber('59228.95'),
user: '0x1d20f66eF3889aa48Bb4Badbbf993dE965BDb029',
tx: '0xf31eab593b86aac54f5fa9fe24bb26105ff52386be60bc24617dd362df7c6f15',
},
{
amount: new BigNumber('206374.1211'),
user: '0x1b979e8AE3BbbaF96Dd1bbbC0060b360A23f2EBE',
tx: '0x2983daa9acf6da5fba0debc2aaaaf47389b92aea0de0c27b20809fb69a63ce69',
},
{
amount: new BigNumber('200000'),
user: '0xe45993F39183E148bC35BA02ba8C289111181c0f',
tx: '0xbda7b70ab8ac629617e74daaaa5451b04d7830bc0da516e10d533efc2eef1530',
},
],
withdrawals: [
{
amount: new BigNumber('0'),
user: '0x4527F5A12bbbbb7c88c5863F8AB9a708928Fe702',
tx: '0xbaa8632cd162265ca46baaaad746ec3d283a474e344727854d962e057380a51',
},
],
users: [
{
address: '0x7fff551249D223f723557a96a0e1aCCCC79cC934',
deposits: [
{
amount: new BigNumber('1'),
user: '0x7fff551249D223f723557a96a0e1aCCCC79cC934',
tranche_id: 2,
tx: '0x55fa59d71aac37428a0000042c48da677a4426a4e92447919a8199520ce20f53',
},
],
withdrawals: [],
total_tokens: new BigNumber('1'),
withdrawn_tokens: new BigNumber('0'),
remaining_tokens: new BigNumber('1'),
},
{
address: '0xCc5CAFD3daA3bb2c1168521F35d1eBEB6cf7c051',
deposits: [
{
amount: new BigNumber('200000'),
user: '0xCc5CAFD3daA3bb2c1168521F35d1eBEB6cf7c051',
tranche_id: 2,
tx: '0x8168230eb08320a7a874ebeeea20f0def842b8059a2b05a036870e00ca624c88',
},
],
withdrawals: [],
total_tokens: new BigNumber('200000'),
withdrawn_tokens: new BigNumber('0'),
remaining_tokens: new BigNumber('200000'),
},
{
address: '0x9cd59376F896a5F2084232E386A65c17EEA4Fe9f',
deposits: [
{
amount: new BigNumber('200000'),
user: '0x9cd59376F896a5F2084232E386A65c17EEA4Fe9f',
tranche_id: 2,
tx: '0x2eb27449e08a245314faaaaf0d93fafc70733586495f18cf2fb69ef979459efd',
},
],
withdrawals: [],
total_tokens: new BigNumber('200000'),
withdrawn_tokens: new BigNumber('0'),
remaining_tokens: new BigNumber('200000'),
},
{
address: '0xe45993F39183E148bC35BA02ba8aaaa807981caa',
deposits: [
{
amount: new BigNumber('200000'),
user: '0xe45993F39183E148bC35BA02ba8aaaa07981caa',
tranche_id: 2,
tx: '0xbda7b70ab8ac629617e74d33575451b04d7830bc0da516e10d533efc2eef1530',
},
],
withdrawals: [],
total_tokens: new BigNumber('200000'),
withdrawn_tokens: new BigNumber('0'),
remaining_tokens: new BigNumber('200000'),
},
],
},
{
tranche_id: 3,
tranche_start: parseJSON('2021-11-05T00:00:00.000Z'),
tranche_end: parseJSON('2023-05-05T00:00:00.000Z'),
total_added: new BigNumber('14597706.0446472999'),
total_removed: new BigNumber('0'),
locked_amount: new BigNumber('14445316.74229298796336861823365303'),
deposits: [
{
amount: new BigNumber('129284.449'),
user: '0x26100B2C8168Cb0A6c869a5698265086A3Dfeaaa',
tx: '0xcc67a776a2e3b48864470aaa9e0940c1814663b4fde6df60c1a099a636dcae79',
},
{
amount: new BigNumber('1151405.093'),
user: '0x777Ec2e2beaB6a63c1E763D0dc4120AF60BEe39F',
tx: '0x1237d45a40aacc5dff7f8f69e8a4c0536fd0460b915de576bd3f0fdf5892c0a4',
},
{
amount: new BigNumber('1151073.595'),
user: '0x5CD0Ec63687588817044794bF15d4e37991efAB3',
tx: '0xb4eaca7d8abeaf7e1d9d28b1f1fa09fc1933af0e11bff4b0120dcef7d2dfc64d',
},
{
amount: new BigNumber('54034.5'),
user: '0xc01F2E57554Bb392384feCA6a54c8E3A3Ca94E42',
tx: '0xf33289a2a73a65b132accdddd600a8d2c7556c2d80784d5f8d4eea1ecacf93cc',
},
{
amount: new BigNumber('115049.22'),
user: '0x01a8055A97b461b58ba8e37cd349721FeAe77A8D',
tx: '0xf650c3599b24d01dfa1f3e19b22f870ff8ac8dfac529893f0b22d548c3535eda',
},
],
withdrawals: [
{
amount: new BigNumber('0'),
user: '0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b',
tx: '0x1af894d1f9ce5ea79aa52d180fbff5f30b8b456e43b76ca5d7d73366e422ea37',
},
],
users: [
{
address: '0x26100B2C8168Cb0A6c869a5698265086A3DfeF98',
deposits: [
{
amount: new BigNumber('129284.449'),
user: '0x26100B2C8168Cb0A6c869a5698265086A3DfeF98',
tranche_id: 3,
tx: '0xcc67a776a2e3b48864470eff9e0940c1814663b4fde6df60c1a099a636dcae79',
},
],
withdrawals: [],
total_tokens: new BigNumber('129284.449'),
withdrawn_tokens: new BigNumber('0'),
remaining_tokens: new BigNumber('129284.449'),
},
{
address: '0xd4632B682228Db5f38E2283869AEe8c29ee6Eec8',
deposits: [
{
amount: new BigNumber('44499.2'),
user: '0xd4632B682228Db5f38E2283869AEe8c29ee6Eec8',
tranche_id: 3,
tx: '0x57019840d1ce05e0ef65c45801d6699e5eb1032bd8ad56493594d4866996ea82',
},
],
withdrawals: [],
total_tokens: new BigNumber('44499.2'),
withdrawn_tokens: new BigNumber('0'),
remaining_tokens: new BigNumber('44499.2'),
},
{
address: '0xe2E6F37cb1f1980418012BF69f43910d6Bc73e73',
deposits: [
{
amount: new BigNumber('66748.8'),
user: '0xe2E6F37cb1f1980418012BF69f43910d6Bc73e73',
tranche_id: 3,
tx: '0xd257a3aacd5bdf86cbea0ed3db3697f55dff9092129db6baedacaf00b50af936',
},
],
withdrawals: [],
total_tokens: new BigNumber('66748.8'),
withdrawn_tokens: new BigNumber('0'),
remaining_tokens: new BigNumber('66748.8'),
},
{
address: '0xc01F2E57554Bb392384feCA6a54c8E3A3Ca94E42',
deposits: [
{
amount: new BigNumber('54034.5'),
user: '0xc01F2E57554Bb392384feCA6a54c8E3A3Ca94E42',
tranche_id: 3,
tx: '0xf33289a2a73a65b132accdddd600a8d2c7556c2d80784d5f8d4eea1ecacf93cc',
},
],
withdrawals: [],
total_tokens: new BigNumber('54034.5'),
withdrawn_tokens: new BigNumber('0'),
remaining_tokens: new BigNumber('54034.5'),
},
],
},
{
tranche_id: 4,
tranche_start: parseJSON('2021-10-05T00:00:00.000Z'),
tranche_end: parseJSON('2023-04-05T00:00:00.000Z'),
total_added: new BigNumber('5198082.8647159303'),
total_removed: new BigNumber('12706.1452878164044708'),
locked_amount: new BigNumber('4849328.20502099651595959714823613'),
deposits: [
{
amount: new BigNumber('110499.5291'),
user: '0xa8679b60612Fb2e19d68964326CA02dCe6a08D08',
tx: '0x9d3432b818054796489848c415af5c523acb16c1540e5865010baf71964c03a7',
},
{
amount: new BigNumber('331498.5873'),
user: '0x39fEc2e2beaB6a63c1E763D0dc4120AF60BEe39F',
tx: '0xdf5c6e44ef0763e785721802704e5fd186fa3964302a566899027447d0dda57b',
},
{
amount: new BigNumber('27624.032275'),
user: '0xF5Fb27b912D987B5b6e02A1B1BE0C1F0740E2c6f',
tx: '0x1860d39ae3e9ad710da9e2a9bf9606eedc1b176fca673473d6854ea91ed8beb5',
},
{
amount: new BigNumber('73666.3527333333'),
user: '0x2895059cB5a492BEd58D1fB22713006EfaD465eA',
tx: '0x260619e2129cc58ae03f6b4ecfc5a6eeab29b5998de69875accb3cb945beed04',
},
],
withdrawals: [
{
amount: new BigNumber('1290.014571009862016'),
user: '0xBc934494675a6ceB639B9EfEe5b9C0f017D35a75',
tx: '0x637c3648ce941a77e08e741f981806a5d56275db6d280f041902386ae8567d06',
},
{
amount: new BigNumber('5197.621879605058623'),
user: '0xafa64cCa337eFEE0AD827F6C2684e69275226e90',
tx: '0xe8b8c1a38d3ae809dcaae54a11adeeba0f46be03924e91d8f251f3f2d48c3553',
},
{
amount: new BigNumber('376.2625308599198808'),
user: '0x1dD2718fd01d05C9F50Fce8Bb723A4C7483A1E15',
tx: '0x78af737235f1123bb1c6a607a0b4b7a3c5ed6859a4e8912f45bb7c812724b1de',
},
{
amount: new BigNumber('4162.301372742020875'),
user: '0xBc934494675a6ceB639B9EfEe5b9C0f017D35a75',
tx: '0x85c7d9979f0e3a3660dc5952732eaf9414f7c28a1c00a9a10f449843f91d85e0',
},
{
amount: new BigNumber('1679.944933599543076'),
user: '0x9058e12e2F32cB1cD4D3123359963D77786477FC',
tx: '0xd92083f2e90e84cb70ef27ac410ed1144200c41b1714fb54d29f5f23ca086ecb',
},
],
users: [
{
address: '0xa8679b60612Fb2e19d68964326CA02dCe6a08D08',
deposits: [
{
amount: new BigNumber('110499.5291'),
user: '0xa8679b60612Fb2e19d68964326CA02dCe6a08D08',
tranche_id: 4,
tx: '0x9d3432b818054796489848c415af5c523acb16c1540e5865010baf71964c03a7',
},
],
withdrawals: [],
total_tokens: new BigNumber('110499.5291'),
withdrawn_tokens: new BigNumber('0'),
remaining_tokens: new BigNumber('110499.5291'),
},
{
address: '0x8767d65677Cabaa2050b764AEf40610f2f9796F5',
deposits: [
{
amount: new BigNumber('1104995.291'),
user: '0x8767d65677Cabaa2050b764AEf40610f2f9796F5',
tranche_id: 4,
tx: '0xc6298f52c173a837abd051ed810b01eb5731be307376b73df6e31b4de39d0122',
},
],
withdrawals: [],
total_tokens: new BigNumber('1104995.291'),
withdrawn_tokens: new BigNumber('0'),
remaining_tokens: new BigNumber('1104995.291'),
},
{
address: '0x91715128a71c9C734CDC20E5EdaaeA02E72e422E',
deposits: [
{
amount: new BigNumber('165749.29365'),
user: '0x91715128a71c9C734CDC20E5EdEEeA02E72e422E',
tranche_id: 4,
tx: '0xf828cea685a0689f27446f02d3376c3afa4398182d3b5bf1c81e949f5965d1c1',
},
],
withdrawals: [],
total_tokens: new BigNumber('165749.29365'),
withdrawn_tokens: new BigNumber('0'),
remaining_tokens: new BigNumber('165749.29365'),
},
{
address: '0x2895059cB5a492BEd58D1fB22713006EfaD465eA',
deposits: [
{
amount: new BigNumber('73666.3527333333'),
user: '0x2895059cB5a492BEd58D1fB22713006EfaD465eA',
tranche_id: 4,
tx: '0x260619e2129cc58ae03f6b4ecfc5a6eeab29b5998de69875accb3cb945beed04',
},
],
withdrawals: [],
total_tokens: new BigNumber('73666.3527333333'),
withdrawn_tokens: new BigNumber('0'),
remaining_tokens: new BigNumber('73666.3527333333'),
},
],
},
{
tranche_id: 23,
tranche_start: parseJSON('2022-04-30T00:00:00.000Z'),
tranche_end: parseJSON('2022-04-30T00:00:00.000Z'),
total_added: new BigNumber('10833.29'),
total_removed: new BigNumber('0'),
locked_amount: new BigNumber('10833.29'),
deposits: [
{
amount: new BigNumber('10833.29'),
user: '0xF3359E5B89f7804c8c9283781Aaaa33BBd979c9D',
tx: '0x65f904ef34d6992b52f449a709d7a24411a501fd07f90aaa9255eacc994bc229',
},
],
withdrawals: [],
users: [
{
address: '0xF3359E5B89f7804c8c9283781Aaaa33BBd979c9D',
deposits: [
{
amount: new BigNumber('10833.29'),
user: '0xF3359E5B89f7804c8c9283781Aaaa33BBd979c9D',
tranche_id: 23,
tx: '0x65f904ef34d6992b52f449a709d7a24411a501fd07f90aaa9255eacc994bc229',
},
],
withdrawals: [],
total_tokens: new BigNumber('10833.29'),
withdrawn_tokens: new BigNumber('0'),
remaining_tokens: new BigNumber('10833.29'),
},
],
},
{
tranche_id: 24,
tranche_start: parseJSON('2022-09-26T00:00:00.000Z'),
tranche_end: parseJSON('2022-09-26T00:00:00.000Z'),
total_added: new BigNumber('16249.93'),
total_removed: new BigNumber('0'),
locked_amount: new BigNumber('16249.93'),
deposits: [
{
amount: new BigNumber('16249.93'),
user: '0xcE96670971ec2E1E79D0d96688adbA2FfD6F6C7f',
tx: '0x3dbd991b7914986505d89a7c1562278dffffa2f5f444bdbf5d6bbd838e3d8d5d',
},
],
withdrawals: [],
users: [
{
address: '0xcE96670971ec2E1E79D0d96688adbA2FfD6F6C7f',
deposits: [
{
amount: new BigNumber('16249.93'),
user: '0xcE96670971ec2E1E79D0d96688adbA2FfD6F6C7f',
tranche_id: 24,
tx: '0x3dbd991b7914986505d89a7c1562278dffffa2f5f444bdbf5d6bbd838e3d8d5d',
},
],
withdrawals: [],
total_tokens: new BigNumber('16249.93'),
withdrawn_tokens: new BigNumber('0'),
remaining_tokens: new BigNumber('16249.93'),
},
],
},
{
tranche_id: 25,
tranche_start: parseJSON('2022-02-10T00:00:00.000Z'),
tranche_end: parseJSON('2023-04-05T00:00:00.000Z'),
total_added: new BigNumber('0'),
total_removed: new BigNumber('0'),
locked_amount: new BigNumber('0'),
deposits: [],
withdrawals: [],
users: [],
},
{
tranche_id: 26,
tranche_start: parseJSON('2022-02-04T00:00:00.000Z'),
tranche_end: parseJSON('2023-04-05T00:00:00.000Z'),
total_added: new BigNumber('135173.4239508'),
total_removed: new BigNumber('0'),
locked_amount: new BigNumber('135173.4239508'),
deposits: [
{
amount: new BigNumber('135173.4239508'),
user: '0xc90eA4d8D214D548221EE3622a8BE1D61f7077A2',
tx: '0x123fb1e293a8246b92d85a47c8d33def9fb6468c7cbb70f1754d78914b12dbf8',
},
],
withdrawals: [],
users: [
{
address: '0x222eA4d8D214D548221EE3622a8BE1D61f7077A2',
deposits: [
{
amount: new BigNumber('135173.4239508'),
user: '0x222eA4d8D214D548221EE3622a8BE1D61f7077A2',
tranche_id: 26,
tx: '0x9fafb1e293a8246b92d85a47c8d33def9fb6468c7cbb70f1754d78914b12dbf8',
},
],
withdrawals: [],
total_tokens: new BigNumber('135173.4239508'),
withdrawn_tokens: new BigNumber('0'),
remaining_tokens: new BigNumber('135173.4239508'),
},
],
},
{
tranche_id: 27,
tranche_start: parseJSON('2022-05-09T00:00:00.000Z'),
tranche_end: parseJSON('2023-04-05T00:00:00.000Z'),
total_added: new BigNumber('32499.86'),
total_removed: new BigNumber('0'),
locked_amount: new BigNumber('32499.86'),
deposits: [
{
amount: new BigNumber('32499.86'),
user: '0x1E7c4E57A1dc4dD4bBE81b833e3E437f69619DaB',
tx: '0x25a3dd4852ce8ac1c15fe42123cfab14e4bf8a5c1cb97167cb4d6fe20bd319ae',
},
],
withdrawals: [],
users: [
{
address: '0x3E7c4E57A1dc4dD4bBE81bbEFBe3Eaaaf69619Da9',
deposits: [
{
amount: new BigNumber('32499.86'),
user: '0x3E7c4E57A1dc4dD4bBE81bbEFBe3Eaaaf69619Da9',
tranche_id: 27,
tx: '0x75a3dd4852ce8ac1c15fe42ff6cfab1455bf8a5c1cb97167cb4d6fe20bd319ae',
},
],
withdrawals: [],
total_tokens: new BigNumber('32499.86'),
withdrawn_tokens: new BigNumber('0'),
remaining_tokens: new BigNumber('32499.86'),
},
],
},
{
tranche_id: 28,
tranche_start: parseJSON('2022-04-30T00:00:00.000Z'),
tranche_end: parseJSON('2023-04-05T00:00:00.000Z'),
total_added: new BigNumber('10833.29'),
total_removed: new BigNumber('0'),
locked_amount: new BigNumber('10833.29'),
deposits: [
{
amount: new BigNumber('10833.29'),
user: '0xF3359E5B89f7804c8c9283781Aaa133BBd979c9D',
tx: '0x166d235eff44e7bcc63597c0d6e698552e4440fe90ec7cf07a1d510c275cf3e0',
},
],
withdrawals: [],
users: [
{
address: '0x12349E5B89f7804c8c9283781A23133BBd979c22',
deposits: [
{
amount: new BigNumber('10833.29'),
user: '0x12349E5B89f7804c8c9283781A23133BBd979c22',
tranche_id: 28,
tx: '0x166d235eff44e7baa6359712345698552e6150fe90ec7cf07a1d510c275cf3e0',
},
],
withdrawals: [],
total_tokens: new BigNumber('10833.29'),
withdrawn_tokens: new BigNumber('0'),
remaining_tokens: new BigNumber('10833.29'),
},
],
},
{
tranche_id: 29,
tranche_start: parseJSON('2022-09-26T00:00:00.000Z'),
tranche_end: parseJSON('2023-04-05T00:00:00.000Z'),
total_added: new BigNumber('16249.93'),
total_removed: new BigNumber('0'),
locked_amount: new BigNumber('16249.93'),
deposits: [
{
amount: new BigNumber('16249.93'),
user: '0xcE96670971ec2E1E79D0d12388adbA2FfD6F6C7f',
tx: '0xa770ab2d05e6c81be46b73ac2326e81a111da4ce55a2d8544bd95b48ad530674',
},
],
withdrawals: [],
users: [
{
address: '0xcE96670971ec2E1E79D0d96688adbA2FfD6F6C7f',
deposits: [
{
amount: new BigNumber('16249.93'),
user: '0xcE96670971ec212379D0d12388adbA2Ffc6F6C7f',
tranche_id: 29,
tx: '0xa220ab2d05e6c81be12373ac2326e81a912da4ce55a2d8544bd95b48ad530674',
},
],
withdrawals: [],
total_tokens: new BigNumber('16249.93'),
withdrawn_tokens: new BigNumber('0'),
remaining_tokens: new BigNumber('16249.93'),
},
],
},
{
tranche_id: 30,
tranche_start: parseJSON('2021-11-01T00:00:00.000Z'),
tranche_end: parseJSON('2022-05-01T00:00:00.000Z'),
total_added: new BigNumber('0'),
total_removed: new BigNumber('0'),
locked_amount: new BigNumber('0'),
deposits: [],
withdrawals: [],
users: [],
},
{
tranche_id: 31,
tranche_start: parseJSON('2022-02-01T00:00:00.000Z'),
tranche_end: parseJSON('2022-08-01T00:00:00.000Z'),
total_added: new BigNumber('0'),
total_removed: new BigNumber('0'),
locked_amount: new BigNumber('0'),
deposits: [],
withdrawals: [],
users: [],
},
{
tranche_id: 32,
tranche_start: parseJSON('2022-05-01T00:00:00.000Z'),
tranche_end: parseJSON('2022-11-01T00:00:00.000Z'),
total_added: new BigNumber('0'),
total_removed: new BigNumber('0'),
locked_amount: new BigNumber('0'),
deposits: [],
withdrawals: [],
users: [],
},
{
tranche_id: 33,
tranche_start: parseJSON('2022-11-01T00:00:00.000Z'),
tranche_end: parseJSON('2023-05-01T00:00:00.000Z'),
total_added: new BigNumber('0'),
total_removed: new BigNumber('0'),
locked_amount: new BigNumber('0'),
deposits: [],
withdrawals: [],
users: [],
},
];
export default json;
@@ -1,21 +0,0 @@
import React from 'react';
import mock from './tranches-mock';
import type { Tranche } from '@vegaprotocol/smart-contracts';
export function useTranches() {
const [tranches, setTranches] = React.useState<Tranche[] | null>(null);
const [error, setError] = React.useState<string | null>(null);
React.useEffect(() => {
const run = async () => {
try {
setTranches(mock);
} catch (err) {
setError((err as Error).message);
}
};
run();
}, []);
return { tranches, error };
}
@@ -0,0 +1,41 @@
import { useCallback } from 'react';
import * as Sentry from '@sentry/react';
import { toBigNum } from '@vegaprotocol/react-helpers';
import { useContracts } from '../contexts/contracts/contracts-context';
import { useAppState } from '../contexts/app-state/app-state-context';
import { useEthereumConfig } from '@vegaprotocol/web3';
export const useGetUserBalances = (account: string | undefined) => {
const { token, vesting } = useContracts();
const { config } = useEthereumConfig();
const {
appState: { decimals },
} = useAppState();
return useCallback(async () => {
if (!account || !config) return;
try {
const [b, w, stats, a] = await Promise.all([
vesting.user_total_all_tranches(account),
token.balanceOf(account),
vesting.user_stats(account),
token.allowance(account, config.staking_bridge_contract.address),
]);
const balance = toBigNum(b, decimals);
const walletBalance = toBigNum(w, decimals);
const lien = toBigNum(stats.lien, decimals);
const allowance = toBigNum(a, decimals);
return {
balanceFormatted: balance,
walletBalance,
lien,
allowance,
balance,
};
} catch (err) {
Sentry.captureException(err);
return null;
}
}, [account, config, decimals, token, vesting]);
};
@@ -1,70 +0,0 @@
import React from 'react';
import * as Sentry from '@sentry/react';
import type { TokenVesting } from '@vegaprotocol/smart-contracts';
import {
AppStateActionType,
useAppState,
} from '../contexts/app-state/app-state-context';
import { BigNumber } from '../lib/bignumber';
import { useTranches } from './use-tranches';
import { toBigNum } from '@vegaprotocol/react-helpers';
import { useBalances } from '../lib/balances/balances-store';
export const useGetUserTrancheBalances = (
address: string,
vesting: TokenVesting
) => {
const {
appState: { decimals },
appDispatch,
} = useAppState();
const { setTranchesBalances } = useBalances();
const { tranches } = useTranches();
return React.useCallback(async () => {
appDispatch({
type: AppStateActionType.SET_TRANCHE_ERROR,
error: null,
});
try {
if (!tranches) {
return;
}
const userTranches = tranches?.filter((t) =>
t.users.some(
({ address: a }) =>
a && address && a.toLowerCase() === address.toLowerCase()
)
);
const trancheIds = [0, ...userTranches.map((t) => t.tranche_id)];
const promises = trancheIds.map(async (tId) => {
const [t, v] = await Promise.all([
vesting.get_tranche_balance(address, tId),
vesting.get_vested_for_tranche(address, tId),
]);
const total = toBigNum(t, decimals);
const vested = toBigNum(v, decimals);
return {
id: tId,
locked: tId === 0 ? total : total.minus(vested),
vested: tId === 0 ? new BigNumber(0) : vested,
};
});
const trancheBalances = await Promise.all(promises);
setTranchesBalances(trancheBalances);
appDispatch({
type: AppStateActionType.SET_TRANCHE_DATA,
tranches,
});
} catch (e) {
Sentry.captureException(e);
appDispatch({
type: AppStateActionType.SET_TRANCHE_ERROR,
error: e as Error,
});
}
}, [appDispatch, tranches, setTranchesBalances, address, vesting, decimals]);
};
-70
View File
@@ -1,70 +0,0 @@
import { useFetch } from '@vegaprotocol/react-helpers';
import type { Tranche } from '@vegaprotocol/smart-contracts';
import React, { useEffect } from 'react';
import type { Networks } from '@vegaprotocol/environment';
import { useEnvironment } from '@vegaprotocol/environment';
import { BigNumber } from '../lib/bignumber';
const TRANCHES_URLS: { [N in Networks]: string } = {
MAINNET: 'https://static.vega.xyz/assets/mainnet-tranches.json',
MIRROR: 'https://static.vega.xyz/assets/mirror-tranches.json',
TESTNET: 'https://static.vega.xyz/assets/testnet-tranches.json',
SANDBOX: 'https://static.vega.xyz/assets/sandbox-tranches.json',
STAGNET1: 'https://static.vega.xyz/assets/stagnet1-tranches.json',
STAGNET3: 'https://static.vega.xyz/assets/stagnet3-tranches.json',
DEVNET: 'https://static.vega.xyz/assets/devnet-tranches.json',
CUSTOM: 'https://static.vega.xyz/assets/testnet-tranches.json',
};
export function useTranches() {
const { VEGA_ENV } = useEnvironment();
const [tranches, setTranches] = React.useState<Tranche[] | null>(null);
const url = React.useMemo(() => TRANCHES_URLS[VEGA_ENV], [VEGA_ENV]);
const {
state: { data, loading, error },
} = useFetch<Tranche[] | null>(url);
useEffect(() => {
const processedTrances = data
?.map((t) => ({
...t,
tranche_start: new Date(t.tranche_start),
tranche_end: new Date(t.tranche_end),
total_added: new BigNumber(t.total_added),
total_removed: new BigNumber(t.total_removed),
locked_amount: new BigNumber(t.locked_amount),
deposits: t.deposits.map((d) => ({
...d,
amount: new BigNumber(d.amount),
})),
withdrawals: t.withdrawals.map((w) => ({
...w,
amount: new BigNumber(w.amount),
})),
users: t.users.map((u) => ({
...u,
// @ts-ignore - types are incorrect in the SDK lib
deposits: u.deposits.map((d) => ({
...d,
amount: new BigNumber(d.amount),
})),
// @ts-ignore - types are incorrect in the SDK lib
withdrawals: u.withdrawals.map((w) => ({
...w,
amount: new BigNumber(w.amount),
})),
total_tokens: new BigNumber(u.total_tokens),
withdrawn_tokens: new BigNumber(u.withdrawn_tokens),
remaining_tokens: new BigNumber(u.remaining_tokens),
})),
}))
.sort((a: Tranche, b: Tranche) => a.tranche_id - b.tranche_id);
setTranches(processedTrances ? processedTrances : null);
}, [data]);
return {
tranches,
loading,
error,
};
}
+10 -1
View File
@@ -744,13 +744,22 @@
"Proposals": "Proposals",
"Validators": "Validators",
"Redeem": "Redeem",
"validatorFormIntro": "To learn more about validators and how scores are calculated,",
"readMoreValidatorForm": "read about staking on Vega",
"StakeDescription": "The total amount $VEGA staked to this validator including self-stake and all delegation.",
"NormalisedVotingPowerDescription": "Voting power is the relative weighting given to the validator in tendermint consensus. It is calculated based on the stake share of the validator minus any penalties due to overstaking or performance.",
"StakeShareDescription": "The stake a validator represents as a share of total stake across the network.",
"TotalPenaltiesDescription": "Total of penalties taking into account performance (considering proportion of blocks proposed against the number of blocks the validator was expected to propose) and any overstaking.",
"PendingStakeDescription": "The amount of stake that will be added or removed from the validator from the next epoch.",
"StakeNeededForPromotionStandbyDescription": "{{prefix}} additional stake needed for promotion to consensus, assuming constant performance in line with previous epoch.",
"StakeNeededForPromotionCandidateDescription": "{{prefix}} additional stake needed for promotion to standby, assuming constant performance in line with previous epoch.",
"StakedByOperatorDescription": "The stake provided as self-stake by the node operator, must be at least the minimum stake as defined by network parameter",
"AboutThisValidatorDescription": "External URL provided by the validator linking to information about themselves",
"ValidatorStatusDescription": "Consensus, Standby or Pending (Candidate), depending on how much stake the validator has attracted",
"StakedByDelegatesDescription": "The stake delegated to the node by other users",
"OverstakedPenaltyDescription": "A penalty applied for having more stake than the optimal stake for the network. Designed to avoid concentration of voting power with a small number of validators",
"PerformancePenaltyDescription": "Performance score is a measure of how often a validator proposed blocks in the last epoch relative to how many they should be expected to propose based on their voting power. Performance penalty is applied for having a performance score of less than 1",
"UnnormalisedVotingPowerDescription": "The voting power of the validator based on their final validator score after all penalties have been applied",
"NormalisedVotingPowerDescription": "The voting power of the validator, adjusted to ensure all validator scores sum to 1, used for distribution of rewards",
"Score": "Score",
"performancePenalty": "Performance penalty",
"overstaked": "Overstaked",
@@ -1,21 +0,0 @@
import type { Tranche } from '@vegaprotocol/smart-contracts';
import { BigNumber } from '../bignumber';
export function generateTranche(id: number): Tranche {
return {
tranche_id: id,
tranche_start: new Date(),
tranche_end: new Date(),
total_added: new BigNumber(0),
total_removed: new BigNumber(0),
locked_amount: new BigNumber(0),
deposits: [],
withdrawals: [],
users: [],
};
}
export function generateTranches(count = 1) {
return new Array(count).fill(null).map((_, i) => generateTranche(i));
}
@@ -1,6 +1,11 @@
import BigNumber from 'bignumber.js';
import { create } from 'zustand';
import type { UserTrancheBalance } from '../../contexts/app-state/app-state-context';
interface UserTrancheBalance {
id: number;
locked: BigNumber;
vested: BigNumber;
}
export interface AssociationBreakdown {
stakingAssociations: { [vegaKey: string]: BigNumber };
@@ -13,8 +18,8 @@ export type BalancesStore = {
balanceFormatted: BigNumber;
totalVestedBalance: BigNumber;
totalLockedBalance: BigNumber;
walletBalance: BigNumber;
trancheBalances: UserTrancheBalance[];
walletBalance: BigNumber;
lien: BigNumber;
walletAssociatedBalance: BigNumber;
vestingAssociatedBalance: BigNumber;
@@ -38,8 +43,8 @@ export const useBalances = create<BalancesStore>((set) => ({
stakingAssociations: {},
vestingAssociations: {},
},
trancheBalances: [],
allowance: new BigNumber(0),
trancheBalances: [],
totalVestedBalance: new BigNumber(0),
totalLockedBalance: new BigNumber(0),
balanceFormatted: new BigNumber(0),
@@ -0,0 +1,80 @@
import { toBigNum } from '@vegaprotocol/react-helpers';
import type { TrancheServiceResponse } from '@vegaprotocol/smart-contracts';
import type BigNumber from 'bignumber.js';
import create from 'zustand';
import { ENV } from '../../config';
export interface Tranche {
tranche_id: number;
tranche_start: Date;
tranche_end: Date;
total_added: BigNumber;
total_removed: BigNumber;
locked_amount: BigNumber;
users: string[];
}
const URL = `${ENV.tranchesServiceUrl}/tranches/stats`;
export interface UserTrancheBalance {
/** ID of tranche */
id: number;
/** Users vesting tokens on tranche */
locked: BigNumber;
/** Users vested tokens on tranche */
vested: BigNumber;
}
export type TranchesStore = {
tranches: Tranche[] | null;
loading: boolean;
error: Error | null;
getTranches: (decimals: number) => void;
};
const secondsToDate = (seconds: number) => new Date(seconds * 1000);
export const useTranches = create<TranchesStore>((set) => ({
tranches: null,
loading: false,
error: null,
getTranches: async (decimals: number) => {
set({ loading: true, error: null });
try {
const res = await fetch(URL);
const data = (await res.json()) as TrancheServiceResponse;
const now = Math.round(Date.now() / 1000);
const tranches = Object.values(data.tranches)
?.map((t) => {
const tranche_progress =
t.duration !== 0 ? (now - t.cliff_start) / t.duration : 0;
const lockedDecimal = tranche_progress < 0 ? 1 : 1 - tranche_progress;
return {
tranche_id: t.tranche_id,
tranche_start: secondsToDate(t.cliff_start),
tranche_end: secondsToDate(t.cliff_start + t.duration),
total_added: toBigNum(t.initial_balance, decimals),
total_removed: toBigNum(t.initial_balance, decimals).minus(
toBigNum(t.current_balance, decimals)
),
locked_amount: toBigNum(t.initial_balance, decimals).times(
lockedDecimal
),
users: t.users,
};
})
.sort((a, b) => a.tranche_id - b.tranche_id);
set({
tranches,
});
} catch (e) {
set({ error: e as unknown as Error });
} finally {
set({
loading: false,
});
}
},
}));
+1 -1
View File
@@ -4,7 +4,6 @@ import { format } from 'date-fns';
import React from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';
import type { Tranche } from '@vegaprotocol/smart-contracts';
import { KeyValueTable, KeyValueTableRow } from '@vegaprotocol/ui-toolkit';
import { useContracts } from '../../contexts/contracts/contracts-context';
@@ -22,6 +21,7 @@ import { TrancheNotFound } from './tranche-not-found';
import { UntargetedClaim } from './untargeted-claim';
import { Verifying } from './verifying';
import type { ClaimAction, ClaimState } from './claim-reducer';
import type { Tranche } from '../../lib/tranches/tranches-store';
interface ClaimFlowProps {
state: ClaimState;
+1 -1
View File
@@ -1,8 +1,8 @@
import { useTranslation } from 'react-i18next';
import { format } from 'date-fns';
import type { Tranche } from '@vegaprotocol/smart-contracts';
import { DATE_FORMAT_LONG } from '../../lib/date-formats';
import type { Tranche } from '../../lib/tranches/tranches-store';
interface ClaimInfoProps {
tranche: Tranche;
+2 -7
View File
@@ -1,7 +1,5 @@
import React from 'react';
import { useAppState } from '../../contexts/app-state/app-state-context';
import { useContracts } from '../../contexts/contracts/contracts-context';
import { useGetUserTrancheBalances } from '../../hooks/use-get-user-tranche-balances';
import { useRefreshBalances } from '../../hooks/use-refresh-balances';
import { useSearchParams } from '../../hooks/use-search-params';
import { ClaimError } from './claim-error';
@@ -13,7 +11,7 @@ import {
initialClaimState,
} from './claim-reducer';
import type { Tranche } from '@vegaprotocol/smart-contracts';
import type { Tranche } from '../../lib/tranches/tranches-store';
const Claim = ({
address,
@@ -23,10 +21,8 @@ const Claim = ({
tranches: Tranche[];
}) => {
const params = useSearchParams();
const { vesting } = useContracts();
const { appState } = useAppState();
const [state, dispatch] = React.useReducer(claimReducer, initialClaimState);
const getUserTrancheBalances = useGetUserTrancheBalances(address, vesting);
const refreshBalances = useRefreshBalances(address);
React.useEffect(() => {
@@ -48,10 +44,9 @@ const Claim = ({
// If the claim has been committed refetch the new VEGA balance
React.useEffect(() => {
if (state.claimStatus === ClaimStatus.Finished && address) {
getUserTrancheBalances();
refreshBalances();
}
}, [address, getUserTrancheBalances, refreshBalances, state.claimStatus]);
}, [address, refreshBalances, state.claimStatus]);
if (state.error) {
return <ClaimError />;
+9 -4
View File
@@ -5,7 +5,7 @@ import { EthConnectPrompt } from '../../components/eth-connect-prompt';
import { Heading } from '../../components/heading';
import { SplashLoader } from '../../components/splash-loader';
import { useDocumentTitle } from '../../hooks/use-document-title';
import { useTranches } from '../../hooks/use-tranches';
import { useTranches } from '../../lib/tranches/tranches-store';
import type { RouteChildProps } from '..';
import Claim from './claim';
import { ClaimRestricted } from './claim-restricted';
@@ -16,7 +16,11 @@ const ClaimIndex = ({ name }: RouteChildProps) => {
useDocumentTitle(name);
const { t } = useTranslation();
const { account } = useWeb3React();
const { tranches, loading, error } = useTranches();
const { tranches, loading, error } = useTranches((state) => ({
loading: state.loading,
error: state.error,
tranches: state.tranches,
}));
if (loading || !tranches) {
return (
@@ -38,13 +42,14 @@ const ClaimIndex = ({ name }: RouteChildProps) => {
if (!account) {
content = (
<EthConnectPrompt>
<>
<p data-testid="eth-connect-prompt">
{t(
"Use the Ethereum wallet you want to send your tokens to. You'll also need enough Ethereum to pay gas."
)}
</p>
</EthConnectPrompt>
<EthConnectPrompt />
</>
);
} else {
content = isRestricted() ? (
@@ -51,11 +51,9 @@ const mockAppState: AppState = {
totalAssociated: new BigNumber('50063005'),
decimals: 18,
totalSupply: new BigNumber(65000000),
tranches: null,
vegaWalletOverlay: false,
vegaWalletManageOverlay: false,
ethConnectOverlay: false,
trancheError: null,
drawerOpen: false,
transactionOverlay: false,
bannerMessage: '',
@@ -5,6 +5,7 @@ import { VoteValue } from '@vegaprotocol/types';
import { useEffect, useState } from 'react';
import { useUserVoteQuery } from './__generated__/Vote';
import { removePaginationWrapper } from '@vegaprotocol/react-helpers';
import type { FinalizedVote } from '@vegaprotocol/governance';
export enum VoteState {
NotCast = 'NotCast',
@@ -21,25 +22,14 @@ export type Vote = {
party: { id: string };
};
export type Votes = Array<Vote | null>;
export function getUserVote(pubkey: string, yesVotes?: Votes, noVotes?: Votes) {
const yesVote = yesVotes?.find((v) => v && v.party.id === pubkey);
const noVote = noVotes?.find((v) => v && v.party.id === pubkey);
if (yesVote) {
return yesVote;
} else if (noVote) {
return noVote;
} else {
return null;
}
}
/**
* Finds the status of a users given vote in a given proposal and provides
* a function to send a vote transaction to your wallet
*/
export function useUserVote(proposalId: string | null | undefined) {
export function useUserVote(
proposalId: string | null | undefined,
finalizedVote?: FinalizedVote | null
) {
const { pubKey } = useVegaWallet();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const [timeout, setTimeoutValue] = useState<any>(null);
@@ -50,10 +40,27 @@ export function useUserVote(proposalId: string | null | undefined) {
variables: { partyId: pubKey || '' },
skip: !pubKey || !proposalId,
});
const [userVote, setUserVote] = useState<FinalizedVote | undefined>(
undefined
);
const userVote = removePaginationWrapper(
data?.party?.votesConnection?.edges
).find(({ proposalId: pId }) => proposalId === pId);
useEffect(() => {
if (finalizedVote?.vote.value) {
setUserVote(finalizedVote);
} else if (data?.party?.votesConnection?.edges) {
// This sets the vote (if any) when the user first loads the page
setUserVote(
removePaginationWrapper(data?.party?.votesConnection?.edges).find(
({ proposalId: pId }) => proposalId === pId
)
);
}
}, [
finalizedVote?.vote.value,
data?.party?.votesConnection?.edges,
finalizedVote,
proposalId,
]);
// If user vote changes update the vote state
useEffect(() => {
@@ -22,6 +22,8 @@ describe('Vote buttons', () => {
minVoterBalance={null}
spamProtectionMinTokens={null}
currentStakeAvailable={new BigNumber(1)}
dialog={() => <div>Blah</div>}
submit={() => Promise.resolve()}
/>
</VegaWalletContext.Provider>
</MockedProvider>
@@ -43,6 +45,8 @@ describe('Vote buttons', () => {
minVoterBalance={null}
spamProtectionMinTokens={null}
currentStakeAvailable={new BigNumber(1)}
dialog={() => <div>Blah</div>}
submit={() => Promise.resolve()}
/>
</VegaWalletContext.Provider>
</MockedProvider>
@@ -75,6 +79,8 @@ describe('Vote buttons', () => {
minVoterBalance={null}
spamProtectionMinTokens={null}
currentStakeAvailable={new BigNumber(1)}
dialog={() => <div>Blah</div>}
submit={() => Promise.resolve()}
/>
</VegaWalletContext.Provider>
</MockedProvider>
@@ -97,6 +103,8 @@ describe('Vote buttons', () => {
minVoterBalance={null}
spamProtectionMinTokens={null}
currentStakeAvailable={new BigNumber(0)}
dialog={() => <div>Blah</div>}
submit={() => Promise.resolve()}
/>
</VegaWalletContext.Provider>
</MockedProvider>
@@ -120,6 +128,8 @@ describe('Vote buttons', () => {
minVoterBalance="2000000000000000000"
spamProtectionMinTokens="1000000000000000000"
currentStakeAvailable={new BigNumber(1)}
dialog={() => <div>Blah</div>}
submit={() => Promise.resolve()}
/>
</VegaWalletContext.Provider>
</MockedProvider>
@@ -145,6 +155,8 @@ describe('Vote buttons', () => {
minVoterBalance="2000000000000000000"
spamProtectionMinTokens="1000000000000000000"
currentStakeAvailable={new BigNumber(10)}
dialog={() => <div>Blah</div>}
submit={() => Promise.resolve()}
/>
</VegaWalletContext.Provider>
</MockedProvider>
@@ -167,6 +179,8 @@ describe('Vote buttons', () => {
minVoterBalance="2000000000000000000"
spamProtectionMinTokens="1000000000000000000"
currentStakeAvailable={new BigNumber(10)}
dialog={() => <div>Blah</div>}
submit={() => Promise.resolve()}
/>
</VegaWalletContext.Provider>
</MockedProvider>
@@ -4,7 +4,6 @@ import { useTranslation } from 'react-i18next';
import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
import { AsyncRenderer, Button, ButtonLink } from '@vegaprotocol/ui-toolkit';
import { addDecimal, toBigNum } from '@vegaprotocol/react-helpers';
import { useVoteSubmit } from '@vegaprotocol/governance';
import { ProposalState, VoteValue } from '@vegaprotocol/types';
import {
AppStateActionType,
@@ -16,6 +15,7 @@ import { VoteState } from './use-user-vote';
import { ProposalMinRequirements, ProposalUserAction } from '../shared';
import { VoteTransactionDialog } from './vote-transaction-dialog';
import { useVoteButtonsQuery } from './__generated__/Stake';
import type { DialogProps } from '@vegaprotocol/wallet';
interface VoteButtonsContainerProps {
voteState: VoteState | null;
@@ -24,6 +24,8 @@ interface VoteButtonsContainerProps {
proposalState: ProposalState;
minVoterBalance: string | null;
spamProtectionMinTokens: string | null;
submit: (voteValue: VoteValue, proposalId: string | null) => Promise<void>;
dialog: (props: DialogProps) => JSX.Element;
className?: string;
}
@@ -62,11 +64,12 @@ export const VoteButtons = ({
currentStakeAvailable,
minVoterBalance,
spamProtectionMinTokens,
submit,
dialog: Dialog,
}: VoteButtonsProps) => {
const { t } = useTranslation();
const { appDispatch } = useAppState();
const { pubKey } = useVegaWallet();
const { submit, Dialog } = useVoteSubmit();
const { openVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
openVegaWalletDialog: store.openVegaWalletDialog,
}));
@@ -2,7 +2,7 @@ import { useTranslation } from 'react-i18next';
import { formatDistanceToNow } from 'date-fns';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { ProposalState } from '@vegaprotocol/types';
import { VoteProgress } from '@vegaprotocol/governance';
import { useVoteSubmit, VoteProgress } from '@vegaprotocol/governance';
import { formatNumber } from '../../../../lib/format-number';
import { ConnectToVega } from '../../../../components/connect-to-vega';
import { useVoteInformation } from '../../hooks';
@@ -44,7 +44,8 @@ export const VoteDetails = ({
} = useVoteInformation({ proposal });
const { t } = useTranslation();
const { voteState, voteDatetime } = useUserVote(proposal?.id);
const { submit, Dialog, finalizedVote } = useVoteSubmit();
const { voteState, voteDatetime } = useUserVote(proposal?.id, finalizedVote);
const defaultDecimals = 2;
const daysLeft = t('daysLeft', {
daysLeft: formatDistanceToNow(new Date(proposal?.terms.closingDatetime)),
@@ -188,6 +189,8 @@ export const VoteDetails = ({
minVoterBalance={minVoterBalance}
spamProtectionMinTokens={spamProtectionMinTokens}
className="flex"
submit={submit}
dialog={Dialog}
/>
)}
</section>
@@ -14,11 +14,9 @@ const mockAppState: AppState = {
totalAssociated: new BigNumber('50063005'),
decimals: 18,
totalSupply: mockTotalSupply,
tranches: null,
vegaWalletOverlay: false,
vegaWalletManageOverlay: false,
ethConnectOverlay: false,
trancheError: null,
drawerOpen: false,
transactionOverlay: false,
bannerMessage: '',
@@ -1,56 +1,81 @@
import { Callout, Intent } from '@vegaprotocol/ui-toolkit';
import { useBalances } from '../../../lib/balances/balances-store';
import React from 'react';
import { useEffect, useMemo, useState } from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { Link, useNavigate, useOutletContext } from 'react-router-dom';
import { Link, useNavigate, useParams } from 'react-router-dom';
import { AddLockedTokenAddress } from '../../../components/add-locked-token';
import { formatNumber } from '../../../lib/format-number';
import { truncateMiddle } from '../../../lib/truncate-middle';
import Routes from '../../routes';
import type { RedemptionState } from '../redemption-reducer';
import { Tranche0Table, TrancheTable } from '../tranche-table';
import { VestingTable } from './vesting-table';
import { useTranches } from '../../../lib/tranches/tranches-store';
import { useGetUserBalances } from '../../../hooks/use-get-user-balances';
import BigNumber from 'bignumber.js';
import { useUserTrancheBalances } from '../hooks';
interface UserBalances {
balanceFormatted: BigNumber;
walletBalance: BigNumber;
lien: BigNumber;
allowance: BigNumber;
balance: BigNumber;
}
export const RedemptionInformation = () => {
const { state, account } = useOutletContext<{
state: RedemptionState;
account: string;
}>();
const navigate = useNavigate();
const { t } = useTranslation();
const {
balanceFormatted,
lien,
totalVestedBalance,
totalLockedBalance,
trancheBalances,
} = useBalances();
const { userTranches } = state;
const filteredTranches = React.useMemo(
const navigate = useNavigate();
const tranches = useTranches((state) => state.tranches);
const { address } = useParams<{ address: string }>();
const [userBalances, setUserBalances] = useState<null | UserBalances>();
const getUsersBalances = useGetUserBalances(address);
useEffect(() => {
getUsersBalances().then(setUserBalances);
}, [getUsersBalances]);
const userTrancheBalances = useUserTrancheBalances(address);
const filteredTranches = useMemo(
() =>
userTranches.filter((tr) => {
const balance = trancheBalances.find(
tranches?.filter((tr) => {
const balance = userTrancheBalances.find(
({ id }) => id.toString() === tr.tranche_id.toString()
);
return (
balance?.locked.isGreaterThan(0) || balance?.vested.isGreaterThan(0)
);
}),
[trancheBalances, userTranches]
}) || [],
[userTrancheBalances, tranches]
);
const { totalLocked, totalVested } = useMemo(() => {
return {
totalLocked: BigNumber.sum.apply(null, [
new BigNumber(0),
...userTrancheBalances.map(({ locked }) => locked),
]),
totalVested: BigNumber.sum.apply(null, [
new BigNumber(0),
...userTrancheBalances.map(({ vested }) => vested),
]),
};
}, [userTrancheBalances]);
const zeroTranche = React.useMemo(() => {
const zeroTranche = trancheBalances.find((t) => t.id === 0);
const zeroTranche = useMemo(() => {
const zeroTranche = userTrancheBalances.find((t) => t.id === 0);
if (zeroTranche && zeroTranche.locked.isGreaterThan(0)) {
return zeroTranche;
}
return null;
}, [trancheBalances]);
}, [userTrancheBalances]);
if (!filteredTranches.length) {
const isAccountValid = useMemo(
() => address && address.length === 42 && address.startsWith('0x'),
[address]
);
if (!isAccountValid || !address) {
return <div>The address {address} is not a valid Ethereum address</div>;
}
if (!filteredTranches.length || !userBalances) {
return (
<section data-testid="redemption-page">
<div className="mb-8">
@@ -79,17 +104,17 @@ export const RedemptionInformation = () => {
{t(
'{{address}} has {{balance}} VEGA tokens in {{tranches}} tranches of the vesting contract.',
{
address: truncateMiddle(account),
balance: formatNumber(balanceFormatted),
address: truncateMiddle(address),
balance: formatNumber(userBalances.balanceFormatted),
tranches: filteredTranches.length,
}
)}
</p>
<div className="mb-24">
<VestingTable
associated={lien}
locked={totalLockedBalance}
vested={totalVestedBalance}
associated={userBalances.lien}
locked={totalLocked}
vested={totalVested}
/>
</div>
{filteredTranches.length ? <h2>{t('Tranche breakdown')}</h2> : null}
@@ -98,7 +123,7 @@ export const RedemptionInformation = () => {
trancheId={0}
total={
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
trancheBalances.find(
userTrancheBalances.find(
({ id }) => id.toString() === zeroTranche.id.toString()
)!.locked
}
@@ -108,22 +133,25 @@ export const RedemptionInformation = () => {
<TrancheTable
key={tr.tranche_id}
tranche={tr}
lien={lien}
lien={userBalances.lien}
locked={
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
trancheBalances.find(
userTrancheBalances.find(
({ id }) => id.toString() === tr.tranche_id.toString()
)!.locked
}
vested={
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
trancheBalances.find(
userTrancheBalances.find(
({ id }) => id.toString() === tr.tranche_id.toString()
)!.vested
}
totalVested={totalVestedBalance}
totalLocked={totalLockedBalance}
onClick={() => navigate(`/vesting/${tr.tranche_id}`)}
totalVested={totalVested}
totalLocked={totalLocked}
onClick={() =>
navigate(`${Routes.REDEEM}/${address}/${tr.tranche_id}`)
}
address={address}
/>
))}
<Callout
@@ -132,7 +160,7 @@ export const RedemptionInformation = () => {
intent={Intent.Warning}
>
<p>{t('Find out more about Staking.')}</p>
<Link to="/staking" className="underline text-white">
<Link to={Routes.VALIDATORS} className="underline text-white">
{t('Stake VEGA tokens')}
</Link>
</Callout>
@@ -12,7 +12,7 @@ export interface VestingTableProps {
}
const VestingTableIndicatorSquare = ({ colour }: { colour: string }) => (
<span className={`bg-${colour} inline-block h-12 w-12 mr-4`} />
<span className={`bg-${colour} inline-block h-4 w-4 mr-1`} />
);
export const VestingTable = ({
@@ -65,17 +65,17 @@ export const VestingTable = ({
</KeyValueTable>
<div className="flex border-white border">
<div
className="bg-vega-pink h-16"
className="bg-vega-pink h-4"
style={{ flex: lockedPercentage.toNumber() }}
/>
<div
className="bg-vega-green h-16"
className="bg-vega-green h-4"
style={{ flex: vestedPercentage.toNumber() }}
/>
</div>
<div className="flex h-4 mt-4">
<div className="flex h-1 mt-1">
<div
className="bg-vega-yellow h-4"
className="bg-vega-yellow h-1"
style={{ flex: stakedPercentage.toNumber() }}
/>
<div
+54
View File
@@ -0,0 +1,54 @@
import { useCallback, useEffect, useState } from 'react';
import { useTranches } from '../../lib/tranches/tranches-store';
import { useContracts } from '../../contexts/contracts/contracts-context';
import BigNumber from 'bignumber.js';
import { toBigNum } from '@vegaprotocol/react-helpers';
import { useAppState } from '../../contexts/app-state/app-state-context';
export const useUserTrancheBalances = (address: string | undefined) => {
const [userTrancheBalances, setUserTrancheBalances] = useState<
{
id: number;
locked: BigNumber;
vested: BigNumber;
}[]
>([]);
const {
appState: { decimals },
} = useAppState();
const { vesting } = useContracts();
const tranches = useTranches((state) => state.tranches);
const loadUserTrancheBalances = useCallback(async () => {
if (!address) return;
const userTranches =
tranches?.filter((t) =>
t.users.some(
(a) => a && address && a.toLowerCase() === address.toLowerCase()
)
) || [];
const trancheIds = [0, ...userTranches.map((t) => t.tranche_id)];
const promises = trancheIds.map(async (tId) => {
const [t, v] = await Promise.all([
vesting.get_tranche_balance(address, tId),
vesting.get_vested_for_tranche(address, tId),
]);
const total = toBigNum(t, decimals);
const vested = toBigNum(v, decimals);
return {
id: tId,
locked: tId === 0 ? total : total.minus(vested),
vested: tId === 0 ? new BigNumber(0) : vested,
};
});
const trancheBalances = await Promise.all(promises);
setUserTrancheBalances(trancheBalances);
}, [address, decimals, tranches, vesting]);
useEffect(() => {
loadUserTrancheBalances();
}, [loadUserTrancheBalances]);
return userTrancheBalances;
};
@@ -1,38 +0,0 @@
import type { Tranche } from '@vegaprotocol/smart-contracts';
import type { BigNumber } from '../../lib/bignumber';
export interface TrancheBalance {
id: number;
locked: BigNumber;
vested: BigNumber;
}
export interface RedemptionState {
userTranches: Tranche[];
}
export const initialRedemptionState: RedemptionState = {
userTranches: [],
};
export enum RedemptionActionType {
SET_USER_TRANCHES,
}
export type RedemptionAction = {
type: RedemptionActionType.SET_USER_TRANCHES;
userTranches: Tranche[];
};
export function redemptionReducer(
state: RedemptionState,
action: RedemptionAction
): RedemptionState {
switch (action.type) {
case RedemptionActionType.SET_USER_TRANCHES:
return {
...state,
userTranches: action.userTranches,
};
}
}
+86 -57
View File
@@ -1,51 +1,62 @@
import { Callout, Intent, Splash } from '@vegaprotocol/ui-toolkit';
import {
Button,
Callout,
FormGroup,
Input,
InputError,
Intent,
Splash,
} from '@vegaprotocol/ui-toolkit';
import { useWeb3React } from '@web3-react/core';
import React from 'react';
import { useCallback } from 'react';
import { useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { Outlet } from 'react-router-dom';
import { Link } from 'react-router-dom';
import { Outlet, useNavigate, useParams } from 'react-router-dom';
import { EthConnectPrompt } from '../../components/eth-connect-prompt';
import { SplashLoader } from '../../components/splash-loader';
import { useTranches } from '../../hooks/use-tranches';
import { useBalances } from '../../lib/balances/balances-store';
import { useTranches } from '../../lib/tranches/tranches-store';
import RoutesConfig from '../routes';
import {
initialRedemptionState,
RedemptionActionType,
redemptionReducer,
} from './redemption-reducer';
interface FormFields {
address: string;
}
const RedemptionRouter = () => {
const { address } = useParams<{ address: string }>();
const navigate = useNavigate();
const { t } = useTranslation();
const [state, dispatch] = React.useReducer(
redemptionReducer,
initialRedemptionState
);
const { trancheBalances } = useBalances();
const { account } = useWeb3React();
const { tranches, error, loading } = useTranches();
React.useEffect(() => {
const run = (address: string) => {
const userTranches = tranches?.filter((t) =>
t.users.some(
({ address: a }) => a.toLowerCase() === address.toLowerCase()
)
);
if (userTranches) {
dispatch({
type: RedemptionActionType.SET_USER_TRANCHES,
userTranches,
});
const validatePubkey = useCallback(
(value: string) => {
if (!value.startsWith('0x')) {
return t('Address must begin with 0x');
} else if (value.length !== 42) {
return t('Pubkey must be 42 characters in length');
} else if (Number.isNaN(+value)) {
return t('Pubkey must be be valid hex');
}
};
return true;
},
[t]
);
const { account } = useWeb3React();
const { tranches, error, loading } = useTranches((state) => ({
loading: state.loading,
error: state.error,
tranches: state.tranches,
}));
const {
register,
handleSubmit,
formState: { errors },
} = useForm<FormFields>();
if (account) {
run(account);
}
}, [account, tranches]);
const onSubmit = useCallback(
(fields: FormFields) => {
navigate(`${RoutesConfig.REDEEM}/${fields.address}`);
},
[navigate]
);
if (error) {
return (
@@ -63,30 +74,48 @@ const RedemptionRouter = () => {
);
}
if (!account) {
if (!address) {
return (
<EthConnectPrompt>
<p data-testid="eth-connect-prompt">
{t(
"Use the Ethereum wallet you want to send your tokens to. You'll also need enough Ethereum to pay gas."
)}
</p>
</EthConnectPrompt>
<div className="max-w-md">
{!account ? (
<EthConnectPrompt />
) : (
<Button
fill={true}
variant="primary"
onClick={() => navigate(`${RoutesConfig.REDEEM}/${account}`)}
>
{t('View connected Eth Wallet')}
</Button>
)}
<p className="py-4 flex justify-center">{t('OR')}</p>
<form
onSubmit={handleSubmit(onSubmit)}
data-testid="view-connector-form"
>
<FormGroup label={'View Ethereum as user:'} labelFor="address">
<Input
{...register('address', {
required: t('Required'),
validate: validatePubkey,
})}
id="address"
data-testid="address"
type="text"
/>
{errors.address?.message && (
<InputError intent="danger">{errors.address.message}</InputError>
)}
</FormGroup>
<Button data-testid="connect" type="submit" fill={true}>
{t('View Ethereum user')}
</Button>
</form>
</div>
);
}
if (!trancheBalances.length) {
return (
<>
<Callout>
<p>{t('You have no VEGA tokens currently vesting.')}</p>
</Callout>
<Link to={RoutesConfig.SUPPLY}>{t('viewAllTranches')}</Link>
</>
);
}
return <Outlet context={{ state, account }} />;
return <Outlet />;
};
export default RedemptionRouter;
@@ -33,10 +33,10 @@ export const TrancheItem = ({
}: TrancheItemProps) => {
const { t } = useTranslation();
const labelClasses =
'inline-block uppercase bg-white text-black py-4 px-8 font-mono';
'inline-block uppercase bg-white text-black py-1 px-2 font-mono';
return (
<section data-testid="tranche-item" className="mb-40">
<section data-testid="tranche-item" className="mb-8">
<div className="flex border-b">
{link ? (
<Link to={link}>
@@ -8,6 +8,7 @@ import { formatNumber } from '../../lib/format-number';
import Routes from '../routes';
import { TrancheItem } from './tranche-item';
import { Button } from '@vegaprotocol/ui-toolkit';
import { useWeb3React } from '@web3-react/core';
export interface TrancheTableProps {
tranche: {
@@ -22,6 +23,7 @@ export interface TrancheTableProps {
totalLocked: BigNumber;
onClick: () => void;
disabled?: boolean;
address: string | null;
}
export const Tranche0Table = ({
@@ -65,9 +67,11 @@ export const TrancheTable = ({
totalVested,
totalLocked,
disabled = false,
address,
}: TrancheTableProps) => {
const { t } = useTranslation();
const total = vested.plus(locked);
const { account: connectedAddress } = useWeb3React();
const trancheFullyLocked =
tranche.tranche_start.getTime() > new Date().getTime();
const totalAllTranches = totalVested.plus(totalLocked);
@@ -93,13 +97,20 @@ export const TrancheTable = ({
amount: reduceAmount,
}}
components={{
stakeLink: <Link to={`/staking`} />,
disassociateLink: <Link to={`/staking/disassociate`} />,
stakeLink: <Link className="underline" to={Routes.VALIDATORS} />,
disassociateLink: (
<Link className="underline" to={Routes.DISASSOCIATE} />
),
}}
/>
</div>
);
} else if (!trancheFullyLocked && redeemable) {
} else if (
!trancheFullyLocked &&
redeemable &&
connectedAddress &&
address === connectedAddress
) {
message = (
<Button onClick={onClick} disabled={disabled}>
{t('Redeem unlocked VEGA from tranche {{id}}', {
@@ -1,7 +1,7 @@
import { useBalances } from '../../../lib/balances/balances-store';
import React from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { Link, useParams, useOutletContext } from 'react-router-dom';
import { Link, useParams } from 'react-router-dom';
import { TransactionCallout } from '../../../components/transaction-callout';
import { useContracts } from '../../../contexts/contracts/contracts-context';
@@ -9,32 +9,36 @@ import {
TransactionActionType,
TxState,
} from '../../../hooks/transaction-reducer';
import { useGetUserTrancheBalances } from '../../../hooks/use-get-user-tranche-balances';
import { useRefreshBalances } from '../../../hooks/use-refresh-balances';
import { useTransaction } from '../../../hooks/use-transaction';
import { BigNumber } from '../../../lib/bignumber';
import { formatNumber } from '../../../lib/format-number';
import Routes from '../../routes';
import type { RedemptionState } from '../redemption-reducer';
import { TrancheTable } from '../tranche-table';
import { useTranches } from '../../../lib/tranches/tranches-store';
import { useWeb3React } from '@web3-react/core';
import { EthConnectPrompt } from '../../../components/eth-connect-prompt';
import { useUserTrancheBalances } from '../hooks';
import { useAppState } from '../../../contexts/app-state/app-state-context';
export const RedeemFromTranche = () => {
const { state, address } = useOutletContext<{
state: RedemptionState;
address: string;
}>();
const { account: address } = useWeb3React();
const { vesting } = useContracts();
const { t } = useTranslation();
const { lien, totalVestedBalance, trancheBalances, totalLockedBalance } =
useBalances();
const refreshBalances = useRefreshBalances(address);
const getUserTrancheBalances = useGetUserTrancheBalances(address, vesting);
const {
appState: { decimals },
} = useAppState();
const { lien, totalVestedBalance, totalLockedBalance } = useBalances();
const refreshBalances = useRefreshBalances(address || '');
const { tranches, getTranches } = useTranches((state) => ({
tranches: state.tranches,
getTranches: state.getTranches,
}));
const { id } = useParams<{ id: string }>();
const numberId = Number(id);
const { userTranches } = state;
const tranche = React.useMemo(
() => userTranches.find(({ tranche_id }) => tranche_id === numberId),
[numberId, userTranches]
() => tranches?.find(({ tranche_id }) => tranche_id === numberId) || null,
[numberId, tranches]
);
const {
state: txState,
@@ -42,7 +46,7 @@ export const RedeemFromTranche = () => {
dispatch: txDispatch,
} = useTransaction(() => vesting.withdraw_from_tranche(numberId));
const { token } = useContracts();
const trancheBalances = useUserTrancheBalances(address || '');
const redeemedAmount = React.useMemo(() => {
return (
trancheBalances.find(({ id: bId }) => bId.toString() === id?.toString())
@@ -55,10 +59,10 @@ export const RedeemFromTranche = () => {
// If the claim has been committed refetch the new VEGA balance
React.useEffect(() => {
if (txState.txState === TxState.Complete && address) {
getUserTrancheBalances();
refreshBalances();
getTranches(decimals);
}
}, [address, getUserTrancheBalances, refreshBalances, txState.txState]);
}, [address, decimals, getTranches, refreshBalances, txState.txState]);
const trancheBalance = React.useMemo(() => {
return trancheBalances.find(
@@ -66,6 +70,10 @@ export const RedeemFromTranche = () => {
);
}, [id, trancheBalances]);
if (!address) {
return <EthConnectPrompt />;
}
if (
!tranche ||
tranche.total_removed.isEqualTo(tranche.total_added) ||
@@ -147,6 +155,7 @@ export const RedeemFromTranche = () => {
locked={trancheBalance.locked}
vested={trancheBalance.vested}
onClick={perform}
address={address || ''}
/>
)}
</section>
@@ -50,10 +50,11 @@ const DisplayReward = ({
>
<button>
<div className="flex flex-col items-start">
<span>{formatNumber(toBigNum(reward, decimals))}</span>
<span>{formatNumber(toBigNum(reward, decimals), 4)}</span>
{percentageOfTotal && (
<span className="text-vega-dark-300">
({formatNumber(toBigNum(percentageOfTotal, 4)).toString()}%)
({formatNumber(percentageOfTotal, 4).toString()}
%)
</span>
)}
</div>
@@ -8,7 +8,7 @@ describe('generateEpochIndividualRewardsList', () => {
amount: '100',
percentageOfTotal: '0.1',
receivedAt: new Date(),
asset: { id: 'usd', symbol: 'USD' },
asset: { id: 'usd', symbol: 'USD', name: 'USD' },
party: { id: 'blah' },
epoch: { id: '1' },
};
@@ -18,7 +18,7 @@ describe('generateEpochIndividualRewardsList', () => {
amount: '50',
percentageOfTotal: '0.05',
receivedAt: new Date(),
asset: { id: 'eur', symbol: 'EUR' },
asset: { id: 'eur', symbol: 'EUR', name: 'EUR' },
party: { id: 'blah' },
epoch: { id: '2' },
};
@@ -28,7 +28,7 @@ describe('generateEpochIndividualRewardsList', () => {
amount: '200',
percentageOfTotal: '0.2',
receivedAt: new Date(),
asset: { id: 'gbp', symbol: 'GBP' },
asset: { id: 'gbp', symbol: 'GBP', name: 'GBP' },
party: { id: 'blah' },
epoch: { id: '2' },
};
@@ -38,7 +38,7 @@ describe('generateEpochIndividualRewardsList', () => {
amount: '100',
percentageOfTotal: '0.1',
receivedAt: new Date(),
asset: { id: 'usd', symbol: 'USD' },
asset: { id: 'usd', symbol: 'USD', name: 'USD' },
party: { id: 'blah' },
epoch: { id: '1' },
};
@@ -48,7 +48,7 @@ describe('generateEpochIndividualRewardsList', () => {
amount: '50',
percentageOfTotal: '0.05',
receivedAt: new Date(),
asset: { id: 'eur', symbol: 'EUR' },
asset: { id: 'eur', symbol: 'EUR', name: 'EUR' },
party: { id: 'blah' },
epoch: { id: '2' },
};
@@ -134,20 +134,20 @@ describe('generateEpochIndividualRewardsList', () => {
epoch: '2',
rewards: [
{
asset: 'EUR',
totalAmount: '50',
asset: 'GBP',
totalAmount: '200',
rewardTypes: {
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY]: {
amount: '0',
percentageOfTotal: '0',
amount: '200',
percentageOfTotal: '0.2',
},
[AccountType.ACCOUNT_TYPE_GLOBAL_REWARD]: {
amount: '50',
percentageOfTotal: '0.05',
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES]: {
amount: '0',
@@ -164,21 +164,21 @@ describe('generateEpochIndividualRewardsList', () => {
},
},
{
asset: 'GBP',
totalAmount: '200',
asset: 'EUR',
totalAmount: '50',
rewardTypes: {
[AccountType.ACCOUNT_TYPE_FEES_INFRASTRUCTURE]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_FEES_LIQUIDITY]: {
amount: '200',
percentageOfTotal: '0.2',
},
[AccountType.ACCOUNT_TYPE_GLOBAL_REWARD]: {
amount: '0',
percentageOfTotal: '0',
},
[AccountType.ACCOUNT_TYPE_GLOBAL_REWARD]: {
amount: '50',
percentageOfTotal: '0.05',
},
[AccountType.ACCOUNT_TYPE_REWARD_MAKER_PAID_FEES]: {
amount: '0',
percentageOfTotal: '0',
@@ -33,7 +33,7 @@ export const generateEpochIndividualRewardsList = (
// We take the rewards and aggregate them by epoch and asset.
const epochIndividualRewards = rewards.reduce((map, reward) => {
const epochId = reward.epoch.id;
const assetName = reward.asset.symbol;
const assetName = reward.asset.name;
const rewardType = reward.rewardType;
const amount = reward.amount;
const percentageOfTotal = reward.percentageOfTotal;
@@ -70,6 +70,12 @@ export const generateEpochIndividualRewardsList = (
'0'
);
if (epoch) {
epoch.rewards = epoch.rewards.sort((a, b) => {
return new BigNumber(b.totalAmount).comparedTo(a.totalAmount);
});
}
return map;
}, new Map<string, EpochIndividualReward>());
@@ -5,6 +5,7 @@ import type {
import { removePaginationWrapper } from '@vegaprotocol/react-helpers';
import { RowAccountTypes } from '../shared-rewards-table-assets/shared-rewards-table-assets';
import type { AccountType } from '@vegaprotocol/types';
import { BigNumber } from '../../../lib/bignumber';
interface EpochSummaryWithNamedReward extends EpochRewardSummaryFieldsFragment {
name: string;
@@ -120,7 +121,9 @@ export const generateEpochTotalRewardsList = (
return {
epoch: epochSummaries[0].epoch,
assetRewards,
assetRewards: assetRewards.sort((a, b) => {
return new BigNumber(b.totalAmount).comparedTo(a.totalAmount);
}),
};
});
@@ -3,6 +3,7 @@ fragment RewardFields on Reward {
asset {
id
symbol
name
}
party {
id
+3 -2
View File
@@ -3,7 +3,7 @@ import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type RewardFieldsFragment = { __typename?: 'Reward', rewardType: Types.AccountType, amount: string, percentageOfTotal: string, receivedAt: any, asset: { __typename?: 'Asset', id: string, symbol: string }, party: { __typename?: 'Party', id: string }, epoch: { __typename?: 'Epoch', id: string } };
export type RewardFieldsFragment = { __typename?: 'Reward', rewardType: Types.AccountType, amount: string, percentageOfTotal: string, receivedAt: any, asset: { __typename?: 'Asset', id: string, symbol: string, name: string }, party: { __typename?: 'Party', id: string }, epoch: { __typename?: 'Epoch', id: string } };
export type DelegationFieldsFragment = { __typename?: 'Delegation', amount: string, epoch: number };
@@ -13,7 +13,7 @@ export type RewardsQueryVariables = Types.Exact<{
}>;
export type RewardsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, rewardsConnection?: { __typename?: 'RewardsConnection', edges?: Array<{ __typename?: 'RewardEdge', node: { __typename?: 'Reward', rewardType: Types.AccountType, amount: string, percentageOfTotal: string, receivedAt: any, asset: { __typename?: 'Asset', id: string, symbol: string }, party: { __typename?: 'Party', id: string }, epoch: { __typename?: 'Epoch', id: string } } } | null> | null } | null, delegationsConnection?: { __typename?: 'DelegationsConnection', edges?: Array<{ __typename?: 'DelegationEdge', node: { __typename?: 'Delegation', amount: string, epoch: number } } | null> | null } | null } | null, epoch: { __typename?: 'Epoch', id: string, timestamps: { __typename?: 'EpochTimestamps', start?: any | null, end?: any | null, expiry?: any | null } } };
export type RewardsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, rewardsConnection?: { __typename?: 'RewardsConnection', edges?: Array<{ __typename?: 'RewardEdge', node: { __typename?: 'Reward', rewardType: Types.AccountType, amount: string, percentageOfTotal: string, receivedAt: any, asset: { __typename?: 'Asset', id: string, symbol: string, name: string }, party: { __typename?: 'Party', id: string }, epoch: { __typename?: 'Epoch', id: string } } } | null> | null } | null, delegationsConnection?: { __typename?: 'DelegationsConnection', edges?: Array<{ __typename?: 'DelegationEdge', node: { __typename?: 'Delegation', amount: string, epoch: number } } | null> | null } | null } | null, epoch: { __typename?: 'Epoch', id: string, timestamps: { __typename?: 'EpochTimestamps', start?: any | null, end?: any | null, expiry?: any | null } } };
export type EpochRewardSummaryFieldsFragment = { __typename?: 'EpochRewardSummary', epoch: number, assetId: string, amount: string, rewardType: Types.AccountType };
@@ -37,6 +37,7 @@ export const RewardFieldsFragmentDoc = gql`
asset {
id
symbol
name
}
party {
id
+1 -1
View File
@@ -13,7 +13,7 @@ export const NoRewards = () => {
return (
<div className={classes}>
<SubHeading title={t('noRewardsHaveBeenDistributedYet')} />
<p className="font-alpha text-xl">{t('checkBackSoon')}</p>
<p className="font-alpha calt text-xl">{t('checkBackSoon')}</p>
</div>
);
};
+11 -6
View File
@@ -300,12 +300,17 @@ const routerConfig = [
element: <LazyRedemption name="Vesting" />,
children: [
{
index: true,
element: <LazyRedemptionIndex />,
},
{
path: ':id',
element: <LazyRedemptionTranche />,
path: ':address',
children: [
{
index: true,
element: <LazyRedemptionIndex />,
},
{
path: ':id',
element: <LazyRedemptionTranche />,
},
],
},
],
},
@@ -16,10 +16,11 @@ export const StakingWalletsContainer = ({
if (!account) {
return (
<EthConnectPrompt>
<>
<p>{t('associateInfo1')}</p>
<p>{t('associateInfo2')}</p>
</EthConnectPrompt>
<EthConnectPrompt />
</>
);
}
@@ -363,6 +363,7 @@ export const ConsensusValidatorsTable = ({
customThemeParams={NODE_LIST_GRID_STYLES}
getRowHeight={(params: RowHeightParams) => getRowHeight(params)}
defaultColDef={defaultColDef}
tooltipShowDelay={0}
animateRows={true}
suppressCellFocus={true}
overlayNoRowsTemplate={t('noValidators')}
@@ -59,8 +59,6 @@ export const defaultColDef = {
comparator: (a: string, b: string) => parseFloat(a) - parseFloat(b),
cellStyle: { margin: '10px 0', padding: '0 12px' },
tooltipComponent: TooltipCellComponent,
tooltipShowDelay: 0,
tooltipHideDelay: 0,
};
interface ValidatorRendererProps {

Some files were not shown because too many files have changed in this diff Show More