+
{ colorInfoEntry("Available to stake", `${formatUnitsToHumanReadable(zilAvailable || 0n, 18)} ZIL`) }
{ colorInfoEntry("Staked", `${humanReadableStakingToken(userStakingPoolData?.stakingTokenAmount || 0n)} ${stakingPoolData.definition.tokenSymbol}`) }
{ colorInfoEntry("Unstake requests", pendingUnstakesValue ? `${humanReadableStakingToken(pendingUnstakesValue)} ${stakingPoolData.definition.tokenSymbol}`: "-" ) }
{ colorInfoEntry("Available to claim", availableToClaim ? `${humanReadableStakingToken(availableToClaim)} ${stakingPoolData.definition.tokenSymbol}` : "-") }
}
-
+
{ greyInfoEntry("Voting power", stakingPoolData.data && formatPercentage(stakingPoolData.data.votingPower)) }
{ greyInfoEntry("Total supply", stakingPoolData.data && `${humanReadableStakingToken(stakingPoolData.data.tvl)} ${stakingPoolData.definition.tokenSymbol}`) }
{ greyInfoEntry("Commission", stakingPoolData.data && formatPercentage(stakingPoolData.data.commission)) }
{ greyInfoEntry("", stakingPoolData.data &&
(
<>
- 1 ZIL =
- {stakingPoolData.data.zilToTokenRate} {stakingPoolData.definition.tokenSymbol}
+ 1 ZIL ~
+ {stakingPoolData.data.zilToTokenRate.toPrecision(3)} {stakingPoolData.definition.tokenSymbol}
>
)) }
diff --git a/src/components/unstakingCalculator.tsx b/src/components/unstakingCalculator.tsx
index a68d10f..d9b46f4 100644
--- a/src/components/unstakingCalculator.tsx
+++ b/src/components/unstakingCalculator.tsx
@@ -5,9 +5,11 @@ import {
formatPercentage,
convertTokenToZil,
formatUnitsToHumanReadable,
+ getHumanFormDuration,
} from '@/misc/formatting';
import { formatUnits, parseEther } from 'viem';
import { StakingOperations } from '@/contexts/stakingOperations';
+import { DateTime } from 'luxon';
const UnstakingCalculator: React.FC = () => {
const { stakingPoolForView } = StakingPoolsStorage.useContainer();
@@ -72,6 +74,10 @@ const UnstakingCalculator: React.FC = () => {
);
};
+ const unboudingPeriod = getHumanFormDuration((
+ DateTime.now().plus({ minutes: stakingPoolForView?.stakingPool.definition.withdrawPeriodInMinutes || 0 })
+ ));
+
return (
stakingPoolForView && (
@@ -111,7 +117,7 @@ const UnstakingCalculator: React.FC = () => {
)}
ZIL
- ~5 days
+ { unboudingPeriod }
@@ -149,7 +155,7 @@ const UnstakingCalculator: React.FC = () => {
Max transaction cost: {zilToUnstake ? '0.01' : '0'}$
- Unbonding Period: {zilToUnstake ? '0.01' : '0'}$
+ Unbonding Period: { unboudingPeriod }
diff --git a/src/contexts/stakingOperations.tsx b/src/contexts/stakingOperations.tsx
index 248c741..aee8b72 100644
--- a/src/contexts/stakingOperations.tsx
+++ b/src/contexts/stakingOperations.tsx
@@ -46,6 +46,7 @@ const useStakingOperations = () => {
if (isDummyWalletConnected) {
setDummyWalletPopupContent(`Now User gonna approve the wallet transaction for staking ZIL`);
setIsDummyWalletPopupOpen(true);
+ setStakingCallTxHash("0x1234567890234567890234567890234567890" as Address);
} else {
writeContract(
wagmiConfig,
@@ -110,6 +111,7 @@ const useStakingOperations = () => {
if (isDummyWalletConnected) {
setDummyWalletPopupContent(`Now User gonna approve the wallet transaction for unstaking ${tokensToUnstake} staked tokens`);
setIsDummyWalletPopupOpen(true);
+ setUnstakingCallTxHash("0x1234567890234567890234567890234567890" as Address);
} else {
writeContract(
wagmiConfig,
diff --git a/src/misc/stakingAbis.ts b/src/misc/stakingAbis.ts
index 5e633d0..1666a21 100644
--- a/src/misc/stakingAbis.ts
+++ b/src/misc/stakingAbis.ts
@@ -1,3 +1,32 @@
+export const depositAbi = [
+ {
+ "inputs": [],
+ "name": "getFutureTotalStake",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "withdrawalPeriod",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ }
+]
+
export const delegatorAbi = [
{
"inputs": [],
@@ -44,5 +73,44 @@ export const delegatorAbi = [
],
"stateMutability": "view",
"type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "getCommissionNumerator",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "getPrice",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "getStake",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
}
]
\ No newline at end of file
diff --git a/src/misc/stakingPoolsConfig.ts b/src/misc/stakingPoolsConfig.ts
index 788c548..4fea7ab 100644
--- a/src/misc/stakingPoolsConfig.ts
+++ b/src/misc/stakingPoolsConfig.ts
@@ -1,6 +1,12 @@
-import { Address, erc20Abi } from "viem";
+import { Address, erc20Abi, formatUnits, parseUnits } from "viem";
import { CHAIN_ZQ2_PROTOTESTNET, CHAIN_ZQ2_DOCKERCOMPOSE, getViemClient, MOCK_CHAIN } from "./chainConfig";
import { readContract } from "viem/actions";
+import { delegatorAbi, depositAbi } from "./stakingAbis";
+
+/**
+ * Deposit address is always the same
+ */
+const DEPOSIT_ADDRESS = "0x00000000005a494c4445504f53495450524f5859" as Address;
export interface StakingPoolDefinition {
id: string;
@@ -11,6 +17,7 @@ export interface StakingPoolDefinition {
tokenSymbol: string;
iconUrl: string;
minimumStake: bigint;
+ withdrawPeriodInMinutes: number;
}
export interface StakingPoolData {
@@ -39,17 +46,76 @@ async function mockDelegatorDataProvider(mockData: StakingPoolData, loadingMilis
});
}
-async function fetchDelegatorDataFromNetwork(mockData: StakingPoolData, definition: StakingPoolDefinition, chainId: number): Promise
{
- try {
- const totalSupply = await readContract(getViemClient(chainId), {
+async function fetchDelegatorDataFromNetwork(definition: StakingPoolDefinition, chainId: number): Promise {
+
+ const viemClient = getViemClient(chainId);
+
+ const readDelegatorContract = async (functionName: string): Promise => {
+ return (await readContract(viemClient, {
+ address: definition.address as Address,
+ abi: delegatorAbi,
+ functionName,
+ })) as T
+ }
+
+ const readTokenContract = async (functionName: "symbol" | "name" | "totalSupply" | "allowance" | "balanceOf" | "decimals"): Promise => {
+ return await (readContract(viemClient, {
address: definition.tokenAddress as Address,
abi: erc20Abi,
- functionName: "totalSupply",
+ functionName,
+ })) as T
+ }
+
+ const readDepositContract = async (functionName: string): Promise => {
+ return await (readContract(viemClient, {
+ address: DEPOSIT_ADDRESS,
+ abi: depositAbi,
+ functionName,
+ })) as T
+ }
+
+ try {
+ const [
+ totalSupply,
+ commissionNumerator,
+ zilToTokenRateWei,
+ delegatorStake,
+ depositTotalStake,
+ ] = await Promise.all([
+ readTokenContract("totalSupply"),
+ readDelegatorContract("getCommissionNumerator"),
+ readDelegatorContract("getPrice"),
+ readDelegatorContract("getStake"),
+ readDepositContract("getFutureTotalStake"),
+ ]);
+
+ const commissionDenominator = 10000;
+ const zilToTokenRate = 1 / parseFloat(formatUnits(zilToTokenRateWei, 18));
+
+ const commission = (parseInt(commissionNumerator.toString()) / commissionDenominator); // percent
+ const votingPower = parseFloat(((delegatorStake * 100n) / depositTotalStake).toString()) / 100; // percent
+ const rewardsPerYearInZil = 51000 * 24 * 365;
+
+ const delegatorYearReward = votingPower * rewardsPerYearInZil;
+ const delegatorRewardForShare = delegatorYearReward * (1 - commission);
+ const apr = delegatorRewardForShare / parseFloat(formatUnits(delegatorStake, 18));
+
+ console.log({
+ commission,
+ votingPower,
+ rewardsPerYearInZil,
+ delegatorYearReward,
+ delegatorRewardForShare,
+ apr
})
return {
- ...mockData,
tvl: totalSupply,
+ commission,
+ zilToTokenRate,
+ votingPower,
+ apr: apr
+
}
} catch (error) {
console.error("Error fetching total supply:", error);
@@ -57,6 +123,8 @@ async function fetchDelegatorDataFromNetwork(mockData: StakingPoolData, definiti
}
}
+const twoWeeksInMinutes = 60 * 24 * 14;
+
export const stakingPoolsConfigForChainId: Record> = {
[MOCK_CHAIN.id]: [
{
@@ -68,11 +136,12 @@ export const stakingPoolsConfigForChainId: Record = [
stakingTokenAmount: [
{
address: "0x1234567890234567890234567890234567890",
- stakingTokenAmount: 1000n,
+ stakingTokenAmount: parseUnits("1000.50", 18),
rewardAcumulated: 10
},
{
address: "0x96525678902345678902345678918278372212",
- stakingTokenAmount: 60n,
+ stakingTokenAmount: parseUnits("60.50", 18),
rewardAcumulated: 50
},
],
@@ -82,12 +82,12 @@ export const dummyWallets: Array = [
stakingTokenAmount: [
{
address: "0x1234567890234567890234567890234567890",
- stakingTokenAmount: 1000n,
+ stakingTokenAmount: parseUnits("1000", 18),
rewardAcumulated: 10
},
{
address: "0x96525678902345678902345678918278372212",
- stakingTokenAmount: 60n,
+ stakingTokenAmount: parseUnits("9991119", 18),
rewardAcumulated: 50
},
],
@@ -126,12 +126,12 @@ export const dummyWallets: Array = [
stakingTokenAmount: [
{
address: "0x96525678902345678902345678918278372212",
- stakingTokenAmount: 123n,
+ stakingTokenAmount: parseUnits("123.522039320", 18),
rewardAcumulated: 40
},
{
address: "0x82245678902345678902345678918278372382",
- stakingTokenAmount: 999n,
+ stakingTokenAmount: parseUnits("99999", 18),
rewardAcumulated: 0
},
],
diff --git a/src/script/fetchPoolStaticData.ts b/src/script/fetchPoolStaticData.ts
index 269351b..0ccd5f1 100644
--- a/src/script/fetchPoolStaticData.ts
+++ b/src/script/fetchPoolStaticData.ts
@@ -43,51 +43,55 @@ const argv = yargs(hideBin(process.argv))
console.log(`Network RPC URL: ${argv.network_id}`);
console.log(`Contract Address: ${argv.contract_address}`);
+
const chainid = parseInt(argv.network_id);
- const tokenAddress = await readContract(getViemClient(chainid), {
- address: argv.contract_address as Address,
- abi: delegatorAbi,
- functionName: "getLST",
- }) as string;
+ const readDelegatorContract = async (functionName: string): Promise => {
+ return (await readContract(getViemClient(chainid), {
+ address: argv.contract_address as Address,
+ abi: delegatorAbi,
+ functionName,
+ })) as T
+ }
+
+ const [tokenAddress] = await Promise.all([
+ readDelegatorContract("getLST"),
+ ]);
+
+ const readTokenContract = async (functionName: string): Promise => {
+ return await (readContract(getViemClient(chainid), {
+ address: tokenAddress,
+ abi: erc20Abi,
+ functionName: "decimals",
+ })) as T
+ }
const [
tokenDecimals,
tokenSymbol,
minimumStake,
] = await Promise.all([
- readContract(getViemClient(chainid), {
- address: tokenAddress as Address,
- abi: erc20Abi,
- functionName: "decimals",
- }),
- readContract(getViemClient(chainid), {
- address: tokenAddress as Address,
- abi: erc20Abi,
- functionName: "symbol",
- }),
- readContract(getViemClient(chainid), {
- address: argv.contract_address as Address,
- abi: delegatorAbi,
- functionName: "MIN_DELEGATION",
- }),
+ readTokenContract("decimals"),
+ readTokenContract("symbol"),
+ readTokenContract("MIN_DELEGATION")
]);
const hash = Buffer.from(argv.contract_address + tokenAddress).toString('base64').slice(0, 8);
+ const twoWeeksInMinutes = 60 * 24 * 14;
const definition: StakingPoolDefinition = {
id: hash,
- address: argv.contract_address,
- tokenAddress,
- iconUrl: argv.icon_url,
- name: argv.name,
- tokenDecimals,
- tokenSymbol,
- minimumStake: minimumStake as bigint,
+ address: argv.contract_address,
+ tokenAddress,
+ iconUrl: argv.icon_url,
+ name: argv.name,
+ tokenDecimals,
+ tokenSymbol,
+ minimumStake: minimumStake as bigint,
+ withdrawPeriodInMinutes: twoWeeksInMinutes,
}
console.log("Add following definition to stakingPoolsConfig.ts");
- // console.log(JSON.stringify({ definition }, null, 2));
console.log({ definition, });
}
)();