From 782255698875f95c3a93edefcb61ed1062708aa8 Mon Sep 17 00:00:00 2001 From: Uncle Fatso Date: Mon, 25 Aug 2025 19:43:11 +0300 Subject: [PATCH] make reward destinations more flexible for the user Signed-off-by: Uncle Fatso --- package.json | 2 +- src/containers/Nominations.tsx | 95 +++++++++++++++++++++++++++++----- src/hooks/useCalldata.tsx | 44 +++++++++++++--- 3 files changed, 118 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index aad832c..b4238bb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghost-lite", - "version": "0.1.5", + "version": "0.1.6", "description": "Web application for Ghost and Casper chain.", "author": "Uncle f4ts0 ", "maintainers": [ diff --git a/src/containers/Nominations.tsx b/src/containers/Nominations.tsx index 631c238..b88ed2b 100644 --- a/src/containers/Nominations.tsx +++ b/src/containers/Nominations.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState, useMemo, useCallback } from "react" -import { Nut, NutOff, Users, PiggyBank } from "lucide-react" +import { Nut, NutOff, Users, PiggyBank, RefreshCcw } from "lucide-react" import { ss58Decode } from "@polkadot-labs/hdkd-helpers" import { toHex } from "@polkadot-api/utils" @@ -7,6 +7,14 @@ import { toHex } from "@polkadot-api/utils" import { lastValueFrom, tap } from "rxjs" import { submitTransaction$ } from "../api" +import { + Select, + SelectValue, + SelectTrigger, + SelectContent, + SelectGroup, + SelectItem, +} from "../components/ui/select" import { Accordion, AccordionContent, @@ -37,6 +45,7 @@ import { useUnstableProvider, RewardPoints, Unlocking, + RewardDestination, } from "../hooks" import { @@ -62,7 +71,6 @@ interface ItemProps { nominated: boolean checkedAddresses: string[] setIsCheckedAddresses: React.Dispatch> - } const Item: React.FC = (props) => { @@ -191,6 +199,8 @@ export const Nominations = () => { const [interestingValidator, setInterestingValidator] = useState(undefined) const [amount, setAmount] = useState("") + const [destinationReceiver, setDestinationReceiver] = useState("") + const [expectedPayee, setExpectedPayee] = useState(undefined) const { provider, @@ -221,6 +231,19 @@ export const Nominations = () => { : undefined }) + const destinationReceiverIsValid = useMemo(() => { + try { + const [, prefix] = ss58Decode(destinationReceiver) + if (prefix !== 1995 && prefix !== 1996) { + throw new Error("bad prefix") + } + return true + } catch { + return false + } + + }, [destinationReceiver]) + const convertedAmount = useMemo(() => { try { return BigInt(Number(amount) * Math.pow(10, tokenDecimals)) @@ -240,24 +263,24 @@ export const Nominations = () => { convertedAmount > 0n ? convertedAmount : undefined ) - const payeeDescription = useMemo(() => { + const payeeDescription = (destination: string | undefined) => { let description = "Unknown reward destination" - switch (payee?.type) { + switch (destination) { case "Staked": - description = "Re-stake rewards" + description = "Re-stake upcoming rewards" break; case "Stash": description = "Withdraw rewards to free" break; case "Account": - description = `Rewards to => ${payee?.value}` + description = `Rewards to account` break; case "None": description = "Refuse to receive rewards" break; } return description - }, [payee]) + } const readyToWithdraw = useMemo(() => { return ledger?.unlocking.reduce((acc: bigint, item: Unlocking) => { @@ -285,6 +308,10 @@ export const Nominations = () => { setIsCheckedAddresses([]) }, [account]) + useEffect(() => { + if (!expectedPayee) setExpectedPayee(payee?.type) + }, [expectedPayee, setExpectedPayee, payee]) + useEffect(() => { if (checkedAddresses.length === 0 && nominations) { setIsCheckedAddresses(nominations?.targets ?? []) @@ -531,13 +558,53 @@ export const Nominations = () => { - } /> + {payee && ( setExpectedPayee(payeeType)} + > + + + + + + {Object.keys(RewardDestination()).map((destinationType, index) => ( + + {payeeDescription(destinationType)} + + ))} + + + + } />)} + {expectedPayee !== payee?.type && expectedPayee === "Account" && ( + setDestinationReceiver(e.target.value)} + value={destinationReceiver} + />} /> + )} + {expectedPayee !== payee?.type && ( + + )} Enum< "Id" >("Id", value) -const RewardDestination = () => Enum< - { - type: "Staked" - value: [] - }, - "Staked" ->("Staked", []) +export const RewardDestination = (account: SS58String | undefined) => { + return { + Staked: () => Enum< + { + type: "Staked" + value: [] + }, + "Staked" + >("Staked", []), + + Stash: () => Enum< + { + type: "Stash" + value: [] + }, + "Stash" + >("Stash", []), + + Account: (account: SS58String) => Enum< + { + type: "Account" + value: account + }, + "Account" + >("Account", account), + + None: () => Enum< + { + type: "None" + value: [] + }, + "None" + >("None", []), + } +} export const useTransferCalldata = (destination: SS58String | undefined, amount: bigint | undefined) => { const { client, chainId } = useUnstableProvider() @@ -86,7 +114,7 @@ export const useBondCalldata = (amount: bigint | undefined) => { new Uint8Array(location), codec.enc({ value: amount, - payee: RewardDestination(), + payee: RewardDestination.Staked(), }), ), )