From 2e90d3f9b0a90eb57255c08a12db65477db20a01 Mon Sep 17 00:00:00 2001 From: Victor Oliva Date: Thu, 25 Jun 2026 10:57:35 +0200 Subject: [PATCH] redesign fixes (#160) * fix: show error on invalid transactions * fix: leave nonce unset if not changed by the user Co-authored-by: Carlo Sala * avoid spamming nonce requests --------- Co-authored-by: Carlo Sala --- .../Extrinsics/ExtrinsicsWorkspaceEntry.tsx | 22 +++-- .../Extrinsics/SubmitTx/SubmitExtrinsic.tsx | 94 ++++++++----------- src/state/polkahub.ts | 19 +++- 3 files changed, 70 insertions(+), 65 deletions(-) diff --git a/src/pages/Extrinsics/ExtrinsicsWorkspaceEntry.tsx b/src/pages/Extrinsics/ExtrinsicsWorkspaceEntry.tsx index 4db8002..b7c21a4 100644 --- a/src/pages/Extrinsics/ExtrinsicsWorkspaceEntry.tsx +++ b/src/pages/Extrinsics/ExtrinsicsWorkspaceEntry.tsx @@ -116,10 +116,18 @@ const ExtrinsicsWorkspaceEntry: FC<{ event: TrackedTransactionEvent }> = ({
Hash
-
- {event.txHash ? shortStr(event.txHash, 8) : ""} - -
+ {event.txHash ? ( +
+ {shortStr(event.txHash, 8)} + +
+ ) : ( +
+ )}
{"block" in event ? (
@@ -159,11 +167,11 @@ const ExtrinsicsWorkspaceEntry: FC<{ event: TrackedTransactionEvent }> = ({
) : null} - {event.type === "error" ? ( + {event.type === "error" || event.type === "invalid" ? (
Error
-
- {JSON.stringify(event.value, jsonSerialize)} +
+
) : null} diff --git a/src/pages/Extrinsics/SubmitTx/SubmitExtrinsic.tsx b/src/pages/Extrinsics/SubmitTx/SubmitExtrinsic.tsx index b70d8fc..6265bd3 100644 --- a/src/pages/Extrinsics/SubmitTx/SubmitExtrinsic.tsx +++ b/src/pages/Extrinsics/SubmitTx/SubmitExtrinsic.tsx @@ -12,7 +12,11 @@ import { import { createState } from "@/lib/externalState" import { PolkahubModalBasedManagers } from "@/pages/Accounts/Providers" import { client$, unsafeApi$ } from "@/state/chains/chain.state" -import { selectedAccount$ } from "@/state/polkahub" +import { + getAccountGenericAddress, + getAccountPublicKey, + selectedAccount$, +} from "@/state/polkahub" import { polkadot_people } from "@polkadot-api/descriptors" import { Button, @@ -27,6 +31,7 @@ import { state, SUSPENSE, useStateObservable, + withDefault, } from "@react-rxjs/core" import { createSignal, @@ -34,7 +39,7 @@ import { switchMapSuspended, } from "@react-rxjs/utils" import { ChevronLeft, Send, Settings, WalletCards } from "lucide-react" -import { AccountId, TxOptions } from "polkadot-api" +import { TxOptions } from "polkadot-api" import { ModalContext, PjsWalletButtons, @@ -45,7 +50,7 @@ import { FC, forwardRef, ReactNode, useState } from "react" import { catchError, combineLatest, - defer, + distinctUntilChanged, map, of, scan, @@ -73,19 +78,17 @@ const customExtensionsCount$ = state( const [nonceChanged$, setNonce] = createSignal() const [nonceBlurred$, blurNonce] = createSignal() -const chainNonce$ = unsafeApi$.pipe( +const chainNonce$ = unsafeApi$.pipeState( switchMapSuspended((api) => selectedAccount$.pipe( - switchMapSuspended((account) => - account?.signer - ? api.apis.AccountNonceApi.account_nonce( - AccountId(42).dec(account.signer.publicKey), - { - at: "best", - }, + switchMapSuspended((account) => { + const address = account && getAccountGenericAddress(account) + return address + ? timer(0, 60_000).pipe( + switchMap(() => api.apis.AccountNonceApi.account_nonce(address)), ) - : [], - ), + : [null] + }), liftSuspense(), catchError((ex) => { console.error(ex) @@ -95,45 +98,20 @@ const chainNonce$ = unsafeApi$.pipe( ), liftSuspense(), map((v) => (v === SUSPENSE ? null : (v as number))), + withDefault(null), ) const isIntegerStr = (str: string) => /^\d+$/.test(str) const nonce$ = state( - defer(() => - mergeWithKey({ - chainNonce$, - nonceChanged$, - nonceBlurred$, - }).pipe( - scan( - ( - acc: { - chain: number | null - inputValue: string - }, - v, - ) => { - switch (v.type) { - case "chainNonce$": - if (v.payload != null) - return { chain: v.payload, inputValue: v.payload.toString() } - break - case "nonceBlurred$": - if (!isIntegerStr(acc.inputValue)) { - return { - chain: acc.chain, - inputValue: acc.chain?.toString() ?? "", - } - } - break - case "nonceChanged$": - return { chain: acc.chain, inputValue: v.payload } - } - return acc - }, - { chain: null, inputValue: "" }, - ), - map((v) => v.inputValue), + mergeWithKey({ + nonceChanged$, + nonceBlurred$, + }).pipe( + scan( + (acc, v) => + v.type === "nonceChanged$" ? v.payload : isIntegerStr(acc) ? acc : "", + "", ), + distinctUntilChanged(), ), "", ) @@ -178,17 +156,20 @@ const txOptions$ = state( {} satisfies TxOptions, ) -const paymentInfo$ = state( +export const paymentInfo$ = state( combineLatest([transaction$, selectedAccount$, txOptions$]).pipe( switchMapSuspended(([tx, account, txOptions]) => { - if (!tx || !account?.signer) return [null] + if (!tx || !account) return [null] // Adding a small delay for debouncing quick input changes return timer(200).pipe( switchMap(() => - tx.getPaymentInfo(account.signer!.publicKey, txOptions), + tx.getPaymentInfo(getAccountPublicKey(account), txOptions), ), - catchError(() => of(null)), + catchError((ex) => { + console.error(ex) + return of(null) + }), ) }), liftSuspense(), @@ -196,16 +177,13 @@ const paymentInfo$ = state( ), null, ) - const accountBalance$ = state( combineLatest([selectedAccount$, client$]).pipe( switchMapSuspended(([account, client]) => - account?.signer + account ? client .getTypedApi(polkadot_people) - .query.System.Account.getValue( - AccountId().dec(account.signer.publicKey), - ) + .query.System.Account.getValue(getAccountGenericAddress(account)) : [], ), liftSuspense(), @@ -226,6 +204,7 @@ const accountBalance$ = state( export const SubmitExtrinsic = forwardRef((_, ref) => { const [account] = useSelectedAccount() + const chainNonce = useStateObservable(chainNonce$) const nonce = useStateObservable(nonce$) const mortality = useStateObservable(mortality$) const tip = useStateObservable(tip$) @@ -284,6 +263,7 @@ export const SubmitExtrinsic = forwardRef((_, ref) => { type="number" min={0} value={nonce} + placeholder={chainNonce?.toString()} onChange={(evt) => setNonce(evt.target.value)} onBlur={blurNonce} className="tabular-nums" diff --git a/src/state/polkahub.ts b/src/state/polkahub.ts index df50ff8..dde135a 100644 --- a/src/state/polkahub.ts +++ b/src/state/polkahub.ts @@ -1,6 +1,6 @@ import { polkadot_people } from "@polkadot-api/descriptors" import { liftSuspense, state, SUSPENSE, withDefault } from "@react-rxjs/core" -import { AccountId, HexString, SS58String } from "polkadot-api" +import { AccountId, Binary, HexString, SS58String } from "polkadot-api" import { Account, createLedgerProvider, @@ -214,3 +214,20 @@ export const toggleExtension = async (id: string) => { : [...extensions, id], ) } + +export const getAccountPublicKey = (account: Account) => + account.signer + ? account.signer.publicKey + : account.address.startsWith("0x") + ? Binary.fromHex(account.address) + : AccountId().enc(account.address) + +// Important, the SS58 format is not guaranteed. Only to be used for internal queries +export const getAccountGenericAddress = (account: Account) => + account.address.startsWith("0x") + ? account.signer + ? Binary.toHex(account.signer.publicKey) + : account.address + : account.signer + ? AccountId().dec(account.signer.publicKey) + : account.address