ava-labs / teleporter

EVM cross-chain messaging protocol built on top of Avalanche Warp Messaging
Other
49 stars 24 forks source link

teleporter

To get started with building applications on top of Teleporter, refer to the avalanche-starter-kit repository. This README is focused on the development of the Teleporter protocol itself.

Teleporter is an EVM compatible cross-subnet communication protocol built on top of Avalanche Warp Messaging (AWM), and implemented as a Solidity smart contract. It provides a mechanism to asynchronously invoke smart contract functions on other EVM blockchains within Avalanche. Teleporter provides a handful of useful features on top of AWM, such as specifying relayer incentives for message delivery, replay protection, message delivery and execution retries, and a standard interface for sending and receiving messages within a dApp deployed across multiple subnets.

It's important to understand the distinction between Avalanche Warp Messaging and Teleporter. AWM allows subnets to communicate with each other via authenticated messages by providing signing and verification primitives in Avalanchego. These are used by the blockchain VMs to sign outgoing messages and verify incoming messages.

The Teleporter protocol, on the other hand, is implemented at the smart contract level, and is a user-friendly interface to AWM, aimed at dApp developers. All of the message signing and verification is abstracted away from developers. Instead, developers simply call sendCrossChainMessage on the TeleporterMessenger contract to send a message invoking a smart contract on another subnet, and implement the ITeleporterReceiver interface to receive messages on the destination subnet. Teleporter handles all of the Warp message construction and sending, as well as the message delivery and execution.

To get started with using Teleporter, see How to Deploy Teleporter Enabled Subnets on a Local Network

Deployed Addresses

Contract Address Chain
TeleporterMessenger 0x253b2784c75e510dD0fF1da844684a1aC0aa5fcf All chains, all networks
TeleporterRegistry 0x7C43605E14F391720e1b37E49C78C4b03A488d98 Mainnet C-Chain
TeleporterRegistry 0xF86Cb19Ad8405AEFa7d09C778215D2Cb6eBfB228 Fuji C-Chain

A Note on Versioning

Release versions follow the semver convention of incompatible Major releases. A new Major version is released whenever the TeleporterMessenger bytecode is changed, and a new version of TeleporterMessenger is meant to be deployed. Due to the use of Nick's method to deploy the contract to the same address on all chains (see Teleporter Contract Deployment for details), this also means that new release versions would result in different Teleporter contract addresses. Minor and Patch versions may pertain to contract changes that do not change the TeleporterMessenger bytecode, or to changes in the test frameworks, and will only be included in tags.

Setup

Initialize the repository

Dependencies

Structure

E2E tests

In addition to the docker setup, end-to-end integration tests written using Ginkgo are provided in the tests/ directory. E2E tests are run as part of CI, but can also be run locally. Any new features or cross-chain example applications checked into the repository should be accompanied by an end-to-end tests. See the Contribution Guide for additional details.

To run the E2E tests locally, you'll need to install Gingko following the instructions here.

Then run the following command from the root of the repository:

./scripts/e2e_test.sh

Run specific E2E tests

To run a specific E2E test, specify the environment variable GINKGO_FOCUS, which will then look for test descriptions that match the provided input. For example, to run the Calculate Teleporter message IDs test:

GINKGO_FOCUS="Calculate Teleporter message IDs" ./scripts/e2e_test.sh

A substring of the full test description can be used as well:

GINKGO_FOCUS="Calculate Teleporter" ./scripts/e2e_test.sh

The E2E tests also supports GINKGO_LABEL_FILTER, making it easy to group test cases and run them together. For example, to run all E2E tests for the example cross chain applications:

    ginkgo.It("Send native tokens from subnet A to B and back",
        ginkgo.Label("cross chain apps"),
        func() {
            flows.NativeTokenBridge(LocalNetworkInstance)
        })
GINKGO_LABEL_FILTER="cross chain apps" ./scripts/e2e_test.sh

Upgradability

The Teleporter contract is non-upgradeable and can not be changed once it is deployed. This provides immutability to the contracts, and ensures that the contract's behavior at each address is unchanging. However, to allow for new features and potential bug fixes, new versions of the Teleporter contract can be deployed to different addresses. The TeleporterRegistry is used to keep track of the deployed versions of Teleporter, and to provide a standard interface for dApps to interact with the different Teleporter versions.

TeleporterRegistry is not mandatory for dApps built on top of Teleporter, but dApp's are recommended to leverage the registry to ensure they use the latest Teleporter version available. Another recommendation standard is to have a single canonical TeleporterRegistry for each Subnet chain, and unlike the Teleporter contract, the registry does not need to be deployed to the same address on every chain. This means the registry does not need a Nick's method deployment, and can be at different contract addresses on different chains.

For more information on the registry and how to integrate with Teleporter dApps, see the Upgradability doc.

Deploy Teleporter to a Subnet

From the root of the repo, the TeleporterMessenger contract can be deployed by calling

./scripts/deploy_teleporter.sh --version <version> --rpc-url <url> [OPTIONS]

Required arguments:

Options:

To ensure that Teleporter can be deployed to the same address on every EVM based chain, it uses Nick's Method to deploy from a static deployer address. Teleporter costs exactly 10eth in the subnet's native gas token to deploy, which must be sent to the deployer address.

deploy_teleporter.sh will send the necessary native tokens to the deployer address if it is provided with a private key for an account with sufficient funds. Alternatively, the deployer address can be funded externally. The deployer address for each version can be found by looking up the appropriate version at https://github.com/ava-labs/teleporter/releases and downloading TeleporterMessenger_Deployer_Address_<VERSION>.txt.

Alternatively for new Subnets, the TeleporterMessenger contract can be directly included in the genesis file as documented here.

Deploy TeleporterRegistry to a Subnet

There should only be one canonical TeleporterRegistry deployed for each chain, but if one does not exist, it is recommended to deploy the registry so Teleporter dApps can always use the most recent Teleporter version available. The registry does not need to be deployed to the same address on every chain, and therefore does not need a Nick's method transaction. To deploy, run the following command from the root of the repository:

./scripts/deploy_registry.sh --version <version> --rpc-url <url> --private-key <private_key> [OPTIONS]

Required arguments:

deploy_registry.sh will deploy a new TeleporterRegistry contract for the intended release version, and will also have the corresponding TeleporterMessenger contract registered as the initial protocol version.

ABI Bindings

To generate Golang ABI bindings for the Solidity smart contracts, run:

./scripts/abi_go_bindings.sh

The auto-generated bindings should be written under the abi-bindings/ directory.

Docs

Resources