Skip to main content

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 every be called via an xcall.

function greet(string calldata greeting) external xrecv  {
require(isXCall(), "XGreeter: only xcall");
emit Greetings(xmsg.sender, xmsg.sourceChainId, greeting);
}