Example
Here's an example of a simple cross chain contract, XGreeter
. This contract lets you send greetings from one chain to another.
XGreeter
Contract
Fetching code from GitHub...
Walkthrough
Let's walk through this step by step.
First, inherit from XApp
.
contract XGreeter is XApp {
constructor(address portal) XApp(portal) { }
// ...
}
Perform a Cross Chain Call
To call a contract on another chain, use xcall
.
function xgreet(uint64 destChainId, address to, string calldata greeting) external {
xcall(
// params for xcall
);
}
Receive a Cross Chain Call
When receiving an xcall
, you can read its context via omni.xmsg()
.
xmsg.sourceChainId // where this xcall came from
xmsg.sender // who sent it
With this context, we can have our XGreeter
emit events detailing the source chain and sender.
function greet(string calldata greeting) external {
emit Greetings(omni.xmsg().sender, omni.xmsg().sourceChainId, greeting);
}
For convenience, XApp
defines the xrecv
modifier. This modifier reads the current xmsg into storage, and deletes after its function's execution.
modifier xrecv() {
xmsg = omni.xmsg();
_;
delete xmsg;
}
It also visually marks a function as the target of an xcall
. Though, the xrecv
modifier is not required to receive an xcall
. Using this modifier, we can simplify our XGreeter
a bit further.
function greet(string calldata greeting) external xrecv {
emit Greetings(xmsg.sender, xmsg.sourceChainId, greeting);
}
Checking for Cross Chain Calls
Note that not every call is an xcall
. In these cases, xmsg
will be its zero value.
xmsg.sourceChainId // 0
xmsg.sender // address(0)
You can check if the current call is an xcall
with isXCall
.
function isXCall() internal view returns (bool) {
return omni.isXCall() && msg.sender == address(omni);
}
Note that not only does isXCall
check with the portal that the current transaction is an xcall
, it also confirms the sender is the portal itself. This helps avoid mistaking calls later in an xcall
stacktrace with the original xcall
. Using this helper, we can ensure that greet()
can only ever be called via an xcall
.
function greet(string calldata greeting) external xrecv {
require(isXCall(), "XGreeter: only xcall");
emit Greetings(xmsg.sender, xmsg.sourceChainId, greeting);
}