Storage Service

Storage service is like a constants service, but for variables.

While its declaration might looks monstrous:

public protocol SubstrateStorage: AnyObject {
    func find(moduleName: String, itemName: String) async throws -> FindStorageItemResult?
    
    func fetch<T: Decodable>(
        moduleName: String,
        itemName: String
    ) async throws -> T?
    
    func fetch<T: Decodable>(
        moduleName: String,
        itemName: String,
        key: Data
    ) async throws -> T?
    
    func fetch<T: Decodable>(
        moduleName: String,
        itemName: String,
        keys: [Data]
    ) async throws -> T?
    
    func fetch<T: Decodable>(
        item: RuntimeModuleStorageItem,
        storage: RuntimeModuleStorage
    ) async throws -> T?
    
    func fetch<T: Decodable>(
        item: RuntimeModuleStorageItem,
        key: Data,
        storage: RuntimeModuleStorage
    ) async throws -> T?
    
    func fetch<T: Decodable>(
        item: RuntimeModuleStorageItem,
        keys: [Data],
        storage: RuntimeModuleStorage
    ) async throws -> T?
}

It is practically divided into 3 behaviors.

Finding storage item

Yes, again proxy method to the lookup service. So if you want to find streamable value use this:

let storageItemResult: FindStorageItemResult? = try await client.storage.find(
    moduleName: "System",
    itemName: "account"
)

This will give you exact item's flow, from where you can look at its contents for a debug purpose.

Result is not just storage item, but combination of this and its holding module storage class, for our internal library purpose:

public struct FindStorageItemResult: Codable {
    public let item: RuntimeModuleStorageItem
    public let storage: RuntimeModuleStorage
}

But for more real life use there are fetch methods:

Fetch by lookup

let account: Account? = try await client.storage.fetch(
    moduleName: "System",
    itemName: "account",
    key: keyPair.publicKey.hex.encode(includePrefix: true).hex.decode()
)

This exact method allows you to "subscribe" to the flow of your account details, but this flow is only updated by every runtime metadata change. You're free to combine this flow with whatever you want, like your balance updates event, to create always up to date assets balance for your application.

Depending on the storage item type, there might be no keys, or even multiple keys. Pleas refer to your network runtime metadata, or use find method to debug this item to see what keys are required if required at all.

Fetch by storage item

If you have storage item stored in your memory, like for continuous updates, there are several async-await functions to get the response:

let client: SubstrateClient
let keyPair: KeyPair
let storageItemResult: FindStorageItemResult

if let item = storageItemResult?.item, let storage = storageItemResult?.storage {
    let account: Account? = try await client.storage.fetch(item: item, storage: storage)
}

Last updated