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