You can also calculate the storage keys and use the getStorage
method to avoid implementing getters.
If you have a contract with storage as follows:
// Contract storage
#[ink(storage)]
pub struct Dapp {
accounts: Lazy<Vec<AccountId>>,
}
And storage in your JSON ABI as follows:
{
"layout": {
"root": {
"layout": {
"leaf": {
"key": "0x87c1e648",
"ty": "8"
}
},
"root_key": "0x87c1e648"
}
},
"name": "accounts"
},
Then you can get the relevant storage key from the ABI using the following functions, although there is probably a better way in polkadot-js to do this.
class YourClass extends ContractPromise {
async getStorageKey(storageName: string): Promise<`0x${string}`> {
// Get the storage entry from the JSON which is the abi in ContractPromise
// Assuming here that you're in a class that extends ContractPromise
const json = this.abi.json
// Returns the JSON object above
let storage = json.storage.root.layout.struct.fields.filter(
(obj: { name: string }) => obj.name === storageName
)[0]
if (storage) {
while ('root' in storage.layout) {
storage = storage.layout.root
}
const rootKey = storage.root_key
const rootKeyReversed = reverseHexString(rootKey.slice(2))
return `0x${rootKeyReversed}`
}
throw new Error('Storage entry not found')
}
}
// used to reverse the hex key 0x87c1e648 above, swapping the Endianness
function reverseHexString(str: string): string {
return (
str
.match(/.{1,2}/g)
?.reverse()
.join('') || ''
)
}
Now get your storage with this code, again assuming you're in YourClass
extending ContractPromise
.
import { firstValueFrom } from 'rxjs'
const storageKey = getStorageKey('accounts')
const type = 'Vec<AccountId>'
const promiseResult = api.rx.call.contractsApi.getStorage(contractAddress, storageKey)
const result = await firstValueFrom(promiseResult)
if (result) {
const optionBytes = this.abi.registry.createType('Option<Bytes>', result)
const accounts = this.abi.registry.createType(type, [optionBytes.unwrap().toU8a(true)])
console.log(accounts)
}
Obviously, this process gets more complicated as your storage types get more complicated e.g. Vec<Struct>
. Then you should be able to use typegen to generate your contract types, import them to the API, and construct them from the results of getStorage
.