grab current value when setting storage

This commit is contained in:
Victor Oliva
2025-05-17 18:35:52 +02:00
parent 506437fcc6
commit a6d3a02f77
2 changed files with 103 additions and 32 deletions
+1 -1
View File
@@ -103,7 +103,7 @@ const [keyValueChange$, setKeyValue] = createSignal<{
idx: number
value: unknown | NOTIN
}>()
const keyValues$ = keys$.pipeState(
export const keyValues$ = keys$.pipeState(
switchMap((keys) => {
const values: unknown[] = keys.map(() => NOTIN)
return keyValueChange$.pipe(
+102 -31
View File
@@ -2,21 +2,76 @@ import { chopsticksInstance$ } from "@/chopsticks/chopsticks"
import { LookupTypeEdit } from "@/codec-components/LookupTypeEdit"
import { Chopsticks } from "@/components/Icons"
import { Button } from "@/components/ui/button"
import { lookup$ } from "@/state/chains/chain.state"
import { chainClient$, lookup$ } from "@/state/chains/chain.state"
import { getTypeComplexity } from "@/utils"
import { setStorage } from "@acala-network/chopsticks-core"
import { toHex } from "@polkadot-api/utils"
import { useStateObservable } from "@react-rxjs/core"
import { state, useStateObservable } from "@react-rxjs/core"
import { createSignal } from "@react-rxjs/utils"
import { FC, useState } from "react"
import { firstValueFrom } from "rxjs"
import {
combineLatest,
filter,
firstValueFrom,
map,
merge,
switchMap,
withLatestFrom,
} from "rxjs"
import { selectedEntry$ } from "./storage.state"
import { encodedKey$, KeyDisplay, StorageKeysInput } from "./StorageQuery"
import { Binary } from "polkadot-api"
const [setValue$, setValue] = createSignal<Uint8Array | "partial" | null>()
const currentValue$ = state(
merge(
combineLatest([
encodedKey$.pipe(filter((v) => v != null)),
selectedEntry$.pipe(filter((v) => v != null)),
chainClient$,
]).pipe(
switchMap(([key, entry, client]) =>
client.chainHead.storage$(
null,
"value",
() => key,
null,
(data, ctx) => {
// We must comply with the original mapper, or the cache will contain a wrong value.
const codec = ctx.dynamicBuilder.buildStorage(
entry.pallet,
entry.entry,
)
return data === null ? codec.fallback : codec.value.dec(data)
},
),
),
withLatestFrom(lookup$, selectedEntry$.pipe(filter((v) => v != null))),
map(([v, lookup, entry]) => {
if (v.raw !== null) return v.raw
const pallet = lookup.metadata.pallets.find(
(p) => p.name == entry.pallet,
)!
const storageItem = pallet.storage!.items.find(
(i) => i.name === entry.entry,
)!
return storageItem.modifier ? storageItem.fallback : null
}),
map((v) => (v != null ? Binary.fromHex(v).asBytes() : v)),
),
setValue$,
).pipe(
withLatestFrom(encodedKey$),
map(([value, encodedKey]) => ({ value, encodedKey })),
),
null,
)
export const StorageSet: FC = () => {
const selectedEntry = useStateObservable(selectedEntry$)
const lookup = useStateObservable(lookup$)
const [value, setValue] = useState<Uint8Array | "partial" | null>(null)
const encodedKey = useStateObservable(encodedKey$)
const currentValue = useStateObservable(currentValue$)
const [isLoading, setIsLoading] = useState(false)
if (!lookup || !selectedEntry) return null
@@ -28,33 +83,49 @@ export const StorageSet: FC = () => {
<div className="flex flex-col gap-4 items-start w-full overflow-hidden">
<KeyDisplay />
<StorageKeysInput disableToggle />
<LookupTypeEdit
className="w-full border rounded pt-2"
type={selectedEntry.value}
value={value}
onValueChange={setValue}
tree={complexity === "tree"}
/>
<Button
variant="secondary"
disabled={isLoading || !encodedKey || !(value instanceof Uint8Array)}
onClick={async () => {
setIsLoading(true)
try {
const chopsticks = await firstValueFrom(chopsticksInstance$)
if (!chopsticks || !encodedKey || !(value instanceof Uint8Array))
return false
{currentValue ? (
<>
<LookupTypeEdit
/* A bit of a shame… this component doesn't change the value reactively... */
key={currentValue.encodedKey}
className="w-full border rounded pt-2"
type={selectedEntry.value}
value={currentValue.value}
onValueChange={setValue}
tree={complexity === "tree"}
/>
<Button
variant="secondary"
disabled={
isLoading ||
!currentValue.encodedKey ||
!(currentValue.value instanceof Uint8Array)
}
onClick={async () => {
setIsLoading(true)
try {
const chopsticks = await firstValueFrom(chopsticksInstance$)
if (
!chopsticks ||
!currentValue.encodedKey ||
!(currentValue.value instanceof Uint8Array)
)
return false
await setStorage(chopsticks, [[encodedKey, toHex(value)]])
await chopsticks.newBlock()
} finally {
setIsLoading(false)
}
}}
>
Set Storage
<Chopsticks />
</Button>
await setStorage(chopsticks, [
[currentValue.encodedKey, toHex(currentValue.value)],
])
await chopsticks.newBlock()
} finally {
setIsLoading(false)
}
}}
>
Set Storage
<Chopsticks />
</Button>
</>
) : null}
</div>
)
}