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.
- Deployed Addresses
- Setup
- Structure
- Run a local testnet in Docker
- E2E tests
- Upgradeability
- Deploy Teleporter to a Subnet
- Deploy TeleporterRegistry to a Subnet
- ABI Bindings
- Docs
- Resources
Contract | Address | Chain |
---|---|---|
TeleporterMessenger |
0x253b2784c75e510dD0fF1da844684a1aC0aa5fcf | All chains, all networks |
TeleporterRegistry |
0x7C43605E14F391720e1b37E49C78C4b03A488d98 | Mainnet C-Chain |
TeleporterRegistry |
0xF86Cb19Ad8405AEFa7d09C778215D2Cb6eBfB228 | Fuji C-Chain |
-
When deployed using Nick's method,
TeleporterMessenger
will be at the same address on all chains. See Teleporter Contract Deployment and Deploy Teleporter to a Subnet for more details. -
TeleporterRegistry
can be deployed to any address. See Deploy TeleporterRegistry to a Subnet for details. The table above enumerates the canonical registry addresses on the Mainnet and Fuji C-Chains.
- Get all submodules:
git submodule update --init --recursive
- Ginkgo for running the end-to-end tests
- Docker and Docker Compose v2 for running the local test network
contracts/
is a Foundry project that includes the implementation of theTeleporterMessenger
contract and example dApps that demonstrate how to write contracts that interact with Teleporter.abi-bindings/
includes Go ABI bindings for the contracts incontracts/
.tests/
includes integration tests for the contracts incontracts/
, written using the Ginkgo testing framework.utils/
includes Go utility functions for interacting with the contracts incontracts/
. Included are Golang scripts to derive the expected EVM contract address deployed from a given EOA at a specific nonce, and also construct a transaction to deploy provided byte code to the same address on any EVM chain using Nick's method.scripts/
includes bash scripts for interacting with Teleporter in various environments, as well as utility scripts.abi_bindings.sh
generates ABI bindings for the contracts incontracts/
and outputs them toabi-bindings/
.lint.sh
performs Solidity and Golang linting.scripts/local/
includes scripts for running Teleporter in Docker.
docker/
includes configurations for a local, containerized setup of Teleporter.
A docker setup for running a local network with Teleporter deployed is provided. This setup provides a convenient way to develop and test Teleporter as well as cross-chain applications built on top of Teleporter. Teleporter messages are relayed between subnets using AWM Relayer, a fully featured implementation of a Warp message relayer.
-
Run
./scripts/local/run.sh
to run the local testnet in Docker containers with the ability to interact with the nodes directly../scripts/local/run.sh
usage is as follows:
-l, --local-relayer-image <tag> Use a local AWM Relayer image instead of pulling from dockerhub -h, --help Print this help message
- If using
-l, --local
to use a local version of theawm-relayer
image, build it using./scripts/build_local_image.sh
from the root of theawm-relayer
repository. - Note that if
-l, --local
is not set, then the latest publishedawm-relayer
image will be pulled from Dockerhub.
-
After calling
./scripts/local/run.sh
, you'll know the network is ready once the "Waiting for subnets to start up." messages from therelayer_run
container stop. Once the network is ready, you can interact with the deployed Teleporter contracts directly, or deploy a cross-chain application contract such asExampleCrossChainMessenger
. To open a terminal in the container and initialize it with the environment variables needed to interact with the contracts, run:
# Open a shell in the container
docker exec -it local_network_run /bin/bash
# In the container:
set -a # export all variables so child processes can access
source vars.sh # source the variables needed to interact with the contracts
-
Once you've opened a shell in the container, try interacting with the network.
- For example, send 1 AVAX on the C-Chain using
cast
c_address=0x333d17d3b42bf7930dbc6e852ca7bcf560a69003 # pick an arbitrary address cast balance --rpc-url $c_chain_rpc_url $c_address cast send --private-key $user_private_key --value 1 $c_address --rpc-url $c_chain_rpc_url cast balance --rpc-url $c_chain_rpc_url $c_address
- An example of how to interact with Teleporter is provided in
scripts/local/examples/basic_send_receive.sh
. This script sends a dummy payload via Teleporter from the C-Chain to a subnet, and back again.
./scripts/local/examples/basic_send_receive.sh
- You should see "Received on Subnet A is true" and "Received on the C-Chain is true" to indicate that Teleporter messages were successfully sent between the C-Chain and Subnet A.
- These examples can be adapted to send messages between any two subnets, or between the C-Chain and any subnet by changing the RPC URLs.
- Use these as a starting point to build and interact with your own cross-chain applications on top of Teleporter!
- For example, send 1 AVAX on the C-Chain using
- The
./scripts/local/run.sh
script runs five local network nodes, with each of the nodes validating the primary network and three subnets (Subnet A, Subnet B, and Subnet C). ./scripts/local/run.sh
will force-recreate the containers, which will reset the network state on each subsequent run.- Logs from the subnets on one of the five nodes are printed to stdout when run using either script.
- These logs can also be found at
~/.avalanche-cli/runs/network_<DATE>_<TIMESTAMP>/node{1,5]/logs/<SUBNET_ID>.log
in thelocal_network_run
container.
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/local/e2e_test.sh
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/local/e2e_test.sh
A substring of the full test description can be used as well:
GINKGO_FOCUS="Calculate Teleporter" ./scripts/local/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/local/e2e_test.sh
The same E2E test flows can be executed against external network by setting the proper environment variables in .env.testnet
and .env
, and running the following commands:
cp .env.example .env # Set proper values after copying.
./scripts/testnet/run_testnet_e2e_flows.sh
The user wallet set in .env
must have native tokens for each of the Subnets used in order for the test flows to be able to send transactions on those networks. The Avalanche Testnet Faucet can be used to obtain native tokens for certain public testnet Subnets.
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 Upgradeability doc.
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:
--version <version>
Specify the release version to deploy. These will all be of the formv1.X.0
. Each Teleporter version can only send and receive messages from the same Teleporter version on another chain. You can see a list of released versions at https://github.com/ava-labs/teleporter/releases.--rpc-url <url>
Specify the rpc url of the node to use.
Options:
--private-key <private_key>
Funds the deployer address with the account held by<private_key>
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
.
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:
--version <version>
Specify the release version to deploy. These will all be of the formv1.X.0
.--rpc-url <url>
Specify the rpc url of the node to use.--private-key <private_key>
Funds the deployer address with the account held by<private_key>
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.
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.