From 0500272a168f391218683b5e137c2d3181b70c4a Mon Sep 17 00:00:00 2001 From: kemuru <102478601+kemuru@users.noreply.github.com> Date: Mon, 10 Mar 2025 05:08:51 +0100 Subject: [PATCH] feat: add section for claiming staking rewards in v2, tested in arb sepolia --- .../Profile/StakingRewardsClaimModal.tsx | 102 ++++++++++++++++++ web/src/pages/Profile/index.tsx | 2 + 2 files changed, 104 insertions(+) create mode 100644 web/src/pages/Profile/StakingRewardsClaimModal.tsx diff --git a/web/src/pages/Profile/StakingRewardsClaimModal.tsx b/web/src/pages/Profile/StakingRewardsClaimModal.tsx new file mode 100644 index 000000000..a1b6e1210 --- /dev/null +++ b/web/src/pages/Profile/StakingRewardsClaimModal.tsx @@ -0,0 +1,102 @@ +import React, { useState, useEffect } from "react"; +import { useAccount, useWriteContract } from "wagmi"; +import { formatEther, parseAbi } from "viem"; +import { DEFAULT_CHAIN } from "consts/chains"; + +const ipfsEndpoint = "https://cdn.kleros.link"; + +const chainIdToParams = { + 421614: { + contractAddress: "0x9DdAeD4e2Ba34d59025c1A549311F621a8ff9b7b", + snapshots: ["QmQBupnUD9zt2dzZcB6tNAENiWtmwfWeKDuZbWEWoKs7s2/arbSepolia-snapshot-2025-02.json"], + startMonth: 2, + }, + 42161: { + contractAddress: "", + snapshots: [], + startMonth: 2, + }, +}; + +const claimMonthsAbi = parseAbi([ + "function claimMonths(address _liquidityProvider, (uint256 month, uint256 balance, bytes32[] merkleProof)[] claims)", +]); + +const ClaimModal = () => { + const { address: account } = useAccount(); + const chainId = DEFAULT_CHAIN; + const chainParams = chainIdToParams[chainId] ?? chainIdToParams[DEFAULT_CHAIN]; + + const [claims, setClaims] = useState([]); + const [loading, setLoading] = useState(false); + const [claimed, setClaimed] = useState(false); + + useEffect(() => { + const fetchClaims = async () => { + if (!account || !chainParams) return; + + const userClaims = []; + for (let index = 0; index < chainParams.snapshots.length; index++) { + const response = await fetch(`${ipfsEndpoint}/ipfs/${chainParams.snapshots[index]}`); + const snapshot = await response.json(); + const claim = snapshot.merkleTree.claims[account]; + + if (claim) { + userClaims.push({ + month: chainParams.startMonth + index, + balance: BigInt(claim.value.hex), + merkleProof: claim.proof, + }); + } + } + setClaims(userClaims); + }; + + fetchClaims(); + }, [account, chainParams]); + + const { writeContractAsync } = useWriteContract(); + + const handleClaim = async () => { + if (!claims.length || !account) return; + setLoading(true); + + try { + await writeContractAsync({ + abi: claimMonthsAbi, + address: chainParams.contractAddress, + functionName: "claimMonths", + args: [account, claims], + gasLimit: 500000, + }); + + setClaimed(true); + } catch (error) { + console.error("Transaction failed:", error); + setClaimed(false); + } + + setLoading(false); + }; + + const totalClaimableTokens = claims.reduce((acc, claim) => acc + claim.balance, BigInt(0)); + + return ( +
Claimable Tokens: {formatEther(totalClaimableTokens)} PNK
+ + > + )} + + {claimed &&🎉 Tokens Claimed 🎉
} +