import "../_dnt.polyfills.js"; import { hex } from "../crypto/mod.js" import { is, Rune, RunicArgs, ValueRune } from "../rune/mod.js" import { Chain } from "./ChainRune.js" import { CodecRune } from "./CodecRune.js" import { PatternRune } from "./PatternRune.js" export class StorageRune< out C extends Chain, out P extends Chain.PalletName, out S extends Chain.StorageName, out U, > extends PatternRune, C, U> { $key = this.into(ValueRune).access("key").unsafeAs().into( CodecRune, Chain.Storage.Key, U>, ) $partialKey = this.into(ValueRune).access("partialKey").unsafeAs().into( CodecRune, Chain.Storage.PartialKey, U>, ) $value = this.into(ValueRune).access("value").unsafeAs().into( CodecRune, Chain.Storage.Value, U>, ) valueRaw( ...[key, blockHash]: RunicArgs, blockHash?: string, ]> ) { const storageKey = this.$key.encoded(key).map(hex.encodePrefixed) return this.chain.connection .call("state_getStorage", storageKey, this.chain.blockHash(blockHash)) .handle(is(null), () => Rune.constant(undefined)) } value( ...[key, blockHash]: RunicArgs, blockHash?: string, ]> ) { return this.$value .decoded(this.valueRaw(key, blockHash).unhandle(is(undefined)).map(hex.decode)) .into(ValueRune) .rehandle(is(undefined)) } size( ...[partialKey, blockHash]: RunicArgs, blockHash?: string, ]> ) { return this.chain.connection .call( "state_getStorageSize", this.$partialKey.encoded(partialKey).map(hex.encodePrefixed), this.chain.blockHash(blockHash), ) .handle(is(null), () => Rune.constant(undefined)) } default() { return this.$value .decoded(this.into(ValueRune).access("default").unhandle(is(undefined))) .rehandle(is(undefined)) } entriesRaw( props: RunicArgs>, ...[blockHash]: RunicArgs ) { const storageKeys = this.keysRaw(props, blockHash) return this.chain.connection.call( "state_queryStorageAt", storageKeys, this.chain.blockHash(blockHash), ) } entries( props: RunicArgs>, ...[blockHash]: RunicArgs ) { return Rune .tuple([this.entriesRaw(props, blockHash).access(0), this.$key, this.$value]) .map(([changeset, $key, $value]) => changeset?.changes.map(([k, v]) => [ $key.decode(hex.decode(k)), v ? $value.decode(hex.decode(v)) : undefined, ]) ?? [] ) .unsafeAs<[Chain.Storage.Key, Chain.Storage.Value][]>() .into(ValueRune) } keysRaw( props: RunicArgs>, ...[blockHash]: RunicArgs ) { const storageKey = this.$partialKey.encoded( Rune.resolve("partialKey" in props ? props.partialKey : null).unsafeAs(), ) .map(hex.encodePrefixed) const startKey = this.$key .encoded(Rune.resolve(props.start).unhandle(is(undefined)).unsafeAs()) .map(hex.encodePrefixed) .rehandle(is(undefined)) return this.chain.connection.call( "state_getKeysPaged", storageKey, Rune.resolve(props.limit).handle(is(undefined), () => Rune.constant(100)), startKey, this.chain.blockHash(blockHash), ) } keys( props: RunicArgs>, ...[blockHash]: RunicArgs ) { const raw = this.keysRaw(props, blockHash) return Rune.tuple([this.$key, raw]) .map(([$key, raw]) => raw.map((keyEncoded) => $key.decode(hex.decode(keyEncoded)))) .into(ValueRune) } } export interface StoragePageProps< out C extends Chain, out P extends Chain.PalletName, out S extends Chain.StorageName, > { limit?: number partialKey?: Chain.Storage.PartialKey start?: Chain.Storage.Key }