From d078016bea5b59bcdae10799aab6d2dbbccb993b Mon Sep 17 00:00:00 2001 From: Mateusz Jasiuk Date: Mon, 9 Jun 2025 17:52:45 +0200 Subject: [PATCH 1/3] fix: claim and stake notifications for ledger device --- .../src/App/Staking/StakingRewards.tsx | 2 +- .../src/atoms/notifications/functions.ts | 5 +--- .../namadillo/src/hooks/useIbcTransaction.tsx | 4 +-- apps/namadillo/src/hooks/useTransaction.tsx | 28 +++++++++++++------ .../src/hooks/useTransactionNotifications.tsx | 12 ++++---- apps/namadillo/src/lib/query.ts | 7 ++--- 6 files changed, 33 insertions(+), 25 deletions(-) diff --git a/apps/namadillo/src/App/Staking/StakingRewards.tsx b/apps/namadillo/src/App/Staking/StakingRewards.tsx index de468bca5e..c156f3a9d3 100644 --- a/apps/namadillo/src/App/Staking/StakingRewards.tsx +++ b/apps/namadillo/src/App/Staking/StakingRewards.tsx @@ -72,7 +72,7 @@ export const StakingRewards = (): JSX.Element => { params: rewardsToClaim, eventType: ["ClaimRewards", "Bond"], parsePendingTxNotification: () => ({ - title: "Claim rewards transaction is in progress", + title: "Claim and stake rewards transaction is in progress", description: ( <> Your rewards claim is being processed and will be staked to the same diff --git a/apps/namadillo/src/atoms/notifications/functions.ts b/apps/namadillo/src/atoms/notifications/functions.ts index 81c78261e3..cd1c8164e3 100644 --- a/apps/namadillo/src/atoms/notifications/functions.ts +++ b/apps/namadillo/src/atoms/notifications/functions.ts @@ -1,11 +1,8 @@ export const notificationIdSeparator = ";"; import { TxProps } from "@namada/types"; -export const createNotificationId = ( - data?: TxProps["hash"] | TxProps["hash"][] -): string => { +export const createNotificationId = (data?: TxProps["hash"][]): string => { if (!data) return Date.now().toString(); - if (typeof data === "string") return data; if (Array.isArray(data)) return data.join(notificationIdSeparator); return data; }; diff --git a/apps/namadillo/src/hooks/useIbcTransaction.tsx b/apps/namadillo/src/hooks/useIbcTransaction.tsx index e4ecd42fd4..ee3b326b92 100644 --- a/apps/namadillo/src/hooks/useIbcTransaction.tsx +++ b/apps/namadillo/src/hooks/useIbcTransaction.tsx @@ -113,7 +113,7 @@ export const useIbcTransaction = ({ const dispatchPendingTxNotification = (tx: TransferTransactionData): void => { invariant(tx.hash, "Error: Transaction hash not provided"); dispatchNotification({ - id: createNotificationId(tx.hash), + id: createNotificationId([tx.hash]), title: "IBC transfer transaction in progress", description: ( <> @@ -129,7 +129,7 @@ export const useIbcTransaction = ({ const dispatchErrorTxNotification = (error: unknown): void => { if (!txHash) return; dispatchNotification({ - id: createNotificationId(txHash), + id: createNotificationId([txHash]), title: "IBC transfer transaction failed", description: "", details: error instanceof Error ? error.message : undefined, diff --git a/apps/namadillo/src/hooks/useTransaction.tsx b/apps/namadillo/src/hooks/useTransaction.tsx index ad220bf137..639e15692a 100644 --- a/apps/namadillo/src/hooks/useTransaction.tsx +++ b/apps/namadillo/src/hooks/useTransaction.tsx @@ -61,6 +61,23 @@ export type UseTransactionOutput = { unknown >; +const getNotificationId = (tx: TransactionPair): string => { + let notificationId: string; + // For ibc transfers(not withdraws, those a re not handled by useTransaction hook), + // we need to create a unique notification ID based on inner transaction hashes. + if (tx.encodedTxData.type === "buildIbcTransfer") { + notificationId = createNotificationId( + tx.encodedTxData.txs.map((tx) => tx.innerTxHashes).flat() + ); + } else { + notificationId = createNotificationId( + tx.encodedTxData.txs.map((tx) => tx.hash) + ); + } + + return notificationId; +}; + export const useTransaction = ({ params, createTxAtom, @@ -101,10 +118,8 @@ export const useTransaction = ({ tx: TransactionPair, notification: PartialNotification ): void => { - const notificationId = - tx.encodedTxData.type === "buildIbcTransfer" ? - createNotificationId(tx.encodedTxData.txs[0].innerTxHashes) - : createNotificationId(tx.encodedTxData.txs[0].hash); + const notificationId = getNotificationId(tx); + dispatchNotification({ ...notification, id: notificationId, @@ -118,10 +133,7 @@ export const useTransaction = ({ notification: PartialNotification, tx: TransactionPair ): void => { - const notificationId = - tx.encodedTxData.type === "buildIbcTransfer" ? - createNotificationId(tx.encodedTxData.txs[0].innerTxHashes) - : createNotificationId(tx.encodedTxData.txs[0].hash); + const notificationId = getNotificationId(tx); dispatchNotification({ ...notification, id: notificationId, diff --git a/apps/namadillo/src/hooks/useTransactionNotifications.tsx b/apps/namadillo/src/hooks/useTransactionNotifications.tsx index 6b85732481..fc51976cff 100644 --- a/apps/namadillo/src/hooks/useTransactionNotifications.tsx +++ b/apps/namadillo/src/hooks/useTransactionNotifications.tsx @@ -28,7 +28,7 @@ const parseTxsData = ( data: T[] ): { id: string; total: BigNumber } => { const id = createNotificationId( - Array.isArray(tx) ? tx.map((t) => t.hash) : tx.hash + Array.isArray(tx) ? tx.map((t) => t.hash) : [tx.hash] ); const total = getTotalAmountFromTransactionList(data); return { total, id }; @@ -414,7 +414,7 @@ export const useTransactionNotifications = (): void => { detail: tx, }: CustomEvent): void => { if (!tx.hash) return; - const id = createNotificationId(tx.hash); + const id = createNotificationId([tx.hash]); const storedTx = searchAllStoredTxByHash(tx.hash); dispatchNotification({ id, @@ -443,7 +443,7 @@ export const useTransactionNotifications = (): void => { detail: tx, }: CustomEvent): void => { if (!tx.hash) return; - const id = createNotificationId(tx.hash); + const id = createNotificationId([tx.hash]); const storedTx = searchAllStoredTxByHash(tx.hash); dispatchNotification({ id, @@ -473,7 +473,7 @@ export const useTransactionNotifications = (): void => { if (!tx.hash) return; invariant(tx.hash, "Notification error: Invalid Tx hash"); - const id = createNotificationId(tx.hash); + const id = createNotificationId([tx.hash]); const title = tx.type === "ShieldedToIbc" || tx.type === "TransparentToIbc" ? "IBC withdraw transaction succeeded" @@ -498,7 +498,7 @@ export const useTransactionNotifications = (): void => { if (!tx) return; invariant(tx.hash, "Notification error: Invalid Tx provider"); - const id = createNotificationId(tx.hash); + const id = createNotificationId([tx.hash]); const title = tx.type === "ShieldedToIbc" || tx.type === "TransparentToIbc" ? "IBC withdraw transaction failed" @@ -523,7 +523,7 @@ export const useTransactionNotifications = (): void => { if (!tx) return; invariant(tx.hash, "Notification error: Invalid Tx provider"); - const id = createNotificationId(tx.hash); + const id = createNotificationId([tx.hash]); const title = "IBC withdraw transaction failed"; dispatchNotification({ diff --git a/apps/namadillo/src/lib/query.ts b/apps/namadillo/src/lib/query.ts index e50f460f0f..02057959c2 100644 --- a/apps/namadillo/src/lib/query.ts +++ b/apps/namadillo/src/lib/query.ts @@ -27,10 +27,9 @@ export type TransactionPair = { export type EncodedTxData = { type: string; - txs: TxProps[] & - { - innerTxHashes: string[]; - }[]; + txs: (TxProps & { + innerTxHashes: string[]; + })[]; wrapperTxProps: WrapperTxProps; meta?: { props: T[]; From 194227b1c88a98384276a118a9bb794796e07292 Mon Sep 17 00:00:00 2001 From: Mateusz Jasiuk Date: Wed, 11 Jun 2025 16:07:12 +0200 Subject: [PATCH 2/3] fix: wrapper hashes in the history and missing unbond txs --- apps/namadillo/src/App/Ibc/IbcWithdraw.tsx | 3 ++- .../src/App/Transactions/TransactionCard.tsx | 25 +++++++++++-------- .../App/Transactions/TransactionHistory.tsx | 1 + .../src/atoms/integrations/services.ts | 3 ++- apps/namadillo/src/hooks/useTransaction.tsx | 15 +++-------- apps/namadillo/src/lib/transactions.ts | 2 ++ apps/namadillo/src/types.ts | 3 ++- 7 files changed, 27 insertions(+), 25 deletions(-) diff --git a/apps/namadillo/src/App/Ibc/IbcWithdraw.tsx b/apps/namadillo/src/App/Ibc/IbcWithdraw.tsx index f93c38b85c..dfa088d372 100644 --- a/apps/namadillo/src/App/Ibc/IbcWithdraw.tsx +++ b/apps/namadillo/src/App/Ibc/IbcWithdraw.tsx @@ -272,7 +272,8 @@ export const IbcWithdraw = (): JSX.Element => { invariant(props, "Invalid transaction data"); const transferTransaction: IbcTransferTransactionData = { - hash: tx.encodedTxData.txs[0].innerTxHashes[0].toLowerCase(), + hash: tx.encodedTxData.txs[0].hash, + innerHash: tx.encodedTxData.txs[0].innerTxHashes[0].toLowerCase(), currentStep: TransferStep.WaitingConfirmation, rpc: "", type: shielded ? "ShieldedToIbc" : "TransparentToIbc", diff --git a/apps/namadillo/src/App/Transactions/TransactionCard.tsx b/apps/namadillo/src/App/Transactions/TransactionCard.tsx index 0788c650dd..78ad80f371 100644 --- a/apps/namadillo/src/App/Transactions/TransactionCard.tsx +++ b/apps/namadillo/src/App/Transactions/TransactionCard.tsx @@ -39,7 +39,7 @@ export function getToken( txn: Tx["tx"], nativeToken: string ): string | undefined { - if (txn?.kind === "bond") return nativeToken; + if (txn?.kind === "bond" || txn?.kind === "unbond") return nativeToken; let parsed; try { parsed = txn?.data ? JSON.parse(txn.data) : undefined; @@ -62,7 +62,7 @@ export function getToken( return undefined; } -const getBondTransactionInfo = ( +const getBondOrUnbondTransactionInfo = ( tx: Tx["tx"] ): { amount: BigNumber; sender?: string; receiver?: string } | undefined => { if (!tx?.data) return undefined; @@ -118,10 +118,12 @@ export const TransactionCard = ({ const token = getToken(transaction, nativeToken ?? ""); const chainAssetsMap = useAtomValue(chainAssetsMapAtom); const asset = token ? chainAssetsMap[token] : undefined; - const isBondingTransaction = transactionTopLevel?.tx?.kind === "bond"; + const isBondingOrUnbondingTransaction = ["bond", "unbond"].includes( + transactionTopLevel?.tx?.kind ?? "" + ); const txnInfo = - isBondingTransaction ? - getBondTransactionInfo(transaction) + isBondingOrUnbondingTransaction ? + getBondOrUnbondTransactionInfo(transaction) : getTransactionInfo(transaction); const receiver = txnInfo?.receiver; const sender = txnInfo?.sender; @@ -154,6 +156,7 @@ export const TransactionCard = ({ if (isReceived) return "Receive"; if (kind.startsWith("ibc")) return "IBC Transfer"; if (kind === "bond") return "Stake"; + if (kind === "unbond") return "Unstake"; if (kind === "claimRewards") return "Claim Rewards"; if (kind === "transparentTransfer") return "Transparent Transfer"; if (kind === "shieldingTransfer") return "Shielding Transfer"; @@ -171,7 +174,9 @@ export const TransactionCard = ({ "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 items-center my-1 font-semibold", "gap-5 bg-neutral-800 rounded-sm px-5 text-white border border-transparent", "transition-colors duration-200 hover:border-neutral-500", - isBondingTransaction && validator?.imageUrl ? "py-3" : "py-5" + isBondingOrUnbondingTransaction && validator?.imageUrl ? + "py-3" + : "py-5" ) )} > @@ -205,7 +210,7 @@ export const TransactionCard = ({
Copy transaction hash @@ -239,7 +244,7 @@ export const TransactionCard = ({ />
- {!isBondingTransaction && ( + {!isBondingOrUnbondingTransaction && (

From @@ -260,14 +265,14 @@ export const TransactionCard = ({

- {isBondingTransaction ? "Validator" : "To"} + {isBondingOrUnbondingTransaction ? "Validator" : "To"}

{isShieldedAddress(receiver ?? "") ? Shielded - : isBondingTransaction ? + : isBondingOrUnbondingTransaction ? validator?.imageUrl ? = { >; const getNotificationId = (tx: TransactionPair): string => { - let notificationId: string; - // For ibc transfers(not withdraws, those a re not handled by useTransaction hook), - // we need to create a unique notification ID based on inner transaction hashes. - if (tx.encodedTxData.type === "buildIbcTransfer") { - notificationId = createNotificationId( - tx.encodedTxData.txs.map((tx) => tx.innerTxHashes).flat() - ); - } else { - notificationId = createNotificationId( - tx.encodedTxData.txs.map((tx) => tx.hash) - ); - } + const notificationId = createNotificationId( + tx.encodedTxData.txs.map((tx) => tx.hash) + ); return notificationId; }; diff --git a/apps/namadillo/src/lib/transactions.ts b/apps/namadillo/src/lib/transactions.ts index 56c641ce44..9f55a5eeb6 100644 --- a/apps/namadillo/src/lib/transactions.ts +++ b/apps/namadillo/src/lib/transactions.ts @@ -162,6 +162,8 @@ export const createTransferDataFromIbc = ( const transferTx: IbcTransferTransactionData = { ...details, hash: tx.transactionHash, + // For IBC transfers(deposits), the innerHash is the same as the transaction hash + innerHash: tx.transactionHash, rpc, asset, feePaid, diff --git a/apps/namadillo/src/types.ts b/apps/namadillo/src/types.ts index 0b08e6265b..b521b7ed33 100644 --- a/apps/namadillo/src/types.ts +++ b/apps/namadillo/src/types.ts @@ -341,7 +341,8 @@ export type TransferStage = IbcTransferStage | NamadaTransferStage; export type BaseTransferTransaction = TransferStage & { rpc: string; asset: Asset; - hash?: string; + hash: string; + innerHash: string; displayAmount: BigNumber; chainId: string; sourceAddress: string; From 362d692cea3cbd4a0e86bf3afcd0a6c2702d97d8 Mon Sep 17 00:00:00 2001 From: Mateusz Jasiuk Date: Wed, 11 Jun 2025 17:18:50 +0200 Subject: [PATCH 3/3] feat: add unstake to filter dropdown --- apps/namadillo/src/App/Transactions/TransactionCard.tsx | 3 ++- apps/namadillo/src/App/Transactions/TransactionHistory.tsx | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/namadillo/src/App/Transactions/TransactionCard.tsx b/apps/namadillo/src/App/Transactions/TransactionCard.tsx index 78ad80f371..ab202cbd3c 100644 --- a/apps/namadillo/src/App/Transactions/TransactionCard.tsx +++ b/apps/namadillo/src/App/Transactions/TransactionCard.tsx @@ -136,7 +136,8 @@ export const TransactionCard = ({ const getBaseAmount = (): BigNumber | undefined => { if (asset && txnInfo?.amount) { - if (isBondingTransaction) return toDisplayAmount(asset, txnInfo.amount); + if (isBondingOrUnbondingTransaction) + return toDisplayAmount(asset, txnInfo.amount); if (isNamadaAsset(asset)) return txnInfo.amount; return toDisplayAmount(asset, txnInfo.amount); } else return undefined; diff --git a/apps/namadillo/src/App/Transactions/TransactionHistory.tsx b/apps/namadillo/src/App/Transactions/TransactionHistory.tsx index e712249064..6c25325a6e 100644 --- a/apps/namadillo/src/App/Transactions/TransactionHistory.tsx +++ b/apps/namadillo/src/App/Transactions/TransactionHistory.tsx @@ -196,6 +196,11 @@ export const TransactionHistory = (): JSX.Element => { value: "Stake", ariaLabel: "Stake", }, + { + id: "unbond", + value: "Unstake", + ariaLabel: "Unstake", + }, ]} />