callContractFunction
The underlying primitive for calling contract read functions — use it when no generated caller covers what you need.
callContractFunction(options)
All generated callers are thin wrappers around callContractFunction. Call it directly when you need to query a contract that isn't in the generated package yet — for example, a freshly deployed contract whose ABI hasn't been added to the registry snapshot.
import { callContractFunction } from "@qubic.org/contracts"
import { buildPayload, decodePayload } from "@qubic.org/registry"
import { identityToPublicKey, publicKeyToIdentity } from "@qubic.org/crypto"
import { createLiveClient } from "@qubic.org/rpc"
const live = createLiveClient()
const result = await callContractFunction({
live,
contractIndex: 42,
inputType: 1,
inputSize: 4,
inputFields: [{ name: "epoch", type: "uint32", offset: 0, byteLength: 4 }],
outputFields: [{ name: "state", type: "uint32", offset: 0, byteLength: 4 }],
structs: {},
input: { epoch: 213 },
})
if (result.ok) {
console.log("State:", result.value.state)
} else {
console.error("Error:", result.error.status, result.error.message)
}Options
| Name | Type | Description |
|---|---|---|
live | SmartContractCaller | Any object with querySmartContract. Typically from createLiveClient(). |
contractIndex | number | Contract index on-chain. |
inputType | number | Function input type number from the ABI. |
inputSize | number | Total byte length of the encoded input. |
inputFields | BinaryField[] | Field definitions for encoding the input. From @qubic.org/registry. |
outputFields | BinaryField[] | Field definitions for decoding the response. From @qubic.org/registry. |
structs | Record<string, NamedStruct> | Named struct definitions referenced by fields. Pass {} if none. |
input | Record<string, unknown> | Input values — must match the field names in inputFields. |
identityToPublicKey | (id: string) => Uint8Array | Required when input contains id-type fields. |
publicKeyToIdentity | (pk: Uint8Array) => string | Required when output contains id-type fields. |
Returns Promise<Result<TOutput, QubicRpcError>>
When to use this
Use callContractFunction when:
- A contract was deployed after the last registry snapshot, so no generated wrapper exists yet.
- You need a function from an older ABI version that has since been replaced.
- You're writing your own code generator and need the underlying primitive to test it.
For all contracts in the current generated package, use the namespace callers directly — they handle field definitions internally.
Using the registry for field definitions
When the contract ABI is available in @qubic.org/registry, use getAbi and getFunction to retrieve field definitions rather than writing them by hand:
import { callContractFunction } from "@qubic.org/contracts"
import { getAbi, getFunction } from "@qubic.org/registry"
import { identityToPublicKey, publicKeyToIdentity } from "@qubic.org/crypto"
import { createLiveClient } from "@qubic.org/rpc"
import registry from "@qubic.org/registry/registry.json"
import type { ContractRegistry } from "@qubic.org/registry"
const reg = registry as ContractRegistry
const live = createLiveClient()
// Look up field definitions from the registry
const { version } = getAbi(reg, 42, 213) // contractIndex, epoch
const fn = getFunction(version, 1) // inputType
const result = await callContractFunction({
live,
contractIndex: 42,
inputType: fn.inputType,
inputSize: fn.inputSize,
inputFields: fn.inputFields,
outputFields: fn.outputFields,
structs: version.structs ?? {},
input: { someField: 42 },
identityToPublicKey,
publicKeyToIdentity,
})
if (result.ok) {
console.log("Output:", result.value)
} else {
console.error("Error:", result.error.status, result.error.message)
}