How to read onchain state
1. Read Example​
SOCKET supports reading public variables and functions from the underlying chains. To understand how this is done, lets extend our MyToken example that was introduced in our guide.
On MyTokenAppGateway
, we will create a fetchSupply
function. This function will read the totalSupply
of a given instance and store it on the AppGateway
.
interface IMyTokenReader {
function totalSupply() external;
}
contract MyTokenAppGateway is AppGatewayBase {
...
// forwarder => supply
mapping(address => uint256) public fetchedSupply;
function fetchSupply(address forwarder) async {
_readCallOn();
IMyTokenReader(forwarder).totalSupply();
IPromise(forwarder).then(
this.fetchSupplyCallback.selector,
abi.encode(forwarder) // passed to callback
);
_readCallOff();
}
function fetchSupplyCallback(
bytes calldata data,
bytes calldata returnData
) external onlyPromises {
uint256 forwarder = abi.decode(data, (address));
uint256 supply = abi.decode(returnData, (uint256));
fetchedSupply[forwarder] = supply;
}
}
Notice following things in above contract -
fetchSupply
function uses theasync
modifier. This modifier needs to be used for both write and read calls to underlying chains.- if
_readCallOn()
is called, it indicates to SOCKET that the call doesn't need to be sent on chain and just the return data needs to be read. - The
totalSupply
call usesIMyTokenReader
interface. ThetotalSupply
function signature is similar to a standard token contract but its visibility is not restricted toview
and it doesnt have a return value. This needs to be followed for all read calls. The interface needs to be changed in this way to be compatible with theasync
forwarder
system on Offchain VM. - Also, unlike a read on single chain, the return data here is not returned synchronously. Instead it has to be read asynchronously via a
promise
and acallback
function.
The contract interface used for reading data needs to be changed to remove visibility modifiers and return values. Eg. we remove the view
modifier and returns (uint256)
from signature of original totalSupply()
function.
The forwarder
address is interfaced as IPromise
and then
function is called on it. In this function we pass the callback function signature as first parameter and data for callback as second parameter.
fetchSupplyCallback
usesonlyPromises
modifier and has 2 params. First param is thedata
passed from original function and second param is thereturnData
from chain.
2. Promises​
Let us look at how this is executed to better understand what is going on.
To support asynchronous composability, SOCKET works with special promise
contracts that are deployed when you call then
function. Each promise contract is immutable and specific to a read request. It can be used only once and holds context about what needs to be called on callback. The AppGatewayBase
contract has utilities like _readCallOn()
, _readCallOff()
, onlyPromises
to make it easier to work with SOCKET primitives.