Skip to main content

On-Chain Data Connectors

If your app needs input directly from the blockchain, you can either use TheGraph to read indexed events from transactions, or you can call view and pure functions to get results. State changing methods and calls are not supported with data connectors.

ChainRead

To make a chain-reading data connector, you will need to add a property to the config called isChainRead which is to be set to true. If you include a hidden field set to true this field will be hidden in the UI and assigned it's default value.

Config Example (Assemblyscript)

  export function configForm(): string {
return `{
"title": "Calls ERC-20's 'totalSupply' function",
"description": "Input config for reading the total supply of a token",
"type": "object",
"required": [
"address"
],
"properties": {
"address": {
"type": "string",
"title": "Contract Address",
"description": "Address of the token to be read"
},
"isChainRead" : {
"type": "boolean",
"title": "Is this a view or pure contract call?",
"default": true,
"hidden": true
}
}
}`;
}

The public facing interface for on-chain data connectors is the same as regular data connectors:

export function initialize(config: string, timestamp: i32): void;
export function main(response: string): string;
export function transform(): string;
export function configForm(): string;

The primary difference in functionality comes in what is returned by the main() function. Where off-chain data connectors return an Axios config object, on-chain data connectors must return a stringified object with the following elements:

interface onChainRequest
{
abi: any[]; // The ABI of the contract being called (only the method being called is required)
address: string; // The address of the contract
method: string; // The name of the method to be called
arguments: any[]; // An array of the input parameters for the method
}

The callback system is the same with on-chain connectors. Once the appropriate response is returned, main() should return 'true' to terminate the callback loop. Final data should be returned when transform() is called.

main() Example (Assemblyscript)

  export function main(response: string): string {

// Check if respone is first call
if (response == ''){
// return payload
return `{
"abi" : [{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}],
"address" : ` + address + `,
"arguments" : [],
"method" : "totalSupply"
}`
}

// Parse through the BN object for the hex
const bigNum = <JSON.Obj>JSON.parse(response);
const _hex = bigNum.getString("hex")
if (_hex == null) throw new Error()
supply = _hex._str;
return 'true'
}
caution

Currently the contract to be called must be on the same network as the associated vault. This will likely change in the future.

Ethers

Under the hood, the node uses Ethers to perform the call. If the function returns a single value, the output will be that type stringified. If the function returns multiple values, they will be returned in a stringified array. The call will be made at a uniform block across the nodes based on epoch timing.

BigNumber

Ethers uses BigNumber for all numeric types. When forming the arguments array, ensure any numeric values are valid BigNumberish types. Any numbers over Javascript's max safe integer will likely cause problems, cast as a string or hex, or make a stringified BigNumber object to ensure intended behaviour. If a return value is within Javascript's safe range, then it will be returned as a regular number type.

Stringified BigNumber objects will resemble the following: {"type":"BigNumber","hex":"0x17"}

Transformation of BigNumbers or logic in the execution/app bundle might require a library for big numbers.

tip

Here are some libraries for handling big numbers in some common languages with no native support:
C/C++: https://github.com/kokke/tiny-bignum-c
AssemblyScript: https://github.com/polywrap/as-bigint

Template

Use this template to get started with your own on-chain data connector.