diff --git a/package.json b/package.json
index 4c49aa50..12966557 100644
--- a/package.json
+++ b/package.json
@@ -33,6 +33,7 @@
"axios": "^1.6.7",
"axios-retry": "^4.0.0",
"base64-arraybuffer": "^1.0.2",
+ "better-react-mathjax": "^2.0.3",
"dexie": "^4.0.8",
"dexie-react-hooks": "^1.1.7",
"fflate": "^0.8.2",
diff --git a/src/App.tsx b/src/App.tsx
index 750101ee..82b82cea 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -10,6 +10,7 @@ import {
createRoutesFromElements,
} from 'react-router-dom';
+import { MathJaxContext } from 'better-react-mathjax';
import GlobalDataProvider from './components/GlobalDataProvider';
import WalletProvider from './components/WalletProvider';
import AppRouterLayout from './layout/AppRouterLayout';
@@ -53,7 +54,8 @@ function App() {
}
- />,
+ />
+ ,
}
- />,
+ />
+ ,
}
- />,
+ />
+ ,
,
- }>
@@ -114,7 +118,9 @@ function App() {
-
+
+
+
diff --git a/src/components/modals/BaseModal.tsx b/src/components/modals/BaseModal.tsx
index 95e80ae2..94661b81 100644
--- a/src/components/modals/BaseModal.tsx
+++ b/src/components/modals/BaseModal.tsx
@@ -20,16 +20,18 @@ const BaseModal = ({
aria-hidden="true"
/>
-
+
{showCloseButton && (
)}
- {children}
+
+ {children}
+
diff --git a/src/components/modals/StakingModal.tsx b/src/components/modals/StakingModal.tsx
index 18535869..ec2609d0 100644
--- a/src/components/modals/StakingModal.tsx
+++ b/src/components/modals/StakingModal.tsx
@@ -1,11 +1,18 @@
import { IOToken, mIOToken } from '@ar.io/sdk/web';
-import { EAY_TOOLTIP_TEXT, IO_LABEL, WRITE_OPTIONS, log } from '@src/constants';
+import {
+ EAY_TOOLTIP_FORMULA,
+ EAY_TOOLTIP_TEXT,
+ IO_LABEL,
+ WRITE_OPTIONS,
+ log,
+} from '@src/constants';
import useGateway from '@src/hooks/useGateway';
import useRewardsInfo from '@src/hooks/useRewardsInfo';
import { useGlobalState } from '@src/store';
import { formatWithCommas } from '@src/utils';
import { showErrorToast } from '@src/utils/toast';
import { useQueryClient } from '@tanstack/react-query';
+import { MathJax } from 'better-react-mathjax';
import { useState } from 'react';
import Button, { ButtonType } from '../Button';
import Tooltip from '../Tooltip';
@@ -265,7 +272,8 @@ const StakingModal = ({
{tab == 0
- ? balances && `Available: ${formatWithCommas(balances.io)} ${IO_LABEL}`
+ ? balances &&
+ `Available: ${formatWithCommas(balances.io)} ${IO_LABEL}`
: `Available to Unstake: ${formatWithCommas(currentStake)} ${IO_LABEL}`}
@@ -349,16 +357,22 @@ const StakingModal = ({
label="EAY:"
value={EAY}
rightIcon={
-
+
+ {EAY_TOOLTIP_TEXT}
+ {EAY_TOOLTIP_FORMULA}
+
+ }
+ >
}
/>
-
+
-
diff --git a/src/constants.ts b/src/constants.ts
index 0d956a93..a5270169 100644
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -47,5 +47,7 @@ export const log = loglevel;
export const EAY_TOOLTIP_TEXT =
'EAY = Estimated yield ratio determined by projecting the current nominal reward conditions over the course of a year. Does NOT include potential observation rewards.';
+export const EAY_TOOLTIP_FORMULA =
+ '\\(EAY = \\frac{RewardsSharedPerEpoch}{TotalDelegatedStake} * EpochsPerYear\\)';
export const IO_LABEL = 'tIO';
diff --git a/src/pages/Gateway/PropertyDisplayPanel.tsx b/src/pages/Gateway/PropertyDisplayPanel.tsx
index f3f08667..137c6647 100644
--- a/src/pages/Gateway/PropertyDisplayPanel.tsx
+++ b/src/pages/Gateway/PropertyDisplayPanel.tsx
@@ -1,15 +1,22 @@
import { AoGateway, mIOToken } from '@ar.io/sdk/web';
+import Button, { ButtonType } from '@src/components/Button';
import Placeholder from '@src/components/Placeholder';
+import ConnectModal from '@src/components/modals/ConnectModal';
+import StakingModal from '@src/components/modals/StakingModal';
import { IO_LABEL } from '@src/constants';
+import { useGlobalState } from '@src/store';
+import { useState } from 'react';
const DisplayRow = ({
label,
value,
type,
+ rightComponent,
}: {
label: string;
value: string | number | boolean | undefined;
type?: string;
+ rightComponent?: React.ReactNode;
}) => {
return (
<>
@@ -22,9 +29,12 @@ const DisplayRow = ({
{value === undefined ? (
) : typeof value === 'boolean' ? (
-
- {value ? 'Enabled' : 'Disabled'}
-
+
+
+ {value ? 'Enabled' : 'Disabled'}
+
+ {rightComponent}
+
) : type == 'address' || type == 'tx' ? (
{
+ const walletAddress = useGlobalState((state) => state.walletAddress);
+
+ const [stakingModalWalletAddress, setStakingModalWalletAddress] =
+ useState();
+
+ const [isConnectModalOpen, setIsConnectModalOpen] = useState(false);
+
const gatewayAddress = gateway
? `${gateway.settings.protocol}://${gateway.settings.fqdn}:${gateway.settings.port}`
: undefined;
@@ -66,7 +83,7 @@ const PropertyDisplayPanel = ({
? [
{
label: 'Reward Share Ratio:',
- value: gateway?.settings.delegateRewardShareRatio,
+ value: `${gateway?.settings.delegateRewardShareRatio}%`,
},
{
label: `Minimum Delegated Stake (${IO_LABEL}):`,
@@ -107,15 +124,49 @@ const PropertyDisplayPanel = ({
{
label: 'Delegated Staking:',
value: gateway?.settings.allowDelegatedStaking,
+ rightComponent: gateway?.settings.allowDelegatedStaking ? (
+
{
.toIO()
.valueOf(),
status: gateway.status,
- rewardRatio: gateway.settings.delegateRewardShareRatio,
+ rewardRatio: gateway.settings.allowDelegatedStaking
+ ? gateway.settings.delegateRewardShareRatio
+ : -1,
streak:
gateway.stats.failedConsecutiveEpochs > 0
? -gateway.stats.failedConsecutiveEpochs
@@ -100,13 +102,13 @@ const Gateways = () => {
}),
columnHelper.accessor('start', {
id: 'start',
- header: 'Start',
+ header: 'Join Date',
sortDescFirst: true,
cell: ({ row }) => formatDate(row.original.start),
}),
columnHelper.accessor('totalStake', {
id: 'totalStake',
- header: 'Total Stake',
+ header: `Total Stake (${IO_LABEL})`,
sortDescFirst: true,
cell: ({ row }) => (
{
{IO_LABEL}
- Total Delegated Stake:{' '}
+ Delegated Stake:{' '}
{formatWithCommas(row.original.totalDelegatedStake)} {IO_LABEL}
@@ -136,7 +138,8 @@ const Gateways = () => {
id: 'rewardRatio',
header: 'Reward Share Ratio',
sortDescFirst: true,
- cell: ({ row }) => `${row.original.rewardRatio}%`,
+ cell: ({ row }) =>
+ row.original.rewardRatio >= 0 ? `${row.original.rewardRatio}%` : 'N/A',
}),
columnHelper.accessor('streak', {
id: 'streak',
diff --git a/src/pages/Staking/DelegateStakeTable.tsx b/src/pages/Staking/DelegateStakeTable.tsx
index 1decb9e0..371f79f8 100644
--- a/src/pages/Staking/DelegateStakeTable.tsx
+++ b/src/pages/Staking/DelegateStakeTable.tsx
@@ -6,13 +6,18 @@ import Tooltip from '@src/components/Tooltip';
import { InfoIcon } from '@src/components/icons';
import ConnectModal from '@src/components/modals/ConnectModal';
import StakingModal from '@src/components/modals/StakingModal';
-import { EAY_TOOLTIP_TEXT } from '@src/constants';
+import {
+ EAY_TOOLTIP_FORMULA,
+ EAY_TOOLTIP_TEXT,
+ IO_LABEL,
+} from '@src/constants';
import useGateways from '@src/hooks/useGateways';
import useProtocolBalance from '@src/hooks/useProtocolBalance';
import { useGlobalState } from '@src/store';
import { formatWithCommas } from '@src/utils';
import { calculateGatewayRewards } from '@src/utils/rewards';
import { ColumnDef, createColumnHelper } from '@tanstack/react-table';
+import { MathJax } from 'better-react-mathjax';
import { useEffect, useState } from 'react';
interface TableData {
@@ -22,6 +27,8 @@ interface TableData {
failedConsecutiveEpochs: number;
rewardRatio: number;
totalDelegatedStake: number;
+ totalStake: number;
+ operatorStake: number;
eay: number;
}
@@ -57,9 +64,19 @@ const DelegateStake = () => {
failedConsecutiveEpochs:
gateway.stats.failedConsecutiveEpochs,
rewardRatio: gateway.settings.delegateRewardShareRatio,
+
totalDelegatedStake: new mIOToken(gateway.totalDelegatedStake)
.toIO()
.valueOf(),
+ operatorStake: new mIOToken(gateway.operatorStake)
+ .toIO()
+ .valueOf(),
+ totalStake: new mIOToken(
+ gateway.totalDelegatedStake + gateway.operatorStake,
+ )
+ .toIO()
+ .valueOf(),
+
eay: calculateGatewayRewards(
new mIOToken(protocolBalance).toIO(),
Object.keys(gateways).length,
@@ -102,10 +119,28 @@ const DelegateStake = () => {
sortDescFirst: false,
cell: ({ row }) => ,
}),
- columnHelper.accessor('totalDelegatedStake', {
- id: 'totalDelegatedStake',
- header: 'Total Stake',
+ columnHelper.accessor('totalStake', {
+ id: 'totalStake',
+ header: `Total Stake (${IO_LABEL})`,
sortDescFirst: true,
+ cell: ({ row }) => (
+
+
+ Operator Stake: {formatWithCommas(row.original.operatorStake)}{' '}
+ {IO_LABEL}
+
+
+ Delegated Stake:{' '}
+ {formatWithCommas(row.original.totalDelegatedStake)} {IO_LABEL}
+
+
+ }
+ >
+ {formatWithCommas(row.getValue('totalStake'))}
+
+ ),
}),
columnHelper.accessor('failedConsecutiveEpochs', {
id: 'failedConsecutiveEpochs',
@@ -123,7 +158,14 @@ const DelegateStake = () => {
header: () => (
EAY
-
+
+ {EAY_TOOLTIP_TEXT}
+ {EAY_TOOLTIP_FORMULA}
+
+ }
+ >
@@ -183,9 +225,9 @@ const DelegateStake = () => {
/>
)}
- {isConnectModalOpen && (
- setIsConnectModalOpen(false)} />
- )}
+ {isConnectModalOpen && (
+ setIsConnectModalOpen(false)} />
+ )}
);
};
diff --git a/yarn.lock b/yarn.lock
index b1cd0864..ffeb7660 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4266,6 +4266,13 @@ bech32@1.1.4:
resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9"
integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==
+better-react-mathjax@^2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/better-react-mathjax/-/better-react-mathjax-2.0.3.tgz#202dc6fe5c7263278f2491516f43f70ba188122f"
+ integrity sha512-wfifT8GFOKb1TWm2+E50I6DJpLZ5kLbch283Lu043EJtwSv0XvZDjr4YfR4d2MjAhqP6SH4VjjrKgbX8R00oCQ==
+ dependencies:
+ mathjax-full "^3.2.2"
+
bigint-buffer@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/bigint-buffer/-/bigint-buffer-1.1.5.tgz#d038f31c8e4534c1f8d0015209bf34b4fa6dd442"
@@ -4841,6 +4848,11 @@ commander@12.1.0:
resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3"
integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==
+commander@9.2.0:
+ version "9.2.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-9.2.0.tgz#6e21014b2ed90d8b7c9647230d8b7a94a4a419a9"
+ integrity sha512-e2i4wANQiSXgnrBlIatyHtP1odfUp0BbV5Y5nEGbxtIrStkEOAAzCUirvLBNXHLr7kwLvJl6V+4V3XV9x7Wd9w==
+
commander@^2.20.3:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
@@ -5883,6 +5895,11 @@ eslint@^8.56.0:
strip-ansi "^6.0.1"
text-table "^0.2.0"
+esm@^3.2.25:
+ version "3.2.25"
+ resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10"
+ integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==
+
espree@^9.6.0, espree@^9.6.1:
version "9.6.1"
resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f"
@@ -8134,6 +8151,16 @@ map-obj@^4.0.0:
resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a"
integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==
+mathjax-full@^3.2.2:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/mathjax-full/-/mathjax-full-3.2.2.tgz#43f02e55219db393030985d2b6537ceae82f1fa7"
+ integrity sha512-+LfG9Fik+OuI8SLwsiR02IVdjcnRCy5MufYLi0C3TdMT56L/pjB0alMVGgoWJF8pN9Rc7FESycZB9BMNWIid5w==
+ dependencies:
+ esm "^3.2.25"
+ mhchemparser "^4.1.0"
+ mj-context-menu "^0.6.1"
+ speech-rule-engine "^4.0.6"
+
md5.js@^1.3.4:
version "1.3.5"
resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
@@ -8179,6 +8206,11 @@ merge2@^1.3.0, merge2@^1.4.1:
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
+mhchemparser@^4.1.0:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/mhchemparser/-/mhchemparser-4.2.1.tgz#d73982e66bc06170a85b1985600ee9dabe157cb0"
+ integrity sha512-kYmyrCirqJf3zZ9t/0wGgRZ4/ZJw//VwaRVGA75C4nhE60vtnIzhl9J9ndkX/h6hxSN7pjg/cE0VxbnNM+bnDQ==
+
micromatch@4.0.6:
version "4.0.6"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.6.tgz#ab4e37c42726b9cd788181ba4a2a4fead8e394a3"
@@ -8304,6 +8336,11 @@ mixme@^0.5.1:
resolved "https://registry.yarnpkg.com/mixme/-/mixme-0.5.10.tgz#d653b2984b75d9018828f1ea333e51717ead5f51"
integrity sha512-5H76ANWinB1H3twpJ6JY8uvAtpmFvHNArpilJAjXRKXSDDLPIMoZArw5SH0q9z+lLs8IrMw7Q2VWpWimFKFT1Q==
+mj-context-menu@^0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/mj-context-menu/-/mj-context-menu-0.6.1.tgz#a043c5282bf7e1cf3821de07b13525ca6f85aa69"
+ integrity sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA==
+
mkdirp@~0.5.1:
version "0.5.6"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6"
@@ -9866,6 +9903,15 @@ spdx-license-ids@^3.0.0:
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz#887da8aa73218e51a1d917502d79863161a93f9c"
integrity sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==
+speech-rule-engine@^4.0.6:
+ version "4.0.7"
+ resolved "https://registry.yarnpkg.com/speech-rule-engine/-/speech-rule-engine-4.0.7.tgz#b655dacbad3dae04acc0f7665e26ef258397dd09"
+ integrity sha512-sJrL3/wHzNwJRLBdf6CjJWIlxC04iYKkyXvYSVsWVOiC2DSkHmxsqOhEeMsBA9XK+CHuNcsdkbFDnoUfAsmp9g==
+ dependencies:
+ commander "9.2.0"
+ wicked-good-xpath "1.3.0"
+ xmldom-sre "0.1.31"
+
split2@^3.0.0, split2@^3.2.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f"
@@ -10887,6 +10933,11 @@ which@^2.0.1, which@^2.0.2:
dependencies:
isexe "^2.0.0"
+wicked-good-xpath@1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/wicked-good-xpath/-/wicked-good-xpath-1.3.0.tgz#81b0e95e8650e49c94b22298fff8686b5553cf6c"
+ integrity sha512-Gd9+TUn5nXdwj/hFsPVx5cuHHiF5Bwuc30jZ4+ronF1qHK5O7HD0sgmXWSEgwKquT3ClLoKPVbO6qGwVwLzvAw==
+
winston-transport@^4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.7.0.tgz#e302e6889e6ccb7f383b926df6936a5b781bd1f0"
@@ -11007,6 +11058,11 @@ xmlchars@^2.2.0:
resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb"
integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==
+xmldom-sre@0.1.31:
+ version "0.1.31"
+ resolved "https://registry.yarnpkg.com/xmldom-sre/-/xmldom-sre-0.1.31.tgz#10860d5bab2c603144597d04bf2c4980e98067f4"
+ integrity sha512-f9s+fUkX04BxQf+7mMWAp5zk61pciie+fFLC9hX9UVvCeJQfNHRHXpeo5MPcR0EUf57PYLdt+ZO4f3Ipk2oZUw==
+
xtend@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"