Skip to content

Commit

Permalink
Add staking flow component, move chain rewards, update paymaster abi
Browse files Browse the repository at this point in the history
  • Loading branch information
dmytrotkk committed Nov 19, 2024
1 parent 14379bf commit 6dce4da
Show file tree
Hide file tree
Showing 10 changed files with 280 additions and 937 deletions.
12 changes: 12 additions & 0 deletions src/App.scss
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,7 @@ input[type=number] {
.chipXs {
border-radius: 15px;
padding: 6px 8px;
text-align: center;

svg {
width: 12px;
Expand Down Expand Up @@ -897,6 +898,11 @@ input[type=number] {
color: #3cda94;
}

.chip_REWARDS {
background: linear-gradient(180deg, #3d390f, #2a230a);
color: #dac83c;
}

.chip_ACCEPTED {
background: linear-gradient(180deg, #233d0f, #0a1b07);
color: #3cda4e;
Expand Down Expand Up @@ -1438,4 +1444,10 @@ input[type=number] {
.MuiTooltip-tooltip {
font-size: 0.8rem !important;
padding: 8px 12px !important;
}

.delegationFlowText {
border-top: 2px #4a4a4a solid;
margin: 0 10px;
padding: 2px 5px 0 5px;
}
2 changes: 1 addition & 1 deletion src/components/Tile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import SkStack from './SkStack'

export default function Tile(props: {
text?: string
value?: string | null
value?: string | null | false
textRi?: string
icon?: ReactElement
className?: string
Expand Down
143 changes: 143 additions & 0 deletions src/components/delegation/ChainRewards.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/**
* @license
* SKALE portal
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* @file ChainRewards.tsx
* @copyright SKALE Labs 2024-Present
*/

import { useEffect, useState } from 'react'
import {
cls,
cmn,
ERC_ABIS,
MetaportCore,
SkPaper,
styles,
TokenIcon
} from '@skalenetwork/metaport'
import { types } from '@/core'

import StarsRoundedIcon from '@mui/icons-material/StarsRounded'
import EventAvailableRoundedIcon from '@mui/icons-material/EventAvailableRounded'

import Headline from '../Headline'
import { formatBalance } from '../../core/helper'
import Tile from '../Tile'
import SkBtn from '../SkBtn'
import { initPaymaster } from '../../core/paymaster'
import { DEFAULT_UPDATE_INTERVAL_MS } from '../../core/constants'
import SkStack from '../SkStack'
import { Contract } from 'ethers'

interface ChainRewardsProps {
mpc: MetaportCore
validator: types.staking.IValidator | null | undefined
customAddress?: string
className?: string
isXs?: boolean
}

const ChainRewards: React.FC<ChainRewardsProps> = ({
mpc,
validator,
customAddress,
className,
isXs
}) => {
const paymaster = initPaymaster(mpc)

const [rewardAmount, setRewardAmount] = useState<bigint | null>(null)
const [sklToken, setSklToken] = useState<Contract | null>(null)
const [tokenBalance, setTokenBalance] = useState<bigint | null>(null)

useEffect(() => {
loadData()
const intervalId = setInterval(loadData, DEFAULT_UPDATE_INTERVAL_MS)
return () => {
clearInterval(intervalId)
}
}, [validator])

async function loadChainRewards() {
if (validator) {
setRewardAmount(await paymaster.getRewardAmount(validator.id))
}
}

async function loadData() {
loadChainRewards()
loadSkaleToken()
}

async function loadSkaleToken() {
const address = await paymaster.skaleToken()
let skl = sklToken
if (skl === null) {
skl = new Contract(address, ERC_ABIS.erc20.abi, paymaster.runner)
setSklToken(skl)
}
setTokenBalance(await skl.balanceOf(address))
}

return (
<SkPaper gray className={cls(cmn.mtop20, className)}>
<Headline
size="small"
text="Chain Rewards"
icon={<StarsRoundedIcon className={cls(styles.chainIconxs)} />}
className={cls(cmn.mbott20)}
/>
<Tile
disabled={rewardAmount === 0n}
value={rewardAmount !== null && formatBalance(rewardAmount, 'SKL')}
text="Rewards on Europa Hub"
icon={<EventAvailableRoundedIcon />}
grow
childrenRi={
<SkStack className={cls(cmn.flex, [cmn.flexcv, !isXs])}>
<SkBtn
// loading={loading}
text="Retrieve"
variant="contained"
size="sm"
className={cls([cmn.mleft20, !isXs], cmn.mri20, cmn.flexcv)}
disabled={customAddress !== undefined}
// onClick={() => {
// }}
/>
<div className={cls(['borderVert', !isXs])}>
<Tile
className={cls(cmn.nop, [cmn.mri10, !isXs], [cmn.mleft20, !isXs])}
size="md"
transparent
grow
// disabled={props.accountInfo?.allowedToDelegate === 0n}
value={tokenBalance !== null && formatBalance(tokenBalance, 'SKL')}
ri={!isXs}
text="Balance on Europa Hub"
icon={<TokenIcon tokenSymbol="skl" size="xs" />}
/>
</div>
</SkStack>
}
/>
</SkPaper>
)
}

export default ChainRewards
12 changes: 11 additions & 1 deletion src/components/delegation/Delegate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { TextField } from '@mui/material'
import AccessTimeRoundedIcon from '@mui/icons-material/AccessTimeRounded'
import TransitEnterexitRoundedIcon from '@mui/icons-material/TransitEnterexitRounded'
import EventRepeatRoundedIcon from '@mui/icons-material/EventRepeatRounded'
import AccountTreeRoundedIcon from '@mui/icons-material/AccountTreeRounded'

import Tile from '../Tile'
import SkStack from '../SkStack'
Expand All @@ -57,6 +58,7 @@ import {
} from '../../core/constants'
import { initActionContract } from '../../core/contracts'
import { types } from '@/core'
import DelegationFlow from './DelegationFlow'

debug.enable('*')
const log = debug('portal:pages:Delegate')
Expand Down Expand Up @@ -162,9 +164,17 @@ export default function Delegate(props: {
value="Auto-renewed"
text="Renewal"
icon={<EventRepeatRoundedIcon />}
color={true ? undefined : 'error'}
/>
</SkStack>

<Tile
text="Delegation flow"
className={cls(cmn.mbott10)}
icon={<AccountTreeRoundedIcon />}
grow
children={<DelegationFlow className={cls(cmn.mtop10)} />}
/>

<SkStack>
<Tile
text="Enter amount to stake"
Expand Down
1 change: 0 additions & 1 deletion src/components/delegation/Delegation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,6 @@ export default function Delegation(props: {
<h4 className={cls(cmn.p, cmn.p700, [cmn.pSec, !isActive])}>{delegationAmount}</h4>
<p className={cls(cmn.p, cmn.p4, cmn.pSec)}>{getStakingText()}</p>
</div>

<ArrowForwardIosRoundedIcon
className={cls(
cmn.pSec,
Expand Down
100 changes: 100 additions & 0 deletions src/components/delegation/DelegationFlow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/**
* @license
* SKALE portal
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* @file DelegationFlow.tsx
* @copyright SKALE Labs 2024-Present
*/

import { cls, cmn } from '@skalenetwork/metaport'
import { types } from '@/core'

import { formatBigIntTimestampSeconds } from '../../core/timeHelper'

interface DelegationFlowProps {
delegation?: types.staking.IDelegation
className?: string
}

const DelegationFlow: React.FC<DelegationFlowProps> = ({ delegation, className }) => {
function formatDate(date: Date): string {
const day = date.getDate().toString().padStart(2, '0')
const month = (date.getMonth() + 1).toString().padStart(2, '0')
const year = date.getFullYear()
return `${day}.${month}.${year}`
}

function getFirstDayNextMonth(): string {
const date = new Date()
date.setMonth(date.getMonth() + 1)
date.setDate(1)
return formatDate(date)
}

function getFirstDayMonthAfterNext(): string {
const date = new Date()
date.setMonth(date.getMonth() + 2)
date.setDate(1)
return formatDate(date)
}

function getCurrentDate(): string {
return formatDate(new Date())
}

return (
<div className={cls(cmn.flex, cmn.flexcv, className)}>
<div>
<div className={cls(`chipXs chip_PROPOSED`)}>
<p className={cls(cmn.p, cmn.p4, 'pOneLine')}>PROPOSED</p>
</div>
<p className={cls(cmn.p, cmn.p5, cmn.pSec, cmn.pCent, cmn.mtop5)}>
{delegation ? formatBigIntTimestampSeconds(delegation.created) : getCurrentDate()}
</p>
</div>
<p className={cls(cmn.p, cmn.p5, cmn.pSec, 'delegationFlowText')}>Validator accepts</p>
<div>
<div className={cls(`chipXs chip_ACCEPTED`)}>
<p className={cls(cmn.p, cmn.p4, 'pOneLine')}>ACCEPTED</p>
</div>
<p className={cls(cmn.p, cmn.p5, cmn.pSec, cmn.pCent, cmn.mtop5)}>
Until {getFirstDayNextMonth()}
</p>
</div>
<p className={cls(cmn.p, cmn.p5, cmn.pSec, 'delegationFlowText')}>Month ends</p>
<div>
<div className={cls(`chipXs chip_DELEGATED`)}>
<p className={cls(cmn.p, cmn.p4)}>DELEGATED</p>
</div>
<p className={cls(cmn.p, cmn.p5, cmn.pSec, cmn.pCent, cmn.mtop5)}>
From {getFirstDayNextMonth()}
</p>
</div>
<p className={cls(cmn.p, cmn.p5, cmn.pSec, 'delegationFlowText')}>Month ends</p>
<div>
<div className={cls(`chipXs chip_REWARDS`)}>
<p className={cls(cmn.p, cmn.p4, 'pOneLine')}>REWARDS GENERATED</p>
</div>
<p className={cls(cmn.p, cmn.p5, cmn.pSec, cmn.pCent, cmn.mtop5)}>
Monthly, starting on {getFirstDayMonthAfterNext()}
</p>
</div>
</div>
)
}

export default DelegationFlow
3 changes: 2 additions & 1 deletion src/core/paymaster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { Contract, id, type InterfaceAbi } from 'ethers'
import { type MetaportCore } from '@skalenetwork/metaport'
import { type types } from '@/core'
import PAYMASTER_INFO from '../data/paymaster'
import PAYMASTER_ABI from '../data/paymasterAbi.json'

export interface PaymasterInfo {
maxReplenishmentPeriod: bigint
Expand Down Expand Up @@ -67,7 +68,7 @@ export function getPaymasterLaunchTs(skaleNetwork: types.SkaleNetwork): bigint {
}

export function getPaymasterAbi(): InterfaceAbi {
return PAYMASTER_INFO.abi
return PAYMASTER_ABI.abi
}

export function initPaymaster(mpc: MetaportCore): Contract {
Expand Down
Loading

0 comments on commit 6dce4da

Please sign in to comment.