Building Crosschain Apps (xApps)

Upgrade your dApp to xChain

Massimo Lomuscio
Connext

--

Connext lets builders create secure xchain dApps (xapps). Our network is the only way to build xapps that retain the security of underlying blockchains.

What are xApps?

xApps (pronounced “zaps”) are decentralized applications that perform operations between independent chains/execution environments, Ethereum and Avalanche, Polygon and Polkadot, but also Optimism and Arbitrum, for example.

Moving from multichain to crosschain.

Multichain deployments are already here. Aave, Yearn, Curve, all have multiple interfaces on many chains.

While you can use all these apps on different chains, they act like different apps, siloed from each other: they are multichain, not xchain.

So how do you build in a xchain paradigm?

  • Unify the interface: build one interface that aggregates data from all chains and shows users a single consolidated experience.
  • Abstract the “home” chain: recognize user balances and actions from any supported chain regardless of where the user initiates their interactions from.
  • xCall to route transactions to any chain: use Connext to let users call to any receiving chain contract in a single step, or even to directly connect your contracts to one another.

The ideal end result is a xapp that has a single interface allowing users to access liquidity or data from any chain. Users should not ever need to care what chain they are on if they don't want to!

What Can You Build?

Here are some ideas:

  1. xChain zaps: similar to LP apps, you have an asset on one chain, you zap it into a farm on another chain where you can do things like split it into the LP and then deposit it directly, all abstracted away from the user.
  2. xChain governance: If you hold governance tokens that have been bridged to a chain that is not the native one of the dApp, you can't vote. xChain voting will be the standard for governance protocols and DAOs.
  3. Yield optimization across chains. Bridge tokens to another chain, harvest, bring back the profits.
  4. Dex arbitrage: an opportunity for Dex arbitrageurs to perform and profit from different marketplace prices across chains.
  5. xChain borrowing: add collateral on chain A, borrow another asset on chain B.

We’ve barely started to scratch the surface of what we can do with xchain operations.

Build xApps with Connext

Building dApps is already pretty hard. When you add more chains, everything such as deploying contracts, managing deployed addresses, reading and writing on the state, managing RPC providers/nodes, exponentially increase the complexity for builders and users.

Connext simplifies the experience of building cross chain applications, with the highest level of security:

  1. A unified smart contract interface for native xApps. You can use Connext to choose precisely what cross chain operations you want to do; a single unified interface to reduce development complexities.
  2. Instant liquidity bridging and calldata passing. This allows you to abstract the gas interface away from the user by letting the protocol call the function on the receiving chain.
  3. Message passing: unidirectional and bi-directional message passing.

Unidirectional message passing means you can trustlessly pass a message from one chain to another and verify it comes from a specific source. If you want to vote from one chain to another, you can do that in a trustworthy way.

Bi-directional, if you need to send a request to a chain (for example, read a TWAP price), and then get a result back on the original chain.

xApps are the new wave of innovation and the future standard for any dApp.

So… How do you build a xApp?

Whether you write smart contracts or use Connext’s SDK in web/Node environments, building a xapp to conduct cross-chain operations eventually comes down to understanding a set of standard parameters in order to send cross-chain calls (“xcalls”). This is a quick primer on how to construct those necessary parameters for xcall.

This is the xcall function signature:

Let’s dive into each parameter.

  • _destination: The to Domain IDs (not equivalent to “Chain IDs”).
  • _to: The target address on the destination chain. `xcall` will send funds to whatever address is specified here regardless of whether it is a contract or EOA. If calldata is provided, `xcall` will additionally attempt to call `xReceive` on this contract.
  • _asset: The contract address of the asset to be bridged. If the xcall is calldata-only (e.g. doesn’t bridge any funds), any registered asset can be used here as long as amount: 0.
  • _delegate: An address on destination domain that has rights to update slippage tolerance, retry transactions, or revert back to origin in the event that a transaction fails at the destination.
  • _amount: The amount of tokens to bridge specified in standard format (i.e. to send 1 ERC20 token with 10¹⁸ decimals, you must specify the amount as 1000000000000000000).
  • _slippage: The maximum slippage a user is willing to take, in BPS, due to the StableSwap Pool(s), if applicable. For example, to achieve 0.03% slippage tolerance this will be 3. If no funds are being sent, this can be anything between 0–10000.
  • _callData: In the case of bridging funds only, this should be empty (“”). If calldata is sent, then the encoded calldata must be passed here.

xcall will return a bytes32 type transferId that is unique to each xcall.
It can be used to track xcall throughout its lifecycle.

The last requirement for sending an xcall is to determine the proper amount of relayerFee to include, denominated in the origin chain’s native gas token. This fee is passed as the value for xcall:


connext.xcall{value: relayerFee}(…)

The relayerFee is a fee paid to relayers for relaying the transaction to the destination domain. The fee must be high enough to satisfy relayers’ cost conditions for relaying a transaction, which includes the gas fee plus a bit extra as incentive. This fee is paid in the origin domain’s native asset — it’s locked on the origin domain and eventually claimed by the relayer. If, for any reason, the initial relayerFee is set too low, a public method on Connext’s contract called bumpTransfer can be called on the origin domain to increase the initial fee until it’s sufficient for relayers.

Armed with this knowledge, you can write a set of smart contracts that sends funds and executable calldata from one chain to another.

HelloSource.sol

HelloTarget.sol

The HelloTarget contract on the destination domain (Mumbai) stores a greeting variable that we want to update. The HelloSource contract on the origin domain (Goerli) will use xcall to execute the updating function on HelloTarget.

HelloTarget requires a payment of 1 TEST token to update the greeting. So in HelloSource’s xcall, we pass in a total of 1.0005003 TEST to account for a 0.05% fee that routers will take on the bridged asset. When the TEST arrives on HelloTarget, it will accept the payment and update the greeting variable.

There are various ways to use xcall, from sending permissioned calldata across chains or simply transferring funds. You can also xcall within an xcall, enabling unique cross-chain functionality that reaches multiple chains.

Connext makes building cross-chain applications much more accessible to developers while retaining our focus on end user experience and security.

Additional resources

About Connext

Connext is a network for fast, trustless communication between chains and rollups. It is the only interoperability system of its type that does this cheaply and quickly without introducing any new trust assumptions. Connext is aimed at developers who are looking to build bridges and other natively cross-chain applications. To date, over $1.5b in transactions have crossed the network.

Website | Build | Twitter | Discord | Github | Blog

Co-written with Eddie Ye

--

--