According to the polygon documentation, "State Sync is the native mechanism to read Ethereum data from the MATIC EVM chain" (also known as polygon).
This allows us to send data, from a parent chain (IE mainnet) to a child
contract on polygon, and we can even do the reverse. Sending data from polygon
to ETH mainnet. Effectively linking two contracts cross chain. *
For this example I built a simple branch to showcase the process of using state sync with scaffold-eth. LINK TO THE REPO
But first we need to talk about how this system works.
The way in which the state sync mechanic works, is a parent contract is made
on eth mainnet. This parent contract sends crafted calldata to a contract
called fxRoot which is declared in the constructor. When this contract
receives a transaction, it broadcasts an event, which contains the address
to interact with on polygon, as well as the calldata to interact with that
contract. This event is processed by validators. After processing
(about 20 mins) the data is sent from the fxChild contract, to the child
contract address with the calldata. And the tx is then executed.
To build our own implimentation of this, an implimentation of the parent contract must be made. This is the simplest contract we have to deal with, which inherits the FxBaseRootTunnel.sol contract(which was nicely crafted by the polygon dev team.) To send data over to the child contract, we have to use the internal function _sendMessageToChild()
and pass in the abi.encoded arguments that we wish to send to the child.
Heres an example:
function setChildPurpose(string memory newPurpose) public {
_sendMessageToChild(abi.encode(newPurpose));
}
This data is then sent to the _fxRoot address defined in the constructor.
Now we need to build out a way for our child contract to meaningfully interact
with that data!
To do this we need to write a child contract on polygon. This contract is
going to inherit the FxBaseChildTunnel.sol contract. And in the constructor,
we need to set the _fxChild address. This is address points to the contract
on polygon that receives message from the parent on mainnet, and send that
data to the child. Or vise versa.
Within this contract there are a couple things we need to implement.
uint256 public latestStateId;
address public latestRootMessageSender;
bytes public latestData;
uint latestStateId
, is used to keep track of the current stateId,
and validate the state with the fxChild contract. We don't manually do anything
with this value.
uint latestRootMessageSender
is the msg.sender of the transaction from the
parent contract.
bytes latestData
is the calldata that was sent from the parent
contract.
We have almost everything set up to test our new implimentation, we just need
to handle the data being passed in.
To do this, we have to implement the internal function _proccessMessageFromRoot()
, which takes in a uint stateId, address sender, and bytes data. All of these values can really be ignored, except for data. To give our contract functionality, we need to write some code within this function, that does something with that data. In our example, we are setting the purpose of the child contract. So our data needs to be abi.decoded into a string, which will be stored in the purpose variable within the contract. In addition to that, we need to update the latestStateId, latestRootMessageSender, and latestData variables within our contract with the new data passed in. Here is how that is done:
function _processMessageFromRoot( uint256 stateId, address sender, bytes memory data ) internal override validateSender(sender)
{
latestStateId = stateId;
latestRootMessageSender = sender;
latestData = data;
purpose = abi.decode(data, (string));
}
And now we have successfully linked our two contracts cross chain!
Calling the function setChildPurpose() from mainnet will update the purpose
of the child contract on polygon roughly 20 minutes later! The reverse can
also be done but takes far longer (7 days?) and as a result I have not tried
it personally.
Feel free to reach out to me on twitter or telegram if you have any questions or concerns about sync-state! @blind_nabler