|
| 1 | +import React, { useState, useEffect } from "react"; |
| 2 | +import { useAccount, useWriteContract } from "wagmi"; |
| 3 | +import { formatEther, parseAbi } from "viem"; |
| 4 | +import { DEFAULT_CHAIN } from "consts/chains"; |
| 5 | + |
| 6 | +const ipfsEndpoint = "https://cdn.kleros.link"; |
| 7 | + |
| 8 | +const chainIdToParams = { |
| 9 | + 421614: { |
| 10 | + contractAddress: "0x9DdAeD4e2Ba34d59025c1A549311F621a8ff9b7b", |
| 11 | + snapshots: ["QmQBupnUD9zt2dzZcB6tNAENiWtmwfWeKDuZbWEWoKs7s2/arbSepolia-snapshot-2025-02.json"], |
| 12 | + startMonth: 2, |
| 13 | + }, |
| 14 | + 42161: { |
| 15 | + contractAddress: "", |
| 16 | + snapshots: [], |
| 17 | + startMonth: 2, |
| 18 | + }, |
| 19 | +}; |
| 20 | + |
| 21 | +const claimMonthsAbi = parseAbi([ |
| 22 | + "function claimMonths(address _liquidityProvider, (uint256 month, uint256 balance, bytes32[] merkleProof)[] claims)", |
| 23 | +]); |
| 24 | + |
| 25 | +const ClaimModal = () => { |
| 26 | + const { address: account } = useAccount(); |
| 27 | + const chainId = DEFAULT_CHAIN; |
| 28 | + const chainParams = chainIdToParams[chainId] ?? chainIdToParams[DEFAULT_CHAIN]; |
| 29 | + |
| 30 | + const [claims, setClaims] = useState([]); |
| 31 | + const [loading, setLoading] = useState(false); |
| 32 | + const [claimed, setClaimed] = useState(false); |
| 33 | + |
| 34 | + useEffect(() => { |
| 35 | + const fetchClaims = async () => { |
| 36 | + if (!account || !chainParams) return; |
| 37 | + |
| 38 | + const userClaims = []; |
| 39 | + for (let index = 0; index < chainParams.snapshots.length; index++) { |
| 40 | + const response = await fetch(`${ipfsEndpoint}/ipfs/${chainParams.snapshots[index]}`); |
| 41 | + const snapshot = await response.json(); |
| 42 | + const claim = snapshot.merkleTree.claims[account]; |
| 43 | + |
| 44 | + if (claim) { |
| 45 | + userClaims.push({ |
| 46 | + month: chainParams.startMonth + index, |
| 47 | + balance: BigInt(claim.value.hex), |
| 48 | + merkleProof: claim.proof, |
| 49 | + }); |
| 50 | + } |
| 51 | + } |
| 52 | + setClaims(userClaims); |
| 53 | + }; |
| 54 | + |
| 55 | + fetchClaims(); |
| 56 | + }, [account, chainParams]); |
| 57 | + |
| 58 | + const { writeContractAsync } = useWriteContract(); |
| 59 | + |
| 60 | + const handleClaim = async () => { |
| 61 | + if (!claims.length || !account) return; |
| 62 | + setLoading(true); |
| 63 | + |
| 64 | + try { |
| 65 | + await writeContractAsync({ |
| 66 | + abi: claimMonthsAbi, |
| 67 | + address: chainParams.contractAddress, |
| 68 | + functionName: "claimMonths", |
| 69 | + args: [account, claims], |
| 70 | + gasLimit: 500000, |
| 71 | + }); |
| 72 | + |
| 73 | + setClaimed(true); |
| 74 | + } catch (error) { |
| 75 | + console.error("Transaction failed:", error); |
| 76 | + setClaimed(false); |
| 77 | + } |
| 78 | + |
| 79 | + setLoading(false); |
| 80 | + }; |
| 81 | + |
| 82 | + const totalClaimableTokens = claims.reduce((acc, claim) => acc + claim.balance, BigInt(0)); |
| 83 | + |
| 84 | + return ( |
| 85 | + <div> |
| 86 | + {loading && <div>Loading...</div>} |
| 87 | + |
| 88 | + {!loading && !claimed && ( |
| 89 | + <> |
| 90 | + <p>Claimable Tokens: {formatEther(totalClaimableTokens)} PNK</p> |
| 91 | + <button onClick={handleClaim} disabled={!claims.length}> |
| 92 | + Claim Tokens |
| 93 | + </button> |
| 94 | + </> |
| 95 | + )} |
| 96 | + |
| 97 | + {claimed && <p>🎉 Tokens Claimed 🎉</p>} |
| 98 | + </div> |
| 99 | + ); |
| 100 | +}; |
| 101 | + |
| 102 | +export default ClaimModal; |
0 commit comments