Compare commits
44
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8af8adc3e7 | ||
|
|
adbffe133f | ||
|
|
4eb6e09bd4 | ||
|
|
a02100b079 | ||
|
|
4bb78e9891 | ||
|
|
79f360dc24 | ||
|
|
718dd5a4e4 | ||
|
|
a3fcd6b7dc | ||
|
|
23ce480daa | ||
|
|
da209d96b0 | ||
|
|
9166a85a55 | ||
|
|
a5ec1f708f | ||
|
|
3afdc0c8da | ||
|
|
757d545d97 | ||
|
|
fc4d40f3cf | ||
|
|
ff47eda692 | ||
|
|
7483d9ce1d | ||
|
|
f9209cf327 | ||
|
|
420a29680d | ||
|
|
19c9e79647 | ||
|
|
4cd856fcb8 | ||
|
|
649cc61280 | ||
|
|
35f47b75ac | ||
|
|
0697acdac9 | ||
|
|
92ec7166bc | ||
|
|
56b5214dbf | ||
|
|
94509a29c5 | ||
|
|
4e2b6b2d04 | ||
|
|
c29087cc96 | ||
|
|
5bde096977 | ||
|
|
923dc09eb6 | ||
|
|
4fbdb337dd | ||
|
|
09bbc75729 | ||
|
|
6f4a5b9097 | ||
|
|
0c26d99ce2 | ||
|
|
5aedeba4ff | ||
|
|
d27758b7f4 | ||
|
|
89530d3a8c | ||
|
|
d76dd79df2 | ||
|
|
8f070432ab | ||
|
|
5789d3496b | ||
|
|
bf37712ac5 | ||
|
|
d95fdca0d4 | ||
|
|
e4bf61c2e2 |
@@ -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>
|
||||
|
||||
@@ -184,9 +184,8 @@ export const MarketDetails = ({
|
||||
content: (
|
||||
<>
|
||||
<p className="text-xs mb-4">
|
||||
{`For liquidity orders count towards a commitment they have to be
|
||||
within either the liquidity or price monitoring bounds (whichever is
|
||||
tighter).`}
|
||||
{`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
|
||||
@@ -249,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,
|
||||
|
||||
+6
-8
@@ -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 @@
|
||||
[]
|
||||
@@ -2761,7 +2761,7 @@
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "86666.297",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "67610.1684478007652751654",
|
||||
"locked_amount": "66600.6885662553549491123",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "86666.297",
|
||||
@@ -2827,7 +2827,7 @@
|
||||
"tranche_end": "2023-06-01T00:00:00.000Z",
|
||||
"total_added": "2500",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "1342.63790318477825",
|
||||
"locked_amount": "1284.23843228530725",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "2500",
|
||||
@@ -3214,8 +3214,8 @@
|
||||
"tranche_start": "2023-02-01T00:00:00.000Z",
|
||||
"tranche_end": "2023-08-01T00:00:00.000Z",
|
||||
"total_added": "37500",
|
||||
"total_removed": "3143.644010625",
|
||||
"locked_amount": "32888.95842925107375",
|
||||
"total_removed": "3295.491386325",
|
||||
"locked_amount": "32008.126630601595",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "7500",
|
||||
@@ -3229,6 +3229,11 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "151.8473757",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0xe69c28fbcb90092d264d098874523f580e45052a36a71b3f423431e84d4ca074"
|
||||
},
|
||||
{
|
||||
"amount": "142.173112275",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -3277,6 +3282,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "151.8473757",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 34,
|
||||
"tx": "0xe69c28fbcb90092d264d098874523f580e45052a36a71b3f423431e84d4ca074"
|
||||
},
|
||||
{
|
||||
"amount": "142.173112275",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -3315,8 +3326,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "7500",
|
||||
"withdrawn_tokens": "868.530827925",
|
||||
"remaining_tokens": "6631.469172075"
|
||||
"withdrawn_tokens": "1020.378203625",
|
||||
"remaining_tokens": "6479.621796375"
|
||||
},
|
||||
{
|
||||
"address": "0x0B4e6fcE839B01ef43DA6F890FAC7B1Afb004600",
|
||||
@@ -3348,7 +3359,7 @@
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "129999.45",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "67548.48267612973569615",
|
||||
"locked_amount": "66539.923817958609949455",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "129999.45",
|
||||
@@ -3414,7 +3425,7 @@
|
||||
"tranche_end": "2023-09-03T00:00:00.000Z",
|
||||
"total_added": "62600",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "32885.41606418061154",
|
||||
"locked_amount": "32156.25787037037408",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "10000",
|
||||
@@ -3607,7 +3618,7 @@
|
||||
"tranche_end": "2023-09-17T00:00:00.000Z",
|
||||
"total_added": "5000",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "2818.411497970573",
|
||||
"locked_amount": "2760.1720256215125",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "5000",
|
||||
@@ -3818,7 +3829,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "97499.58",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "9480.9707024081796853206",
|
||||
"locked_amount": "8491.6684140496565878092",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "97499.58",
|
||||
@@ -3851,7 +3862,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "135173.4239508",
|
||||
"total_removed": "98230.390980249184455396",
|
||||
"locked_amount": "12958.850128884592263306813732",
|
||||
"locked_amount": "11606.644696613363239057508256",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "135173.4239508",
|
||||
@@ -3897,7 +3908,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "32499.86",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "3988.4806468966147934938",
|
||||
"locked_amount": "3572.2982585208873489478",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "32499.86",
|
||||
@@ -3930,7 +3941,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "10833.29",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "1298.2117472647740781949",
|
||||
"locked_amount": "1162.7484183867779537778",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "10833.29",
|
||||
@@ -3963,7 +3974,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "22749.93",
|
||||
"total_removed": "4720.860935375",
|
||||
"locked_amount": "4853.005461632852062938",
|
||||
"locked_amount": "4346.6132830988218703751",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "6500",
|
||||
@@ -4114,8 +4125,8 @@
|
||||
"tranche_start": "2022-11-01T00:00:00.000Z",
|
||||
"tranche_end": "2023-05-01T00:00:00.000Z",
|
||||
"total_added": "22500",
|
||||
"total_removed": "4680.6740139",
|
||||
"locked_amount": "8296.91096915285415",
|
||||
"total_removed": "4832.532899775",
|
||||
"locked_amount": "7768.411889963167125",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "7500",
|
||||
@@ -4129,6 +4140,11 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "151.858885875",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0xe098f85d049dae2f5ab1d8057e7ca1d1a02bc6c95602a8db87e2d78013e236a3"
|
||||
},
|
||||
{
|
||||
"amount": "142.17311235",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -4232,6 +4248,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "151.858885875",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 33,
|
||||
"tx": "0xe098f85d049dae2f5ab1d8057e7ca1d1a02bc6c95602a8db87e2d78013e236a3"
|
||||
},
|
||||
{
|
||||
"amount": "142.17311235",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -4342,8 +4364,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "7500",
|
||||
"withdrawn_tokens": "4680.6740139",
|
||||
"remaining_tokens": "2819.3259861"
|
||||
"withdrawn_tokens": "4832.532899775",
|
||||
"remaining_tokens": "2667.467100225"
|
||||
},
|
||||
{
|
||||
"address": "0x2539b51EbDE65a75672aBcfE9439a706a99D18D1",
|
||||
@@ -4368,7 +4390,7 @@
|
||||
"tranche_end": "2023-06-02T00:00:00.000Z",
|
||||
"total_added": "1939928.38",
|
||||
"total_removed": "928642.9598472029154",
|
||||
"locked_amount": "524811.956971216996029364",
|
||||
"locked_amount": "502215.87592198306198629",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1852091.69",
|
||||
@@ -9777,10 +9799,35 @@
|
||||
"tranche_id": 11,
|
||||
"tranche_start": "2021-09-03T00:00:00.000Z",
|
||||
"tranche_end": "2022-09-03T00:00:00.000Z",
|
||||
"total_added": "54621.000000000000000003",
|
||||
"total_removed": "43553.21518131551",
|
||||
"total_added": "54766.000000000000000003",
|
||||
"total_removed": "43683.21518131551",
|
||||
"locked_amount": "0",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "15",
|
||||
"user": "0x4043fD11285B4f98A0f7b383D973a17F03e23EC5",
|
||||
"tx": "0x842269dc960af54f5f20e903f8cc2dae77d68b6c051b238a1467fa93e0ec34c3"
|
||||
},
|
||||
{
|
||||
"amount": "80",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tx": "0xde7e3f48359ad1473d4b6f05582e2bee121458b1103687037fca29ab95c9f50a"
|
||||
},
|
||||
{
|
||||
"amount": "20",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tx": "0xfeb720f64f2951e185db6e872e022575d3fd8477f85b2698890f70d8820fd596"
|
||||
},
|
||||
{
|
||||
"amount": "15",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tx": "0x8d55eb2b5f4091eaa0dee96242f8eb6bac12312415c202007695da4b9df96ac6"
|
||||
},
|
||||
{
|
||||
"amount": "15",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tx": "0xf7e1cb4b03d0f7664b4d7688029ed8ad4c468bf4b2e6ef941c59de4dce680496"
|
||||
},
|
||||
{
|
||||
"amount": "30",
|
||||
"user": "0xf83aaA5786516F7016DF9ead2CD9F14616dA0A13",
|
||||
@@ -19893,6 +19940,11 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "130",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tx": "0xc39eefed84fded9118b3e8a84f7fdb79789725ce078421c07e4b9f0b14bb78f2"
|
||||
},
|
||||
{
|
||||
"amount": "12",
|
||||
"user": "0x1D92cb812FdeDF1a5aFE3c5080B2D3Ec102694c6",
|
||||
@@ -20895,6 +20947,151 @@
|
||||
}
|
||||
],
|
||||
"users": [
|
||||
{
|
||||
"address": "0x4043fD11285B4f98A0f7b383D973a17F03e23EC5",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "15",
|
||||
"user": "0x4043fD11285B4f98A0f7b383D973a17F03e23EC5",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x842269dc960af54f5f20e903f8cc2dae77d68b6c051b238a1467fa93e0ec34c3"
|
||||
},
|
||||
{
|
||||
"amount": "30",
|
||||
"user": "0x4043fD11285B4f98A0f7b383D973a17F03e23EC5",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x407d9a64209bd8f656d969ee2dde00c24347cbdb9c3f53d9026278390c80e325"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"total_tokens": "45",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "45"
|
||||
},
|
||||
{
|
||||
"address": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "80",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0xde7e3f48359ad1473d4b6f05582e2bee121458b1103687037fca29ab95c9f50a"
|
||||
},
|
||||
{
|
||||
"amount": "20",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0xfeb720f64f2951e185db6e872e022575d3fd8477f85b2698890f70d8820fd596"
|
||||
},
|
||||
{
|
||||
"amount": "15",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x8d55eb2b5f4091eaa0dee96242f8eb6bac12312415c202007695da4b9df96ac6"
|
||||
},
|
||||
{
|
||||
"amount": "15",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0xf7e1cb4b03d0f7664b4d7688029ed8ad4c468bf4b2e6ef941c59de4dce680496"
|
||||
},
|
||||
{
|
||||
"amount": "25",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x3a6f6a47608e017b8d8a1495821514beed5fbb265176665aba6213987a4e0bde"
|
||||
},
|
||||
{
|
||||
"amount": "20",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x1656fec2cd5d9bf5aeb907e64b222843e13ac0921f4dc9451e6db7d02611c742"
|
||||
},
|
||||
{
|
||||
"amount": "30",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x20652e7dddc270c76be42c7496a968f5a0831dae46c12d1866c8b720c1070cb4"
|
||||
},
|
||||
{
|
||||
"amount": "60",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x89b232cab8db6ae361d824c55ec20b0e59c0bc14fadb71d902bba3a801338258"
|
||||
},
|
||||
{
|
||||
"amount": "15",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x5032a6328b99e190e893bd7feca96d465fca1996939c71fda986bdddc89897d8"
|
||||
},
|
||||
{
|
||||
"amount": "20",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x9217321eb5e9b64157da6b8ab97a1ce927e64671095da3086be0edd7cd0ef709"
|
||||
},
|
||||
{
|
||||
"amount": "200",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0xf88b8ed5ce899f00f466830936599112ea678a4e5911801fb3e445c22eb0295f"
|
||||
},
|
||||
{
|
||||
"amount": "100",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x0c0ea0139cc752d22c0f8a6b3ffa5c4bcdca1c5604089ebd0f34898f1049db61"
|
||||
},
|
||||
{
|
||||
"amount": "90",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x29371816157718f7d5136d0ed8a0f1e09045ee3cfcd67199d45e3f4157f7e011"
|
||||
},
|
||||
{
|
||||
"amount": "35",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x6a081b2c5dfa2d5c916a598569519605322721c5511d26cf4aed8e08e49cf700"
|
||||
},
|
||||
{
|
||||
"amount": "30",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0xc37be614ef14bbbedc808ffc7651fbb7a3c04e4d1612f00f19299da7916003e6"
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "130",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0xc39eefed84fded9118b3e8a84f7fdb79789725ce078421c07e4b9f0b14bb78f2"
|
||||
},
|
||||
{
|
||||
"amount": "58.26122352505",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x249318d3c808f6ec92369ae9008fb479b35a0791fab00cc9d1a1b88a2fdd4ce8"
|
||||
},
|
||||
{
|
||||
"amount": "170",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x7e67e8f61e2da7b26a4b08053f9ec3f63fa03c7d1c1907b440fc1d63317370b7"
|
||||
},
|
||||
{
|
||||
"amount": "396.73877647495",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x01702228af643636ceb22064a23b1b22b66a992f3ec9be8f6d1788e6a996312b"
|
||||
}
|
||||
],
|
||||
"total_tokens": "755",
|
||||
"withdrawn_tokens": "755",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0xf83aaA5786516F7016DF9ead2CD9F14616dA0A13",
|
||||
"deposits": [
|
||||
@@ -29046,21 +29243,6 @@
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "12"
|
||||
},
|
||||
{
|
||||
"address": "0x4043fD11285B4f98A0f7b383D973a17F03e23EC5",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "30",
|
||||
"user": "0x4043fD11285B4f98A0f7b383D973a17F03e23EC5",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x407d9a64209bd8f656d969ee2dde00c24347cbdb9c3f53d9026278390c80e325"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"total_tokens": "30",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "30"
|
||||
},
|
||||
{
|
||||
"address": "0x17bDc5F0D55c81754c4378Ea99C1888cb38DED72",
|
||||
"deposits": [
|
||||
@@ -31417,100 +31599,6 @@
|
||||
"withdrawn_tokens": "2",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "25",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x3a6f6a47608e017b8d8a1495821514beed5fbb265176665aba6213987a4e0bde"
|
||||
},
|
||||
{
|
||||
"amount": "20",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x1656fec2cd5d9bf5aeb907e64b222843e13ac0921f4dc9451e6db7d02611c742"
|
||||
},
|
||||
{
|
||||
"amount": "30",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x20652e7dddc270c76be42c7496a968f5a0831dae46c12d1866c8b720c1070cb4"
|
||||
},
|
||||
{
|
||||
"amount": "60",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x89b232cab8db6ae361d824c55ec20b0e59c0bc14fadb71d902bba3a801338258"
|
||||
},
|
||||
{
|
||||
"amount": "15",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x5032a6328b99e190e893bd7feca96d465fca1996939c71fda986bdddc89897d8"
|
||||
},
|
||||
{
|
||||
"amount": "20",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x9217321eb5e9b64157da6b8ab97a1ce927e64671095da3086be0edd7cd0ef709"
|
||||
},
|
||||
{
|
||||
"amount": "200",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0xf88b8ed5ce899f00f466830936599112ea678a4e5911801fb3e445c22eb0295f"
|
||||
},
|
||||
{
|
||||
"amount": "100",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x0c0ea0139cc752d22c0f8a6b3ffa5c4bcdca1c5604089ebd0f34898f1049db61"
|
||||
},
|
||||
{
|
||||
"amount": "90",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x29371816157718f7d5136d0ed8a0f1e09045ee3cfcd67199d45e3f4157f7e011"
|
||||
},
|
||||
{
|
||||
"amount": "35",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x6a081b2c5dfa2d5c916a598569519605322721c5511d26cf4aed8e08e49cf700"
|
||||
},
|
||||
{
|
||||
"amount": "30",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0xc37be614ef14bbbedc808ffc7651fbb7a3c04e4d1612f00f19299da7916003e6"
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "58.26122352505",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x249318d3c808f6ec92369ae9008fb479b35a0791fab00cc9d1a1b88a2fdd4ce8"
|
||||
},
|
||||
{
|
||||
"amount": "170",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x7e67e8f61e2da7b26a4b08053f9ec3f63fa03c7d1c1907b440fc1d63317370b7"
|
||||
},
|
||||
{
|
||||
"amount": "396.73877647495",
|
||||
"user": "0x94097462EF7c43D0aC732E7B18f830096D95207C",
|
||||
"tranche_id": 11,
|
||||
"tx": "0x01702228af643636ceb22064a23b1b22b66a992f3ec9be8f6d1788e6a996312b"
|
||||
}
|
||||
],
|
||||
"total_tokens": "625",
|
||||
"withdrawn_tokens": "625",
|
||||
"remaining_tokens": "0"
|
||||
},
|
||||
{
|
||||
"address": "0xc6A53Dbb3423555C990Fc842A28CF58edC35DC73",
|
||||
"deposits": [
|
||||
@@ -36681,8 +36769,8 @@
|
||||
"tranche_start": "2022-03-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-06-05T00:00:00.000Z",
|
||||
"total_added": "3732368.4671",
|
||||
"total_removed": "609657.626547646980493",
|
||||
"locked_amount": "830954.582477534719107679776",
|
||||
"total_removed": "615950.831401702010493",
|
||||
"locked_amount": "796232.273024709558568810279",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1998.95815",
|
||||
@@ -36856,6 +36944,11 @@
|
||||
"user": "0xB523235B6c7C74DDB26b10E78bFb2d0Cb63Ae289",
|
||||
"tx": "0x2c5cfeee95fba21323fdbfde219501aeafe8d7f236d1283b4f8f7c7760e4401c"
|
||||
},
|
||||
{
|
||||
"amount": "6293.20485405503",
|
||||
"user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0",
|
||||
"tx": "0x5952d8d6e0f304875b996b35428690f70a896151c547cedf9dc46699c0094d19"
|
||||
},
|
||||
{
|
||||
"amount": "144779.049152",
|
||||
"user": "0x1da69E9C22d77Ef8Ccbf5a1F2d83eDBc5Dcc20fA",
|
||||
@@ -37220,6 +37313,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "6293.20485405503",
|
||||
"user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0",
|
||||
"tranche_id": 1,
|
||||
"tx": "0x5952d8d6e0f304875b996b35428690f70a896151c547cedf9dc46699c0094d19"
|
||||
},
|
||||
{
|
||||
"amount": "2069.469124279649",
|
||||
"user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0",
|
||||
@@ -37498,8 +37597,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "187637.95",
|
||||
"withdrawn_tokens": "139761.298849858013",
|
||||
"remaining_tokens": "47876.651150141987"
|
||||
"withdrawn_tokens": "146054.503703913043",
|
||||
"remaining_tokens": "41583.446296086957"
|
||||
},
|
||||
{
|
||||
"address": "0x1A71e3ED1996CAbB91bB043f880CE963D601707e",
|
||||
@@ -38019,8 +38118,8 @@
|
||||
"tranche_start": "2022-06-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "15870102.715470999700000001",
|
||||
"total_removed": "577690.67124866818551952",
|
||||
"locked_amount": "8246199.182722636897614681448803811226007",
|
||||
"total_removed": "581409.88924190582035452",
|
||||
"locked_amount": "8123076.1027882686093883722947201633400919",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "16249.93",
|
||||
@@ -38524,6 +38623,21 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "827.191309560501875",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0xf1829033f07f9492807a2ca3684d491d7f6986b4c28c795be46873dcebc31e46"
|
||||
},
|
||||
{
|
||||
"amount": "549.637752174555",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0x2d99d4051c6ac81037db1eebf0f86b335ed9d1957f281134d07da192644a6a8c"
|
||||
},
|
||||
{
|
||||
"amount": "1468.73477394015521",
|
||||
"user": "0xe3eB4CF43C072658401996b71D43eE26E573562D",
|
||||
"tx": "0x525f9427c131bc2fdea7f556d16b7781faaa41e09c7735d1c02d1f7585cc49ab"
|
||||
},
|
||||
{
|
||||
"amount": "535.4042378778335",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -38599,6 +38713,16 @@
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0xb55fa2352ed3079722cfc023a587ac1d089f287267f6e2eedb4ebfbda89ac6c9"
|
||||
},
|
||||
{
|
||||
"amount": "345.7620519411935",
|
||||
"user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0",
|
||||
"tx": "0x6d7ba07ccbaab604d1842555433ea542422320c14d35d633bc032f4c8d2c9dce"
|
||||
},
|
||||
{
|
||||
"amount": "527.89210562122925",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tx": "0x681298b3ed6fe2181d9e4391f57c92855bd069bbc989fadfe9d45abbb865b08e"
|
||||
},
|
||||
{
|
||||
"amount": "856.08784586478614",
|
||||
"user": "0xe3eB4CF43C072658401996b71D43eE26E573562D",
|
||||
@@ -40277,6 +40401,18 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "827.191309560501875",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 2,
|
||||
"tx": "0xf1829033f07f9492807a2ca3684d491d7f6986b4c28c795be46873dcebc31e46"
|
||||
},
|
||||
{
|
||||
"amount": "549.637752174555",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 2,
|
||||
"tx": "0x2d99d4051c6ac81037db1eebf0f86b335ed9d1957f281134d07da192644a6a8c"
|
||||
},
|
||||
{
|
||||
"amount": "535.4042378778335",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -40343,6 +40479,12 @@
|
||||
"tranche_id": 2,
|
||||
"tx": "0xb55fa2352ed3079722cfc023a587ac1d089f287267f6e2eedb4ebfbda89ac6c9"
|
||||
},
|
||||
{
|
||||
"amount": "527.89210562122925",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
"tranche_id": 2,
|
||||
"tx": "0x681298b3ed6fe2181d9e4391f57c92855bd069bbc989fadfe9d45abbb865b08e"
|
||||
},
|
||||
{
|
||||
"amount": "966.75883976995675",
|
||||
"user": "0x20CD77B9FC2f1fEDfb6F184E25f7127BFE991C8b",
|
||||
@@ -41485,8 +41627,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "259998.8875",
|
||||
"withdrawn_tokens": "124670.831698608740875",
|
||||
"remaining_tokens": "135328.055801391259125"
|
||||
"withdrawn_tokens": "126575.552865965027",
|
||||
"remaining_tokens": "133423.334634034973"
|
||||
},
|
||||
{
|
||||
"address": "0x89051CAb67Bc7F8CC44F7e270c6EDaf1EC57676c",
|
||||
@@ -41707,6 +41849,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "1468.73477394015521",
|
||||
"user": "0xe3eB4CF43C072658401996b71D43eE26E573562D",
|
||||
"tranche_id": 2,
|
||||
"tx": "0x525f9427c131bc2fdea7f556d16b7781faaa41e09c7735d1c02d1f7585cc49ab"
|
||||
},
|
||||
{
|
||||
"amount": "1640.93679110232897",
|
||||
"user": "0xe3eB4CF43C072658401996b71D43eE26E573562D",
|
||||
@@ -41949,8 +42097,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "150551.801",
|
||||
"withdrawn_tokens": "71968.00074341356817",
|
||||
"remaining_tokens": "78583.80025658643183"
|
||||
"withdrawn_tokens": "73436.73551735372338",
|
||||
"remaining_tokens": "77115.06548264627662"
|
||||
},
|
||||
{
|
||||
"address": "0x4d982Ab0823fD2f48e934a7be2bb0a5374a26148",
|
||||
@@ -42825,6 +42973,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "345.7620519411935",
|
||||
"user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0",
|
||||
"tranche_id": 2,
|
||||
"tx": "0x6d7ba07ccbaab604d1842555433ea542422320c14d35d633bc032f4c8d2c9dce"
|
||||
},
|
||||
{
|
||||
"amount": "113.697899560567",
|
||||
"user": "0xE6CacAE56Cca8dFdB7910b5A13578719D4E57DA0",
|
||||
@@ -43085,8 +43239,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "12362.05",
|
||||
"withdrawn_tokens": "5603.4115869825835",
|
||||
"remaining_tokens": "6758.6384130174165"
|
||||
"withdrawn_tokens": "5949.173638923777",
|
||||
"remaining_tokens": "6412.876361076223"
|
||||
},
|
||||
{
|
||||
"address": "0xb091D456d0dFCB94dcba6f355379056C5bb995fC",
|
||||
@@ -43717,8 +43871,8 @@
|
||||
"tranche_start": "2021-11-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-05-05T00:00:00.000Z",
|
||||
"total_added": "14597706.0446472999",
|
||||
"total_removed": "4397854.702109741180950406",
|
||||
"locked_amount": "1891393.20672031899417706569431457",
|
||||
"total_removed": "5576016.212508497282613906",
|
||||
"locked_amount": "1777726.765473197066260457387430519",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "129284.449",
|
||||
@@ -43927,6 +44081,16 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "1147.2913244855584015",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0xabe4091d256d6a561d5629b7e74395716317fd5c1e705b696e054328ffc7e3b6"
|
||||
},
|
||||
{
|
||||
"amount": "762.6075292623334365",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0xb4d9a135d2cfa85e52b9bb68a09ffaecde4ae4d1fab95e6f44d4dd902e2a45c9"
|
||||
},
|
||||
{
|
||||
"amount": "800.792718381487871",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
@@ -43987,6 +44151,21 @@
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0x4b9a1720f8b7cdd71f9b219186b0d8b5f07864ccac02b3ec278201064ca5b5ac"
|
||||
},
|
||||
{
|
||||
"amount": "731.1824013272954955",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0xc6bcc24f815785c515cad1409206cdd00d671fdaabc89ef4970b53c08ef8ac90"
|
||||
},
|
||||
{
|
||||
"amount": "1004822.05039197353623",
|
||||
"user": "0x39fEc2e2beaB6a63c1E763D0dc4120AF60BEe39F",
|
||||
"tx": "0xa91210c18bbbb96be0a03cc722bd55849e52b0a3be2e16bbcb9d4315699ad9ec"
|
||||
},
|
||||
{
|
||||
"amount": "170698.3787517073781",
|
||||
"user": "0x01a8055A97b461b58ba8e37cd349721FeAe77A8D",
|
||||
"tx": "0xae40853fda1f0e1e9a1cb5433049e4f9d14dc06783bc0514a9f0a890043f684f"
|
||||
},
|
||||
{
|
||||
"amount": "1333.9237119810715295",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
@@ -46751,10 +46930,17 @@
|
||||
"tx": "0x9637d45a40aacc5dff7f8f69e8a4c0536fd0460b915de576bd3f0fdf5892c0a4"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "1004822.05039197353623",
|
||||
"user": "0x39fEc2e2beaB6a63c1E763D0dc4120AF60BEe39F",
|
||||
"tranche_id": 3,
|
||||
"tx": "0xa91210c18bbbb96be0a03cc722bd55849e52b0a3be2e16bbcb9d4315699ad9ec"
|
||||
}
|
||||
],
|
||||
"total_tokens": "1151405.093",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "1151405.093"
|
||||
"withdrawn_tokens": "1004822.05039197353623",
|
||||
"remaining_tokens": "146583.04260802646377"
|
||||
},
|
||||
{
|
||||
"address": "0x5CD0Ec63687588817044794bF15d4e37991efAB3",
|
||||
@@ -46809,10 +46995,17 @@
|
||||
"tx": "0xf650c3599b24d01dfa1f3e19b22f870ff8ac8dfac529893f0b22d548c3535eda"
|
||||
}
|
||||
],
|
||||
"withdrawals": [],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "170698.3787517073781",
|
||||
"user": "0x01a8055A97b461b58ba8e37cd349721FeAe77A8D",
|
||||
"tranche_id": 3,
|
||||
"tx": "0xae40853fda1f0e1e9a1cb5433049e4f9d14dc06783bc0514a9f0a890043f684f"
|
||||
}
|
||||
],
|
||||
"total_tokens": "195584.17",
|
||||
"withdrawn_tokens": "0",
|
||||
"remaining_tokens": "195584.17"
|
||||
"withdrawn_tokens": "170698.3787517073781",
|
||||
"remaining_tokens": "24885.7912482926219"
|
||||
},
|
||||
{
|
||||
"address": "0x7043Da7e9437b01075AdEd8ceaEC8595427895eB",
|
||||
@@ -46853,6 +47046,18 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "1147.2913244855584015",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tranche_id": 3,
|
||||
"tx": "0xabe4091d256d6a561d5629b7e74395716317fd5c1e705b696e054328ffc7e3b6"
|
||||
},
|
||||
{
|
||||
"amount": "762.6075292623334365",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tranche_id": 3,
|
||||
"tx": "0xb4d9a135d2cfa85e52b9bb68a09ffaecde4ae4d1fab95e6f44d4dd902e2a45c9"
|
||||
},
|
||||
{
|
||||
"amount": "800.792718381487871",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
@@ -46919,6 +47124,12 @@
|
||||
"tranche_id": 3,
|
||||
"tx": "0x4b9a1720f8b7cdd71f9b219186b0d8b5f07864ccac02b3ec278201064ca5b5ac"
|
||||
},
|
||||
{
|
||||
"amount": "731.1824013272954955",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tranche_id": 3,
|
||||
"tx": "0xc6bcc24f815785c515cad1409206cdd00d671fdaabc89ef4970b53c08ef8ac90"
|
||||
},
|
||||
{
|
||||
"amount": "1333.9237119810715295",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
@@ -49363,8 +49574,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "359123.469575",
|
||||
"withdrawn_tokens": "312272.154922915220267",
|
||||
"remaining_tokens": "46851.314652084779733"
|
||||
"withdrawn_tokens": "314913.2361779904076005",
|
||||
"remaining_tokens": "44210.2333970095923995"
|
||||
},
|
||||
{
|
||||
"address": "0xBdd412797c1B78535Afc5F71503b91fAbD0160fB",
|
||||
@@ -50708,7 +50919,7 @@
|
||||
"tranche_end": "2023-04-05T00:00:00.000Z",
|
||||
"total_added": "5778205.3912159303",
|
||||
"total_removed": "3055768.040200763217391295",
|
||||
"locked_amount": "430397.491485895010372183109398268",
|
||||
"locked_amount": "385487.193100244108102591696423251",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "552496.6455",
|
||||
@@ -52746,8 +52957,8 @@
|
||||
"tranche_start": "2022-06-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-06-05T00:00:00.000Z",
|
||||
"total_added": "472355.6199999996",
|
||||
"total_removed": "34175.2617719782685",
|
||||
"locked_amount": "131669.503532461224227659702080144",
|
||||
"total_removed": "34416.2282090650685",
|
||||
"locked_amount": "126167.555118478468636691490005064",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "3000",
|
||||
@@ -59366,6 +59577,21 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "129.867928716",
|
||||
"user": "0x09996E1a67c371400bD5f52DF841f77B1741eB9d",
|
||||
"tx": "0x6384e0bc0ae55ff0d56b1ade7096a8b706b1f71f50ee5b6e2de23dc139295352"
|
||||
},
|
||||
{
|
||||
"amount": "53.3902891928",
|
||||
"user": "0xB168ce7397Dc52ed13B4eD8119f309ec30DDa2c9",
|
||||
"tx": "0x2bb633b4c030fb357ab2c015702366a956459c3b68187b16718629a78ff0ac23"
|
||||
},
|
||||
{
|
||||
"amount": "45.06605784",
|
||||
"user": "0x7708B79e2bc3b7ab816E66aF33A8c9385f0FcA4b",
|
||||
"tx": "0x1c5bff9afd9ddc3c385d5a089f9784606b0bac24e59dba9f16e1445e52a9c41b"
|
||||
},
|
||||
{
|
||||
"amount": "57.900076104",
|
||||
"user": "0x96d882E908C06cD697Ea07266Fb8D14ae129A50b",
|
||||
@@ -59476,6 +59702,11 @@
|
||||
"user": "0xF55A2B967DDAA5049f537D8402b791901cC9d34E",
|
||||
"tx": "0x7a9a67e318e04dfb381e22d4305c9711a331db3a5ca8136a8cbd849bd89d32f4"
|
||||
},
|
||||
{
|
||||
"amount": "12.642161338",
|
||||
"user": "0x479F059c46c6873C6B970A92911084b3eA036d56",
|
||||
"tx": "0x788465bb6094c84382566a7287c05a4a91ebbb374030ad3bce890e0d8d60620f"
|
||||
},
|
||||
{
|
||||
"amount": "13.1116203702",
|
||||
"user": "0x4cBC0C88d8FE503f62823B42f30a4900292C13bE",
|
||||
@@ -69021,6 +69252,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "53.3902891928",
|
||||
"user": "0xB168ce7397Dc52ed13B4eD8119f309ec30DDa2c9",
|
||||
"tranche_id": 5,
|
||||
"tx": "0x2bb633b4c030fb357ab2c015702366a956459c3b68187b16718629a78ff0ac23"
|
||||
},
|
||||
{
|
||||
"amount": "48.7169590306",
|
||||
"user": "0xB168ce7397Dc52ed13B4eD8119f309ec30DDa2c9",
|
||||
@@ -69029,8 +69266,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "140",
|
||||
"withdrawn_tokens": "48.7169590306",
|
||||
"remaining_tokens": "91.2830409694"
|
||||
"withdrawn_tokens": "102.1072482234",
|
||||
"remaining_tokens": "37.8927517766"
|
||||
},
|
||||
{
|
||||
"address": "0xdD37b0ff9aE7e2EDbABdc291e8d44431084dA4c2",
|
||||
@@ -75066,6 +75303,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "129.867928716",
|
||||
"user": "0x09996E1a67c371400bD5f52DF841f77B1741eB9d",
|
||||
"tranche_id": 5,
|
||||
"tx": "0x6384e0bc0ae55ff0d56b1ade7096a8b706b1f71f50ee5b6e2de23dc139295352"
|
||||
},
|
||||
{
|
||||
"amount": "15.684119736",
|
||||
"user": "0x09996E1a67c371400bD5f52DF841f77B1741eB9d",
|
||||
@@ -75074,8 +75317,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "200",
|
||||
"withdrawn_tokens": "15.684119736",
|
||||
"remaining_tokens": "184.315880264"
|
||||
"withdrawn_tokens": "145.552048452",
|
||||
"remaining_tokens": "54.447951548"
|
||||
},
|
||||
{
|
||||
"address": "0xb2495ea94f7f329Ca3d91342e0c7422d97ac5a9F",
|
||||
@@ -77646,6 +77889,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "12.642161338",
|
||||
"user": "0x479F059c46c6873C6B970A92911084b3eA036d56",
|
||||
"tranche_id": 5,
|
||||
"tx": "0x788465bb6094c84382566a7287c05a4a91ebbb374030ad3bce890e0d8d60620f"
|
||||
},
|
||||
{
|
||||
"amount": "9.342237444",
|
||||
"user": "0x479F059c46c6873C6B970A92911084b3eA036d56",
|
||||
@@ -77666,8 +77915,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "200",
|
||||
"withdrawn_tokens": "131.696949518",
|
||||
"remaining_tokens": "68.303050482"
|
||||
"withdrawn_tokens": "144.339110856",
|
||||
"remaining_tokens": "55.660889144"
|
||||
},
|
||||
{
|
||||
"address": "0x311944e80915b08248111173671093623Fd74851",
|
||||
@@ -77860,6 +78109,12 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "45.06605784",
|
||||
"user": "0x7708B79e2bc3b7ab816E66aF33A8c9385f0FcA4b",
|
||||
"tranche_id": 5,
|
||||
"tx": "0x1c5bff9afd9ddc3c385d5a089f9784606b0bac24e59dba9f16e1445e52a9c41b"
|
||||
},
|
||||
{
|
||||
"amount": "39.25738204",
|
||||
"user": "0x7708B79e2bc3b7ab816E66aF33A8c9385f0FcA4b",
|
||||
@@ -77886,8 +78141,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "400",
|
||||
"withdrawn_tokens": "247.514294772",
|
||||
"remaining_tokens": "152.485705228"
|
||||
"withdrawn_tokens": "292.580352612",
|
||||
"remaining_tokens": "107.419647388"
|
||||
},
|
||||
{
|
||||
"address": "0x32836171Ef226Dbb40bc9463993deC054e72a2E5",
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
[]
|
||||
@@ -1 +0,0 @@
|
||||
[]
|
||||
@@ -1 +0,0 @@
|
||||
[]
|
||||
@@ -1 +0,0 @@
|
||||
[]
|
||||
@@ -1 +0,0 @@
|
||||
[]
|
||||
@@ -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
|
||||
|
||||
@@ -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 () {
|
||||
|
||||
@@ -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'.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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]);
|
||||
};
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
+8
-3
@@ -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,
|
||||
});
|
||||
}
|
||||
},
|
||||
}));
|
||||
@@ -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,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;
|
||||
|
||||
@@ -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 />;
|
||||
|
||||
@@ -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: '',
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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 />,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
+3
-2
@@ -16,10 +16,11 @@ export const StakingWalletsContainer = ({
|
||||
|
||||
if (!account) {
|
||||
return (
|
||||
<EthConnectPrompt>
|
||||
<>
|
||||
<p>{t('associateInfo1')}</p>
|
||||
<p>{t('associateInfo2')}</p>
|
||||
</EthConnectPrompt>
|
||||
<EthConnectPrompt />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,35 +1,34 @@
|
||||
import { BigNumber } from '../../../lib/bignumber';
|
||||
import { sumCirculatingTokens } from './token-details-circulating';
|
||||
import type { Tranche } from '@vegaprotocol/smart-contracts';
|
||||
|
||||
it('It sums some easy tranches correctly', () => {
|
||||
const tranches: Partial<Tranche>[] = [
|
||||
{ total_added: new BigNumber('100'), locked_amount: new BigNumber(0) },
|
||||
{ total_added: new BigNumber('100'), locked_amount: new BigNumber(0) },
|
||||
{ total_added: new BigNumber('100'), locked_amount: new BigNumber(0) },
|
||||
const tranches = [
|
||||
{ total_added: new BigNumber(100), locked_amount: new BigNumber(0) },
|
||||
{ total_added: new BigNumber(100), locked_amount: new BigNumber(0) },
|
||||
{ total_added: new BigNumber(100), locked_amount: new BigNumber(0) },
|
||||
];
|
||||
|
||||
const result = sumCirculatingTokens(tranches as Tranche[]);
|
||||
const result = sumCirculatingTokens(tranches);
|
||||
expect(result.toString()).toEqual('300');
|
||||
});
|
||||
|
||||
it('It sums some longer tranches correctly', () => {
|
||||
const tranches: Partial<Tranche>[] = [
|
||||
const tranches = [
|
||||
{
|
||||
total_added: new BigNumber('10000000000'),
|
||||
total_added: new BigNumber(10000000000),
|
||||
locked_amount: new BigNumber(0),
|
||||
},
|
||||
{ total_added: new BigNumber('20'), locked_amount: new BigNumber(0) },
|
||||
{ total_added: new BigNumber('3000'), locked_amount: new BigNumber(3020) },
|
||||
{ total_added: new BigNumber(20), locked_amount: new BigNumber(0) },
|
||||
{ total_added: new BigNumber(3000), locked_amount: new BigNumber(3020) },
|
||||
];
|
||||
|
||||
const result = sumCirculatingTokens(tranches as Tranche[]);
|
||||
const result = sumCirculatingTokens(tranches);
|
||||
expect(result.toString()).toEqual('10000000000');
|
||||
});
|
||||
|
||||
it('Handles null tranche array', () => {
|
||||
const tranches = null;
|
||||
|
||||
const result = sumCirculatingTokens(tranches as unknown as Tranche[]);
|
||||
const result = sumCirculatingTokens(tranches);
|
||||
expect(result.toString()).toEqual('0');
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { BigNumber } from '../../../lib/bignumber';
|
||||
import { formatNumber } from '../../../lib/format-number';
|
||||
import type { Tranche } from '@vegaprotocol/smart-contracts';
|
||||
import type { Tranche } from '../../../lib/tranches/tranches-store';
|
||||
|
||||
/**
|
||||
* Add together the circulating tokens from all tranches
|
||||
@@ -9,7 +9,9 @@ import type { Tranche } from '@vegaprotocol/smart-contracts';
|
||||
* @param decimals decimal places for the formatted result
|
||||
* @return The total circulating tokens from all tranches
|
||||
*/
|
||||
export function sumCirculatingTokens(tranches: Tranche[] | null): BigNumber {
|
||||
export function sumCirculatingTokens(
|
||||
tranches: { total_added: BigNumber; locked_amount: BigNumber }[] | null
|
||||
): BigNumber {
|
||||
let totalCirculating: BigNumber = new BigNumber(0);
|
||||
|
||||
tranches?.forEach(
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
KeyValueTableRow,
|
||||
RoundedWrapper,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useTranches } from '../../../hooks/use-tranches';
|
||||
import { useTranches } from '../../../lib/tranches/tranches-store';
|
||||
import type { BigNumber } from '../../../lib/bignumber';
|
||||
import { formatNumber } from '../../../lib/format-number';
|
||||
import { TokenDetailsCirculating } from './token-details-circulating';
|
||||
@@ -25,7 +25,11 @@ export const TokenDetails = ({
|
||||
const { ETHERSCAN_URL } = useEnvironment();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { tranches, loading, error } = useTranches();
|
||||
const { tranches, loading, error } = useTranches((state) => ({
|
||||
loading: state.loading,
|
||||
error: state.error,
|
||||
tranches: state.tranches,
|
||||
}));
|
||||
const { config } = useEthereumConfig();
|
||||
const { token } = useContracts();
|
||||
|
||||
|
||||
@@ -4,14 +4,18 @@ import { Outlet } from 'react-router-dom';
|
||||
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 type { RouteChildProps } from '..';
|
||||
import { Callout, Intent, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { useTranches } from '../../lib/tranches/tranches-store';
|
||||
|
||||
const TrancheRouter = ({ name }: RouteChildProps) => {
|
||||
useDocumentTitle(name);
|
||||
const { t } = useTranslation();
|
||||
const { tranches, error, loading } = useTranches();
|
||||
const { tranches, error, loading } = useTranches((state) => ({
|
||||
loading: state.loading,
|
||||
error: state.error,
|
||||
tranches: state.tranches,
|
||||
}));
|
||||
|
||||
if (!tranches || loading) {
|
||||
return (
|
||||
|
||||
@@ -1,48 +1,32 @@
|
||||
import type { Tranche as ITranche } from '@vegaprotocol/smart-contracts';
|
||||
import { Link } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
KeyValueTable,
|
||||
KeyValueTableRow,
|
||||
Link,
|
||||
RoundedWrapper,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { Link as RouterLink } from 'react-router-dom';
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useParams } from 'react-router';
|
||||
import { Navigate } from 'react-router-dom';
|
||||
import { formatNumber } from '@vegaprotocol/react-helpers';
|
||||
|
||||
import { useOutletContext } from 'react-router-dom';
|
||||
import { useEnvironment } from '@vegaprotocol/environment';
|
||||
import { BigNumber } from '../../lib/bignumber';
|
||||
import { formatNumber } from '../../lib/format-number';
|
||||
import { TrancheItem } from '../redemption/tranche-item';
|
||||
import Routes from '../routes';
|
||||
import { TrancheLabel } from './tranche-label';
|
||||
|
||||
const TrancheProgressContents = ({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) => (
|
||||
<div className="flex justify-between gap-4 font-mono py-2 px-4">
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
import { useTranches } from '../../lib/tranches/tranches-store';
|
||||
|
||||
export const Tranche = () => {
|
||||
const tranches = useOutletContext<ITranche[]>();
|
||||
const tranches = useTranches((state) => state.tranches);
|
||||
const { ETHERSCAN_URL } = useEnvironment();
|
||||
const { t } = useTranslation();
|
||||
const { trancheId } = useParams<{ trancheId: string }>();
|
||||
const { trancheId } = useParams<{ trancheId: string; address: string }>();
|
||||
const { chainId } = useWeb3React();
|
||||
const tranche = tranches.find(
|
||||
const tranche = tranches?.find(
|
||||
(tranche) => trancheId && parseInt(trancheId) === tranche.tranche_id
|
||||
);
|
||||
|
||||
const lockedData = React.useMemo(() => {
|
||||
if (!tranche) return null;
|
||||
const locked = tranche.locked_amount.div(tranche.total_added);
|
||||
return {
|
||||
locked,
|
||||
unlocked: new BigNumber(1).minus(locked),
|
||||
};
|
||||
}, [tranche]);
|
||||
|
||||
if (!tranche) {
|
||||
return <Navigate to={Routes.NOT_FOUND} />;
|
||||
}
|
||||
@@ -67,33 +51,36 @@ export const Tranche = () => {
|
||||
</div>
|
||||
<h2>{t('Holders')}</h2>
|
||||
{tranche.users.length ? (
|
||||
<ul role="list">
|
||||
{tranche.users.map((user, i) => {
|
||||
const unlocked = user.remaining_tokens.times(
|
||||
lockedData?.unlocked || 0
|
||||
);
|
||||
const locked = user.remaining_tokens.times(lockedData?.locked || 0);
|
||||
return (
|
||||
<li className="pb-4" key={i}>
|
||||
<Link
|
||||
title={t('View on Etherscan (opens in a new tab)')}
|
||||
href={`${ETHERSCAN_URL}/tx/${user.address}`}
|
||||
target="_blank"
|
||||
>
|
||||
{user.address}
|
||||
</Link>
|
||||
<TrancheProgressContents>
|
||||
<span>{t('Locked')}</span>
|
||||
<span>{t('Unlocked')}</span>
|
||||
</TrancheProgressContents>
|
||||
<TrancheProgressContents>
|
||||
<span>{formatNumber(locked)}</span>
|
||||
<span>{formatNumber(unlocked)}</span>
|
||||
</TrancheProgressContents>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
<RoundedWrapper>
|
||||
<KeyValueTable>
|
||||
<KeyValueTableRow>
|
||||
<h1>{t('Ethereum Address')}</h1>
|
||||
<h1>{t('View tranche data')}</h1>
|
||||
</KeyValueTableRow>
|
||||
{tranche.users.map((user) => (
|
||||
<KeyValueTableRow key={user}>
|
||||
{
|
||||
<Link
|
||||
title={t('View on Etherscan (opens in a new tab)')}
|
||||
href={`${ETHERSCAN_URL}/address/${user}`}
|
||||
target="_blank"
|
||||
>
|
||||
{user}
|
||||
</Link>
|
||||
}
|
||||
{
|
||||
<RouterLink
|
||||
className="underline"
|
||||
title={t('View vesting information')}
|
||||
to={`${Routes.REDEEM}/${user}`}
|
||||
>
|
||||
{t('View vesting information')}
|
||||
</RouterLink>
|
||||
}
|
||||
</KeyValueTableRow>
|
||||
))}
|
||||
</KeyValueTable>
|
||||
</RoundedWrapper>
|
||||
) : (
|
||||
<p>{t('No users')}</p>
|
||||
)}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { useOutletContext } from 'react-router-dom';
|
||||
import type { Tranche } from '@vegaprotocol/smart-contracts';
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -10,6 +8,8 @@ import { TrancheLabel } from './tranche-label';
|
||||
import { VestingChart } from './vesting-chart';
|
||||
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||
import { useEthereumConfig } from '@vegaprotocol/web3';
|
||||
import type { Tranche } from '../../lib/tranches/tranches-store';
|
||||
import { useTranches } from '../../lib/tranches/tranches-store';
|
||||
|
||||
const trancheMinimum = 10;
|
||||
|
||||
@@ -17,7 +17,7 @@ const shouldShowTranche = (t: Tranche) =>
|
||||
!t.total_added.isLessThanOrEqualTo(trancheMinimum);
|
||||
|
||||
export const Tranches = () => {
|
||||
const tranches = useOutletContext<Tranche[]>();
|
||||
const tranches = useTranches((state) => state.tranches);
|
||||
const [showAll, setShowAll] = React.useState<boolean>(false);
|
||||
const { t } = useTranslation();
|
||||
const { chainId } = useWeb3React();
|
||||
@@ -38,25 +38,24 @@ export const Tranches = () => {
|
||||
<ul role="list">
|
||||
{(showAll ? tranches : filteredTranches).map((tranche) => {
|
||||
return (
|
||||
<React.Fragment key={tranche.tranche_id}>
|
||||
<TrancheItem
|
||||
link={`${tranche.tranche_id}`}
|
||||
tranche={tranche}
|
||||
locked={tranche.locked_amount}
|
||||
unlocked={tranche.total_added.minus(tranche.locked_amount)}
|
||||
total={tranche.total_added}
|
||||
secondaryHeader={
|
||||
<TrancheLabel chainId={chainId} id={tranche.tranche_id} />
|
||||
}
|
||||
/>
|
||||
</React.Fragment>
|
||||
<TrancheItem
|
||||
key={tranche.tranche_id}
|
||||
link={`${tranche.tranche_id}`}
|
||||
tranche={tranche}
|
||||
locked={tranche.locked_amount}
|
||||
unlocked={tranche.total_added.minus(tranche.locked_amount)}
|
||||
total={tranche.total_added}
|
||||
secondaryHeader={
|
||||
<TrancheLabel chainId={chainId} id={tranche.tranche_id} />
|
||||
}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
) : (
|
||||
<p>{t('No tranches')}</p>
|
||||
)}
|
||||
<section className="text-center mt-32">
|
||||
<section className="text-center mt-4">
|
||||
<ButtonLink onClick={() => setShowAll(!showAll)}>
|
||||
{showAll
|
||||
? t(
|
||||
|
||||
@@ -22,6 +22,7 @@ module.exports = defineConfig({
|
||||
viewportHeight: 900,
|
||||
responseTimeout: 50000,
|
||||
requestTimeout: 20000,
|
||||
retries: 2,
|
||||
},
|
||||
env: {
|
||||
ETHERSCAN_URL: 'https://sepolia.etherscan.io',
|
||||
|
||||
@@ -190,6 +190,24 @@ describe('capsule', { tags: '@slow' }, () => {
|
||||
cy.setVegaWallet();
|
||||
});
|
||||
|
||||
it('shows node health', function () {
|
||||
const market = this.market;
|
||||
cy.visit(`/#/markets/${market.id}`);
|
||||
cy.getByTestId('node-health')
|
||||
.children()
|
||||
.first()
|
||||
.should('contain.text', 'Operational')
|
||||
.next()
|
||||
.should('contain.text', new URL(Cypress.env('VEGA_URL')).origin)
|
||||
.next()
|
||||
.then(($el) => {
|
||||
const blockHeight = parseInt($el.text());
|
||||
// block height will increase over the course of the test run so best
|
||||
// we can do here is check that its showing something sensible
|
||||
expect(blockHeight).to.be.greaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
it('can place and receive an order', function () {
|
||||
const market = this.market;
|
||||
cy.visit(`/#/markets/${market.id}`);
|
||||
|
||||
@@ -304,4 +304,18 @@ describe('home', { tags: '@regression' }, () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('footer', () => {
|
||||
it('shows current block height', () => {
|
||||
cy.visit('/');
|
||||
cy.getByTestId('node-health')
|
||||
.children()
|
||||
.first()
|
||||
.should('contain.text', 'Operational')
|
||||
.next()
|
||||
.should('contain.text', new URL(Cypress.env('VEGA_URL')).origin)
|
||||
.next()
|
||||
.should('contain.text', '100'); // all mocked queries have x-block-height header set to 100
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -178,9 +178,9 @@ function openMarketDropDown() {
|
||||
if (button.is(':visible')) {
|
||||
cy.get('[data-testid^="market-link-"]').should('not.be.empty');
|
||||
cy.getByTestId(dialogCloseBtn).click();
|
||||
cy.get('[data-testid^="ask-vol-"]').should('be.visible');
|
||||
cy.getByTestId(popoverTrigger).click({ force: true });
|
||||
cy.contains('Loading market data...').should('not.exist');
|
||||
}
|
||||
cy.get('[data-testid^="ask-vol-"]').should('be.visible');
|
||||
cy.getByTestId(popoverTrigger).click({ force: true });
|
||||
cy.contains('Loading market data...').should('not.exist');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { mockConnectWallet } from '@vegaprotocol/cypress';
|
||||
|
||||
before(() => {
|
||||
beforeEach(() => {
|
||||
cy.mockTradingPage();
|
||||
cy.mockSubscription();
|
||||
cy.visit('/');
|
||||
|
||||
@@ -84,7 +84,7 @@ export const TradeMarketHeader = ({
|
||||
heading={t('Volume (24h)')}
|
||||
testId="market-volume"
|
||||
description={t(
|
||||
'The total amount of assets traded in the last 24 hours.'
|
||||
'The total number of contracts traded in the last 24 hours.'
|
||||
)}
|
||||
>
|
||||
<Last24hVolume
|
||||
|
||||
@@ -3,12 +3,14 @@ query AccountHistory(
|
||||
$assetId: ID!
|
||||
$accountTypes: [AccountType!]
|
||||
$dateRange: DateRange
|
||||
$marketIds: [ID!]
|
||||
) {
|
||||
balanceChanges(
|
||||
filter: {
|
||||
partyIds: [$partyId]
|
||||
accountTypes: $accountTypes
|
||||
assetId: $assetId
|
||||
marketIds: $marketIds
|
||||
}
|
||||
dateRange: $dateRange
|
||||
) {
|
||||
|
||||
@@ -8,6 +8,7 @@ export type AccountHistoryQueryVariables = Types.Exact<{
|
||||
assetId: Types.Scalars['ID'];
|
||||
accountTypes?: Types.InputMaybe<Array<Types.AccountType> | Types.AccountType>;
|
||||
dateRange?: Types.InputMaybe<Types.DateRange>;
|
||||
marketIds?: Types.InputMaybe<Array<Types.Scalars['ID']> | Types.Scalars['ID']>;
|
||||
}>;
|
||||
|
||||
|
||||
@@ -23,9 +24,9 @@ export type AccountsWithBalanceQuery = { __typename?: 'Query', balanceChanges: {
|
||||
|
||||
|
||||
export const AccountHistoryDocument = gql`
|
||||
query AccountHistory($partyId: ID!, $assetId: ID!, $accountTypes: [AccountType!], $dateRange: DateRange) {
|
||||
query AccountHistory($partyId: ID!, $assetId: ID!, $accountTypes: [AccountType!], $dateRange: DateRange, $marketIds: [ID!]) {
|
||||
balanceChanges(
|
||||
filter: {partyIds: [$partyId], accountTypes: $accountTypes, assetId: $assetId}
|
||||
filter: {partyIds: [$partyId], accountTypes: $accountTypes, assetId: $assetId, marketIds: $marketIds}
|
||||
dateRange: $dateRange
|
||||
) {
|
||||
edges {
|
||||
@@ -58,6 +59,7 @@ export const AccountHistoryDocument = gql`
|
||||
* assetId: // value for 'assetId'
|
||||
* accountTypes: // value for 'accountTypes'
|
||||
* dateRange: // value for 'dateRange'
|
||||
* marketIds: // value for 'marketIds'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
|
||||
@@ -6,8 +6,9 @@ import {
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import compact from 'lodash/compact';
|
||||
import uniqBy from 'lodash/uniqBy';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import type { AccountHistoryQuery } from './__generated__/AccountHistory';
|
||||
import { useAccountHistoryQuery } from './__generated__/AccountHistory';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
@@ -25,8 +26,10 @@ import {
|
||||
import { AccountTypeMapping } from '@vegaprotocol/types';
|
||||
import { PriceChart } from 'pennant';
|
||||
import 'pennant/dist/style.css';
|
||||
import { accountsOnlyDataProvider } from '@vegaprotocol/accounts';
|
||||
import type { Account } from '@vegaprotocol/accounts';
|
||||
import { accountsDataProvider } from '@vegaprotocol/accounts';
|
||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import type { Market } from '@vegaprotocol/market-list';
|
||||
|
||||
const DateRange = {
|
||||
RANGE_1D: '1D',
|
||||
@@ -97,7 +100,7 @@ const AccountHistoryManager = ({
|
||||
);
|
||||
|
||||
const { data: accounts } = useDataProvider({
|
||||
dataProvider: accountsOnlyDataProvider,
|
||||
dataProvider: accountsDataProvider,
|
||||
variables: variablesForOneTimeQuery,
|
||||
skip: !pubKey,
|
||||
});
|
||||
@@ -118,6 +121,39 @@ const AccountHistoryManager = ({
|
||||
const [range, setRange] = useState<typeof DateRange[keyof typeof DateRange]>(
|
||||
DateRange.RANGE_1M
|
||||
);
|
||||
const [market, setMarket] = useState<Market | null>(null);
|
||||
const marketFilterCb = useCallback(
|
||||
(item: Market) =>
|
||||
!asset?.id ||
|
||||
item.tradableInstrument.instrument.product.settlementAsset.id ===
|
||||
asset?.id,
|
||||
[asset?.id]
|
||||
);
|
||||
const markets = useMemo<Market[] | null>(() => {
|
||||
const arr =
|
||||
accounts
|
||||
?.filter((item: Account) => Boolean(item && item.market))
|
||||
.map<Market>((item) => item.market as Market) ?? null;
|
||||
return arr
|
||||
? uniqBy(arr.filter(marketFilterCb), 'id').sort((a, b) =>
|
||||
a.tradableInstrument.instrument.code.localeCompare(
|
||||
b.tradableInstrument.instrument.code
|
||||
)
|
||||
)
|
||||
: null;
|
||||
}, [accounts, marketFilterCb]);
|
||||
const resolveMarket = useCallback(
|
||||
(m: Market) => {
|
||||
setMarket(m);
|
||||
const newAssetId =
|
||||
m.tradableInstrument.instrument.product.settlementAsset.id;
|
||||
const newAsset = assets.find((item) => item.id === newAssetId);
|
||||
if ((!asset || (assets && newAssetId !== asset.id)) && newAsset) {
|
||||
setAsset(newAsset);
|
||||
}
|
||||
},
|
||||
[asset, assets]
|
||||
);
|
||||
|
||||
const variables = useMemo(
|
||||
() => ({
|
||||
@@ -126,62 +162,113 @@ const AccountHistoryManager = ({
|
||||
accountTypes: accountType ? [accountType] : undefined,
|
||||
dateRange:
|
||||
range === 'All' ? undefined : { start: calculateStartDate(range) },
|
||||
marketIds: market?.id ? [market.id] : undefined,
|
||||
}),
|
||||
[pubKey, asset, accountType, range]
|
||||
[pubKey, asset, accountType, range, market?.id]
|
||||
);
|
||||
|
||||
const { data } = useAccountHistoryQuery({
|
||||
variables,
|
||||
skip: !asset || !pubKey,
|
||||
});
|
||||
|
||||
const accountTypeMenu = useMemo(() => {
|
||||
return (
|
||||
<DropdownMenu
|
||||
trigger={
|
||||
<DropdownMenuTrigger>
|
||||
{accountType
|
||||
? `${
|
||||
AccountTypeMapping[
|
||||
accountType as keyof typeof Schema.AccountType
|
||||
]
|
||||
} Account`
|
||||
: t('Select account type')}
|
||||
</DropdownMenuTrigger>
|
||||
}
|
||||
>
|
||||
<DropdownMenuContent>
|
||||
{[
|
||||
Schema.AccountType.ACCOUNT_TYPE_GENERAL,
|
||||
Schema.AccountType.ACCOUNT_TYPE_BOND,
|
||||
Schema.AccountType.ACCOUNT_TYPE_MARGIN,
|
||||
].map((type) => (
|
||||
<DropdownMenuItem
|
||||
key={type}
|
||||
onClick={() => setAccountType(type as Schema.AccountType)}
|
||||
>
|
||||
{AccountTypeMapping[type as keyof typeof Schema.AccountType]}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
}, [accountType]);
|
||||
const assetsMenu = useMemo(() => {
|
||||
return (
|
||||
<DropdownMenu
|
||||
trigger={
|
||||
<DropdownMenuTrigger>
|
||||
{asset ? asset.symbol : t('Select asset')}
|
||||
</DropdownMenuTrigger>
|
||||
}
|
||||
>
|
||||
<DropdownMenuContent>
|
||||
{assets.map((a) => (
|
||||
<DropdownMenuItem key={a.id} onClick={() => setAsset(a)}>
|
||||
{a.symbol}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
}, [assets, asset]);
|
||||
const marketsMenu = useMemo(() => {
|
||||
return accountType === Schema.AccountType.ACCOUNT_TYPE_MARGIN &&
|
||||
markets?.length ? (
|
||||
<DropdownMenu
|
||||
trigger={
|
||||
<DropdownMenuTrigger>
|
||||
{market
|
||||
? market.tradableInstrument.instrument.code
|
||||
: t('Select market')}
|
||||
</DropdownMenuTrigger>
|
||||
}
|
||||
>
|
||||
<DropdownMenuContent>
|
||||
{market && (
|
||||
<DropdownMenuItem key="0" onClick={() => setMarket(null)}>
|
||||
{t('All markets')}
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
{markets?.map((m) => (
|
||||
<DropdownMenuItem key={m.id} onClick={() => resolveMarket(m)}>
|
||||
{m.tradableInstrument.instrument.code}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
) : null;
|
||||
}, [markets, market, accountType, resolveMarket]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
accountType !== Schema.AccountType.ACCOUNT_TYPE_MARGIN ||
|
||||
market?.tradableInstrument.instrument.product.settlementAsset.id !==
|
||||
asset?.id
|
||||
) {
|
||||
setMarket(null);
|
||||
}
|
||||
}, [accountType, asset?.id, market]);
|
||||
|
||||
return (
|
||||
<div className="h-full w-full flex flex-col gap-8">
|
||||
<div className="w-full flex flex-col-reverse lg:flex-row items-start lg:items-center justify-between gap-4 px-2">
|
||||
<div className="flex items-center gap-4 shrink-0">
|
||||
<DropdownMenu
|
||||
trigger={
|
||||
<DropdownMenuTrigger>
|
||||
{accountType
|
||||
? `${
|
||||
AccountTypeMapping[
|
||||
accountType as keyof typeof Schema.AccountType
|
||||
]
|
||||
} Account`
|
||||
: t('Select account type')}
|
||||
</DropdownMenuTrigger>
|
||||
}
|
||||
>
|
||||
<DropdownMenuContent>
|
||||
{[
|
||||
Schema.AccountType.ACCOUNT_TYPE_GENERAL,
|
||||
Schema.AccountType.ACCOUNT_TYPE_BOND,
|
||||
Schema.AccountType.ACCOUNT_TYPE_MARGIN,
|
||||
].map((type) => (
|
||||
<DropdownMenuItem
|
||||
key={type}
|
||||
onClick={() => setAccountType(type as Schema.AccountType)}
|
||||
>
|
||||
{AccountTypeMapping[type as keyof typeof Schema.AccountType]}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<DropdownMenu
|
||||
trigger={
|
||||
<DropdownMenuTrigger>
|
||||
{asset ? asset.symbol : t('Select asset')}
|
||||
</DropdownMenuTrigger>
|
||||
}
|
||||
>
|
||||
<DropdownMenuContent>
|
||||
{assets.map((a) => (
|
||||
<DropdownMenuItem key={a.id} onClick={() => setAsset(a)}>
|
||||
{a.symbol}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<>
|
||||
{accountTypeMenu}
|
||||
{assetsMenu}
|
||||
{marketsMenu}
|
||||
</>
|
||||
</div>
|
||||
<div className="pt-1 justify-items-end">
|
||||
<Toggle
|
||||
|
||||
@@ -12,7 +12,7 @@ import type { ReactNode } from 'react';
|
||||
import { AppFailure } from './app-failure';
|
||||
import { Web3Provider } from './web3-provider';
|
||||
|
||||
const DynamicLoader = dynamic(() => import('../preloader/preloader'), {
|
||||
export const DynamicLoader = dynamic(() => import('../preloader/preloader'), {
|
||||
loading: () => <>Loading...</>,
|
||||
});
|
||||
|
||||
|
||||
@@ -1,20 +1,35 @@
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import { NodeUrl, NodeHealth } from './footer';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { NodeHealth, NodeUrl, HealthIndicator } from './footer';
|
||||
|
||||
describe('NodeUrl', () => {
|
||||
it('can open node switcher by clicking the node url', () => {
|
||||
const mockOpenNodeSwitcher = jest.fn();
|
||||
const node = 'https://api.n99.somenetwork.vega.xyz';
|
||||
|
||||
render(<NodeUrl url={node} openNodeSwitcher={mockOpenNodeSwitcher} />);
|
||||
|
||||
fireEvent.click(screen.getByText(/n99/));
|
||||
expect(mockOpenNodeSwitcher).toHaveBeenCalled();
|
||||
describe('NodeHealth', () => {
|
||||
it('controls the node switcher dialog', async () => {
|
||||
const mockOnClick = jest.fn();
|
||||
render(
|
||||
<NodeHealth
|
||||
onClick={mockOnClick}
|
||||
url={'https://api.n99.somenetwork.vega.xyz'}
|
||||
blockHeight={100}
|
||||
blockDiff={0}
|
||||
/>
|
||||
);
|
||||
await userEvent.click(screen.getByRole('button'));
|
||||
expect(mockOnClick).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('NodeHealth', () => {
|
||||
const mockOpenNodeSwitcher = jest.fn();
|
||||
describe('NodeUrl', () => {
|
||||
it('renders correct part of node url', () => {
|
||||
const node = 'https://api.n99.somenetwork.vega.xyz';
|
||||
const expectedText = node.split('.').slice(1).join('.');
|
||||
|
||||
render(<NodeUrl url={node} />);
|
||||
|
||||
expect(screen.getByText(expectedText)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('HealthIndicator', () => {
|
||||
const cases = [
|
||||
{ diff: 0, classname: 'bg-vega-green-550', text: 'Operational' },
|
||||
{ diff: 5, classname: 'bg-warning', text: '5 Blocks behind' },
|
||||
@@ -23,16 +38,9 @@ describe('NodeHealth', () => {
|
||||
it.each(cases)(
|
||||
'renders correct text and indicator color for $diff block difference',
|
||||
(elem) => {
|
||||
render(
|
||||
<NodeHealth
|
||||
blockDiff={elem.diff}
|
||||
openNodeSwitcher={mockOpenNodeSwitcher}
|
||||
/>
|
||||
);
|
||||
render(<HealthIndicator blockDiff={elem.diff} />);
|
||||
expect(screen.getByTestId('indicator')).toHaveClass(elem.classname);
|
||||
expect(screen.getByText(elem.text)).toBeInTheDocument();
|
||||
fireEvent.click(screen.getByText(elem.text));
|
||||
expect(mockOpenNodeSwitcher).toHaveBeenCalled();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { useEnvironment, useNodeHealth } from '@vegaprotocol/environment';
|
||||
import { t, useNavigatorOnline } from '@vegaprotocol/react-helpers';
|
||||
import { ButtonLink, Indicator, Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import { Indicator, Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import classNames from 'classnames';
|
||||
import type { ButtonHTMLAttributes, ReactNode } from 'react';
|
||||
import { useGlobalStore } from '../../stores';
|
||||
|
||||
export const Footer = () => {
|
||||
@@ -8,45 +10,64 @@ export const Footer = () => {
|
||||
const setNodeSwitcher = useGlobalStore(
|
||||
(store) => (open: boolean) => store.update({ nodeSwitcherDialog: open })
|
||||
);
|
||||
const { blockDiff } = useNodeHealth();
|
||||
const { blockDiff, datanodeBlockHeight } = useNodeHealth();
|
||||
|
||||
return (
|
||||
<footer className="px-4 py-1 text-xs border-t border-default">
|
||||
<div className="flex justify-between">
|
||||
<div className="flex gap-2">
|
||||
{VEGA_URL && (
|
||||
<>
|
||||
<NodeHealth
|
||||
blockDiff={blockDiff}
|
||||
openNodeSwitcher={() => setNodeSwitcher(true)}
|
||||
/>
|
||||
{' | '}
|
||||
<NodeUrl
|
||||
url={VEGA_URL}
|
||||
openNodeSwitcher={() => setNodeSwitcher(true)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<footer className="px-4 py-1 text-xs border-t border-default text-vega-light-300 dark:text-vega-dark-300">
|
||||
{/* Pull left to align with top nav, due to button padding */}
|
||||
<div className="-ml-2">
|
||||
{VEGA_URL && (
|
||||
<NodeHealth
|
||||
url={VEGA_URL}
|
||||
blockHeight={datanodeBlockHeight}
|
||||
blockDiff={blockDiff}
|
||||
onClick={() => setNodeSwitcher(true)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
interface NodeHealthProps {
|
||||
url: string;
|
||||
blockHeight: number | undefined;
|
||||
blockDiff: number | null;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
export const NodeHealth = ({
|
||||
url,
|
||||
blockHeight,
|
||||
blockDiff,
|
||||
onClick,
|
||||
}: NodeHealthProps) => {
|
||||
return (
|
||||
<FooterButton onClick={onClick} data-testid="node-health">
|
||||
<FooterButtonPart>
|
||||
<HealthIndicator blockDiff={blockDiff} />
|
||||
</FooterButtonPart>
|
||||
<FooterButtonPart>
|
||||
<NodeUrl url={url} />
|
||||
</FooterButtonPart>
|
||||
<FooterButtonPart>
|
||||
<span title={t('Block height')}>{blockHeight}</span>
|
||||
</FooterButtonPart>
|
||||
</FooterButton>
|
||||
);
|
||||
};
|
||||
|
||||
interface NodeUrlProps {
|
||||
url: string;
|
||||
openNodeSwitcher: () => void;
|
||||
}
|
||||
|
||||
export const NodeUrl = ({ url, openNodeSwitcher }: NodeUrlProps) => {
|
||||
export const NodeUrl = ({ url }: NodeUrlProps) => {
|
||||
// get base url from api url, api sub domain
|
||||
const urlObj = new URL(url);
|
||||
const nodeUrl = urlObj.origin.replace(/^[^.]+\./g, '');
|
||||
return <ButtonLink onClick={openNodeSwitcher}>{nodeUrl}</ButtonLink>;
|
||||
return <span title={t('Connected node')}>{nodeUrl}</span>;
|
||||
};
|
||||
|
||||
interface NodeHealthProps {
|
||||
openNodeSwitcher: () => void;
|
||||
interface HealthIndicatorProps {
|
||||
blockDiff: number | null;
|
||||
}
|
||||
|
||||
@@ -54,10 +75,7 @@ interface NodeHealthProps {
|
||||
// deemed acceptable for "Good" status
|
||||
const BLOCK_THRESHOLD = 3;
|
||||
|
||||
export const NodeHealth = ({
|
||||
blockDiff,
|
||||
openNodeSwitcher,
|
||||
}: NodeHealthProps) => {
|
||||
export const HealthIndicator = ({ blockDiff }: HealthIndicatorProps) => {
|
||||
const online = useNavigatorOnline();
|
||||
|
||||
let intent = Intent.Success;
|
||||
@@ -76,9 +94,36 @@ export const NodeHealth = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<span title={t('Node health')}>
|
||||
<Indicator variant={intent} />
|
||||
<ButtonLink onClick={openNodeSwitcher}>{text}</ButtonLink>
|
||||
</>
|
||||
{text}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
type FooterButtonProps = ButtonHTMLAttributes<HTMLButtonElement>;
|
||||
|
||||
const FooterButton = (props: FooterButtonProps) => {
|
||||
const buttonClasses = classNames(
|
||||
'px-2 py-0.5 rounded-md',
|
||||
'enabled:hover:bg-vega-light-150',
|
||||
'dark:enabled:hover:bg-vega-dark-150'
|
||||
);
|
||||
return <button {...props} className={buttonClasses} />;
|
||||
};
|
||||
|
||||
const FooterButtonPart = ({ children }: { children: ReactNode }) => {
|
||||
return (
|
||||
<span
|
||||
className={classNames(
|
||||
'relative inline-block mr-2 last:mr-0 pr-2 last:pr-0',
|
||||
'last:after:hidden',
|
||||
'after:content after:absolute after:right-0 after:top-1/2 after:-translate-y-1/2',
|
||||
'after:h-3 after:w-1 after:border-r',
|
||||
'after:border-vega-light-300 dark:after:border-vega-dark-300'
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -33,7 +33,7 @@ import { Connectors } from '../lib/vega-connectors';
|
||||
import { ViewingBanner } from '../components/viewing-banner';
|
||||
import { Banner } from '../components/banner';
|
||||
import classNames from 'classnames';
|
||||
import { AppLoader } from '../components/app-loader';
|
||||
import { AppLoader, DynamicLoader } from '../components/app-loader';
|
||||
|
||||
const DEFAULT_TITLE = t('Welcome to Vega trading!');
|
||||
|
||||
@@ -115,7 +115,7 @@ function VegaTradingApp(props: AppProps) {
|
||||
// Prevent HashRouter from being server side rendered as it
|
||||
// relies on presence of document object
|
||||
if (status === 'default') {
|
||||
return null;
|
||||
return <DynamicLoader />;
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -12,6 +12,8 @@ export default function Document() {
|
||||
type="font/woff2"
|
||||
crossOrigin="anonymous"
|
||||
/>
|
||||
{/* eslint-disable-next-line @next/next/no-css-tags */}
|
||||
<link rel="stylesheet" href="/preloader.css" media="all" />
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/x-icon"
|
||||
@@ -22,7 +24,7 @@ export default function Document() {
|
||||
<script src="/assets/env-config.js" type="text/javascript" />
|
||||
) : null}
|
||||
</Head>
|
||||
<body className="font-alpha liga-0-calt-0">
|
||||
<body className="font-alpha">
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
.pre-loader {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(0) {
|
||||
animation-delay: 0ms;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:first-child {
|
||||
animation-delay: -0.2s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(2) {
|
||||
animation-delay: 0.1s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(3) {
|
||||
animation-delay: -0.15s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(4) {
|
||||
animation-delay: 1s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(5) {
|
||||
animation-delay: -0.25s;
|
||||
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.05s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(8) {
|
||||
animation-delay: 0.8s;
|
||||
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: 0.5s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(11) {
|
||||
animation-delay: -2.75s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(12) {
|
||||
animation-delay: 2.4s;
|
||||
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: -3s;
|
||||
animation-direction: alternate;
|
||||
}
|
||||
.pre-loader .loader-item:nth-child(16) {
|
||||
animation-delay: 2.4s;
|
||||
animation-direction: reverse;
|
||||
}
|
||||
.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 {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: #000;
|
||||
animation: flickering 0.4s steps(2, jump-none) infinite alternate;
|
||||
}
|
||||
@keyframes flickering {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
25% {
|
||||
opacity: 1;
|
||||
}
|
||||
26% {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@@ -98,7 +98,7 @@ export const AssetDetailsDialog = ({
|
||||
}}
|
||||
>
|
||||
{content}
|
||||
<p className="text-sm mb-4">
|
||||
<p className="text-sm my-4">
|
||||
{t(
|
||||
'There is 1 unit of the settlement asset (%s) to every 1 quote unit.',
|
||||
[assetSymbol]
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { useEtherscanLink } from '@vegaprotocol/environment';
|
||||
import { ContractAddressLink } from '@vegaprotocol/environment';
|
||||
import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers';
|
||||
import type * as Schema from '@vegaprotocol/types';
|
||||
import type { KeyValueTableRowProps } from '@vegaprotocol/ui-toolkit';
|
||||
import { CopyWithTooltip, Icon } from '@vegaprotocol/ui-toolkit';
|
||||
import { Link } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
KeyValueTable,
|
||||
KeyValueTableRow,
|
||||
@@ -276,16 +275,3 @@ export const AssetDetailsTable = ({
|
||||
</KeyValueTable>
|
||||
);
|
||||
};
|
||||
|
||||
// Separate component for the link as otherwise eslint will complain
|
||||
// about useEnvironment being used in a component
|
||||
// named with a lowercase 'value'
|
||||
const ContractAddressLink = ({ address }: { address: string }) => {
|
||||
const etherscanLink = useEtherscanLink();
|
||||
const href = etherscanLink(`/address/${address}`);
|
||||
return (
|
||||
<Link href={href} target="_blank" title={t('View on etherscan')}>
|
||||
{address}
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -18,6 +18,7 @@ import { addMockTransactionResponse } from './lib/commands/mock-transaction-resp
|
||||
import { addCreateMarket } from './lib/commands/create-market';
|
||||
import { addConnectPublicKey } from './lib/commands/add-connect-public-key';
|
||||
import { addVegaWalletSubmitProposal } from './lib/commands/vega-wallet-submit-proposal';
|
||||
import { addGetNodes } from './lib/commands/get-nodes';
|
||||
|
||||
addGetTestIdcommand();
|
||||
addSlackCommand();
|
||||
@@ -28,6 +29,7 @@ addMockWeb3ProviderCommand();
|
||||
addHighlightLog();
|
||||
addVegaWalletReceiveFaucetedAsset();
|
||||
addGetAssets();
|
||||
addGetNodes();
|
||||
addContainsExactly();
|
||||
addGetNetworkParameters();
|
||||
addUpdateCapsuleMultiSig();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user