2

The previous answer is now incorrect due to the deprecation of the RPCs.

How do we query the historic contract state now?

In the PR comment it states:

The high level contracts API in polkadot.js already uses state_call so upgrading to the latest version here is enough. If you are using api.rpc.contracts directly you need to switch to api.call.contractsApi.

However, switching to api.rx.call.contractsApi.call does not give an option to pass at. There is the option to create an instance of the api at a specific block but there is no explanation of how to query contracts using this.

The following does not work as the returned type of api.at (ApiDecoration<"promise">) is not equivalent to ApiPromise

        if (atBlock) {
            const atApi = atBlock ? await api.at(atBlock) : api
            contract = new ContractPromise(atApi, abi, contractAddress)
        }

1 Answer 1

1

To access historic contract state you do not need a ContractPromise. It will not construct using the at API. Instead, you need to replicate the calls made in the polkadot-js/api package using your at API.

e.g.

        // choose either the existing api or a historic api
        let api: ApiBase<'promise'> | ApiDecoration<'promise'> = this.api
        if (atBlock) {
            api = atBlock ? await this.api.at(atBlock) : this.api
        }

        // Make the call to the contracts API, specifying the contract address
        // This next part is copied from polkadot-js packages/api-contract/src/base/Contract.ts
        const responseObservable = api.rx.call.contractsApi
            .call<ContractExecResult>(
                callerAddress,
                this.contract.address,
                callParams.value,
                callParams.gasLimit,
                null, //storageDepositLimit
                methodObj.toU8a(encodedArgs)
            )
            .pipe(
                map(
                    ({ debugMessage, gasConsumed, gasRequired, result, storageDeposit }): ContractCallOutcome => ({
                        debugMessage,
                        gasConsumed,
                        gasRequired:
                            gasRequired && !convertWeight(gasRequired).v1Weight.isZero() ? gasRequired : gasConsumed,
                        output:
                            result.isOk && methodObj.returnType
                                ? this.contract.abi.registry.createTypeUnsafe(
                                      methodObj.returnType.lookupName || methodObj.returnType.type,
                                      [result.asOk.data.toU8a(true)],
                                      { isPedantic: true }
                                  )
                                : null,
                        result,
                        storageDeposit,
                    })
                )
            )
        const response = await firstValueFrom(responseObservable)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.