Skip to main content

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 the async 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 uses IMyTokenReader interface. The totalSupply function signature is similar to a standard token contract but its visibility is not restricted to view 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 the async 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 a callback function.
tip

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 uses onlyPromises modifier and has 2 params. First param is the data passed from original function and second param is the returnData from chain.

2. Promises​

Let us look at how this is executed to better understand what is going on.

deployment_flow.png

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.