Merge branch 'master' of github.com:vegaprotocol/frontend-monorepo
This commit is contained in:
commit
f51681cb86
@ -28,3 +28,9 @@ Feature: Blocks Page
|
||||
And jump to first block
|
||||
Then previous button is disabled
|
||||
And I am on the second block when I click next
|
||||
|
||||
Scenario: Infinite scroll shows at least 300 new blocks
|
||||
Given I am on the homepage
|
||||
When I navigate to the blocks page
|
||||
And I scroll down to the last block on the page
|
||||
Then I can expect to see at least 100 blocks if i scroll 7 times
|
@ -14,10 +14,10 @@ export default class BlocksPage extends BasePage {
|
||||
nextBlockBtn = 'next-block';
|
||||
jumpToBlockInput = 'block-input';
|
||||
jumpToBlockSubmit = 'go-submit';
|
||||
infiniteScrollWrapper = 'infinite-scroll-wrapper';
|
||||
|
||||
private waitForBlocksResponse() {
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(1000);
|
||||
cy.contains('Loading...').should('not.exist', { timeout: 18000 });
|
||||
}
|
||||
|
||||
validateBlocksPageDisplayed() {
|
||||
@ -37,8 +37,6 @@ export default class BlocksPage extends BasePage {
|
||||
validateBlockValidatorPage() {
|
||||
cy.getByTestId(this.minedByValidator).should('not.be.empty');
|
||||
cy.getByTestId(this.blockTime).should('not.be.empty');
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(1000); // Wait for transactions to load if there are any
|
||||
cy.get('body').then(($body) => {
|
||||
if ($body.find(`[data-testid=${this.transactionsRow}] > td`).length) {
|
||||
cy.get(`[data-testid=${this.transactionsRow}] > td`).each(($cell) => {
|
||||
@ -85,6 +83,50 @@ export default class BlocksPage extends BasePage {
|
||||
});
|
||||
}
|
||||
|
||||
navigateToLastBlockOnPage() {
|
||||
this.waitForBlocksResponse();
|
||||
cy.getByTestId(this.infiniteScrollWrapper).children().scrollTo('bottom');
|
||||
}
|
||||
|
||||
navigateToOlderBlocksWithInfiniteScroll(
|
||||
expectedBlocks: number,
|
||||
scrollAttempts: number
|
||||
) {
|
||||
cy.intercept('*blockchain?maxHeight*').as('blockchain_load');
|
||||
|
||||
cy.getByTestId(this.blockHeight)
|
||||
.last()
|
||||
.invoke('text')
|
||||
.then(($initialLastBlockHeight) => {
|
||||
for (let index = 0; index < scrollAttempts; index++) {
|
||||
cy.getByTestId(this.infiniteScrollWrapper)
|
||||
.children()
|
||||
.children()
|
||||
.invoke('css', 'height')
|
||||
.then((scrollTarget) => {
|
||||
cy.getByTestId(this.infiniteScrollWrapper)
|
||||
.children()
|
||||
.scrollTo(0, scrollTarget.toString(), { easing: 'linear' })
|
||||
.wait('@blockchain_load');
|
||||
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(50); // Need this as although network response has arrived it takes a few millisecs for the css height to expand
|
||||
});
|
||||
}
|
||||
|
||||
cy.getByTestId(this.blockHeight)
|
||||
.last()
|
||||
.invoke('text')
|
||||
.then(($lastBlockHeight) => {
|
||||
const totalBlocksLoadedSinceScrollBegan =
|
||||
parseInt($initialLastBlockHeight) - parseInt($lastBlockHeight);
|
||||
expect(totalBlocksLoadedSinceScrollBegan).to.be.at.least(
|
||||
expectedBlocks
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
clickPreviousBlock() {
|
||||
cy.getByTestId(this.previousBlockBtn).click();
|
||||
}
|
||||
|
@ -34,3 +34,17 @@ Then('previous button is disabled', () => {
|
||||
Then('I am on the second block when I click next', () => {
|
||||
blocksPage.navigateToNextBlock();
|
||||
});
|
||||
|
||||
Then('I scroll down to the last block on the page', () => {
|
||||
blocksPage.navigateToLastBlockOnPage();
|
||||
});
|
||||
|
||||
Then(
|
||||
'I can expect to see at least {int} blocks if i scroll {int} times',
|
||||
(expectedBlocks, scrollAttempts) => {
|
||||
blocksPage.navigateToOlderBlocksWithInfiniteScroll(
|
||||
expectedBlocks,
|
||||
scrollAttempts
|
||||
);
|
||||
}
|
||||
);
|
||||
|
@ -18,12 +18,13 @@ NX_URL=$URL
|
||||
NX_DEPLOY_URL=$DEPLOY_URL
|
||||
NX_DEPLOY_PRIME_URL=$DEPLOY_PRIME_URL
|
||||
|
||||
NX_CHAIN_EXPLORER_URL = "https://explorer.vega.trading/.netlify/functions/chain-explorer-api"
|
||||
NX_TENDERMINT_URL = "https://lb.testnet.vega.xyz/tm"
|
||||
NX_TENDERMINT_WEBSOCKET_URL = "wss://lb.testnet.vega.xyz/tm/websocket"
|
||||
NX_VEGA_URL = "https://lb.testnet.vega.xyz/query"
|
||||
NX_CHAIN_EXPLORER_URL = 'https://explorer.vega.trading/.netlify/functions/chain-explorer-api'
|
||||
NX_TENDERMINT_URL = 'https://lb.testnet.vega.xyz/tm'
|
||||
NX_TENDERMINT_WEBSOCKET_URL = 'wss://lb.testnet.vega.xyz/tm/websocket'
|
||||
NX_VEGA_URL = 'https://lb.testnet.vega.xyz/query'
|
||||
NX_VEGA_ENV = 'TESTNET'
|
||||
NX_VEGA_REST = 'https://lb.testnet.vega.xyz/datanode/rest'
|
||||
NX_VEGA_NETWORKS = '{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}'
|
||||
CYPRESS_VEGA_TENDERMINT_URL='https://lb.testnet.vega.xyz/tm'
|
||||
|
||||
# App flags
|
||||
|
@ -3,6 +3,7 @@ NX_CHAIN_EXPLORER_URL = "https://explorer.vega.trading/.netlify/functions/chain-
|
||||
NX_TENDERMINT_URL = "http://localhost:26617"
|
||||
NX_TENDERMINT_WEBSOCKET_URL = "wss://localhost:26617/websocket"
|
||||
NX_VEGA_URL = "http://localhost:3028/query"
|
||||
NX_VEGA_NETWORKS = '{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}'
|
||||
NX_VEGA_ENV = 'LOCAL'
|
||||
NX_VEGA_REST = 'http://localhost:3029'
|
||||
|
||||
|
@ -3,5 +3,6 @@ NX_CHAIN_EXPLORER_URL = "https://explorer.vega.trading/.netlify/functions/chain-
|
||||
NX_TENDERMINT_URL = "https://n04.d.vega.xyz/tm"
|
||||
NX_TENDERMINT_WEBSOCKET_URL = "wss://n04.d.vega.xyz/tm/websocket"
|
||||
NX_VEGA_URL = "https://n04.d.vega.xyz/query"
|
||||
NX_VEGA_NETWORKS = '{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}'
|
||||
NX_VEGA_ENV = 'DEVNET'
|
||||
NX_VEGA_REST = 'https://n04.d.vega.xyz/datanode/rest'
|
||||
|
@ -3,5 +3,6 @@ NX_CHAIN_EXPLORER_URL = "https://explorer.vega.trading/.netlify/functions/chain-
|
||||
NX_TENDERMINT_URL = "https://mainnet-observer-proxy01.ops.vega.xyz/"
|
||||
NX_TENDERMINT_WEBSOCKET_URL = "wss://mainnet-observer-proxy01.ops.vega.xyz/websocket"
|
||||
NX_VEGA_URL = "https://api.token.vega.xyz/query"
|
||||
NX_VEGA_NETWORKS = '{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}'
|
||||
NX_VEGA_ENV = 'MAINNET'
|
||||
NX_VEGA_REST = 'https://api.token.vega.xyz/'
|
||||
|
@ -3,5 +3,6 @@ NX_CHAIN_EXPLORER_URL = "https://explorer.vega.trading/.netlify/functions/chain-
|
||||
NX_TENDERMINT_URL = "https://n03.s.vega.xyz/tm"
|
||||
NX_TENDERMINT_WEBSOCKET_URL = "wss://n03.s.vega.xyz/tm/websocket"
|
||||
NX_VEGA_URL = "https://n03.s.vega.xyz/query"
|
||||
NX_VEGA_NETWORKS = '{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}'
|
||||
NX_VEGA_ENV = 'STAGNET'
|
||||
NX_VEGA_REST = 'https://n03.s.vega.xyz/datanode/rest'
|
||||
|
@ -3,5 +3,6 @@ NX_CHAIN_EXPLORER_URL = "https://explorer.vega.trading/.netlify/functions/chain-
|
||||
NX_TENDERMINT_URL = "https://n03.stagnet2.vega.xyz/tm"
|
||||
NX_TENDERMINT_WEBSOCKET_URL = "wss://n03.stagnet2.vega.xyz/tm/websocket"
|
||||
NX_VEGA_URL = "https://n03.stagnet2.vega.xyz/query"
|
||||
NX_VEGA_NETWORKS = '{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}'
|
||||
NX_VEGA_ENV = 'STAGNET2'
|
||||
NX_VEGA_REST = 'https://n01.stagnet2.vega.xyz/datanode/rest'
|
||||
|
@ -3,5 +3,6 @@ NX_CHAIN_EXPLORER_URL = "https://explorer.vega.trading/.netlify/functions/chain-
|
||||
NX_TENDERMINT_URL = "https://lb.testnet.vega.xyz/tm"
|
||||
NX_TENDERMINT_WEBSOCKET_URL = "wss://lb.testnet.vega.xyz/tm/websocket"
|
||||
NX_VEGA_URL = "https://lb.testnet.vega.xyz/query"
|
||||
NX_VEGA_NETWORKS = '{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz"}'
|
||||
NX_VEGA_ENV = 'TESTNET'
|
||||
NX_VEGA_REST = 'https://lb.testnet.vega.xyz/datanode/rest'
|
||||
|
@ -1,11 +1,8 @@
|
||||
import { useState, useEffect, useMemo } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { ApolloProvider } from '@apollo/client';
|
||||
import { ThemeContext } from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
useThemeSwitcher,
|
||||
EnvironmentProvider,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import { ThemeContext, useThemeSwitcher } from '@vegaprotocol/react-helpers';
|
||||
import { EnvironmentProvider } from '@vegaprotocol/network-switcher';
|
||||
import { createClient } from './lib/apollo-client';
|
||||
import { Nav } from './components/nav';
|
||||
import { Header } from './components/header';
|
||||
|
@ -6,6 +6,7 @@ const vegaCustomClasses = require('../../libs/tailwindcss-config/src/vega-custom
|
||||
module.exports = {
|
||||
content: [
|
||||
join(__dirname, 'src/**/*.{js,ts,jsx,tsx}'),
|
||||
'libs/ui-toolkit/src/utils/shared.ts',
|
||||
...createGlobPatternsForDependencies(__dirname),
|
||||
],
|
||||
darkMode: 'class',
|
||||
|
@ -9,7 +9,7 @@ import {
|
||||
VegaManageDialog,
|
||||
VegaWalletProvider,
|
||||
} from '@vegaprotocol/wallet';
|
||||
import { EnvironmentProvider } from '@vegaprotocol/react-helpers';
|
||||
import { EnvironmentProvider } from '@vegaprotocol/network-switcher';
|
||||
import { VegaWalletConnectButton } from './components/vega-wallet-connect-button';
|
||||
import { ThemeSwitcher } from '@vegaprotocol/ui-toolkit';
|
||||
import { Connectors } from './lib/vega-connectors';
|
||||
|
59
apps/simple-trading-app/src/app/components/deal-ticket/__generated__/PartyBalanceQuery.ts
generated
Normal file
59
apps/simple-trading-app/src/app/components/deal-ticket/__generated__/PartyBalanceQuery.ts
generated
Normal file
@ -0,0 +1,59 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @generated
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: PartyBalanceQuery
|
||||
// ====================================================
|
||||
|
||||
export interface PartyBalanceQuery_party_accounts_asset {
|
||||
__typename: "Asset";
|
||||
/**
|
||||
* The id of the asset
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* The symbol of the asset (e.g: GBP)
|
||||
*/
|
||||
symbol: string;
|
||||
/**
|
||||
* The full name of the asset (e.g: Great British Pound)
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* The precision of the asset
|
||||
*/
|
||||
decimals: number;
|
||||
}
|
||||
|
||||
export interface PartyBalanceQuery_party_accounts {
|
||||
__typename: "Account";
|
||||
/**
|
||||
* Balance as string - current account balance (approx. as balances can be updated several times per second)
|
||||
*/
|
||||
balance: string;
|
||||
/**
|
||||
* Asset, the 'currency'
|
||||
*/
|
||||
asset: PartyBalanceQuery_party_accounts_asset;
|
||||
}
|
||||
|
||||
export interface PartyBalanceQuery_party {
|
||||
__typename: "Party";
|
||||
/**
|
||||
* Collateral accounts relating to a party
|
||||
*/
|
||||
accounts: PartyBalanceQuery_party_accounts[] | null;
|
||||
}
|
||||
|
||||
export interface PartyBalanceQuery {
|
||||
/**
|
||||
* An entity that is trading on the VEGA network
|
||||
*/
|
||||
party: PartyBalanceQuery_party | null;
|
||||
}
|
||||
|
||||
export interface PartyBalanceQueryVariables {
|
||||
partyId: string;
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
import * as React from 'react';
|
||||
import type { DealTicketQuery_market_tradableInstrument_instrument_product_settlementAsset } from '@vegaprotocol/deal-ticket';
|
||||
import type { PartyBalanceQuery_party_accounts } from './__generated__/PartyBalanceQuery';
|
||||
import { useSettlementAccount } from '../../hooks/use-settlement-account';
|
||||
import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers';
|
||||
|
||||
interface DealTicketBalanceProps {
|
||||
settlementAsset: DealTicketQuery_market_tradableInstrument_instrument_product_settlementAsset;
|
||||
accounts: PartyBalanceQuery_party_accounts[];
|
||||
isWalletConnected: boolean;
|
||||
}
|
||||
|
||||
export const DealTicketBalance = ({
|
||||
settlementAsset,
|
||||
accounts,
|
||||
isWalletConnected,
|
||||
}: DealTicketBalanceProps) => {
|
||||
const settlementAssetId = settlementAsset?.id;
|
||||
const settlementAssetSymbol = settlementAsset?.symbol;
|
||||
const settlementAccount = useSettlementAccount(settlementAssetId, accounts);
|
||||
const formatedNumber =
|
||||
settlementAccount?.balance &&
|
||||
settlementAccount.asset.decimals &&
|
||||
addDecimalsFormatNumber(
|
||||
settlementAccount.balance,
|
||||
settlementAccount.asset.decimals
|
||||
);
|
||||
|
||||
const balance = settlementAccount ? (
|
||||
<p>
|
||||
{t(
|
||||
`${formatedNumber} ${settlementAccount.asset.symbol} available to trade`
|
||||
)}
|
||||
</p>
|
||||
) : (
|
||||
<p>{t(`You have no ${settlementAssetSymbol} available to trade`)}</p>
|
||||
);
|
||||
|
||||
const connectWallet = (
|
||||
<p>
|
||||
{t(
|
||||
"Please connect your Vega wallet to see your balance for this market's settlement asset"
|
||||
)}
|
||||
</p>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="text-right">
|
||||
<div className="border border-current p-16 inline-block">
|
||||
<small className="text-text">{t('Balance')}</small>
|
||||
{isWalletConnected ? balance : connectWallet}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -4,15 +4,58 @@ import {
|
||||
DealTicketContainer as Container,
|
||||
} from '@vegaprotocol/deal-ticket';
|
||||
import { DealTicketSteps } from './deal-ticket-steps';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { gql, useQuery } from '@apollo/client';
|
||||
import { DealTicketBalance } from './deal-ticket-balance';
|
||||
import * as React from 'react';
|
||||
import type { PartyBalanceQuery } from './__generated__/PartyBalanceQuery';
|
||||
|
||||
const tempEmptyText = <p>Please select a market from the markets page</p>;
|
||||
|
||||
const PARTY_BALANCE_QUERY = gql`
|
||||
query PartyBalanceQuery($partyId: ID!) {
|
||||
party(id: $partyId) {
|
||||
accounts {
|
||||
balance
|
||||
asset {
|
||||
id
|
||||
symbol
|
||||
name
|
||||
decimals
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const DealTicketContainer = () => {
|
||||
const { marketId } = useParams<{ marketId: string }>();
|
||||
const { keypair } = useVegaWallet();
|
||||
|
||||
const { data: partyData, loading } = useQuery<PartyBalanceQuery>(
|
||||
PARTY_BALANCE_QUERY,
|
||||
{
|
||||
variables: { partyId: keypair?.pub },
|
||||
skip: !keypair?.pub,
|
||||
}
|
||||
);
|
||||
|
||||
return marketId ? (
|
||||
<Container marketId={marketId}>
|
||||
{(data) => (
|
||||
<DealTicketManager market={data.market}>
|
||||
{loading ? (
|
||||
'Loading...'
|
||||
) : (
|
||||
<DealTicketBalance
|
||||
settlementAsset={
|
||||
data.market.tradableInstrument.instrument.product
|
||||
?.settlementAsset
|
||||
}
|
||||
accounts={partyData?.party?.accounts || []}
|
||||
isWalletConnected={!!keypair?.pub}
|
||||
/>
|
||||
)}
|
||||
<DealTicketSteps market={data.market} />
|
||||
</DealTicketManager>
|
||||
)}
|
||||
|
@ -1,15 +1,15 @@
|
||||
import { TailwindIntents } from '@vegaprotocol/ui-toolkit';
|
||||
import { Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import { MarketState } from '@vegaprotocol/types';
|
||||
|
||||
export const MARKET_STATUS: Record<MarketState | '', TailwindIntents> = {
|
||||
[MarketState.Active]: TailwindIntents.Success,
|
||||
[MarketState.Cancelled]: TailwindIntents.Highlight,
|
||||
[MarketState.Closed]: TailwindIntents.Help,
|
||||
[MarketState.Pending]: TailwindIntents.Warning,
|
||||
[MarketState.Proposed]: TailwindIntents.Prompt,
|
||||
[MarketState.Rejected]: TailwindIntents.Danger,
|
||||
[MarketState.Settled]: TailwindIntents.Highlight,
|
||||
[MarketState.Suspended]: TailwindIntents.Warning,
|
||||
[MarketState.TradingTerminated]: TailwindIntents.Danger,
|
||||
'': TailwindIntents.Highlight,
|
||||
export const MARKET_STATUS: Record<MarketState | '', Intent> = {
|
||||
[MarketState.Active]: Intent.Success,
|
||||
[MarketState.Cancelled]: Intent.Primary,
|
||||
[MarketState.Closed]: Intent.None,
|
||||
[MarketState.Pending]: Intent.Warning,
|
||||
[MarketState.Proposed]: Intent.Warning,
|
||||
[MarketState.Rejected]: Intent.Danger,
|
||||
[MarketState.Settled]: Intent.Primary,
|
||||
[MarketState.Suspended]: Intent.Warning,
|
||||
[MarketState.TradingTerminated]: Intent.Danger,
|
||||
'': Intent.Primary,
|
||||
};
|
||||
|
@ -43,7 +43,7 @@ const getColor = (change: number | string) => {
|
||||
if (parseFloat(change as string) < 0) {
|
||||
return theme.colors.vega.pink;
|
||||
}
|
||||
return theme.colors.intent.highlight;
|
||||
return theme.colors.black[10];
|
||||
};
|
||||
|
||||
const SimpleMarketPercentChangeWrapper = (props: Props) => {
|
||||
|
@ -0,0 +1,61 @@
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { useSettlementAccount } from './use-settlement-account';
|
||||
import type { PartyBalanceQuery_party_accounts } from '../components/deal-ticket/__generated__/PartyBalanceQuery';
|
||||
|
||||
describe('useSettlementAccount Hook', () => {
|
||||
it('should filter accounts by settlementAssetId', () => {
|
||||
const accounts: PartyBalanceQuery_party_accounts[] = [
|
||||
{
|
||||
__typename: 'Account',
|
||||
balance: '2000000000000000000000',
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
|
||||
symbol: 'tBTC',
|
||||
name: 'tBTC TEST',
|
||||
decimals: 5,
|
||||
},
|
||||
},
|
||||
{
|
||||
__typename: 'Account',
|
||||
balance: '1000000000',
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
|
||||
symbol: 'tDAI',
|
||||
name: 'tDAI TEST',
|
||||
decimals: 5,
|
||||
},
|
||||
},
|
||||
{
|
||||
__typename: 'Account',
|
||||
balance: '5000000000000000000',
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
id: 'fc7fd956078fb1fc9db5c19b88f0874c4299b2a7639ad05a47a28c0aef291b55',
|
||||
symbol: 'VEGA',
|
||||
name: 'Vega (testnet)',
|
||||
decimals: 18,
|
||||
},
|
||||
},
|
||||
];
|
||||
const settlementAssetId =
|
||||
'6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61';
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useSettlementAccount(settlementAssetId, accounts)
|
||||
);
|
||||
expect(result.current?.balance).toBe(accounts[1].balance);
|
||||
expect(result.current?.asset).toEqual(accounts[1].asset);
|
||||
});
|
||||
|
||||
it('should return null if no accounts', () => {
|
||||
const accounts: PartyBalanceQuery_party_accounts[] = [];
|
||||
const settlementAssetId =
|
||||
'6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61';
|
||||
const { result } = renderHook(() =>
|
||||
useSettlementAccount(settlementAssetId, accounts)
|
||||
);
|
||||
expect(result.current).toBe(undefined);
|
||||
});
|
||||
});
|
@ -0,0 +1,12 @@
|
||||
import type { PartyBalanceQuery_party_accounts } from '../components/deal-ticket/__generated__/PartyBalanceQuery';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useSettlementAccount = (
|
||||
settlementAssetId: string,
|
||||
accounts: PartyBalanceQuery_party_accounts[]
|
||||
): PartyBalanceQuery_party_accounts | null => {
|
||||
const callback = () =>
|
||||
accounts.find((account) => account.asset.id === settlementAssetId);
|
||||
const account = useMemo(callback, [accounts, settlementAssetId]);
|
||||
return account as PartyBalanceQuery_party_accounts;
|
||||
};
|
@ -6,6 +6,7 @@ const vegaCustomClasses = require('../../libs/tailwindcss-config/src/vega-custom
|
||||
module.exports = {
|
||||
content: [
|
||||
join(__dirname, 'src/**/*.{js,ts,jsx,tsx}'),
|
||||
'libs/ui-toolkit/src/utils/shared.ts',
|
||||
...createGlobPatternsForDependencies(__dirname),
|
||||
],
|
||||
darkMode: 'class',
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -38,7 +38,7 @@
|
||||
"tranche_end": "2022-11-26T13:48:10.000Z",
|
||||
"total_added": "100",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "47.187921740233385",
|
||||
"locked_amount": "45.544174911212587",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "100",
|
||||
@ -242,7 +242,7 @@
|
||||
"tranche_end": "2022-10-12T00:53:20.000Z",
|
||||
"total_added": "100",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "34.71173579401319",
|
||||
"locked_amount": "33.06798896499239",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "100",
|
||||
|
@ -67,12 +67,112 @@
|
||||
"tranche_id": 2,
|
||||
"tranche_start": "2021-10-12T00:53:20.000Z",
|
||||
"tranche_end": "2022-10-12T00:53:20.000Z",
|
||||
"total_added": "0",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "0",
|
||||
"deposits": [],
|
||||
"withdrawals": [],
|
||||
"users": []
|
||||
"total_added": "1010.000000000000000001",
|
||||
"total_removed": "668.3761174488",
|
||||
"locked_amount": "333.9866885464231390003306798896499239",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1000",
|
||||
"user": "0x0d18ACaa868f87BB4666F918326141cAEAe893Fa",
|
||||
"tx": "0x6c22362848c237c4a5c7134e88c179d6ba90cb79498e0b7a33e4c76089448ddd"
|
||||
},
|
||||
{
|
||||
"amount": "10.000000000000000001",
|
||||
"user": "0x970Bf6C66E55f90a7D455354954Af5CaBA11318C",
|
||||
"tx": "0xcab88d53d9fe946b7089ce0b2e252ed6a589bc8a1900a733fdd6bd3a6fc6f514"
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "661.48985286",
|
||||
"user": "0x0d18ACaa868f87BB4666F918326141cAEAe893Fa",
|
||||
"tx": "0xdabed7e1d1f354e9102f3a678db8fa80cad17596be9b73f9b517fb0417a56954"
|
||||
},
|
||||
{
|
||||
"amount": "6.6172349061",
|
||||
"user": "0x970Bf6C66E55f90a7D455354954Af5CaBA11318C",
|
||||
"tx": "0x5ff4b9826a54f8540e246519c5d3bd4a8ef1adc4fbfc324cf864beef8abd1a97"
|
||||
},
|
||||
{
|
||||
"amount": "0.26864536",
|
||||
"user": "0x0d18ACaa868f87BB4666F918326141cAEAe893Fa",
|
||||
"tx": "0x7f8b379c5718352726b63438a4352e0d5657d7f0f08bf103c6fe942226e6d69d"
|
||||
},
|
||||
{
|
||||
"amount": "0.0003652968",
|
||||
"user": "0x970Bf6C66E55f90a7D455354954Af5CaBA11318C",
|
||||
"tx": "0xf65916a587ded089d316b8c9b7ca2d6300f5814beb190860c1bb76dc41e63148"
|
||||
},
|
||||
{
|
||||
"amount": "0.0000190259",
|
||||
"user": "0x970Bf6C66E55f90a7D455354954Af5CaBA11318C",
|
||||
"tx": "0xcbc22a50267244f1cbb61c1018270f7e9d0052815141c7c1158393036e93be5b"
|
||||
}
|
||||
],
|
||||
"users": [
|
||||
{
|
||||
"address": "0x0d18ACaa868f87BB4666F918326141cAEAe893Fa",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1000",
|
||||
"user": "0x0d18ACaa868f87BB4666F918326141cAEAe893Fa",
|
||||
"tranche_id": 2,
|
||||
"tx": "0x6c22362848c237c4a5c7134e88c179d6ba90cb79498e0b7a33e4c76089448ddd"
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "661.48985286",
|
||||
"user": "0x0d18ACaa868f87BB4666F918326141cAEAe893Fa",
|
||||
"tranche_id": 2,
|
||||
"tx": "0xdabed7e1d1f354e9102f3a678db8fa80cad17596be9b73f9b517fb0417a56954"
|
||||
},
|
||||
{
|
||||
"amount": "0.26864536",
|
||||
"user": "0x0d18ACaa868f87BB4666F918326141cAEAe893Fa",
|
||||
"tranche_id": 2,
|
||||
"tx": "0x7f8b379c5718352726b63438a4352e0d5657d7f0f08bf103c6fe942226e6d69d"
|
||||
}
|
||||
],
|
||||
"total_tokens": "1000",
|
||||
"withdrawn_tokens": "661.75849822",
|
||||
"remaining_tokens": "338.24150178"
|
||||
},
|
||||
{
|
||||
"address": "0x970Bf6C66E55f90a7D455354954Af5CaBA11318C",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "10.000000000000000001",
|
||||
"user": "0x970Bf6C66E55f90a7D455354954Af5CaBA11318C",
|
||||
"tranche_id": 2,
|
||||
"tx": "0xcab88d53d9fe946b7089ce0b2e252ed6a589bc8a1900a733fdd6bd3a6fc6f514"
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "6.6172349061",
|
||||
"user": "0x970Bf6C66E55f90a7D455354954Af5CaBA11318C",
|
||||
"tranche_id": 2,
|
||||
"tx": "0x5ff4b9826a54f8540e246519c5d3bd4a8ef1adc4fbfc324cf864beef8abd1a97"
|
||||
},
|
||||
{
|
||||
"amount": "0.0003652968",
|
||||
"user": "0x970Bf6C66E55f90a7D455354954Af5CaBA11318C",
|
||||
"tranche_id": 2,
|
||||
"tx": "0xf65916a587ded089d316b8c9b7ca2d6300f5814beb190860c1bb76dc41e63148"
|
||||
},
|
||||
{
|
||||
"amount": "0.0000190259",
|
||||
"user": "0x970Bf6C66E55f90a7D455354954Af5CaBA11318C",
|
||||
"tranche_id": 2,
|
||||
"tx": "0xcbc22a50267244f1cbb61c1018270f7e9d0052815141c7c1158393036e93be5b"
|
||||
}
|
||||
],
|
||||
"total_tokens": "10.000000000000000001",
|
||||
"withdrawn_tokens": "6.6176192288",
|
||||
"remaining_tokens": "3.382380771200000001"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tranche_id": 3,
|
||||
|
@ -3,7 +3,7 @@ import { DATA_SOURCES } from './config';
|
||||
import { Header } from './components/header';
|
||||
import { StatsManager } from '@vegaprotocol/network-stats';
|
||||
import { ThemeContext } from '@vegaprotocol/react-helpers';
|
||||
import { EnvironmentProvider } from '@vegaprotocol/react-helpers';
|
||||
import { EnvironmentProvider } from '@vegaprotocol/network-switcher';
|
||||
import { useThemeSwitcher } from '@vegaprotocol/react-helpers';
|
||||
|
||||
const envName = DATA_SOURCES.envName;
|
||||
|
@ -6,6 +6,7 @@ const vegaCustomClasses = require('../../libs/tailwindcss-config/src/vega-custom
|
||||
module.exports = {
|
||||
content: [
|
||||
join(__dirname, 'src/**/*.{js,ts,jsx,tsx}'),
|
||||
'libs/ui-toolkit/src/utils/shared.ts',
|
||||
...createGlobPatternsForDependencies(__dirname),
|
||||
],
|
||||
darkMode: 'class',
|
||||
|
@ -6,7 +6,7 @@ describe('token', () => {
|
||||
it('should always have a header title based on environment', () => {
|
||||
cy.get('[data-testid="header-title"]', { timeout: 8000 }).should(
|
||||
'have.text',
|
||||
`${fairgroundSet ? 'Fairground token' : '$VEGA TOKEN'}`
|
||||
`${fairgroundSet ? 'Fairground token' : 'VEGA TOKEN'}`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -25,6 +25,8 @@ NX_ETHEREUM_CHAIN_ID = 3
|
||||
NX_ETHEREUM_PROVIDER_URL = "https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8"
|
||||
NX_ETHERSCAN_URL = "https://ropsten.etherscan.io"
|
||||
NX_FAIRGROUND = false
|
||||
NX_IS_NEW_BRIDGE_CONTRACT = true
|
||||
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET":"https://dev.token.vega.xyz","STAGNET2":"staging2.token.vega.xyz","TESTNET":"token.fairground.wtf","MAINNET":"token.vega.xyz"}'
|
||||
|
||||
#Test configuration variables
|
||||
CYPRESS_FAIRGROUND = false
|
||||
|
@ -1,6 +1,7 @@
|
||||
# App configuration variables
|
||||
NX_VEGA_ENV = "DEVNET"
|
||||
NX_VEGA_URL = "https://n04.d.vega.xyz/query"
|
||||
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET":"https://dev.token.vega.xyz","STAGNET2":"staging2.token.vega.xyz","TESTNET":"token.fairground.wtf","MAINNET":"token.vega.xyz"}'
|
||||
NX_ETHEREUM_CHAIN_ID = 3
|
||||
NX_ETHEREUM_PROVIDER_URL = "https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8"
|
||||
NX_ETHERSCAN_URL = "https://ropsten.etherscan.io"
|
||||
NX_ETHERSCAN_URL = "https://ropsten.etherscan.io"
|
||||
|
@ -1,6 +1,7 @@
|
||||
# App configuration variables
|
||||
NX_VEGA_ENV = "MAINNET"
|
||||
NX_VEGA_URL = "https://api.token.vega.xyz/query"
|
||||
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET":"https://dev.token.vega.xyz","STAGNET2":"staging2.token.vega.xyz","TESTNET":"token.fairground.wtf","MAINNET":"token.vega.xyz"}'
|
||||
NX_ETHEREUM_CHAIN_ID = 1
|
||||
NX_ETHEREUM_PROVIDER_URL = "https://mainnet.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8"
|
||||
NX_ETHERSCAN_URL = "https://etherscan.io"
|
||||
NX_ETHERSCAN_URL = "https://etherscan.io"
|
||||
|
@ -1,6 +1,7 @@
|
||||
# App configuration variables
|
||||
NX_VEGA_ENV = "STAGNET"
|
||||
NX_VEGA_URL = "https://n03.s.vega.xyz/query"
|
||||
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET":"https://dev.token.vega.xyz","STAGNET2":"staging2.token.vega.xyz","TESTNET":"token.fairground.wtf","MAINNET":"token.vega.xyz"}'
|
||||
NX_ETHEREUM_CHAIN_ID = 3
|
||||
NX_ETHEREUM_PROVIDER_URL = "https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8"
|
||||
NX_ETHERSCAN_URL = "https://ropsten.etherscan.io"
|
||||
NX_ETHERSCAN_URL = "https://ropsten.etherscan.io"
|
||||
|
@ -1,6 +1,7 @@
|
||||
# App configuration variables
|
||||
NX_VEGA_ENV = "STAGNET2"
|
||||
NX_VEGA_URL = "https://n03.stagnet2.vega.xyz/query"
|
||||
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET":"https://dev.token.vega.xyz","STAGNET2":"staging2.token.vega.xyz","TESTNET":"token.fairground.wtf","MAINNET":"token.vega.xyz"}'
|
||||
NX_ETHEREUM_CHAIN_ID = 3
|
||||
NX_ETHEREUM_PROVIDER_URL = "https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8"
|
||||
NX_ETHERSCAN_URL = "https://ropsten.etherscan.io"
|
||||
NX_ETHERSCAN_URL = "https://ropsten.etherscan.io"
|
||||
|
@ -1,6 +1,7 @@
|
||||
# App configuration variables
|
||||
NX_VEGA_ENV = "TESTNET"
|
||||
NX_VEGA_URL = "https://lb.testnet.vega.xyz/query"
|
||||
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET":"https://dev.token.vega.xyz","STAGNET2":"staging2.token.vega.xyz","TESTNET":"token.fairground.wtf","MAINNET":"token.vega.xyz"}'
|
||||
NX_ETHEREUM_CHAIN_ID = 3
|
||||
NX_ETHEREUM_PROVIDER_URL = "https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8"
|
||||
NX_ETHERSCAN_URL = "https://ropsten.etherscan.io"
|
||||
NX_ETHERSCAN_URL = "https://ropsten.etherscan.io"
|
||||
|
@ -1,4 +1,5 @@
|
||||
import * as Sentry from '@sentry/react';
|
||||
import { toBigNum } from '@vegaprotocol/react-helpers';
|
||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet, useEagerConnect } from '@vegaprotocol/wallet';
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
@ -43,11 +44,16 @@ export const AppLoader = ({ children }: { children: React.ReactElement }) => {
|
||||
vesting.totalStaked(),
|
||||
token.decimals(),
|
||||
]);
|
||||
|
||||
const totalSupply = toBigNum(supply, decimals);
|
||||
const totalWallet = toBigNum(totalAssociatedWallet, decimals);
|
||||
const totalVesting = toBigNum(totalAssociatedVesting, decimals);
|
||||
|
||||
appDispatch({
|
||||
type: AppStateActionType.SET_TOKEN,
|
||||
decimals,
|
||||
totalSupply: supply,
|
||||
totalAssociated: totalAssociatedWallet.plus(totalAssociatedVesting),
|
||||
totalSupply,
|
||||
totalAssociated: totalWallet.plus(totalVesting),
|
||||
});
|
||||
setBalancesLoaded(true);
|
||||
} catch (err) {
|
||||
|
@ -1,14 +1,12 @@
|
||||
import './i18n';
|
||||
|
||||
import React from 'react';
|
||||
import { ApolloProvider } from '@apollo/client';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
|
||||
import { AppLoader } from './app-loader';
|
||||
import { AppBanner } from './components/app-banner';
|
||||
import { AppFooter } from './components/app-footer';
|
||||
import { BalanceManager } from './components/balance-manager';
|
||||
import { EthWallet } from './components/eth-wallet';
|
||||
import { GraphQlProvider } from './components/graphql-provider';
|
||||
import { TemplateSidebar } from './components/page-templates/template-sidebar';
|
||||
import { TransactionModal } from './components/transactions-modal';
|
||||
import { VegaWallet } from './components/vega-wallet';
|
||||
@ -20,12 +18,13 @@ import { Web3Provider } from '@vegaprotocol/web3';
|
||||
import { Connectors } from './lib/web3-connectors';
|
||||
import { VegaWalletDialogs } from './components/vega-wallet-dialogs';
|
||||
import { VegaWalletProvider } from '@vegaprotocol/wallet';
|
||||
import { EnvironmentProvider } from '@vegaprotocol/react-helpers';
|
||||
import { EnvironmentProvider } from '@vegaprotocol/network-switcher';
|
||||
import { client } from './lib/apollo-client';
|
||||
|
||||
function App() {
|
||||
const sideBar = React.useMemo(() => [<EthWallet />, <VegaWallet />], []);
|
||||
return (
|
||||
<GraphQlProvider>
|
||||
<ApolloProvider client={client}>
|
||||
<Router>
|
||||
<EnvironmentProvider>
|
||||
<AppStateProvider>
|
||||
@ -55,7 +54,7 @@ function App() {
|
||||
</AppStateProvider>
|
||||
</EnvironmentProvider>
|
||||
</Router>
|
||||
</GraphQlProvider>
|
||||
</ApolloProvider>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,15 +1,15 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useEnvironment } from '@vegaprotocol/react-helpers';
|
||||
import { useEnvironment } from '@vegaprotocol/network-switcher';
|
||||
import { useAddAssetSupported } from '../../hooks/use-add-asset-to-wallet';
|
||||
import vegaVesting from '../../images/vega_vesting.png';
|
||||
import { AddTokenButtonLink } from '../add-token-button/add-token-button';
|
||||
import { Callout } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
export const AddLockedTokenAddress = () => {
|
||||
const { ADDRESSES } = useEnvironment();
|
||||
const { t } = useTranslation();
|
||||
const addSupported = useAddAssetSupported();
|
||||
const { ADDRESSES } = useEnvironment();
|
||||
return (
|
||||
<Callout
|
||||
title={t(
|
||||
|
@ -12,7 +12,7 @@ export const AppBanner = () => {
|
||||
return (
|
||||
<div className="bg-white p-8 text-black" role="alert">
|
||||
<p>
|
||||
<span className="inline-block relative top-[1px] text-intent-danger text-ui mr-[5px]">
|
||||
<span className="inline-block relative top-[1px] text-danger text-ui mr-[5px]">
|
||||
<Error />
|
||||
</span>
|
||||
{bannerMessage}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { Link } from '@vegaprotocol/ui-toolkit';
|
||||
import { Trans } from 'react-i18next';
|
||||
|
||||
import { Links } from '../../config';
|
||||
@ -13,8 +14,12 @@ export const AppFooter = () => {
|
||||
i18nKey="footerLinksText"
|
||||
components={{
|
||||
/* eslint-disable */
|
||||
feedbackLink: <a href={Links.FEEDBACK} />,
|
||||
githubLink: <a href={Links.GITHUB} />,
|
||||
feedbackLink: (
|
||||
<Link className="text-white underline" href={Links.FEEDBACK} />
|
||||
),
|
||||
githubLink: (
|
||||
<Link className="text-white underline" href={Links.GITHUB} />
|
||||
),
|
||||
/* eslint-enable */
|
||||
}}
|
||||
/>
|
||||
|
@ -1,8 +1,9 @@
|
||||
import * as Sentry from '@sentry/react';
|
||||
import { toBigNum } from '@vegaprotocol/react-helpers';
|
||||
import { useEthereumConfig } from '@vegaprotocol/web3';
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
import React from 'react';
|
||||
|
||||
import { useEnvironment } from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
AppStateActionType,
|
||||
useAppState,
|
||||
@ -10,17 +11,19 @@ import {
|
||||
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 { BigNumber } from '../../lib/bignumber';
|
||||
|
||||
interface BalanceManagerProps {
|
||||
children: React.ReactElement;
|
||||
}
|
||||
|
||||
export const BalanceManager = ({ children }: BalanceManagerProps) => {
|
||||
const { ADDRESSES } = useEnvironment();
|
||||
const contracts = useContracts();
|
||||
const { account } = useWeb3React();
|
||||
const { appDispatch } = useAppState();
|
||||
const {
|
||||
appState: { decimals },
|
||||
appDispatch,
|
||||
} = useAppState();
|
||||
const { config } = useEthereumConfig();
|
||||
|
||||
const getUserTrancheBalances = useGetUserTrancheBalances(
|
||||
account || '',
|
||||
@ -35,17 +38,26 @@ export const BalanceManager = ({ children }: BalanceManagerProps) => {
|
||||
// update balances on connect to Ethereum
|
||||
React.useEffect(() => {
|
||||
const updateBalances = async () => {
|
||||
if (!account) return;
|
||||
if (!account || !config) return;
|
||||
try {
|
||||
const [balance, walletBalance, lien, allowance] = await Promise.all([
|
||||
contracts.vesting.getUserBalanceAllTranches(account),
|
||||
const [b, w, stats, a] = await Promise.all([
|
||||
contracts.vesting.userTotalAllTranches(account),
|
||||
contracts.token.balanceOf(account),
|
||||
contracts.vesting.getLien(account),
|
||||
contracts.token.allowance(account, ADDRESSES.stakingBridge),
|
||||
contracts.vesting.userStats(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);
|
||||
|
||||
appDispatch({
|
||||
type: AppStateActionType.UPDATE_ACCOUNT_BALANCES,
|
||||
balance: new BigNumber(balance),
|
||||
balance,
|
||||
walletBalance,
|
||||
lien,
|
||||
allowance,
|
||||
@ -57,11 +69,12 @@ export const BalanceManager = ({ children }: BalanceManagerProps) => {
|
||||
|
||||
updateBalances();
|
||||
}, [
|
||||
decimals,
|
||||
appDispatch,
|
||||
contracts?.token,
|
||||
contracts?.vesting,
|
||||
account,
|
||||
ADDRESSES.stakingBridge,
|
||||
config,
|
||||
]);
|
||||
|
||||
// This use effect hook is very expensive and is kept separate to prevent expensive reloading of data.
|
||||
|
@ -9,7 +9,7 @@ interface BulletHeaderProps {
|
||||
export const BulletHeader = ({ tag, children, style }: BulletHeaderProps) => {
|
||||
return React.createElement(
|
||||
tag,
|
||||
{ className: 'mt-24 pt-8 pb-20 uppercase', style },
|
||||
{ className: 'mt-24 pt-8 pb-20 uppercase text-white', style },
|
||||
<>
|
||||
<span className="inline-block w-[12px] h-[12px] mr-12 bg-white" />
|
||||
{children}
|
||||
|
@ -1,39 +0,0 @@
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import {
|
||||
AppStateActionType,
|
||||
useAppState,
|
||||
} from '../../contexts/app-state/app-state-context';
|
||||
import { Ethereum } from '../icons';
|
||||
import { Button } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
interface EthWalletContainerProps {
|
||||
children: (address: string) => React.ReactElement;
|
||||
}
|
||||
|
||||
export const EthWalletContainer = ({ children }: EthWalletContainerProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { appDispatch } = useAppState();
|
||||
const { account } = useWeb3React();
|
||||
|
||||
if (!account) {
|
||||
return (
|
||||
<Button
|
||||
data-testid="connect-to-eth-btn"
|
||||
onClick={() =>
|
||||
appDispatch({
|
||||
type: AppStateActionType.SET_ETH_WALLET_OVERLAY,
|
||||
isOpen: true,
|
||||
})
|
||||
}
|
||||
>
|
||||
<div>{t('connectEthWallet')}</div>
|
||||
<Ethereum />
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
return children(account);
|
||||
};
|
@ -1 +0,0 @@
|
||||
export * from './eth-wallet-container';
|
@ -22,7 +22,7 @@ import {
|
||||
WalletCardHeader,
|
||||
WalletCardRow,
|
||||
} from '../wallet-card';
|
||||
import { Button, Loader } from '@vegaprotocol/ui-toolkit';
|
||||
import { Loader } from '@vegaprotocol/ui-toolkit';
|
||||
import { theme } from '@vegaprotocol/tailwindcss-config';
|
||||
|
||||
const Colors = theme.colors;
|
||||
@ -163,15 +163,15 @@ const ConnectedKey = () => {
|
||||
/>
|
||||
)}
|
||||
<WalletCardActions>
|
||||
<Link style={{ flex: 1 }} to={`${Routes.STAKING}/associate`}>
|
||||
<Button variant="primary" className="w-full">
|
||||
<Link className="flex-1" to={`${Routes.STAKING}/associate`}>
|
||||
<span className="flex items-center justify-center w-full text-center px-28 border h-28">
|
||||
{t('associate')}
|
||||
</Button>
|
||||
</span>
|
||||
</Link>
|
||||
<Link style={{ flex: 1 }} to={`${Routes.STAKING}/disassociate`}>
|
||||
<Button variant="primary" className="w-full">
|
||||
<Link className="flex-1" to={`${Routes.STAKING}/disassociate`}>
|
||||
<span className="flex items-center justify-center w-full px-28 border h-28">
|
||||
{t('disassociate')}
|
||||
</Button>
|
||||
</span>
|
||||
</Link>
|
||||
</WalletCardActions>
|
||||
</>
|
||||
@ -187,14 +187,14 @@ export const EthWallet = () => {
|
||||
return (
|
||||
<WalletCard>
|
||||
<WalletCardHeader>
|
||||
<h1 className="text-h3 px-8 uppercase">{t('ethereumKey')}</h1>
|
||||
<h1 className="text-h3 uppercase">{t('ethereumKey')}</h1>
|
||||
{account && (
|
||||
<div className="font-mono px-4 text-right">
|
||||
<div>{truncateMiddle(account)}</div>
|
||||
<div className="px-4 text-right">
|
||||
<div className="font-mono">{truncateMiddle(account)}</div>
|
||||
{pendingTxs && (
|
||||
<div>
|
||||
<Button
|
||||
className="flex gap-2 justify-between p-4, bg-black text-white flex-nowrap whitespace-nowrap"
|
||||
<button
|
||||
className="flex items-center gap-4 p-4 border whitespace-nowrap"
|
||||
data-testid="pending-transactions-btn"
|
||||
onClick={() =>
|
||||
appDispatch({
|
||||
@ -203,9 +203,9 @@ export const EthWallet = () => {
|
||||
})
|
||||
}
|
||||
>
|
||||
<Loader size="small" />
|
||||
<Loader size="small" forceTheme="light" />
|
||||
{t('pendingTransactions')}
|
||||
</Button>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -215,8 +215,8 @@ export const EthWallet = () => {
|
||||
{account ? (
|
||||
<ConnectedKey />
|
||||
) : (
|
||||
<Button
|
||||
className="fill button-secondary--inverted"
|
||||
<button
|
||||
className="w-full px-28 border h-28"
|
||||
onClick={() =>
|
||||
appDispatch({
|
||||
type: AppStateActionType.SET_ETH_WALLET_OVERLAY,
|
||||
@ -226,7 +226,7 @@ export const EthWallet = () => {
|
||||
data-test-id="connect-to-eth-wallet-button"
|
||||
>
|
||||
{t('connectEthWalletToAssociate')}
|
||||
</Button>
|
||||
</button>
|
||||
)}
|
||||
{account && (
|
||||
<WalletCardActions>
|
||||
|
@ -1,12 +0,0 @@
|
||||
import { ApolloProvider } from '@apollo/client';
|
||||
import React from 'react';
|
||||
|
||||
import { client } from '../../lib/apollo-client';
|
||||
|
||||
export const GraphQlProvider = ({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
return <ApolloProvider client={client}>{children}</ApolloProvider>;
|
||||
};
|
@ -1 +0,0 @@
|
||||
export * from './graphql-provider';
|
@ -7,7 +7,7 @@ export const Heading = ({ title }: HeadingProps) => {
|
||||
|
||||
return (
|
||||
<header className="my-0 mx-auto">
|
||||
<h1 className="font-alpha font-normal text-h3 uppercase m-0 mb-4">
|
||||
<h1 className="font-alpha calt text-h3 text-white uppercase mb-4">
|
||||
{title}
|
||||
</h1>
|
||||
</header>
|
||||
|
@ -1 +0,0 @@
|
||||
export * from './loader';
|
@ -1,35 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
interface LoaderProps {
|
||||
invert?: boolean;
|
||||
}
|
||||
|
||||
export const Loader = ({ invert = false }: LoaderProps) => {
|
||||
const [, forceRender] = React.useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
forceRender((x) => !x);
|
||||
}, 100);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<span className="flex flex-row flex-wrap w-[15px] h-[15px]">
|
||||
{new Array(9).fill(null).map((_, i) => {
|
||||
return (
|
||||
<span
|
||||
key={i}
|
||||
style={{
|
||||
opacity: Math.random() > 0.5 ? 1 : 0,
|
||||
}}
|
||||
className={`block w-5 h-5 opacity-0 ${
|
||||
invert ? 'bg-black' : 'bg-white'
|
||||
}`}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</span>
|
||||
);
|
||||
};
|
@ -15,7 +15,7 @@ const ProgressContents = ({
|
||||
}) => (
|
||||
<div
|
||||
className={`flex justify-between py-2 font-mono ${
|
||||
light ? 'gap-0 px-0 text-black' : 'gap-y-0 gap-x-4 px-4 text-black-60'
|
||||
light ? 'gap-0 px-0 text-black' : 'gap-y-0 gap-x-4 px-4'
|
||||
}`}
|
||||
>
|
||||
{children}
|
||||
@ -72,7 +72,7 @@ export const LockedProgress = ({
|
||||
unlocked,
|
||||
leftLabel,
|
||||
rightLabel,
|
||||
leftColor = Colors.pink,
|
||||
leftColor = Colors.vega.pink,
|
||||
rightColor = Colors.green.DEFAULT,
|
||||
light = false,
|
||||
}: LockedProgressProps) => {
|
||||
|
@ -5,14 +5,13 @@ import debounce from 'lodash/debounce';
|
||||
import React from 'react';
|
||||
import * as Dialog from '@radix-ui/react-dialog';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link, NavLink } from 'react-router-dom';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
|
||||
import { Flags } from '../../config';
|
||||
import {
|
||||
AppStateActionType,
|
||||
useAppState,
|
||||
} from '../../contexts/app-state/app-state-context';
|
||||
import vegaWhite from '../../images/vega_white.png';
|
||||
import { Routes } from '../../routes/router-config';
|
||||
import { EthWallet } from '../eth-wallet';
|
||||
import { VegaWallet } from '../vega-wallet';
|
||||
@ -36,14 +35,14 @@ export const Nav = () => {
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`p-8 ${
|
||||
className={`p-16 ${
|
||||
inverted
|
||||
? 'bg-clouds bg-no-repeat bg-cover bg-vega-yellow'
|
||||
: 'border-b-white border-b-1'
|
||||
}`}
|
||||
>
|
||||
{isDesktop && <NavHeader fairground={inverted} />}
|
||||
<div className="flex justify-between items-center mx-auto gap-12 lg:justify-start lg:ml-8">
|
||||
<div className="flex justify-between items-center mx-auto gap-12 lg:justify-start">
|
||||
{!isDesktop && <NavHeader fairground={inverted} />}
|
||||
<div className="flex gap-12 lg:flex-auto">
|
||||
{isDesktop ? (
|
||||
@ -61,76 +60,10 @@ const NavHeader = ({ fairground }: { fairground: boolean }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="h-[30px] inline-flex items-center ml-8 lg:h-40 uppercase">
|
||||
<Link to="/">
|
||||
{fairground ? (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="33"
|
||||
height="20"
|
||||
viewBox="0 0 200 116"
|
||||
fill="none"
|
||||
data-testid="fairground-icon"
|
||||
>
|
||||
<g clip-path="url(#clip0)">
|
||||
<path
|
||||
d="M70.5918 32.8569L70.5918 22.7932L60.5254 22.7932L60.5254 32.8569L70.5918 32.8569Z"
|
||||
fill="black"
|
||||
></path>
|
||||
<path
|
||||
d="M80.6641 83.2006L80.6641 73.1377L70.5977 73.1377L70.5977 83.2006L80.6641 83.2006Z"
|
||||
fill="black"
|
||||
></path>
|
||||
<path
|
||||
d="M70.5918 93.2409L70.5918 83.1772L60.5254 83.1772L60.5254 93.2409L70.5918 93.2409Z"
|
||||
fill="black"
|
||||
></path>
|
||||
<path
|
||||
d="M100.797 93.2636L100.797 73.1377L90.7305 73.1377L90.7305 93.2636L100.797 93.2636Z"
|
||||
fill="black"
|
||||
></path>
|
||||
<path
|
||||
d="M90.7285 103.33L90.7285 93.2671L80.662 93.2671L80.662 103.33L90.7285 103.33Z"
|
||||
fill="black"
|
||||
></path>
|
||||
<path
|
||||
d="M90.7285 22.8026L90.7285 12.74L80.662 12.74L80.662 22.8026L90.7285 22.8026Z"
|
||||
fill="black"
|
||||
></path>
|
||||
<path
|
||||
d="M110.869 12.6108L110.869 2.54785L100.803 2.54785L100.803 12.6108L110.869 12.6108Z"
|
||||
fill="black"
|
||||
></path>
|
||||
<path
|
||||
d="M120.934 103.326L120.934 73.1377L110.867 73.1377L110.867 103.326L120.934 103.326Z"
|
||||
fill="black"
|
||||
></path>
|
||||
<path
|
||||
d="M110.869 113.384L110.869 103.321L100.803 103.321L100.803 113.384L110.869 113.384Z"
|
||||
fill="black"
|
||||
></path>
|
||||
<path
|
||||
d="M161.328 52.9855L161.328 42.9226L151.262 42.9226L151.262 52.9855L161.328 52.9855Z"
|
||||
fill="black"
|
||||
></path>
|
||||
<path
|
||||
d="M20.133 83.187L30.3354 83.187L30.3354 73.124L40.4017 73.124L40.4017 63.0613L50.4681 63.0613L50.4681 73.124L60.5345 73.124L60.5345 63.0613L70.6008 63.0613L80.6672 63.0613L131.135 63.0613L131.135 113.376L161.334 113.376L161.334 103.313L171.4 103.313L171.4 93.25L181.467 93.25L181.467 83.187L191.533 83.187L191.533 63.0613L181.467 63.0613L181.467 73.1241L171.4 73.1241L171.4 83.187L161.334 83.187L161.334 73.1241L171.4 73.1241L171.4 63.0613L161.334 63.0613L151.268 63.0613L141.201 63.0613L141.201 52.9983L141.201 32.8726L161.334 32.8726L171.4 32.8726L171.4 63.0613L181.467 63.0613L181.467 52.9983L191.533 52.9983L191.533 32.8726L181.467 32.8726L181.467 22.8096L171.4 22.8096L171.4 12.7467L161.334 12.7467L161.334 2.54785L141.201 2.54785L131.135 2.54785L131.135 52.9983L120.933 52.9983L120.933 12.7467L110.866 12.7467L110.866 52.9983L100.8 52.9983L100.8 22.8096L90.7336 22.8096L90.7336 52.9983L80.6672 52.9983L80.6672 32.8726L70.6008 32.8726L70.6008 52.9983L60.5345 52.9983L60.5345 42.9354L50.4681 42.9354L50.4681 52.9983L40.4017 52.9983L40.4017 42.9354L30.3354 42.9354L30.3354 32.8726L20.133 32.8726L20.133 22.8096L0.000308081 22.8096L0.000307201 42.9354L10.0666 42.9354L10.0666 52.9983L20.133 52.9983L20.133 63.0613L10.0666 63.0613L10.0666 73.124L0.000305881 73.124L0.000305002 93.25L20.133 93.25L20.133 83.187Z"
|
||||
fill="black"
|
||||
></path>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0">
|
||||
<rect width="200" height="116" fill="none"></rect>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
) : (
|
||||
<img alt="Vega" src={vegaWhite} className="w-[30px] lg:w-40" />
|
||||
)}
|
||||
</Link>
|
||||
<div className="h-[30px] inline-flex items-center lg:h-40 uppercase">
|
||||
<h1
|
||||
data-testid="header-title"
|
||||
className={`text-[28px] lg:text-h3 pl-8 ${
|
||||
className={`text-h3 font-alpha uppercase calt mb-2 ${
|
||||
fairground ? 'text-black' : 'text-white'
|
||||
}`}
|
||||
>
|
||||
|
@ -12,7 +12,7 @@ export function TemplateSidebar({ children, sidebar }: TemplateSidebarProps) {
|
||||
<div className="border-b border-white lg:grid lg:grid-rows-[auto_minmax(600px,_1fr)] lg:grid-cols-[1fr_450px]">
|
||||
<Nav />
|
||||
<main className="p-20">{children}</main>
|
||||
<aside className="hidden lg:block lg:col-start-2 lg:col-end-3 lg:row-start-1 lg: row-end-3 p-20 bg-banner bg-cover border-l border-white">
|
||||
<aside className="hidden lg:block lg:col-start-2 lg:col-end-3 lg:row-start-1 lg: row-end-3 p-20 bg-banner bg-contain border-l border-white">
|
||||
{sidebar.map((Component, i) => (
|
||||
<section className="mb-20 last:mb-0" key={i}>
|
||||
{Component}
|
||||
|
@ -1 +0,0 @@
|
||||
export * from './stateful-button';
|
@ -1,14 +0,0 @@
|
||||
import type { ButtonHTMLAttributes } from 'react';
|
||||
import { Button } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
export const StatefulButton = (
|
||||
props: ButtonHTMLAttributes<HTMLButtonElement>
|
||||
) => {
|
||||
const classProp = props.className || '';
|
||||
return (
|
||||
<Button
|
||||
{...props}
|
||||
className={`flex justify-center items-center gap-12 disabled:cursor-default ${classProp}`}
|
||||
/>
|
||||
);
|
||||
};
|
@ -4,6 +4,7 @@ import {
|
||||
Input,
|
||||
Intent,
|
||||
FormGroup,
|
||||
Lozenge,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@ -25,7 +26,6 @@ export const AmountInput = ({
|
||||
amount,
|
||||
setAmount,
|
||||
maximum,
|
||||
// TODO: render currency in input when https://github.com/vegaprotocol/frontend-monorepo/issues/273
|
||||
currency,
|
||||
}: {
|
||||
amount: string;
|
||||
@ -36,25 +36,31 @@ export const AmountInput = ({
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<div className="flex">
|
||||
<Input
|
||||
data-testid="token-amount-input"
|
||||
className="flex-1"
|
||||
name={inputName}
|
||||
id={inputName}
|
||||
onChange={(e) => setAmount(e.target.value)}
|
||||
value={amount}
|
||||
autoComplete="off"
|
||||
type="number"
|
||||
max={maximum.toString()}
|
||||
min={0}
|
||||
step="any"
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<Input
|
||||
data-testid="token-amount-input"
|
||||
name={inputName}
|
||||
id={inputName}
|
||||
onChange={(e) => setAmount(e.target.value)}
|
||||
value={amount}
|
||||
autoComplete="off"
|
||||
type="number"
|
||||
max={maximum.toString()}
|
||||
min={0}
|
||||
step="any"
|
||||
appendElement={
|
||||
<Lozenge className="text-[10px] relative top-[-2px]">
|
||||
{currency}
|
||||
</Lozenge>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
{maximum && (
|
||||
<Button
|
||||
variant="inline-link"
|
||||
onClick={() => setAmount(maximum.toString())}
|
||||
data-testid="token-amount-use-maximum"
|
||||
className="flex flex-col justify-center text-ui p-8 h-28 my-0 mx-8"
|
||||
className="flex flex-col justify-center p-8 h-28 my-0 mx-8"
|
||||
>
|
||||
{t('Use maximum')}
|
||||
</Button>
|
||||
@ -69,7 +75,6 @@ export const TokenInput = ({
|
||||
perform,
|
||||
submitText,
|
||||
currency,
|
||||
|
||||
approveText,
|
||||
allowance,
|
||||
approve,
|
||||
@ -84,7 +89,6 @@ export const TokenInput = ({
|
||||
perform: () => void;
|
||||
submitText: string;
|
||||
currency: string;
|
||||
|
||||
requireApproval?: boolean;
|
||||
maximum?: BigNumber;
|
||||
minimum?: BigNumber;
|
||||
@ -128,6 +132,7 @@ export const TokenInput = ({
|
||||
new BigNumber(amount).isLessThan(minimum)
|
||||
);
|
||||
}, [amount, isApproved, maximum, requireApproval, minimum]);
|
||||
|
||||
let approveContent = null;
|
||||
|
||||
if (showApproveButton) {
|
||||
@ -158,11 +163,9 @@ export const TokenInput = ({
|
||||
}
|
||||
} else if (requireApproval) {
|
||||
approveContent = (
|
||||
<Callout
|
||||
iconName="tick"
|
||||
intent={Intent.Success}
|
||||
title={`${currency} are approved for staking`}
|
||||
/>
|
||||
<Callout iconName="tick" intent={Intent.Success}>
|
||||
<p>{`${currency} are approved for staking`}</p>
|
||||
</Callout>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
export * from './transaction-button';
|
@ -1,159 +0,0 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import type { TransactionState } from '../../hooks/transaction-reducer';
|
||||
import { TxState } from '../../hooks/transaction-reducer';
|
||||
import { truncateMiddle } from '../../lib/truncate-middle';
|
||||
import { Button, Link } from '@vegaprotocol/ui-toolkit';
|
||||
import { useEnvironment } from '@vegaprotocol/react-helpers';
|
||||
import { Error, HandUp, Tick } from '../icons';
|
||||
import { Loader } from '../loader';
|
||||
import { StatefulButton } from '../stateful-button';
|
||||
|
||||
interface TransactionButtonProps {
|
||||
text: string;
|
||||
transactionState: TransactionState;
|
||||
/** txHash of the transaction if already complete */
|
||||
forceTxHash: string | null;
|
||||
forceTxState?: TxState;
|
||||
disabled?: boolean;
|
||||
start: () => void;
|
||||
reset: () => void;
|
||||
}
|
||||
|
||||
const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<div className="mb-20">{children}</div>
|
||||
);
|
||||
|
||||
const Text = ({ children }: { children: React.ReactNode }) => (
|
||||
<p className="flex justify-center items-center gap-10 m-0 py-12 px-32 leading-[1.15]">
|
||||
{children}
|
||||
</p>
|
||||
);
|
||||
|
||||
export const TransactionButton = ({
|
||||
text,
|
||||
transactionState,
|
||||
forceTxHash,
|
||||
forceTxState,
|
||||
disabled = false,
|
||||
start,
|
||||
reset,
|
||||
}: TransactionButtonProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { txState, txData } = transactionState;
|
||||
const txHash = forceTxHash || txData.hash;
|
||||
const state = forceTxState || txState;
|
||||
|
||||
if (state === TxState.Complete) {
|
||||
return (
|
||||
<Wrapper>
|
||||
<Text>
|
||||
<span className="text-vega-green">
|
||||
<Tick />
|
||||
</span>
|
||||
<span>{t('txButtonComplete')}</span>
|
||||
</Text>
|
||||
<TransactionButtonFooter txHash={txHash} />
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
|
||||
// User as started transaction and we are awaiting confirmation from the users wallet
|
||||
if (state === TxState.Requested) {
|
||||
return (
|
||||
<Wrapper>
|
||||
<StatefulButton disabled={true}>
|
||||
<HandUp />
|
||||
<span>{t('txButtonActionRequired')}</span>
|
||||
</StatefulButton>
|
||||
<TransactionButtonFooter
|
||||
message={t('transactionHashPrompt')}
|
||||
txHash={txHash}
|
||||
/>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
|
||||
if (state === TxState.Pending) {
|
||||
return (
|
||||
<Wrapper>
|
||||
<StatefulButton disabled={true}>
|
||||
<Loader />
|
||||
<span>{t('txButtonAwaiting')}</span>
|
||||
</StatefulButton>
|
||||
<TransactionButtonFooter txHash={txHash} />
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
|
||||
if (state === TxState.Error) {
|
||||
return (
|
||||
<Wrapper>
|
||||
<Text>
|
||||
<span className="text-intent-danger">
|
||||
<Error />
|
||||
</span>
|
||||
<span>{t('txButtonFailure')}</span>
|
||||
<Button onClick={reset} variant="inline-link">
|
||||
{t('Try again')}
|
||||
</Button>
|
||||
</Text>
|
||||
<TransactionButtonFooter txHash={txHash} />
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
|
||||
// Idle
|
||||
return (
|
||||
<Wrapper>
|
||||
<StatefulButton onClick={start} disabled={disabled}>
|
||||
{text}
|
||||
</StatefulButton>
|
||||
<TransactionButtonFooter txHash={txHash} />
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
interface TransactionButtonFooterProps {
|
||||
txHash: string | null;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export const TransactionButtonFooter = ({
|
||||
txHash,
|
||||
message,
|
||||
}: TransactionButtonFooterProps) => {
|
||||
const { ETHERSCAN_URL } = useEnvironment();
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (message) {
|
||||
return (
|
||||
<div className="mt-4 mb-0 mx-0">
|
||||
<p className="m-0 py-4 pl-8 border-l border-[3px] border-intent-warning text-ui">
|
||||
<span className="relative top-2 mr-4 text-intent-warning">
|
||||
<Error />
|
||||
</span>
|
||||
{message}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (txHash) {
|
||||
return (
|
||||
<div className="transaction-button__footer">
|
||||
<p className="flex justify-between items-start m-0 text-ui">
|
||||
<span>{t('transaction')}</span>
|
||||
<Link
|
||||
href={`${ETHERSCAN_URL}/tx/${txHash}`}
|
||||
title={t('View on Etherscan')}
|
||||
>
|
||||
{truncateMiddle(txHash)}
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
@ -1,7 +1,7 @@
|
||||
import { Callout, Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link } from '@vegaprotocol/ui-toolkit';
|
||||
import { useEnvironment } from '@vegaprotocol/react-helpers';
|
||||
import { useEnvironment } from '@vegaprotocol/network-switcher';
|
||||
import type { ReactElement } from 'react';
|
||||
|
||||
export const TransactionComplete = ({
|
||||
@ -23,13 +23,18 @@ export const TransactionComplete = ({
|
||||
intent={Intent.Success}
|
||||
title={heading || t('Complete')}
|
||||
>
|
||||
{body && <p data-testid="transaction-complete-body">{body}</p>}
|
||||
<p>
|
||||
{body && (
|
||||
<p className="mb-8" data-testid="transaction-complete-body">
|
||||
{body}
|
||||
</p>
|
||||
)}
|
||||
<p className="mb-8">
|
||||
<Link
|
||||
title={t('View transaction on Etherscan')}
|
||||
target="_blank"
|
||||
href={`${ETHERSCAN_URL}/tx/${hash}`}
|
||||
>
|
||||
{hash}
|
||||
{t('View transaction on Etherscan')}
|
||||
</Link>
|
||||
</p>
|
||||
{footer && <p data-testid="transaction-complete-footer">{footer}</p>}
|
||||
|
@ -2,7 +2,7 @@ import { Button, Callout, Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Link } from '@vegaprotocol/ui-toolkit';
|
||||
import { useEnvironment } from '@vegaprotocol/react-helpers';
|
||||
import { useEnvironment } from '@vegaprotocol/network-switcher';
|
||||
|
||||
export interface TransactionErrorProps {
|
||||
error: Error | null;
|
||||
@ -20,12 +20,15 @@ export const TransactionError = ({
|
||||
|
||||
return (
|
||||
<Callout iconName="error" intent={Intent.Danger}>
|
||||
<p>{error ? error.message : t('Something went wrong')}</p>
|
||||
<p className="mb-8">
|
||||
{error ? error.message : t('Something went wrong')}
|
||||
</p>
|
||||
{hash ? (
|
||||
<p>
|
||||
<p className="mb-8">
|
||||
<Link
|
||||
title={t('View transaction on Etherscan')}
|
||||
href={`${ETHERSCAN_URL}/tx/${hash}`}
|
||||
target="_blank"
|
||||
>
|
||||
{hash}
|
||||
</Link>
|
||||
|
@ -1,8 +1,8 @@
|
||||
import React from 'react';
|
||||
import { Callout } from '@vegaprotocol/ui-toolkit';
|
||||
import { Callout, Loader } from '@vegaprotocol/ui-toolkit';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link } from '@vegaprotocol/ui-toolkit';
|
||||
import { useEnvironment } from '@vegaprotocol/react-helpers';
|
||||
import { useEnvironment } from '@vegaprotocol/network-switcher';
|
||||
|
||||
export const TransactionPending = ({
|
||||
hash,
|
||||
@ -37,11 +37,16 @@ export const TransactionPending = ({
|
||||
return defaultTitle;
|
||||
}, [heading, remainingConfirmations, t]);
|
||||
return (
|
||||
<Callout iconName="refresh" title={title}>
|
||||
{body && <p data-testid="transaction-pending-body">{body}</p>}
|
||||
<p>
|
||||
<Callout icon={<Loader size="small" />} title={title}>
|
||||
{body && (
|
||||
<p className="mb-8" data-testid="transaction-pending-body">
|
||||
{body}
|
||||
</p>
|
||||
)}
|
||||
<p className="mb-8">
|
||||
<Link
|
||||
title={t('View transaction on Etherscan')}
|
||||
target="_blank"
|
||||
href={`${ETHERSCAN_URL}/tx/${hash}`}
|
||||
>
|
||||
{hash}
|
||||
|
@ -6,8 +6,8 @@ export const TransactionRequested = () => {
|
||||
return (
|
||||
<Callout
|
||||
iconName="hand-up"
|
||||
intent={Intent.Prompt}
|
||||
title={t('Awaiting action in Ethereum wallet (e.g. metamask)')}
|
||||
intent={Intent.Warning}
|
||||
title={t('Awaiting action in Ethereum wallet (e.g. MetaMask)')}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -1,6 +1,5 @@
|
||||
import type { TxData } from '@vegaprotocol/smart-contracts';
|
||||
import { Dialog, Link } from '@vegaprotocol/ui-toolkit';
|
||||
import { useEnvironment } from '@vegaprotocol/react-helpers';
|
||||
import { useEnvironment } from '@vegaprotocol/network-switcher';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
@ -8,9 +7,10 @@ import {
|
||||
AppStateActionType,
|
||||
useAppState,
|
||||
} from '../../contexts/app-state/app-state-context';
|
||||
import { useContracts } from '../../contexts/contracts/contracts-context';
|
||||
import { truncateMiddle } from '../../lib/truncate-middle';
|
||||
import { Tick } from '../icons';
|
||||
import type { TxData } from '../../stores/transactions';
|
||||
import { useTransactionStore } from '../../stores/transactions';
|
||||
|
||||
const TransactionModalTh = ({ children }: { children: React.ReactNode }) => (
|
||||
<th className="border-b border-black-25 text-black-60 text-left font-normal">
|
||||
@ -31,7 +31,7 @@ const TransactionModalStatus = ({
|
||||
export const TransactionModal = () => {
|
||||
const { ETHERSCAN_URL } = useEnvironment();
|
||||
const { t } = useTranslation();
|
||||
const { transactions } = useContracts();
|
||||
const { transactions } = useTransactionStore();
|
||||
const { appState, appDispatch } = useAppState();
|
||||
|
||||
const renderStatus = (txObj: TxData) => {
|
||||
@ -84,6 +84,7 @@ export const TransactionModal = () => {
|
||||
<TransactionModalTd>
|
||||
<Link
|
||||
title={t('View transaction on Etherscan')}
|
||||
target="_blank"
|
||||
href={`${ETHERSCAN_URL}/tx/${transaction.tx.hash}`}
|
||||
>
|
||||
{truncateMiddle(transaction.tx.hash)}
|
||||
|
@ -1,31 +1,22 @@
|
||||
import { Link } from '@vegaprotocol/ui-toolkit';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Links } from '../../config';
|
||||
|
||||
export const DownloadWalletPrompt = () => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<>
|
||||
<div className="mt-8">
|
||||
<h3>{t('getWallet')}</h3>
|
||||
<p style={{ margin: 0 }}>
|
||||
<a
|
||||
className={'text-deemphasise'}
|
||||
href={Links.WALLET_GUIDE}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<p>
|
||||
<Link className="text-deemphasise" href={Links.WALLET_GUIDE}>
|
||||
{t('readGuide')}
|
||||
</a>
|
||||
</Link>
|
||||
</p>
|
||||
<p style={{ margin: 0 }}>
|
||||
<a
|
||||
className={'text-deemphasise'}
|
||||
href={Links.WALLET_RELEASES}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<p>
|
||||
<Link className="text-deemphasise" href={Links.WALLET_RELEASES}>
|
||||
{t('downloadWallet')}
|
||||
</a>
|
||||
</Link>
|
||||
</p>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -17,7 +17,7 @@ import type {
|
||||
DelegationsVariables,
|
||||
} from './__generated__/Delegations';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { useEnvironment } from '@vegaprotocol/react-helpers';
|
||||
import { useEnvironment } from '@vegaprotocol/network-switcher';
|
||||
|
||||
const DELEGATIONS_QUERY = gql`
|
||||
query Delegations($partyId: ID!) {
|
||||
|
@ -41,10 +41,8 @@ export const VegaWallet = () => {
|
||||
<WalletCard dark={true}>
|
||||
<WalletCardHeader dark={true}>
|
||||
<div>
|
||||
<h1 className="text-h3 px-8 uppercase">{t('vegaWallet')}</h1>
|
||||
<span className="mx-8 text-h6">
|
||||
{keypair && `(${keypair.name})`}
|
||||
</span>
|
||||
<h1 className="text-h3 uppercase">{t('vegaWallet')}</h1>
|
||||
<span className="text-h6">{keypair && `(${keypair.name})`}</span>
|
||||
</div>
|
||||
{keypair && (
|
||||
<span className="font-mono px-8">
|
||||
@ -72,6 +70,7 @@ const VegaWalletNotConnected = () => {
|
||||
})
|
||||
}
|
||||
variant="secondary"
|
||||
className="w-full"
|
||||
data-testid="connect-vega"
|
||||
>
|
||||
{t('connectVegaWalletToUseAssociated')}
|
||||
@ -182,10 +181,14 @@ const VegaWalletConnected = ({ vegaKeys }: VegaWalletConnectedProps) => {
|
||||
))}
|
||||
<WalletCardActions>
|
||||
<Link style={{ flex: 1 }} to={Routes.GOVERNANCE}>
|
||||
<Button className="w-full">{t('governance')}</Button>
|
||||
<span className="flex items-center justify-center w-full px-28 border h-28 bg-white text-black">
|
||||
{t('governance')}
|
||||
</span>
|
||||
</Link>
|
||||
<Link style={{ flex: 1 }} to={Routes.STAKING}>
|
||||
<Button className="w-full">{t('staking')}</Button>
|
||||
<span className="flex items-center justify-center w-full px-28 border h-28 bg-white text-black">
|
||||
{t('staking')}
|
||||
</span>
|
||||
</Link>
|
||||
</WalletCardActions>
|
||||
<VegaWalletAssetList accounts={accounts} />
|
||||
|
@ -1,3 +1,4 @@
|
||||
import classNames from 'classnames';
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
@ -27,15 +28,13 @@ interface WalletCardProps {
|
||||
dark?: boolean;
|
||||
}
|
||||
|
||||
export const WalletCard = ({ dark, children }: WalletCardProps) => (
|
||||
<div
|
||||
className={`text-ui border border-white ${
|
||||
dark ? 'bg-black text-white' : 'bg-white text-black'
|
||||
}`}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
export const WalletCard = ({ dark, children }: WalletCardProps) => {
|
||||
const className = classNames('text-ui border border-white', 'p-8', {
|
||||
'bg-black text-white': dark,
|
||||
'bg-white text-black': !dark,
|
||||
});
|
||||
return <div className={className}>{children}</div>;
|
||||
};
|
||||
|
||||
interface WalletCardHeaderProps {
|
||||
children: React.ReactNode;
|
||||
@ -44,7 +43,7 @@ interface WalletCardHeaderProps {
|
||||
|
||||
export const WalletCardHeader = ({ children }: WalletCardHeaderProps) => {
|
||||
return (
|
||||
<div className="flex justify-between items-center py-8">{children}</div>
|
||||
<div className="flex gap-4 justify-between items-center">{children}</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -53,7 +52,7 @@ interface WalletCardContentProps {
|
||||
}
|
||||
|
||||
export const WalletCardContent = ({ children }: WalletCardContentProps) => {
|
||||
return <div className="my-4 mx-8">{children}</div>;
|
||||
return <div className="mt-8">{children}</div>;
|
||||
};
|
||||
|
||||
export const WalletCardRow = ({
|
||||
|
@ -8,4 +8,7 @@ export const Flags = {
|
||||
MOCK: TRUTHY.includes(process.env['NX_MOCKED'] as string),
|
||||
FAIRGROUND: TRUTHY.includes(process.env['NX_FAIRGROUND'] as string),
|
||||
NETWORK_LIMITS: TRUTHY.includes(process.env['NX_NETWORK_LIMITS'] as string),
|
||||
USE_NEW_BRIDGE_CONTRACT: TRUTHY.includes(
|
||||
process.env['NX_IS_NEW_BRIDGE_CONTRACT'] as string
|
||||
),
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Networks } from '@vegaprotocol/smart-contracts';
|
||||
import { Networks } from '@vegaprotocol/react-helpers';
|
||||
|
||||
interface VegaNode {
|
||||
url: string;
|
||||
|
@ -1,20 +1,16 @@
|
||||
import type {
|
||||
TxData,
|
||||
VegaClaim,
|
||||
VegaErc20Bridge,
|
||||
VegaStaking,
|
||||
ERC20Token,
|
||||
VegaVesting,
|
||||
Claim,
|
||||
Token,
|
||||
TokenVesting,
|
||||
StakingBridge,
|
||||
} from '@vegaprotocol/smart-contracts';
|
||||
import React from 'react';
|
||||
|
||||
export interface ContractsContextShape {
|
||||
token: ERC20Token;
|
||||
staking: VegaStaking;
|
||||
vesting: VegaVesting;
|
||||
claim: VegaClaim;
|
||||
erc20Bridge: VegaErc20Bridge;
|
||||
transactions: TxData[];
|
||||
token: Token;
|
||||
staking: StakingBridge;
|
||||
vesting: TokenVesting;
|
||||
claim: Claim;
|
||||
}
|
||||
|
||||
export const ContractsContext = React.createContext<
|
||||
|
@ -1,33 +1,29 @@
|
||||
import type { TxData } from '@vegaprotocol/smart-contracts';
|
||||
import {
|
||||
VegaClaim,
|
||||
VegaErc20Bridge,
|
||||
VegaStaking,
|
||||
ERC20Token,
|
||||
VegaVesting,
|
||||
Token,
|
||||
TokenVesting,
|
||||
Claim,
|
||||
StakingBridge,
|
||||
} from '@vegaprotocol/smart-contracts';
|
||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
import uniqBy from 'lodash/uniqBy';
|
||||
import React from 'react';
|
||||
import { useEnvironment } from '@vegaprotocol/react-helpers';
|
||||
|
||||
import { SplashLoader } from '../../components/splash-loader';
|
||||
import type { ContractsContextShape } from './contracts-context';
|
||||
import { ContractsContext } from './contracts-context';
|
||||
import { defaultProvider } from '../../lib/web3-connectors';
|
||||
import { useEthereumConfig } from '@vegaprotocol/web3';
|
||||
import { useEnvironment } from '@vegaprotocol/network-switcher';
|
||||
|
||||
/**
|
||||
* Provides Vega Ethereum contract instances to its children.
|
||||
*/
|
||||
export const ContractsProvider = ({ children }: { children: JSX.Element }) => {
|
||||
const { ADDRESSES, VEGA_ENV } = useEnvironment();
|
||||
const { provider: activeProvider, account } = useWeb3React();
|
||||
const [txs, setTxs] = React.useState<TxData[]>([]);
|
||||
const [contracts, setContracts] = React.useState<Pick<
|
||||
ContractsContextShape,
|
||||
'token' | 'staking' | 'vesting' | 'claim' | 'erc20Bridge'
|
||||
> | null>(null);
|
||||
const { config } = useEthereumConfig();
|
||||
const { VEGA_ENV, ADDRESSES } = useEnvironment();
|
||||
const [contracts, setContracts] =
|
||||
React.useState<ContractsContextShape | null>(null);
|
||||
|
||||
// Create instances of contract classes. If we have an account use a signer for the
|
||||
// contracts so that we can sign transactions, otherwise use the provider for just
|
||||
@ -45,49 +41,21 @@ export const ContractsProvider = ({ children }: { children: JSX.Element }) => {
|
||||
signer = provider.getSigner();
|
||||
}
|
||||
|
||||
if (provider) {
|
||||
if (provider && config) {
|
||||
setContracts({
|
||||
token: new ERC20Token(
|
||||
ADDRESSES.vegaTokenAddress,
|
||||
// @ts-ignore Cant accept JsonRpcProvider provider
|
||||
provider,
|
||||
signer
|
||||
token: new Token(ADDRESSES.vegaTokenAddress, signer || provider),
|
||||
staking: new StakingBridge(
|
||||
config.staking_bridge_contract.address,
|
||||
signer || provider
|
||||
),
|
||||
// @ts-ignore Cant accept JsonRpcProvider provider
|
||||
staking: new VegaStaking(VEGA_ENV, provider, signer),
|
||||
// @ts-ignore Cant accept JsonRpcProvider provider
|
||||
vesting: new VegaVesting(VEGA_ENV, provider, signer),
|
||||
// @ts-ignore Cant accept JsonRpcProvider provider
|
||||
claim: new VegaClaim(VEGA_ENV, provider, signer),
|
||||
erc20Bridge: new VegaErc20Bridge(
|
||||
VEGA_ENV,
|
||||
// @ts-ignore Cant accept JsonRpcProvider provider
|
||||
provider,
|
||||
signer
|
||||
vesting: new TokenVesting(
|
||||
config.token_vesting_contract.address,
|
||||
signer || provider
|
||||
),
|
||||
claim: new Claim(ADDRESSES.claimAddress, signer || provider),
|
||||
});
|
||||
}
|
||||
}, [activeProvider, account, ADDRESSES.vegaTokenAddress, VEGA_ENV]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!contracts) return;
|
||||
|
||||
const mergeTxs = (existing: TxData[], incoming: TxData[]) => {
|
||||
return uniqBy([...incoming, ...existing], 'tx.hash');
|
||||
};
|
||||
|
||||
contracts.staking.listen((txs) => {
|
||||
setTxs((curr) => mergeTxs(curr, txs));
|
||||
});
|
||||
|
||||
contracts.vesting.listen((txs) => {
|
||||
setTxs((curr) => mergeTxs(curr, txs));
|
||||
});
|
||||
}, [contracts]);
|
||||
|
||||
React.useEffect(() => {
|
||||
setTxs([]);
|
||||
}, [account]);
|
||||
}, [activeProvider, account, config, ADDRESSES, VEGA_ENV]);
|
||||
|
||||
if (!contracts) {
|
||||
return (
|
||||
@ -98,7 +66,7 @@ export const ContractsProvider = ({ children }: { children: JSX.Element }) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<ContractsContext.Provider value={{ ...contracts, transactions: txs }}>
|
||||
<ContractsContext.Provider value={contracts}>
|
||||
{children}
|
||||
</ContractsContext.Provider>
|
||||
);
|
||||
|
@ -1,9 +1,9 @@
|
||||
import React from 'react';
|
||||
import * as Sentry from '@sentry/react';
|
||||
import { Networks } from '@vegaprotocol/react-helpers';
|
||||
import { useWeb3React } from '@web3-react/core';
|
||||
import { MetaMask } from '@web3-react/metamask';
|
||||
import { useEnvironment } from '@vegaprotocol/react-helpers';
|
||||
import { Networks } from '@vegaprotocol/smart-contracts';
|
||||
import { useEnvironment } from '@vegaprotocol/network-switcher';
|
||||
|
||||
export const useAddAssetSupported = () => {
|
||||
const { connector } = useWeb3React();
|
||||
|
@ -31,9 +31,9 @@ export function useAnimateValue(
|
||||
) {
|
||||
elRef.current?.animate(
|
||||
[
|
||||
{ backgroundColor: Colors.red.vega, color: Colors.white.DEFAULT },
|
||||
{ backgroundColor: Colors.vega.red, color: Colors.white.DEFAULT },
|
||||
{
|
||||
backgroundColor: Colors.red.vega,
|
||||
backgroundColor: Colors.vega.red,
|
||||
color: Colors.white.DEFAULT,
|
||||
offset: 0.8,
|
||||
},
|
||||
@ -55,11 +55,11 @@ export function useAnimateValue(
|
||||
elRef.current?.animate(
|
||||
[
|
||||
{
|
||||
backgroundColor: Colors.green.vega,
|
||||
backgroundColor: Colors.vega.green,
|
||||
color: Colors.white.DEFAULT,
|
||||
},
|
||||
{
|
||||
backgroundColor: Colors.green.vega,
|
||||
backgroundColor: Colors.vega.green,
|
||||
color: Colors.white.DEFAULT,
|
||||
offset: 0.8,
|
||||
},
|
||||
|
@ -1,38 +0,0 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export function useCopyToClipboard() {
|
||||
const [copied, setCopied] = React.useState(false);
|
||||
|
||||
// Once copied flip a boolean so we can display
|
||||
// a message to the user such as 'Copied!' which will
|
||||
// revert after 800 milliseconds
|
||||
React.useEffect(() => {
|
||||
let timeout: ReturnType<typeof setTimeout>;
|
||||
if (copied) {
|
||||
timeout = setTimeout(() => {
|
||||
setCopied(false);
|
||||
}, 800);
|
||||
}
|
||||
return () => clearTimeout(timeout);
|
||||
}, [copied]);
|
||||
|
||||
// Create an input we can copy text from and render it
|
||||
// off screen
|
||||
function handler(text: string) {
|
||||
const input = document.createElement('input');
|
||||
input.style.position = 'fixed';
|
||||
input.style.left = '100vw';
|
||||
input.style.opacity = '0';
|
||||
input.value = text;
|
||||
document.body.appendChild(input);
|
||||
input.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(input);
|
||||
setCopied(true);
|
||||
}
|
||||
|
||||
return {
|
||||
copy: handler,
|
||||
copied,
|
||||
};
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
import * as Sentry from '@sentry/react';
|
||||
import React from 'react';
|
||||
|
||||
import { NetworkParams } from '../config';
|
||||
import { useNetworkParam } from './use-network-param';
|
||||
|
||||
export const useEthereumConfig = () => {
|
||||
const { data: ethereumConfigJSON, loading } = useNetworkParam([
|
||||
NetworkParams.ETHEREUM_CONFIG,
|
||||
]);
|
||||
const ethereumConfig = React.useMemo(() => {
|
||||
if (!ethereumConfigJSON && !loading) {
|
||||
Sentry.captureMessage(
|
||||
`No ETH config found for network param ${NetworkParams.ETHEREUM_CONFIG}`
|
||||
);
|
||||
return null;
|
||||
} else if (!ethereumConfigJSON) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const [configJson] = ethereumConfigJSON;
|
||||
return JSON.parse(configJson);
|
||||
} catch {
|
||||
Sentry.captureMessage('Ethereum config JSON is invalid');
|
||||
return null;
|
||||
}
|
||||
}, [ethereumConfigJSON, loading]);
|
||||
|
||||
if (!ethereumConfig) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
confirmations: ethereumConfig.confirmations,
|
||||
};
|
||||
};
|
@ -1,24 +1,33 @@
|
||||
import React from 'react';
|
||||
import type { ethers } from 'ethers';
|
||||
import * as Sentry from '@sentry/react';
|
||||
import type { VegaStaking, VegaVesting } from '@vegaprotocol/smart-contracts';
|
||||
import { addDecimal } from '@vegaprotocol/react-helpers';
|
||||
import type {
|
||||
StakingBridge,
|
||||
TokenVesting,
|
||||
} from '@vegaprotocol/smart-contracts';
|
||||
|
||||
import {
|
||||
AppStateActionType,
|
||||
useAppState,
|
||||
} from '../contexts/app-state/app-state-context';
|
||||
import BigNumber from 'bignumber.js';
|
||||
|
||||
export function useGetAssociationBreakdown(
|
||||
ethAddress: string,
|
||||
staking: VegaStaking,
|
||||
vesting: VegaVesting
|
||||
staking: StakingBridge,
|
||||
vesting: TokenVesting
|
||||
): () => Promise<void> {
|
||||
const { appDispatch } = useAppState();
|
||||
const {
|
||||
appState: { decimals },
|
||||
appDispatch,
|
||||
} = useAppState();
|
||||
|
||||
const getAssociationBreakdown = React.useCallback(async () => {
|
||||
try {
|
||||
const [stakingAssociations, vestingAssociations] = await Promise.all([
|
||||
staking.userTotalStakedByVegaKey(ethAddress),
|
||||
vesting.userTotalStakedByVegaKey(ethAddress),
|
||||
userTotalStakedByVegaKey(staking, ethAddress, decimals),
|
||||
userTotalStakedByVegaKey(vesting, ethAddress, decimals),
|
||||
]);
|
||||
|
||||
appDispatch({
|
||||
@ -31,7 +40,59 @@ export function useGetAssociationBreakdown(
|
||||
} catch (err) {
|
||||
Sentry.captureException(err);
|
||||
}
|
||||
}, [ethAddress, staking, vesting, appDispatch]);
|
||||
}, [ethAddress, staking, vesting, decimals, appDispatch]);
|
||||
|
||||
return getAssociationBreakdown;
|
||||
}
|
||||
|
||||
async function userTotalStakedByVegaKey(
|
||||
contract: StakingBridge | TokenVesting,
|
||||
ethereumAccount: string,
|
||||
decimals: number
|
||||
): Promise<{ [vegaKey: string]: BigNumber }> {
|
||||
const addFilter = contract.contract.filters.Stake_Deposited(ethereumAccount);
|
||||
const removeFilter = contract.contract.filters.Stake_Removed(ethereumAccount);
|
||||
const addEvents = await contract.contract.queryFilter(addFilter);
|
||||
const removeEvents = await contract.contract.queryFilter(removeFilter);
|
||||
const res = combineStakeEventsByVegaKey(
|
||||
[...addEvents, ...removeEvents],
|
||||
decimals
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
function combineStakeEventsByVegaKey(
|
||||
events: ethers.Event[],
|
||||
decimals: number
|
||||
): { [vegaKey: string]: BigNumber } {
|
||||
const res = events.reduce((obj, e) => {
|
||||
const vegaKey = e.args?.vega_public_key;
|
||||
const amount = parseEventAmount(e, decimals);
|
||||
const isDeposit = e.event === 'Stake_Deposited';
|
||||
const isRemove = e.event === 'Stake_Removed';
|
||||
|
||||
if (!isDeposit && !isRemove) return obj;
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(obj, vegaKey)) {
|
||||
if (isDeposit) {
|
||||
obj[vegaKey] = obj[vegaKey].plus(amount);
|
||||
} else {
|
||||
obj[vegaKey] = obj[vegaKey].minus(amount);
|
||||
}
|
||||
} else {
|
||||
if (isDeposit) {
|
||||
obj[vegaKey] = amount;
|
||||
} else {
|
||||
obj[vegaKey] = new BigNumber(0);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}, {} as { [vegaKey: string]: BigNumber });
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
function parseEventAmount(e: ethers.Event, decimals: number) {
|
||||
const rawAmount = new BigNumber(e.args?.amount.toString() || 0);
|
||||
return new BigNumber(addDecimal(rawAmount.toString(), decimals));
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import * as Sentry from '@sentry/react';
|
||||
import type { VegaVesting } from '@vegaprotocol/smart-contracts';
|
||||
import type { TokenVesting } from '@vegaprotocol/smart-contracts';
|
||||
|
||||
import {
|
||||
AppStateActionType,
|
||||
@ -8,12 +8,16 @@ import {
|
||||
} from '../contexts/app-state/app-state-context';
|
||||
import { BigNumber } from '../lib/bignumber';
|
||||
import { useTranches } from './use-tranches';
|
||||
import { toBigNum } from '@vegaprotocol/react-helpers';
|
||||
|
||||
export const useGetUserTrancheBalances = (
|
||||
address: string,
|
||||
vesting: VegaVesting
|
||||
vesting: TokenVesting
|
||||
) => {
|
||||
const { appDispatch } = useAppState();
|
||||
const {
|
||||
appState: { decimals },
|
||||
appDispatch,
|
||||
} = useAppState();
|
||||
const { tranches } = useTranches();
|
||||
return React.useCallback(async () => {
|
||||
appDispatch({
|
||||
@ -32,10 +36,14 @@ export const useGetUserTrancheBalances = (
|
||||
);
|
||||
const trancheIds = [0, ...userTranches.map((t) => t.tranche_id)];
|
||||
const promises = trancheIds.map(async (tId) => {
|
||||
const [total, vested] = await Promise.all([
|
||||
vesting.userTrancheTotalBalance(address, tId),
|
||||
vesting.userTrancheVestedBalance(address, tId),
|
||||
const [t, v] = await Promise.all([
|
||||
vesting.getTrancheBalance(address, tId),
|
||||
vesting.getVestedForTranche(address, tId),
|
||||
]);
|
||||
|
||||
const total = toBigNum(t, decimals);
|
||||
const vested = toBigNum(v, decimals);
|
||||
|
||||
return {
|
||||
id: tId,
|
||||
locked: tId === 0 ? total : total.minus(vested),
|
||||
@ -56,5 +64,5 @@ export const useGetUserTrancheBalances = (
|
||||
error: e as Error,
|
||||
});
|
||||
}
|
||||
}, [address, appDispatch, tranches, vesting]);
|
||||
}, [address, decimals, appDispatch, tranches, vesting]);
|
||||
};
|
||||
|
@ -1,9 +1,8 @@
|
||||
import React from 'react';
|
||||
|
||||
import { useContracts } from '../contexts/contracts/contracts-context';
|
||||
import { useTransactionStore } from '../stores/transactions';
|
||||
|
||||
export const usePendingTransactions = () => {
|
||||
const { transactions } = useContracts();
|
||||
const { transactions } = useTransactionStore();
|
||||
|
||||
return React.useMemo(() => {
|
||||
return transactions.some((tx) => tx.pending);
|
||||
|
@ -14,8 +14,8 @@ export function useRefreshAssociatedBalances() {
|
||||
async (ethAddress: string, vegaKey: string) => {
|
||||
const [walletAssociatedBalance, vestingAssociatedBalance] =
|
||||
await Promise.all([
|
||||
staking.stakeBalance(ethAddress, vegaKey),
|
||||
vesting.stakeBalance(ethAddress, vegaKey),
|
||||
staking.stakeBalance(ethAddress, `0x${vegaKey}`),
|
||||
vesting.stakeBalance(ethAddress, `0x${vegaKey}`),
|
||||
]);
|
||||
|
||||
appDispatch({
|
||||
|
@ -1,8 +1,9 @@
|
||||
import * as Sentry from '@sentry/react';
|
||||
import { toBigNum } from '@vegaprotocol/react-helpers';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { useEthereumConfig } from '@vegaprotocol/web3';
|
||||
import React from 'react';
|
||||
|
||||
import { useEnvironment } from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
AppStateActionType,
|
||||
useAppState,
|
||||
@ -10,29 +11,35 @@ import {
|
||||
import { useContracts } from '../contexts/contracts/contracts-context';
|
||||
|
||||
export const useRefreshBalances = (address: string) => {
|
||||
const { ADDRESSES } = useEnvironment();
|
||||
const { appDispatch } = useAppState();
|
||||
const {
|
||||
appState: { decimals },
|
||||
appDispatch,
|
||||
} = useAppState();
|
||||
const { keypair } = useVegaWallet();
|
||||
const { token, staking, vesting } = useContracts();
|
||||
const { config } = useEthereumConfig();
|
||||
|
||||
return React.useCallback(async () => {
|
||||
if (!config) return;
|
||||
try {
|
||||
const [
|
||||
balance,
|
||||
walletBalance,
|
||||
lien,
|
||||
allowance,
|
||||
walletAssociatedBalance,
|
||||
vestingAssociatedBalance,
|
||||
] = await Promise.all([
|
||||
vesting.getUserBalanceAllTranches(address),
|
||||
token.balanceOf(address),
|
||||
vesting.getLien(address),
|
||||
token.allowance(address, ADDRESSES.stakingBridge),
|
||||
// Refresh connected vega key balances as well if we are connected to a vega key
|
||||
keypair?.pub ? staking.stakeBalance(address, keypair.pub) : null,
|
||||
keypair?.pub ? vesting.stakeBalance(address, keypair.pub) : null,
|
||||
]);
|
||||
const [b, w, stats, a, walletStakeBalance, vestingStakeBalance] =
|
||||
await Promise.all([
|
||||
vesting.userTotalAllTranches(address),
|
||||
token.balanceOf(address),
|
||||
vesting.userStats(address),
|
||||
token.allowance(address, config.staking_bridge_contract.address),
|
||||
// Refresh connected vega key balances as well if we are connected to a vega key
|
||||
keypair?.pub ? staking.stakeBalance(address, keypair.pub) : null,
|
||||
keypair?.pub ? vesting.stakeBalance(address, keypair.pub) : null,
|
||||
]);
|
||||
|
||||
const balance = toBigNum(b, decimals);
|
||||
const walletBalance = toBigNum(w, decimals);
|
||||
const lien = toBigNum(stats.lien, decimals);
|
||||
const allowance = toBigNum(a, decimals);
|
||||
const walletAssociatedBalance = toBigNum(walletStakeBalance, decimals);
|
||||
const vestingAssociatedBalance = toBigNum(vestingStakeBalance, decimals);
|
||||
|
||||
appDispatch({
|
||||
type: AppStateActionType.REFRESH_BALANCES,
|
||||
balance,
|
||||
@ -47,11 +54,12 @@ export const useRefreshBalances = (address: string) => {
|
||||
}
|
||||
}, [
|
||||
address,
|
||||
decimals,
|
||||
appDispatch,
|
||||
keypair?.pub,
|
||||
staking,
|
||||
token,
|
||||
vesting,
|
||||
ADDRESSES.stakingBridge,
|
||||
config,
|
||||
]);
|
||||
};
|
||||
|
@ -1,7 +1,8 @@
|
||||
import type { Networks } from '@vegaprotocol/react-helpers';
|
||||
import { useFetch } from '@vegaprotocol/react-helpers';
|
||||
import type { Networks, Tranche } from '@vegaprotocol/smart-contracts';
|
||||
import type { Tranche } from '@vegaprotocol/smart-contracts';
|
||||
import React, { useEffect } from 'react';
|
||||
import { useEnvironment } from '@vegaprotocol/react-helpers';
|
||||
import { useEnvironment } from '@vegaprotocol/network-switcher';
|
||||
|
||||
import { BigNumber } from '../lib/bignumber';
|
||||
|
||||
|
@ -2,19 +2,20 @@ import React from 'react';
|
||||
import * as Sentry from '@sentry/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import type { ethers } from 'ethers';
|
||||
|
||||
import { isUnexpectedError, isUserRejection } from '../lib/web3-utils';
|
||||
import {
|
||||
initialState,
|
||||
TransactionActionType,
|
||||
transactionReducer,
|
||||
} from './transaction-reducer';
|
||||
import { useTransactionStore } from '../stores/transactions';
|
||||
|
||||
export const useTransaction = (
|
||||
performTransaction: () => Promise<ethers.ContractTransaction>,
|
||||
requiredConfirmations = 1
|
||||
) => {
|
||||
const { t } = useTranslation();
|
||||
const store = useTransactionStore();
|
||||
const [state, dispatch] = React.useReducer(transactionReducer, {
|
||||
...initialState,
|
||||
requiredConfirmations,
|
||||
@ -62,10 +63,12 @@ export const useTransaction = (
|
||||
try {
|
||||
const tx = await performTransaction();
|
||||
|
||||
store.add({ tx, receipt: null, pending: true, requiredConfirmations });
|
||||
dispatch({
|
||||
type: TransactionActionType.TX_SUBMITTED,
|
||||
txHash: tx.hash,
|
||||
});
|
||||
|
||||
Sentry.addBreadcrumb({
|
||||
type: 'Transaction',
|
||||
level: Sentry.Severity.Log,
|
||||
@ -83,6 +86,7 @@ export const useTransaction = (
|
||||
|
||||
for (let i = 1; i <= requiredConfirmations; i++) {
|
||||
receipt = await tx.wait(i);
|
||||
store.update({ tx, receipt, pending: true, requiredConfirmations });
|
||||
dispatch({
|
||||
type: TransactionActionType.TX_CONFIRMATION,
|
||||
confirmations: receipt.confirmations,
|
||||
@ -93,11 +97,13 @@ export const useTransaction = (
|
||||
throw new Error('No receipt after confirmations are met');
|
||||
}
|
||||
|
||||
store.update({ tx, receipt, pending: false, requiredConfirmations });
|
||||
dispatch({
|
||||
type: TransactionActionType.TX_COMPLETE,
|
||||
receipt,
|
||||
confirmations: receipt.confirmations,
|
||||
});
|
||||
|
||||
Sentry.addBreadcrumb({
|
||||
type: 'Transaction',
|
||||
level: Sentry.Severity.Log,
|
||||
@ -114,7 +120,7 @@ export const useTransaction = (
|
||||
} catch (err) {
|
||||
handleError(err as Error);
|
||||
}
|
||||
}, [performTransaction, requiredConfirmations, handleError]);
|
||||
}, [performTransaction, requiredConfirmations, handleError, store]);
|
||||
|
||||
const reset = () => {
|
||||
dispatch({ type: TransactionActionType.TX_RESET });
|
||||
|
@ -1,9 +1,9 @@
|
||||
{
|
||||
"Home": "Home",
|
||||
"fairgroundTitle": "Fairground token",
|
||||
"pageTitleHome": "$VEGA Tokens",
|
||||
"pageTitleHome": "The $VEGA token",
|
||||
"pageTitleClaim": "Claim $VEGA tokens",
|
||||
"pageTitleAssociate": "Associate $VEGA tokens with $VEGA Key",
|
||||
"pageTitleAssociate": "Associate $VEGA tokens with Vega Key",
|
||||
"pageTitleRedemption": "Vesting",
|
||||
"pageTitleLiquidity": "Incentivised Liquidity Programme",
|
||||
"pageTitleRedemptionTranche": "Redeem from Tranche",
|
||||
@ -79,6 +79,7 @@
|
||||
"Incomplete": "Incomplete",
|
||||
"Complete": "Complete",
|
||||
"View on Etherscan (opens in a new tab)": "View on Etherscan (opens in a new tab)",
|
||||
"View transaction on Etherscan": "View transaction on Etherscan",
|
||||
"Transaction in progress": "Transaction in progress",
|
||||
"Unknown error": "Unknown error",
|
||||
"Awaiting action in Ethereum wallet (e.g. MetaMask)": "Awaiting action in Ethereum wallet (e.g. MetaMask)",
|
||||
@ -126,7 +127,6 @@
|
||||
"noVestingTokens": "You do not have any vesting $VEGA tokens. Switch to another Ethereum address to check what can be redeemed, or view <tranchesLink>all tranches</tranchesLink>",
|
||||
"ethereumKey": "Ethereum key",
|
||||
"checkingForProvider": "Checking for provider",
|
||||
"Awaiting action in wallet...": "Awaiting action in Ethereum wallet (e.g. MetaMask)",
|
||||
"In wallet": "In wallet",
|
||||
"Not staked": "Not staked",
|
||||
"viewKeys": "View keys",
|
||||
@ -149,7 +149,6 @@
|
||||
"Stake VEGA tokens": "Stake $VEGA tokens",
|
||||
"Tranche breakdown": "Tranche breakdown",
|
||||
"Across all tranches": "Across all tranches",
|
||||
"theVegaToken": "The {{symbol}} token",
|
||||
"Token Vesting": "Vesting",
|
||||
"Rewards": "Rewards",
|
||||
"Governance": "Governance",
|
||||
@ -238,7 +237,7 @@
|
||||
"VEGA Tokens": "$VEGA Tokens",
|
||||
"SLP Tokens": "SLP Tokens",
|
||||
"Connected Vega key": "Connected Vega key",
|
||||
"What Vega wallet/key is going to control your stake?": "What Vega Wallet/key is going to control your stake?",
|
||||
"What Vega key is going to control your stake?": "What Vega key is going to control your stake?",
|
||||
"Where would you like to stake from?": "Where would you like to associate from?",
|
||||
"associateNoVega": "Your connected Ethereum address does not have any $VEGA",
|
||||
"associateInfo1": "To participate in governance or to nominate a Validator you'll need to associate $VEGA tokens with a Vega wallet/key.",
|
||||
@ -322,7 +321,7 @@
|
||||
"Associate VEGA tokens": "Associate $VEGA tokens",
|
||||
"VEGA token holders can vote on proposed changes to the network and create proposals.": "$VEGA token holders can vote on proposed changes to the network and create proposals.",
|
||||
"VEGA token holders can nominate a validator node and receive staking rewards.": "$VEGA token holders can nominate a validator node and receive staking rewards.",
|
||||
"USE YOUR VEGA TOKENS": "USE YOUR $VEGA TOKENS",
|
||||
"Use your Vega tokens": "Use your Vega tokens",
|
||||
"Check your vesting VEGA tokens": "Check your vesting $VEGA tokens",
|
||||
"Tokens from this Tranche have been redeemed": "Tokens from this Tranche have been redeemed",
|
||||
"You have redeemed {{redeemedAmount}} VEGA tokens from this tranche. They are now free to transfer from your Ethereum wallet.": "You have redeemed {{redeemedAmount}} $VEGA tokens from this tranche. They are now free to transfer from your Ethereum wallet.",
|
||||
@ -450,12 +449,12 @@
|
||||
"transaction": "Transaction",
|
||||
"associated": "Associated",
|
||||
"notAssociated": "Not Associated",
|
||||
"title": "$VEGA TOKEN",
|
||||
"title": "VEGA TOKEN",
|
||||
"Use the Ethereum wallet you want to send your tokens to. You'll also need enough Ethereum to pay gas.": "Connect to the Ethereum wallet that holds your $VEGA tokens to see what can be redeemed from vesting tranches. To redeem tokens you will need some ETH to pay gas fees.\n",
|
||||
"Staked on Vega validator": "Staked $VEGA",
|
||||
"You can associate tokens while they are held in the vesting contract, when they unlock you will need to disassociate them before they can be redeemed.": "You can associate tokens while they are held in the vesting contract, when they unlock you will need to disassociate them before they can be redeemed.",
|
||||
"Nominate Stake to Validator Node": "Select a validator to nominate",
|
||||
"Vega key {{vegaKey}} can now participate in governance and Nominate a validator with it's stake.": "Vega key {{vegaKey}} can now participate in governance and nominate a validator with your associated $VEGA.",
|
||||
"successfullAssociationMessage": "Vega key {{vegaKey}} can now participate in governance and nominate a validator with your associated $VEGA.",
|
||||
"stakingStep2Text": "Your tokens need to be associated with a Vega Wallet so that you can control your stake",
|
||||
"stakingStep3": "Step 3. Select the validator you'd like to nominate",
|
||||
"stakeAddSuccessMessage": "You can cancel your nomination at any time",
|
||||
|
@ -1,17 +0,0 @@
|
||||
/**
|
||||
* From:
|
||||
* https://github.com/ChainSafe/web3.js/blob/436e77a8eaa061fbaa183a9f73ca590c2e1d7697/packages/web3-utils/src/index.js
|
||||
*/
|
||||
export const asciiToHex = (str: string) => {
|
||||
if (!str) return '0x00';
|
||||
|
||||
let hex = '';
|
||||
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
const code = str.charCodeAt(i);
|
||||
const n = code.toString(16);
|
||||
hex += n.length < 2 ? '0' + n : n;
|
||||
}
|
||||
|
||||
return '0x' + hex;
|
||||
};
|
@ -6,6 +6,7 @@ export function addDecimal(value: BigNumber, decimals: number): string {
|
||||
.decimalPlaces(decimals)
|
||||
.toString();
|
||||
}
|
||||
|
||||
export function removeDecimal(value: BigNumber, decimals: number): string {
|
||||
return value.times(Math.pow(10, decimals)).toFixed(0);
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import { AddLockedTokenAddress } from '../../components/add-locked-token';
|
||||
export const CodeUsed = () => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Callout intent={Intent.Prompt} iconName="error" title={t('codeUsed')}>
|
||||
<Callout intent={Intent.Warning} iconName="error" title={t('codeUsed')}>
|
||||
<p>{t('codeUsedText')}</p>
|
||||
<AddLockedTokenAddress />
|
||||
</Callout>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Callout, Intent, Link, Button } from '@vegaprotocol/ui-toolkit';
|
||||
import { useEnvironment } from '@vegaprotocol/react-helpers';
|
||||
import { useEnvironment } from '@vegaprotocol/network-switcher';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { Link as RouteLink } from 'react-router-dom';
|
||||
|
||||
@ -38,6 +38,7 @@ export const Complete = ({
|
||||
<Link
|
||||
title={t('View transaction on Etherscan')}
|
||||
href={`${ETHERSCAN_URL}/tx/${commitTxHash}`}
|
||||
target="_blank"
|
||||
>
|
||||
{commitTxHash}
|
||||
</Link>
|
||||
@ -49,6 +50,7 @@ export const Complete = ({
|
||||
<Link
|
||||
title={t('View transaction on Etherscan')}
|
||||
href={`${ETHERSCAN_URL}/tx/${claimTxHash}`}
|
||||
target="_blank"
|
||||
>
|
||||
{claimTxHash}
|
||||
</Link>
|
||||
|
@ -1,8 +1,14 @@
|
||||
import { useContracts } from '../../contexts/contracts/contracts-context';
|
||||
import { useTransaction } from '../../hooks/use-transaction';
|
||||
import type { IClaimTokenParams } from '@vegaprotocol/smart-contracts';
|
||||
import { removeDecimal } from '@vegaprotocol/react-helpers';
|
||||
import { useAppState } from '../../contexts/app-state/app-state-context';
|
||||
|
||||
export const useClaim = (claimData: IClaimTokenParams, address: string) => {
|
||||
const {
|
||||
appState: { decimals },
|
||||
} = useAppState();
|
||||
|
||||
const claimArgs = {
|
||||
...claimData,
|
||||
...claimData.signature,
|
||||
@ -10,6 +16,7 @@ export const useClaim = (claimData: IClaimTokenParams, address: string) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
country: claimData.country!,
|
||||
account: address,
|
||||
amount: removeDecimal(claimData.claim.amount.toString(), decimals),
|
||||
};
|
||||
const { claim } = useContracts();
|
||||
return useTransaction(() => claim.claim(claimArgs));
|
||||
|
@ -1,22 +1,63 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link } from '@vegaprotocol/ui-toolkit';
|
||||
import { useEnvironment } from '@vegaprotocol/react-helpers';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { Link, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import type { EthereumConfig } from '@vegaprotocol/web3';
|
||||
import { useEthereumConfig } from '@vegaprotocol/web3';
|
||||
import { useEnvironment } from '@vegaprotocol/network-switcher';
|
||||
import { Heading } from '../../components/heading';
|
||||
import { SplashLoader } from '../../components/splash-loader';
|
||||
|
||||
const Contracts = () => {
|
||||
const { config } = useEthereumConfig();
|
||||
const { ADDRESSES, ETHERSCAN_URL } = useEnvironment();
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (!config) {
|
||||
return (
|
||||
<Splash>
|
||||
<SplashLoader />
|
||||
</Splash>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<section>
|
||||
<Heading title={'Contracts'} />
|
||||
<hr />
|
||||
{[
|
||||
'collateral_bridge_contract',
|
||||
'multisig_control_contract',
|
||||
'staking_bridge_contract',
|
||||
'token_vesting_contract',
|
||||
].map((key) => {
|
||||
const contract = config[key as keyof EthereumConfig] as {
|
||||
address: string;
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
key={key}
|
||||
style={{ display: 'flex', justifyContent: 'space-between' }}
|
||||
>
|
||||
<div>{key}:</div>
|
||||
<Link
|
||||
title={t('View address on Etherscan')}
|
||||
href={`${ETHERSCAN_URL}/address/${contract.address}`}
|
||||
>
|
||||
{config.collateral_bridge_contract.address}
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{Object.entries(ADDRESSES).map(([key, value]) => (
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
<div
|
||||
key={key}
|
||||
style={{ display: 'flex', justifyContent: 'space-between' }}
|
||||
>
|
||||
<div>{key}:</div>
|
||||
<Link
|
||||
title={t('View address on Etherscan')}
|
||||
href={`${ETHERSCAN_URL}/address/${value}`}
|
||||
>
|
||||
asdfasd
|
||||
{value}
|
||||
</Link>
|
||||
</div>
|
||||
|
@ -14,7 +14,7 @@ export const CurrentProposalState = ({
|
||||
state === ProposalState.Failed ||
|
||||
state === ProposalState.Rejected
|
||||
) {
|
||||
className = 'text-intent-danger';
|
||||
className = 'text-danger';
|
||||
} else if (
|
||||
state === ProposalState.Enacted ||
|
||||
state === ProposalState.Passed
|
||||
|
@ -11,7 +11,7 @@ const StatusPass = ({ children }: { children: React.ReactNode }) => (
|
||||
);
|
||||
|
||||
const StatusFail = ({ children }: { children: React.ReactNode }) => (
|
||||
<span className="text-intent-danger">{children}</span>
|
||||
<span className="text-danger">{children}</span>
|
||||
);
|
||||
|
||||
export const CurrentProposalStatus = ({
|
||||
|
@ -10,7 +10,7 @@ export const ProposalTermsJson = ({
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<section>
|
||||
<h2>{t('proposalTerms')}</h2>
|
||||
<h2 className="text-h4 text-white mb-8">{t('proposalTerms')}</h2>
|
||||
<SyntaxHighlighter data={terms} />
|
||||
</section>
|
||||
);
|
||||
|
@ -37,6 +37,7 @@ export const ProposalVotesTable = ({ proposal }: ProposalVotesTableProps) => {
|
||||
data-testid="proposal-votes-table"
|
||||
muted={true}
|
||||
numerical={true}
|
||||
headingLevel={4}
|
||||
>
|
||||
<KeyValueTableRow>
|
||||
{t('willPass')}
|
||||
|
@ -20,58 +20,67 @@ export const ProposalsList = ({ proposals }: ProposalsListProps) => {
|
||||
return <p>{t('noProposals')}</p>;
|
||||
}
|
||||
|
||||
const renderRow = (proposal: Proposals_proposals) => {
|
||||
if (!proposal || !proposal.id) return null;
|
||||
|
||||
return (
|
||||
<li className="last:mb-0 mb-24" key={proposal.id}>
|
||||
<Link to={proposal.id} className="underline">
|
||||
<header>{getProposalName(proposal)}</header>
|
||||
</Link>
|
||||
<KeyValueTable muted={true}>
|
||||
<KeyValueTableRow>
|
||||
{t('state')}
|
||||
<span data-testid="governance-proposal-state">
|
||||
<CurrentProposalState proposal={proposal} />
|
||||
</span>
|
||||
</KeyValueTableRow>
|
||||
<KeyValueTableRow>
|
||||
{isFuture(new Date(proposal.terms.closingDatetime))
|
||||
? t('closesOn')
|
||||
: t('closedOn')}
|
||||
|
||||
<span data-testid="governance-proposal-closingDate">
|
||||
{format(
|
||||
new Date(proposal.terms.closingDatetime),
|
||||
DATE_FORMAT_DETAILED
|
||||
)}
|
||||
</span>
|
||||
</KeyValueTableRow>
|
||||
<KeyValueTableRow>
|
||||
{isFuture(new Date(proposal.terms.enactmentDatetime))
|
||||
? t('proposedEnactment')
|
||||
: t('enactedOn')}
|
||||
|
||||
<span data-testid="governance-proposal-enactmentDate">
|
||||
{format(
|
||||
new Date(proposal.terms.enactmentDatetime),
|
||||
DATE_FORMAT_DETAILED
|
||||
)}
|
||||
</span>
|
||||
</KeyValueTableRow>
|
||||
</KeyValueTable>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Heading title={t('pageTitleGovernance')} />
|
||||
<p>{t('proposedChangesToVegaNetwork')}</p>
|
||||
<p>{t('vegaTokenHoldersCanVote')}</p>
|
||||
<p>{t('requiredMajorityDescription')}</p>
|
||||
<h2>{t('proposals')}</h2>
|
||||
<ul>{proposals.map((row) => renderRow(row))}</ul>
|
||||
<p className="mb-8">{t('proposedChangesToVegaNetwork')}</p>
|
||||
<p className="mb-8">{t('vegaTokenHoldersCanVote')}</p>
|
||||
<p className="mb-8">{t('requiredMajorityDescription')}</p>
|
||||
<h2 className="text-h4 text-white">{t('proposals')}</h2>
|
||||
<ul>
|
||||
{proposals.map((proposal) => (
|
||||
<ProposalListItem proposal={proposal} />
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
interface ProposalListItemProps {
|
||||
proposal: Proposals_proposals;
|
||||
}
|
||||
|
||||
const ProposalListItem = ({ proposal }: ProposalListItemProps) => {
|
||||
const { t } = useTranslation();
|
||||
if (!proposal || !proposal.id) return null;
|
||||
|
||||
return (
|
||||
<li className="last:mb-0 mb-24" key={proposal.id}>
|
||||
<Link to={proposal.id} className="underline text-white">
|
||||
<header>{getProposalName(proposal)}</header>
|
||||
</Link>
|
||||
<KeyValueTable muted={true}>
|
||||
<KeyValueTableRow>
|
||||
{t('state')}
|
||||
<span data-testid="governance-proposal-state">
|
||||
<CurrentProposalState proposal={proposal} />
|
||||
</span>
|
||||
</KeyValueTableRow>
|
||||
<KeyValueTableRow>
|
||||
{isFuture(new Date(proposal.terms.closingDatetime))
|
||||
? t('closesOn')
|
||||
: t('closedOn')}
|
||||
|
||||
<span data-testid="governance-proposal-closingDate">
|
||||
{format(
|
||||
new Date(proposal.terms.closingDatetime),
|
||||
DATE_FORMAT_DETAILED
|
||||
)}
|
||||
</span>
|
||||
</KeyValueTableRow>
|
||||
<KeyValueTableRow>
|
||||
{isFuture(new Date(proposal.terms.enactmentDatetime))
|
||||
? t('proposedEnactment')
|
||||
: t('enactedOn')}
|
||||
|
||||
<span data-testid="governance-proposal-enactmentDate">
|
||||
{format(
|
||||
new Date(proposal.terms.enactmentDatetime),
|
||||
DATE_FORMAT_DETAILED
|
||||
)}
|
||||
</span>
|
||||
</KeyValueTableRow>
|
||||
</KeyValueTable>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
@ -3,10 +3,8 @@ import { format } from 'date-fns';
|
||||
import * as React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import {
|
||||
ProposalState,
|
||||
VoteValue,
|
||||
} from '../../../../__generated__/globalTypes';
|
||||
import { ProposalState } from '../../../../__generated__/globalTypes';
|
||||
import { VoteValue } from '../../../../__generated__/globalTypes';
|
||||
import {
|
||||
AppStateActionType,
|
||||
useAppState,
|
||||
@ -136,14 +134,11 @@ export const VoteButtons = ({
|
||||
(voteState === VoteState.Yes || voteState === VoteState.No)
|
||||
) {
|
||||
const className =
|
||||
voteState === VoteState.Yes
|
||||
? 'text-intent-success'
|
||||
: 'text-intent-danger';
|
||||
voteState === VoteState.Yes ? 'text-success' : 'text-danger';
|
||||
return (
|
||||
<p>
|
||||
<span>{t('youVoted')}</span>{' '}
|
||||
<span className={className}>{t(`voteState_${voteState}`)}</span>
|
||||
{'. '}
|
||||
<span>{t('youVoted')}:</span>{' '}
|
||||
<span className={className}>{t(`voteState_${voteState}`)}</span>{' '}
|
||||
{voteDatetime ? (
|
||||
<span>{format(voteDatetime, DATE_FORMAT_LONG)}. </span>
|
||||
) : null}
|
||||
@ -167,17 +162,11 @@ export const VoteButtons = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex">
|
||||
<Button
|
||||
onClick={() => submitVote(VoteValue.Yes)}
|
||||
className="w-[calc(50%_-_7px)] mt-4 mr-12"
|
||||
>
|
||||
<div className="flex gap-4">
|
||||
<Button onClick={() => submitVote(VoteValue.Yes)} className="flex-1">
|
||||
{t('voteFor')}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => submitVote(VoteValue.No)}
|
||||
className="w-[calc(50%_-_7px)] mt-4"
|
||||
>
|
||||
<Button onClick={() => submitVote(VoteValue.No)} className="flex-1">
|
||||
{t('voteAgainst')}
|
||||
</Button>
|
||||
</div>
|
||||
|
@ -44,15 +44,15 @@ export const VoteDetails = ({ proposal }: VoteDetailsProps) => {
|
||||
|
||||
return (
|
||||
<section>
|
||||
<h3>{t('votes')}</h3>
|
||||
<p className="mb-0">
|
||||
<h3 className="text-h4 text-white mb-8">{t('votes')}</h3>
|
||||
<p className="mb-8">
|
||||
<span>
|
||||
<CurrentProposalStatus proposal={proposal} />
|
||||
</span>
|
||||
.
|
||||
{proposal.state === ProposalState.Open ? daysLeft : null}
|
||||
</p>
|
||||
<table className="w-full font-normal">
|
||||
<table className="w-full font-normal mb-12">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="text-vega-green w-[18%] text-left">{t('for')}</th>
|
||||
@ -62,9 +62,7 @@ export const VoteDetails = ({ proposal }: VoteDetailsProps) => {
|
||||
progress={yesPercentage}
|
||||
/>
|
||||
</th>
|
||||
<th className="text-intent-danger w-[18%] text-right">
|
||||
{t('against')}
|
||||
</th>
|
||||
<th className="text-danger w-[18%] text-right">{t('against')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -86,19 +84,19 @@ export const VoteDetails = ({ proposal }: VoteDetailsProps) => {
|
||||
{formatNumber(yesTokens, defaultDecimals)}
|
||||
</td>
|
||||
<td></td>
|
||||
<td className="text-white-60">
|
||||
<td className="text-white-60 text-right">
|
||||
{formatNumber(noTokens, defaultDecimals)}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>
|
||||
<p className="mb-8">
|
||||
{t('participation')}
|
||||
{': '}
|
||||
{participationMet ? (
|
||||
<span className="text-vega-green mx-4">{t('met')}</span>
|
||||
) : (
|
||||
<span className="text-intent-danger mx-4">{t('notMet')}</span>
|
||||
<span className="text-danger mx-4">{t('notMet')}</span>
|
||||
)}{' '}
|
||||
{formatNumber(totalTokensVoted, defaultDecimals)}{' '}
|
||||
{formatNumber(totalTokensPercentage, defaultDecimals)}%
|
||||
@ -109,7 +107,7 @@ export const VoteDetails = ({ proposal }: VoteDetailsProps) => {
|
||||
</p>
|
||||
{keypair ? (
|
||||
<>
|
||||
<h3>{t('yourVote')}</h3>
|
||||
<h3 className="text-h4 text-white mb-8">{t('yourVote')}</h3>
|
||||
<VoteButtonsContainer
|
||||
voteState={voteState}
|
||||
castVote={castVote}
|
||||
|
@ -8,21 +8,21 @@ export const VoteProgress = ({
|
||||
progress: BigNumber;
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<div className="w-full h-4 relative">
|
||||
<div
|
||||
data-testid="vote-progress-indicator"
|
||||
className="relative top-[10px] w-[1px] h-16 bg-white z-[1]"
|
||||
className="absolute top-[-5px] w-[1px] h-16 bg-white z-[1]"
|
||||
style={{ left: `${threshold}%` }}
|
||||
/>
|
||||
<div className="bp3-progress-bar bp3-no-stripes bg-intent-danger rounded-none h-5">
|
||||
<div className="w-full h-4">
|
||||
<div
|
||||
className="bp3-progress-meter bg-vega-green rounded-none"
|
||||
className="absolute left-0 bg-vega-green h-4"
|
||||
data-testid="vote-progress-bar"
|
||||
style={{
|
||||
width: `${progress}%`,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -34,7 +34,7 @@ const Home = ({ name }: RouteChildProps) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Heading title={t('theVegaToken', { symbol: '$VEGA' })} />
|
||||
<Heading title={t('pageTitleHome')} />
|
||||
<HomeSection>
|
||||
<TokenDetails
|
||||
totalSupply={appState.totalSupply}
|
||||
@ -42,7 +42,7 @@ const Home = ({ name }: RouteChildProps) => {
|
||||
/>
|
||||
</HomeSection>
|
||||
<HomeSection>
|
||||
<h2 className="text-h4">{t('Token Vesting')}</h2>
|
||||
<h2 className="text-h4 text-white">{t('Token Vesting')}</h2>
|
||||
<p className="mb-8">
|
||||
{t(
|
||||
'The vesting contract holds VEGA tokens until they have become unlocked.'
|
||||
@ -68,7 +68,7 @@ const Home = ({ name }: RouteChildProps) => {
|
||||
</Link>
|
||||
</HomeSection>
|
||||
<HomeSection>
|
||||
<h2 className="text-h4">{t('USE YOUR VEGA TOKENS')}</h2>
|
||||
<h2 className="text-h4 text-white">{t('Use your Vega tokens')}</h2>
|
||||
<p className="mb-8">
|
||||
{t(
|
||||
'To use your tokens on the Vega network they need to be associated with a Vega wallet/key.'
|
||||
@ -83,6 +83,7 @@ const Home = ({ name }: RouteChildProps) => {
|
||||
<a
|
||||
data-test-id="get-vega-wallet-link"
|
||||
href={Links.WALLET_GUIDE}
|
||||
className="underline text-white"
|
||||
target="_blank"
|
||||
rel="nofollow noreferrer"
|
||||
>
|
||||
@ -90,15 +91,18 @@ const Home = ({ name }: RouteChildProps) => {
|
||||
</a>
|
||||
</p>
|
||||
<p data-test-id="associate-vega-tokens-link-on-homepage">
|
||||
<Link to={`${Routes.STAKING}/associate`}>
|
||||
<Link
|
||||
to={`${Routes.STAKING}/associate`}
|
||||
className="underline text-white"
|
||||
>
|
||||
{t('Associate VEGA tokens')}
|
||||
</Link>
|
||||
</p>
|
||||
</HomeSection>
|
||||
<div style={{ display: 'flex', gap: 36 }}>
|
||||
<div style={{ flex: 1 }}>
|
||||
<div className="flex gap-40">
|
||||
<div className="flex-1">
|
||||
<HomeSection>
|
||||
<h2 className="text-h4">{t('Staking')}</h2>
|
||||
<h2 className="text-h4 text-white">{t('Staking')}</h2>
|
||||
<p className="mb-8">
|
||||
{t(
|
||||
'VEGA token holders can nominate a validator node and receive staking rewards.'
|
||||
@ -111,9 +115,9 @@ const Home = ({ name }: RouteChildProps) => {
|
||||
</p>
|
||||
</HomeSection>
|
||||
</div>
|
||||
<div style={{ flex: 1 }}>
|
||||
<div className="flex-1">
|
||||
<HomeSection>
|
||||
<h2 className="text-h4">{t('Governance')}</h2>
|
||||
<h2 className="text-h4 text-white">{t('Governance')}</h2>
|
||||
<p className="mb-8">
|
||||
{t(
|
||||
'VEGA token holders can vote on proposed changes to the network and create proposals.'
|
||||
|
@ -1,13 +1,14 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Callout, Link, Intent, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { useEnvironment } from '@vegaprotocol/react-helpers';
|
||||
import { useEnvironment } from '@vegaprotocol/network-switcher';
|
||||
import { KeyValueTable, KeyValueTableRow } from '@vegaprotocol/ui-toolkit';
|
||||
import { useTranches } from '../../../hooks/use-tranches';
|
||||
import type { BigNumber } from '../../../lib/bignumber';
|
||||
import { formatNumber } from '../../../lib/format-number';
|
||||
import { TokenDetailsCirculating } from './token-details-circulating';
|
||||
import { SplashLoader } from '../../../components/splash-loader';
|
||||
import { useEthereumConfig } from '@vegaprotocol/web3';
|
||||
|
||||
export const TokenDetails = ({
|
||||
totalSupply,
|
||||
@ -20,6 +21,7 @@ export const TokenDetails = ({
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { tranches, loading, error } = useTranches();
|
||||
const { config } = useEthereumConfig();
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
@ -29,7 +31,7 @@ export const TokenDetails = ({
|
||||
);
|
||||
}
|
||||
|
||||
if (!tranches || loading) {
|
||||
if (!tranches || loading || !config) {
|
||||
return (
|
||||
<Splash>
|
||||
<SplashLoader />
|
||||
@ -43,22 +45,23 @@ export const TokenDetails = ({
|
||||
{t('Token address').toUpperCase()}
|
||||
<Link
|
||||
data-testid="token-address"
|
||||
title={t('View address on Etherscan')}
|
||||
title={t('View on Etherscan (opens in a new tab)')}
|
||||
className="font-mono"
|
||||
href={`${ETHERSCAN_URL}/address/${ADDRESSES.vegaTokenAddress}`}
|
||||
target="_blank"
|
||||
>
|
||||
{ADDRESSES.vegaTokenAddress}
|
||||
</Link>
|
||||
</KeyValueTableRow>
|
||||
<KeyValueTableRow>
|
||||
{t('Vesting contract'.toUpperCase())}
|
||||
{t('Vesting contract').toUpperCase()}
|
||||
<Link
|
||||
data-testid="token-contract"
|
||||
title={t('View address on Etherscan')}
|
||||
title={t('View on Etherscan (opens in a new tab)')}
|
||||
className="font-mono"
|
||||
href={`${ETHERSCAN_URL}/address/${ADDRESSES.vestingAddress}`}
|
||||
href={`${ETHERSCAN_URL}/address/${config.token_vesting_contract.address}`}
|
||||
>
|
||||
{ADDRESSES.vestingAddress}
|
||||
{config.token_vesting_contract.address}
|
||||
</Link>
|
||||
</KeyValueTableRow>
|
||||
<KeyValueTableRow>
|
||||
|
@ -13,9 +13,9 @@ import { Tranche0Table, TrancheTable } from '../tranche-table';
|
||||
import { VestingTable } from './vesting-table';
|
||||
|
||||
export const RedemptionInformation = () => {
|
||||
const { state, address } = useOutletContext<{
|
||||
const { state, account } = useOutletContext<{
|
||||
state: RedemptionState;
|
||||
address: string;
|
||||
account: string;
|
||||
}>();
|
||||
const navigate = useNavigate();
|
||||
const { t } = useTranslation();
|
||||
@ -28,7 +28,9 @@ export const RedemptionInformation = () => {
|
||||
trancheBalances,
|
||||
},
|
||||
} = useAppState();
|
||||
|
||||
const { userTranches } = state;
|
||||
|
||||
const filteredTranches = React.useMemo(
|
||||
() =>
|
||||
userTranches.filter((tr) => {
|
||||
@ -41,6 +43,7 @@ export const RedemptionInformation = () => {
|
||||
}),
|
||||
[trancheBalances, userTranches]
|
||||
);
|
||||
|
||||
const zeroTranche = React.useMemo(() => {
|
||||
const zeroTranche = trancheBalances.find((t) => t.id === 0);
|
||||
if (zeroTranche && zeroTranche.locked.isGreaterThan(0)) {
|
||||
@ -56,7 +59,9 @@ export const RedemptionInformation = () => {
|
||||
<Trans
|
||||
i18nKey="noVestingTokens"
|
||||
components={{
|
||||
tranchesLink: <Link to={Routes.TRANCHES} />,
|
||||
tranchesLink: (
|
||||
<Link className="underline text-white" to={Routes.TRANCHES} />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
@ -67,25 +72,29 @@ export const RedemptionInformation = () => {
|
||||
|
||||
return (
|
||||
<section data-testid="redemption-page">
|
||||
<Callout>
|
||||
<div className="mb-12">
|
||||
<AddLockedTokenAddress />
|
||||
</Callout>
|
||||
<p className="mb-12" data-testid="redemption-description">
|
||||
</div>
|
||||
<p className="mb-24" data-testid="redemption-description">
|
||||
{t(
|
||||
'{{address}} has {{balance}} VEGA tokens in {{tranches}} tranches of the vesting contract.',
|
||||
{
|
||||
address: truncateMiddle(address),
|
||||
address: truncateMiddle(account),
|
||||
balance: formatNumber(balanceFormatted),
|
||||
tranches: filteredTranches.length,
|
||||
}
|
||||
)}
|
||||
</p>
|
||||
<VestingTable
|
||||
associated={lien}
|
||||
locked={totalLockedBalance}
|
||||
vested={totalVestedBalance}
|
||||
/>
|
||||
{filteredTranches.length ? <h2>{t('Tranche breakdown')}</h2> : null}
|
||||
<div className="mb-24">
|
||||
<VestingTable
|
||||
associated={lien}
|
||||
locked={totalLockedBalance}
|
||||
vested={totalVestedBalance}
|
||||
/>
|
||||
</div>
|
||||
{filteredTranches.length ? (
|
||||
<h2 className="text-h4 text-white mb-12">{t('Tranche breakdown')}</h2>
|
||||
) : null}
|
||||
{zeroTranche && (
|
||||
<Tranche0Table
|
||||
trancheId={0}
|
||||
@ -122,10 +131,12 @@ export const RedemptionInformation = () => {
|
||||
<Callout
|
||||
title={t('Stake your Locked VEGA tokens!')}
|
||||
iconName="hand-up"
|
||||
intent={Intent.Prompt}
|
||||
intent={Intent.Warning}
|
||||
>
|
||||
<p>{t('Find out more about Staking.')}</p>
|
||||
<Link to="/staking">{t('Stake VEGA tokens')}</Link>
|
||||
<p className="mb-12">{t('Find out more about Staking.')}</p>
|
||||
<Link to="/staking" className="underline text-white">
|
||||
{t('Stake VEGA tokens')}
|
||||
</Link>
|
||||
</Callout>
|
||||
</section>
|
||||
);
|
||||
|
@ -4,11 +4,13 @@ import { Heading } from '../../components/heading';
|
||||
import { useDocumentTitle } from '../../hooks/use-document-title';
|
||||
import type { RouteChildProps } from '..';
|
||||
import RedemptionRouter from './redemption';
|
||||
import { useMatch } from 'react-router-dom';
|
||||
import { Routes } from '../router-config';
|
||||
|
||||
const RedemptionIndex = ({ name }: RouteChildProps) => {
|
||||
useDocumentTitle(name);
|
||||
const { t } = useTranslation();
|
||||
const tranche = ':id';
|
||||
const tranche = useMatch(`${Routes.VESTING}/:id`);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -70,7 +70,7 @@ const RedemptionRouter = () => {
|
||||
if (!account) {
|
||||
return (
|
||||
<EthConnectPrompt>
|
||||
<p data-testid="eth-connect-prompt">
|
||||
<p data-testid="eth-connect-prompt" className="mb-8">
|
||||
{t(
|
||||
"Use the Ethereum wallet you want to send your tokens to. You'll also need enough Ethereum to pay gas."
|
||||
)}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user