Quickstart
Last updated
Last updated
This quickstart will teach you how to use xcall
, the cross-chain communication primitive, to send funds and data across chains.
In this guide, we will build a cross-chain Greeter. The DestinationGreeter
contract on the destination chain has an updateGreeting
function that changes a stored greeting
variable. The SourceGreeter
contract on the origin chain uses xcall
to send encoded calldata for updateGreeting
.
To demonstrate a combination of an asset transfer and an arbitrary call in a single xcall
, the updateGreeting
function will require a payment to update the greeting. For this example, the contract will be okay with any amount greater than 0.
updateGreeting
is implemented as an unauthenticated call (there are no checks to determine who is calling the function). Therefore, this type of xcall
will be go through the "Fast Path".
If you prefer to fork a repo instead of following this step-by-step guide, our kit contains a full example of this quickstart (plus more) and is compatible with both Hardhat and Foundry.
Node v18 installed
Follow the instructions to install and use Node.js v18. We also recommend installing nvm
, a node version manager, which will make switching versions easier.
An Ethereum development environment like Foundry, Hardhat, Truffle, etc.
This guide will be using Hardhat. Follow the instructions to install .
If you don't already have gas funds on Goerli, try these faucets to get some:
https://goerli-faucet.mudit.blog/ (Requires Twitter account)
https://goerlifaucet.com/ (Requires signing up with Alchemy)
Create a new project by running the following command:
Choose a Javascript project. Choose y
on all of the prompts.
Install the latest version of Connext contracts package in your project:
Next, install the OpenZeppelin contract package:
You'll need to manually install the library @openzeppelin/contracts-upgradeable
Install dotenv
to protect your private key needed to deploy your contract:
In the root of your project, create a new .env
file. Here you will store your private key used to deploy your contract.
Update .env
with the following line:
The source contract initiates the cross-chain operation with xcall
and passes the encoded greeting into the call. All xcall
params are detailed here.
In the /contracts
directory, create a new contract called SourceGreeter.sol
:
xUpdateGreeting
is what the user will call on origin to initiate the xcall
.
Make sure the solidity compiler version in your hardhat.config.js
is at least 0.8.17
.
Compile the contract with the following command:
Note: Hardhat may require you to manually install dependencies for @nomicfoundation/hardhat-toolbox. If you get an error about missing dependencies for that plugin, run the following command:
Update the hardhat.config.js
file:
Create a /scripts/deploySource.js
file with the following:
Now run the deploy script:
Output:
Contract deployed to: 0x9Af84578B89FcA019580af02326388987A074ca1
Add an etherScan
section to hardhat.config.js
with your goerli
api key (note: Etherscan API keys for the mainnet explorers will work for testnets):
Using the contract address you just deployed, run the hardhat verify
command, including the contract address and its constructor arguments:
If you run into any errors like ProviderError: Too Many Requests
, then replace the public RPC url in hardhat.config.js
with another one from https://chainlist.org/ or use your own private RPC from a provider like Infura or Alchemy.
In the /contracts
directory, create another contract called DestinationGreeter.sol
:
All target contracts must implement Connext's IXReceiver
interface. This interface ensures that Connext can call the contract and pass necessary data.
Compile:
Add another entry to hardhat.config.js
, this time for Optimism-Goerli.
Create a scripts/deployTarget.js
file with the following:
Then run the deploy script:
Output:
Contract deployed to: 0xC4e508cEe84499958a84C3562e92bD9e71d7D38a
Add an apiKey
to hardhat.config.js
for optimism-goerli
:
Using the contract address you just deployed, verify it:
If you run into any errors like ProviderError: Too Many Requests
, then replace the public RPC url in hardhat.config.js
with another one from https://chainlist.org/ or use your own private RPC with a provider like Infura or Alchemy.
You should try the following steps on your own deployed contracts. For the lazy ones, you can just use these contracts we've deployed already:
First, you will need some TEST tokens. Recall that the destination contract requires a payment > 0 TEST in order to update its greeting.
Since you'll be updating the greeting from the origin chain, you will need to acquire some TEST tokens on the origin chain.
A new tab will show up with all write functions of the contract. Connect your wallet, switch to the Goerli network, and enter the parameters for the mint
function:
account
: <YOUR_WALLET_ADDRESS>
amount
: 10000000000000000000
10 TEST. You can actually mint however much you want.
Tokens will move from User's wallet
=> SourceGreeter
=> Connext
=> DestinationGreeter
.
The user must first approve a spending allowance of the TEST ERC20 to the SourceGreeter
contract. The require
clause starting on line 39 checks for this allowance.
Again, on the Etherscan page for the TEST token, enter the parameters for the approve
function:
spender
: 0x9Af84578B89FcA019580af02326388987A074ca1
This is the address of SourceGreeter
.
amount
: 10000000000000000000
Then "Write" to the approve
function.
xUpdateGreeting
Similarly to the approval function for TEST, navigate to the SourceGreeter
contract on Etherscan. Fill out the xUpdateGreeting
function parameters and "Write" to the contract.
Let's walk through the different parameters.
xUpdateGreeting
(payableAmount): 0.03
This is the native gas that you're sending into the xcall
. This value must match what you pass in as relayerFee
, but note that it's in ETH units here and wei units in relayerFee
.
target
: 0xC4e508cEe84499958a84C3562e92bD9e71d7D38a
The address of DestinationGreeter
.
destinationDomain
: 1735356532
The Domain ID of the destination chain. You can find a mapping of Domain IDs here. For this example, DestinationGreeter
is deployed to Optimism-Goerli.
newGreeting
: hello chain!
Whatever string you want to update the greeting to.
amount
: 1000000000000000000
The amount of TEST tokens to pay. We send 1 TEST here.
relayerFee
: 30000000000000000
0.03 goerli ETH, in wei units. Just a conservative estimate for relayers on testnet.
IMPORTANT! This is a fee paid to relayers, which are off-chain agents that help execute the final leg of the cross-chain transfer on destination. Relayers get paid in the origin chain's native asset. This is why SourceGreeter
passes the fee like so:
Note that if your relayerFee
was too low, the explorer will prompt you to increase it.
DestinationGreeter
DestinationGreeter
should be updated in just a few minutes (because this call is unauthenticated!). Cross-chain calls are not always this fast - see our guide on Authentication.
Head over to the DestinationGreeter
contract on Etherscan. This time, we'll go to the Read Contract
tab and look at the value of greeting
. It has updated!
Send a couple more updates from SourceGreeter
but make it a different string. At some point, your TEST allowance to HelloSource
will run out and you'll need to do the approval dance again.
Congrats! You've gone cross-chain!
The addresses for Connext and supported tokens in different domains can be referenced . We'll be using Goerli as our origin domain and the TEST token for this contract.
You can use Etherscan to call functions on (verified) contracts. Go to the and click on the "Write Contract" button.
As a xApp developer, you have some tools available to estimate what this relayerFee
should be. For now, there are offchain methods for doing so - check out the guide on .
After executing updateGreeting
, you can use to check the status of the xcall
. Just search up the transaction hash from the execution transaction.
Try of an xcall
after you send it.
Learn about and important security considerations.
See how can open up infinite cross-chain possibilities.
Fork the (includes code for this example) and build your own xApp.