From f05ccc92eb41ed76aefc7f36119001cde3ae6f7a Mon Sep 17 00:00:00 2001 From: Owen Date: Wed, 11 Sep 2024 22:20:14 +0400 Subject: [PATCH] Cleanup ICM Course (#150) --- .../02-recap-bytes-encoding-decoding.mdx | 4 +- .../04-icm-basics/03-sending-a-message.mdx | 12 +- .../04-create-sender-contract.mdx | 104 ++++++++++-------- .../04-icm-basics/05-receiving-a-message.mdx | 10 +- .../06-create-receiver-contract.mdx | 25 +++-- .../04-icm-basics/07-send-a-message.mdx | 4 +- .../08-adapting-the-contract-exercise.mdx | 2 +- .../01-two-way-communication.mdx | 6 +- .../03-create-sender-contract.mdx | 18 ++- .../04-receiver-contract.mdx | 8 +- .../05-create-the-receiver-contract.mdx | 23 ++-- .../06-send-a-roundtrip-message.mdx | 5 + .../02-encoding-multiple-values.mdx | 4 +- .../03-create-simple-calculator-sender.mdx | 20 +++- .../04-create-simple-calulcator-receiver.mdx | 22 +++- .../05-call-simple-calculator.mdx | 12 +- .../06-encoding-function-name.mdx | 40 +++++-- .../07-extend-calculator.mdx | 6 +- .../02-how-the-icm-registry-works.mdx | 4 +- .../03-interact-with-the-registry.mdx | 50 ++++++++- .../04-retrieving-icm-from-registry.mdx | 6 +- .../01-securing-cross-chain-communication.mdx | 2 +- .../02-signature-schemes.mdx | 2 +- .../04-multi-signature-schemes.mdx | 2 +- .../05-signature-aggregation.mdx | 2 +- .../07-trusted-third-parties.mdx | 2 +- .../04-awm-relayer.mdx | 4 +- .../07-message-delivery.mdx | 2 +- .../09-trust-assumption-of-awm.mdx | 4 +- .../01-running-a-relayer.mdx | 6 +- .../02-control-the-avalanche-cli-relayer.mdx | 4 +- .../03-install-relayer.mdx | 2 +- .../04-relayer-configuration.mdx | 28 ++--- .../05-analyze-relayer-logs.mdx | 2 +- .../01-restricting-the-relayer.mdx | 4 +- .../02-allowed-relayers.mdx | 6 +- .../01-incentivizing-a-relayer.mdx | 2 +- .../02-fee-data-flow.mdx | 11 +- .../03-determining-the-fee-amount.mdx | 13 ++- .../04-setting-incentives.mdx | 12 +- .../05-deploy-fee-token-contract.mdx | 17 ++- .../06-incentivize-an-awm-relayer.mdx | 24 ++-- .../07-interaction-flow-with-fees.mdx | 43 ++++++-- 43 files changed, 375 insertions(+), 204 deletions(-) diff --git a/content/course/interchain-messaging/04-icm-basics/02-recap-bytes-encoding-decoding.mdx b/content/course/interchain-messaging/04-icm-basics/02-recap-bytes-encoding-decoding.mdx index 6815c9cd..15df3606 100644 --- a/content/course/interchain-messaging/04-icm-basics/02-recap-bytes-encoding-decoding.mdx +++ b/content/course/interchain-messaging/04-icm-basics/02-recap-bytes-encoding-decoding.mdx @@ -10,7 +10,7 @@ When we send an interchain message, we are just sending a single value of type b In this section we will recap these topics: -- **Bytes:** What is this data types and why are we using it? +- **Bytes:** What is this data type and why are we using it? - **Encoding:** How do we turn values into bytes? - **Decoding:** How can we turn the bytes back into the values? @@ -23,7 +23,7 @@ This makes it a pragmatic choice for encapsulating diverse data and data type en ## Encoding & Decoding -In solidity we can use the functions `abi.encode()` and `abi.decode()` for encoding and decoding. These are part of the solidity language, so we do not need to import anything to use them. +In Solidity we can use the functions `abi.encode()` and `abi.decode()` for encoding and decoding. These are part of the solidity language, so we do not need to import anything to use them. ![Encoding and Decoding](/common-images/solidity/encoding-decoding.png) diff --git a/content/course/interchain-messaging/04-icm-basics/03-sending-a-message.mdx b/content/course/interchain-messaging/04-icm-basics/03-sending-a-message.mdx index 9b50ada5..555b1e4a 100644 --- a/content/course/interchain-messaging/04-icm-basics/03-sending-a-message.mdx +++ b/content/course/interchain-messaging/04-icm-basics/03-sending-a-message.mdx @@ -55,9 +55,9 @@ interface ITeleporterMessenger { The `sendCrossChainMessage` function takes `TeleporterMessageInput` struct as an input. In that multiple values are contained: This data will then be included in the payload of the Warp message: -- **destinationChainID:** The chainID where the contract that should receive the message is deployed. This is not the EVM chain ID you may know from adding a network to a wallet, but the blockchain ID on the P-Chain. The P-Chain uses the transaction ID of the transaction that created those blockchain on the P-Chain for the chain ID, e.g.: 0xd7cdc6f08b167595d1577e24838113a88b1005b471a6c430d79c48b4c89cfc53 -- **destinationAddress:** The address of the contract that should receive the message -- **feeInfo:** A struct consisting of a contract address of an ERC20 which the fee is paid in as well as the amount of tokens to be paid as an incentive for the relayer. We will look at this later in more detail. -- **requiredGasLimit:** The amount of gas the delivery of the message requires. If the relayer provides the required gas, the message will be considered delivered whether or not its execution succeeds, such that the relayer can claim their fee reward. -- **allowedRelayerAddresses:** An array of addresses of allowed relayers. An empty allowed relayers list means anyone is allowed to deliver the message. We will look at this later in more detail. -- **message:** The message to be sent as bytes. The message can contain multiple encoded values. DApps using Interchain Messaging are responsible for defining the exact format of this payload in a way that can be decoded on the receiving end. The message can hold multiple values that be encoded in a single bytes object. For example, applications may encode multiple method parameters on the sending side, then decode this data in the contract implementing the receiveTeleporterMessage function and call another contract with the parameters from there. +- **`destinationChainID`:** The chainID where the contract that should receive the message is deployed. This is not the EVM chain ID you may know from adding a network to a wallet, but the blockchain ID on the P-Chain. The P-Chain uses the transaction ID of the transaction that created those blockchain on the P-Chain for the chain ID, e.g.: 0xd7cdc6f08b167595d1577e24838113a88b1005b471a6c430d79c48b4c89cfc53 +- **`destinationAddress`:** The address of the contract that should receive the message +- **`feeInfo`:** A struct consisting of a contract address of an ERC20 which the fee is paid in as well as the amount of tokens to be paid as an incentive for the relayer. We will look at this later in more detail. +- **`requiredGasLimit`:** The amount of gas the delivery of the message requires. If the relayer provides the required gas, the message will be considered delivered whether or not its execution succeeds, such that the relayer can claim their fee reward. +- **`allowedRelayerAddresses`:** An array of addresses of allowed relayers. An empty allowed relayers list means anyone is allowed to deliver the message. We will look at this later in more detail. +- **`message`:** The message to be sent as bytes. The message can contain multiple encoded values. DApps using Interchain Messaging are responsible for defining the exact format of this payload in a way that can be decoded on the receiving end. The message can hold multiple values that be encoded in a single bytes object. For example, applications may encode multiple method parameters on the sending side, then decode this data in the contract implementing the receiveTeleporterMessage function and call another contract with the parameters from there. diff --git a/content/course/interchain-messaging/04-icm-basics/04-create-sender-contract.mdx b/content/course/interchain-messaging/04-icm-basics/04-create-sender-contract.mdx index c70645ed..8dfdedd5 100644 --- a/content/course/interchain-messaging/04-icm-basics/04-create-sender-contract.mdx +++ b/content/course/interchain-messaging/04-icm-basics/04-create-sender-contract.mdx @@ -49,11 +49,11 @@ contract SenderOnCChain { The key things to understand: -- **Importing ITeleporterMessenger (Line 8):** We are importing the ITeleporterMessenger Interface we looked at in the previous activity. -- **Defining teleporterMessenger contract (Line 12):** We are defining a the teleporterMessenger contract using the imported interface. It is important to note, that our cross-chain dApp is not implementing the interface itself, but initializes a contract using that interface. -- **Sending the message (Line 21):** We are sending the message by calling the function of our teleporterMessenger. As an input we are defining a TeleporterMessageInput. Make sure to replace the `destinationChainId` with the one of your Blockchain. We will need to provide the address of the receiving contract on the Avalanche L1 as a parameter to the function, since we have not deployed it yet and don't know the address at this time. +- **Importing ITeleporterMessenger (Line 8):** We are importing the `ITeleporterMessenger` Interface we looked at in the previous activity. +- **Defining teleporterMessenger contract (Line 12):** We are defining a `teleporterMessenger` contract using the imported interface. It is important to note, that our cross-chain dApp is not implementing the interface itself, but initializes a contract using that interface. +- **Sending the message (Line 21):** We are sending the message by calling the function of our `teleporterMessenger`. As an input we are defining a `TeleporterMessageInput`. Make sure to replace the `destinationChainId` with the one of your Blockchain. We will need to provide the address of the receiving contract on the Avalanche L1 as a parameter to the function, since we have not deployed it yet and don't know the address at this time. - **No fees (Line 25):** In this exercise we are not providing any fees to the relayer for relaying the message. This is only possible since the relayer we are running here is configured to pick up any message even if it does not provide any rewards. -- **Encoding the Message (Line 31):** The TeleporterMessageInput defines a message as an array of bytes. For now we will just simply encode the string with abi.encode(). In the future activities, you will see how we can encode multiple values of any type in that message. +- **Encoding the Message (Line 31):** The `TeleporterMessageInput` defines a message as an array of bytes. For now we will just simply encode the string with `abi.encode()`. In the future activities, you will see how we can encode multiple values of any type in that message. @@ -63,47 +63,31 @@ The key things to understand: To get the blockchainID on our Avalanche L1 let's use the Avalanche-CLI built in feature with the command: ``` bash -avalanche subnet describe myblockchain +avalanche blockchain describe myblockchain ``` -In the Details section of the output you will find something like this: +In the output you will find the blockchain details: -```bash - _____ _ _ _ -| __ \ | | (_) | -| | | | ___| |_ __ _ _| |___ -| | | |/ _ \ __/ _ | | / __| -| |__| | __/ || (_| | | \__ \ -|_____/ \___|\__\__,_|_|_|___/ -+--------------------------------+-------------------------------------------------------------------------------------+ -| PARAMETER | VALUE | -+--------------------------------+-------------------------------------------------------------------------------------+ -| Avalanche L1 Name | myblockchain | -+--------------------------------+-------------------------------------------------------------------------------------+ -| ChainID | 123498765 | -+--------------------------------+-------------------------------------------------------------------------------------+ -| Token Name | test Token | -+--------------------------------+-------------------------------------------------------------------------------------+ -| Token Symbol | test | -+--------------------------------+-------------------------------------------------------------------------------------+ -| VM Version | v0.6.4 | -+--------------------------------+-------------------------------------------------------------------------------------+ -| VM ID | qDNsVQJfGpi2RfCcESbeZauGqPVjtXwoopVMtrGkdoUxmFKov | -+--------------------------------+-------------------------------------------------------------------------------------+ -| Local Network Avalanche L1ID | 2CZP2ndbQnZxTzGuZjPrJAm5b4s2K2Bcjh8NqWoymi8NZMLYQk | -+--------------------------------+-------------------------------------------------------------------------------------+ -| Local Network RPC URL | http://127.0.0.1:9650/ext/bc/2mJS3tyZ26vVWapQGY9eamBtcx5o4fjGyfn9ZKpL8axnUDy5yx/rpc | -+--------------------------------+-------------------------------------------------------------------------------------+ -| Local Network BlockchainID | 2mJS3tyZ26vVWapQGY9eamBtcx5o4fjGyfn9ZKpL8axnUDy5yx | -+ +-------------------------------------------------------------------------------------+ -| | 0xe849319dbab299f063eaccca029eb70f3a3337e10106d2c44d09a168385e570a | -+--------------------------------+-------------------------------------------------------------------------------------+ -| Local Network Interchain Messaging | 0x253b2784c75e510dD0fF1da844684a1aC0aa5fcf | -| Messenger Address | | -+--------------------------------+-------------------------------------------------------------------------------------+ -| Local Network Interchain Messaging | 0x7001E06DF22d22Df4BBCa750CA0969FFf3739A7A | -| Registry Address | | -+--------------------------------+-------------------------------------------------------------------------------------+ +``` ++---------------------------------------------------------------------------------------------------------------+ +| MYBLOCKCHAIN | ++---------------+-----------------------------------------------------------------------------------------------+ +| Name | myblockchain | ++---------------+-----------------------------------------------------------------------------------------------+ +| VM ID | qDNV9vtxZYYNqm7TN1mYBuaaknLdefDbFK8bFmMLTJQJKaWjV | ++---------------+-----------------------------------------------------------------------------------------------+ +| VM Version | v0.6.9 | ++---------------+--------------------------+--------------------------------------------------------------------+ +| Local Network | ChainID | 1 | +| +--------------------------+--------------------------------------------------------------------+ +| | SubnetID | 2AKbBT8jFUfUsUJ2hhRiDUnAAajJdNhTKeNgEe3q77spMj1N8F | +| +--------------------------+--------------------------------------------------------------------+ +| | Owners (Threhold=1) | P-custom18jma8ppw3nhx5r4ap8clazz0dps7rv5u9xde7p | +| +--------------------------+--------------------------------------------------------------------+ +| | BlockchainID (CB58) | krN11ZE6BNgenbX71Wu3YWv2SS5C3p9pD3WLkkRLVhuETGNJb | +| +--------------------------+--------------------------------------------------------------------+ +| | BlockchainID (HEX) | 0x6391b85bafc78f1b10aec35695c2399c2fb7fff9f3b18ea903f77345e9e96e3e | // [!code highlight] ++---------------+--------------------------+--------------------------------------------------------------------+ ``` @@ -111,8 +95,30 @@ In the Details section of the output you will find something like this: ### Replace `destinationBlockchainID` -Replace the destinationBlockchainID in your sender code. +Replace the destinationBlockchainID in `senderOnCChain.sol` with `BlockchainID (HEX)` + +```solidity +contract SenderOnCChain { + ITeleporterMessenger public immutable messenger = ITeleporterMessenger(0x253b2784c75e510dD0fF1da844684a1aC0aa5fcf); + /** + * @dev Sends a message to another chain. + */ + function sendMessage(address destinationAddress, string calldata message) external { + messenger.sendCrossChainMessage( + TeleporterMessageInput({ + // Replace with blockchainID of your Subnet (see instructions in Readme) + destinationBlockchainID: 0x6391b85bafc78f1b10aec35695c2399c2fb7fff9f3b18ea903f77345e9e96e3e, // [!code highlight] + destinationAddress: destinationAddress, + feeInfo: TeleporterFeeInfo({feeTokenAddress: address(0), amount: 0}), + requiredGasLimit: 100000, + allowedRelayerAddresses: new address[](0), + message: abi.encode(message) + }) + ); + } +} +``` @@ -123,7 +129,15 @@ To deploy a contract using Foundry use the following command: ```bash forge create --rpc-url local-c --private-key $PK src/0-send-receive/senderOnCChain.sol:SenderOnCChain ``` - +``` +[⠊] Compiling... +[⠒] Compiling 2 files with Solc 0.8.18 +[⠢] Solc 0.8.18 finished in 81.53ms +Compiler run successful! +Deployer: 0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC +Deployed to: 0x5DB9A7629912EBF95876228C24A848de0bfB43A9 // [!code highlight] +Transaction hash: 0xcde7873e9e3c68fb00a2ad6644dceb64a01a41941da46de5a0f559d6d70a1638 +``` @@ -132,7 +146,7 @@ forge create --rpc-url local-c --private-key $PK src/0-send-receive/senderOnCCha Then save the sender contract address in an environment variable: ```bash -export SENDER_ADDRESS="0x123..." +export SENDER_ADDRESS=0x5DB9A7629912EBF95876228C24A848de0bfB43A9 ``` diff --git a/content/course/interchain-messaging/04-icm-basics/05-receiving-a-message.mdx b/content/course/interchain-messaging/04-icm-basics/05-receiving-a-message.mdx index 555c79cb..f8dd5780 100644 --- a/content/course/interchain-messaging/04-icm-basics/05-receiving-a-message.mdx +++ b/content/course/interchain-messaging/04-icm-basics/05-receiving-a-message.mdx @@ -8,7 +8,7 @@ icon: BookOpen To receive a message we need to enable our cross-Subnet dApps to being called by the Interchain Messaging contract. - +![](/course-images/teleporter/teleporter-source-destination-with-relayer.png) The Interchain Messaging does not know our contract and what functions it has. Therefore, our dApp on the destination Subnet has to implement the ITeleporterReceiver interface. It is very straight forward and only requires a single method for receiving the message that then can be called by the Interchain Messaging contract: @@ -36,9 +36,9 @@ interface ITeleporterReceiver { The function receiveTeleporterMessage has three parameters: -- **originChainID**: The chainID where the message originates from, meaning where the user or contract called the sendCrossChainMessage function of the Interchain Messaging contract -- **originSenderAddress**: The address of the user or contract that called the sendCrossChainMessage function of the Interchain Messaging contract on the origin Subnet -- **message**: The message encoded in bytes +- **`originChainID`**: The chainID where the message originates from, meaning where the user or contract called the `sendCrossChainMessage` function of the Interchain Messaging contract +- **`originSenderAddress`**: The address of the user or contract that called the `sendCrossChainMessage` function of the Interchain Messaging contract on the origin Subnet +- **`message`**: The message encoded in bytes An example for a contract being able to receive Interchain Messaging messages and storing these in a mapping could look like this: @@ -88,4 +88,4 @@ contract MessageReceiver is ITeleporterReceiver { } ``` -This contract stores the last message and it's sender of each chain it has received. When it is instantiated, the address of the Interchain Messaging contract is supplied to the constructor. The contract implements the ITelepoterReceiver interface and therefore we also implement the receiveTeleporterMessage function. +This contract stores the last `Message` and it's sender of each chain it has received. When it is instantiated, the address of the Interchain Messaging contract is supplied to the constructor. The contract implements the `ITelepoterReceiver` interface and therefore we also implement the `receiveTeleporterMessage` function. diff --git a/content/course/interchain-messaging/04-icm-basics/06-create-receiver-contract.mdx b/content/course/interchain-messaging/04-icm-basics/06-create-receiver-contract.mdx index 0864f420..17fa1400 100644 --- a/content/course/interchain-messaging/04-icm-basics/06-create-receiver-contract.mdx +++ b/content/course/interchain-messaging/04-icm-basics/06-create-receiver-contract.mdx @@ -7,7 +7,7 @@ icon: Terminal --- import { Step, Steps } from 'fumadocs-ui/components/steps'; -Now it's time to deploy our receiver contract on our Subnet. It will implement the callback for the TeleporterMessenger contract when the message is received, decoding our message and storing the last received string. +Now it's time to deploy our receiver contract to our L1. It will implement the callback for the `TeleporterMessenger` contract when the message is received, decoding our message and storing the last received string. @@ -42,14 +42,12 @@ contract ReceiverOnSubnet is ITeleporterReceiver { } ``` -The key things to understand: - -- **The key things to understand:** -- **Importing Interchain Messaging contracts (L8, L9):** We are importing the ITeleporterMessenger and ITeleporterReceiver interface we looked at in the previous activity. -- **Inheriting from ITeleporterReceiver (L11):** We are inheriting the interface that will require us to implement the receiveTeleporterMessage() function. -- **Defining the lastMessage variable (L14):** Setting the lastMessage variable as public, will make that variable readable from the outside without the need of a getValue function. +**The key things to understand:** +- **Importing Interchain Messaging contracts (L8, L9):** We are importing the `ITeleporterMessenger` and `ITeleporterReceiver` interface we looked at in the previous activity. +- **Inheriting from ITeleporterReceiver (L11):** We are inheriting the interface that will require us to implement the `receiveTeleporterMessage()` function. +- **Defining the lastMessage variable (L14):** Setting the `lastMessage` variable as `public`, will make that variable readable from the outside without the need of a `getValue` function. - **Implementing receiveTeleporterMessage (L16):** We implement the function that will be called when the message is received. Please note that we are not checking who calls that function for now. So anyone can pretend to deliver messages for now. -- **Decode message (L21):** We decode the message using abi.decode(message, (string)), which takes the bytes array as the first input and a tupel of the types of the encoded data in the message. Since our message only contains a single value, the tupel only has one value. +- **Decode message (L21):** We decode the message using `abi.decode(message, (string))`, which takes the bytes array as the first input and a tuple of the types of the encoded data in the message. Since our message only contains a single value, the tuple only has one value. @@ -61,6 +59,15 @@ To deploy a contract using Foundry use the following command: ```bash forge create --rpc-url myblockchain --private-key $PK src/0-send-receive/receiverOnSubnet.sol:ReceiverOnSubnet ``` +``` +[⠊] Compiling... +[⠢] Compiling 2 files with Solc 0.8.18 +[⠆] Solc 0.8.18 finished in 158.51ms +Compiler run successful! +Deployer: 0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC +Deployed to: 0x52C84043CD9c865236f11d9Fc9F56aa003c1f922 // [!code highlight] +Transaction hash: 0x48a1ffaa8aa8011f842147a908ff35a1ebfb75a5a07eb37ae96a4cc8d7feafd7 +``` @@ -70,7 +77,7 @@ forge create --rpc-url myblockchain --private-key $PK src/0-send-receive/receive Then save the receiver contract address in an environment variable: ```bash -export RECEIVER_ADDRESS="0x123..." +export RECEIVER_ADDRESS=0x52C84043CD9c865236f11d9Fc9F56aa003c1f922 ``` diff --git a/content/course/interchain-messaging/04-icm-basics/07-send-a-message.mdx b/content/course/interchain-messaging/04-icm-basics/07-send-a-message.mdx index 9a4ac842..7ea6a1cf 100644 --- a/content/course/interchain-messaging/04-icm-basics/07-send-a-message.mdx +++ b/content/course/interchain-messaging/04-icm-basics/07-send-a-message.mdx @@ -25,7 +25,7 @@ A relayer launched when you deployed the Avalanche L1 will now take the message ### Verify Message was Received -Now let's check if the "Hello" string sent from our C-chain was actually stored properly on the lastMessage variable on our Avalanche L1. Run the following command replacing the receiver contract address. +Now let's check if the "Hello" string sent from our C-chain was actually stored properly on the `lastMessage` variable on our Avalanche L1. Run the following command replacing the receiver contract address. ```bash cast call --rpc-url myblockchain $RECEIVER_ADDRESS "lastMessage()(string)" @@ -37,4 +37,4 @@ If the output says `Hello` then the message was successfully delivered and proce -Congratulations 🎉 You have just sent your first cross-Avalanche L1 message. This will be one of many to come! \ No newline at end of file +Congratulations 🎉 You have just sent your first cross-chain message. This will be one of many to come! \ No newline at end of file diff --git a/content/course/interchain-messaging/04-icm-basics/08-adapting-the-contract-exercise.mdx b/content/course/interchain-messaging/04-icm-basics/08-adapting-the-contract-exercise.mdx index 392b18ad..bd7d7915 100644 --- a/content/course/interchain-messaging/04-icm-basics/08-adapting-the-contract-exercise.mdx +++ b/content/course/interchain-messaging/04-icm-basics/08-adapting-the-contract-exercise.mdx @@ -8,4 +8,4 @@ icon: Terminal To create a deeper understanding of the concepts, now change the provided contracts. Instead of sending a string, now send a number and add up the numbers on the destination chain: -Once you finished with the assignment you can review the correct answer at /src/0b-send-receive in the [Avalanche-Starter-Kit](https://github.com/ava-labs/avalanche-starter-kit) +Once you finished with the assignment you can review the correct answer at `/src/0b-send-receive` in the [Avalanche-Starter-Kit](https://github.com/ava-labs/avalanche-starter-kit) diff --git a/content/course/interchain-messaging/05-two-way-communication/01-two-way-communication.mdx b/content/course/interchain-messaging/05-two-way-communication/01-two-way-communication.mdx index 89158e92..7608333b 100644 --- a/content/course/interchain-messaging/05-two-way-communication/01-two-way-communication.mdx +++ b/content/course/interchain-messaging/05-two-way-communication/01-two-way-communication.mdx @@ -6,7 +6,7 @@ authors: [martineckardt] icon: Book --- -When we send message with Interchain Messaging, we can see check if a message has been delivered, but we do not get any feedback wether the message has been processed correctly or any return value. If we wanted to achieve this, we need to send a message back from the receiver to the original sender. +When we send messages with Interchain Messaging, we can see check if a message has been delivered, but we do not get any feedback wether the message has been processed correctly or any return value. If we wanted to achieve this, we need to send a message back from the receiver to the original sender. ![](/common-images/teleporter/two-way-communication.png) @@ -19,11 +19,11 @@ In this section, you will go through the following topics: - **Adapt the example:** Take what you learned and adapt the example ## Exercises -You will apply your learned knowledge by building your first Cross-Chain application! This application will be deployed on two chains: C-chain and your own Avalanche L1, both running on a Local Network. +You will apply your learned knowledge by building your first Cross-Chain application! This application will be deployed on two chains: C-Chain and your own Avalanche L1, both running on a Local Network. Therefore, you will deploy two contracts: - **Sender on Local C-Chain:** Send a message with a simple string - **Receiver on your Avalanche L1:** Receives the message, adds something to the string and send it back -At the end of the section, you will be adapting the example to build an a cross-Avalanche L1 dApp that send a number to a contract on another Avalanche L1 and receives the result of a mathematical operation. This application is similar to the example above, but will the message will include a number. The receiving contract performs a mathematical operation. \ No newline at end of file +At the end of the section, you will be adapting the example to build a cross-chain Avalanche L1 dApp that send a number to a contract on another Avalanche L1 then receives the result of a mathematical operation. This application is similar to the example above, but the message will include a number. The receiving contract will perform a mathematical operation. \ No newline at end of file diff --git a/content/course/interchain-messaging/05-two-way-communication/03-create-sender-contract.mdx b/content/course/interchain-messaging/05-two-way-communication/03-create-sender-contract.mdx index 91cb8424..9bf6b8a5 100644 --- a/content/course/interchain-messaging/05-two-way-communication/03-create-sender-contract.mdx +++ b/content/course/interchain-messaging/05-two-way-communication/03-create-sender-contract.mdx @@ -15,9 +15,9 @@ Go ahead and deploy the sender contract on the C-Chain. ### Adapt the Sender Contract -Perform the changes described in the previous section. +Perform the changes on `senderOnCChain.sol` described in the [previous section.](/course/interchain-messaging/04-icm-basics/04-create-sender-contract) - + @@ -27,16 +27,24 @@ Perform the changes described in the previous section. ```bash forge create --rpc-url local-c --private-key $PK src/1-send-roundtrip/senderOnCChain.sol:SenderOnCChain ``` - +``` +[⠊] Compiling... +[⠢] Compiling 1 files with Solc 0.8.18 +[⠆] Solc 0.8.18 finished in 165.79ms +Compiler run successful! +Deployer: 0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC +Deployed to: 0xA4cD3b0Eb6E5Ab5d8CE4065BcCD70040ADAB1F00 // [!code highlight] +Transaction hash: 0x4f41cf829fbc525b64d9773c41dc9fabb3b93dfd03bf6c1568dcc4a4c6bdeb1a +``` ### Update the Sender Address -Then overwrite the sender contract address in the environment variable issue the following command with the new address: +Overwrite the `SENDER_ADDRESS` environment variable with the new address: ```bash -export SENDER_ADDRESS="0x123..." +export SENDER_ADDRESS=0xA4cD3b0Eb6E5Ab5d8CE4065BcCD70040ADAB1F00 ``` \ No newline at end of file diff --git a/content/course/interchain-messaging/05-two-way-communication/04-receiver-contract.mdx b/content/course/interchain-messaging/05-two-way-communication/04-receiver-contract.mdx index b54bce5c..17871278 100644 --- a/content/course/interchain-messaging/05-two-way-communication/04-receiver-contract.mdx +++ b/content/course/interchain-messaging/05-two-way-communication/04-receiver-contract.mdx @@ -1,17 +1,17 @@ --- title: Receiver Contract -description: Adapt the receiver contract to also send messages back +description: Adapt the receiver contract to send messages back updated: 2024-05-31 authors: [martineckardt] icon: BookOpen --- -The receiver contract now also has two tasks: +The receiver contract now has two tasks: -- **Receive a message from the sender**: Same as in the last example +- **Receive a message from the sender**: Same as in the [last example](/course/interchain-messaging/04-icm-basics/05-receiving-a-message) - **Send a message back to the sender**: Now our receiver contract needs to be able to send a message back to the sender. -Therefore, we need to change the receiver contract to be able to send a message back. We will need to instantiate a `TeleporterMessenger` and call the the `sendCrossChainMessage()` function. +Therefore, we need to change the receiver contract to be able to send a message back. We will need to instantiate a `TeleporterMessenger` and call the `sendCrossChainMessage()` function. ```solidity title="src/1-send-roundtrip/receiverOnSubnet.sol" // (c) 2023, Ava Labs, Inc. All rights reserved. diff --git a/content/course/interchain-messaging/05-two-way-communication/05-create-the-receiver-contract.mdx b/content/course/interchain-messaging/05-two-way-communication/05-create-the-receiver-contract.mdx index 327a2e48..c64c41f8 100644 --- a/content/course/interchain-messaging/05-two-way-communication/05-create-the-receiver-contract.mdx +++ b/content/course/interchain-messaging/05-two-way-communication/05-create-the-receiver-contract.mdx @@ -13,17 +13,19 @@ Go ahead and deploy the receiver contract: -### Adapt the Sender Contract - -Perform the changes described in the previous section. - - - - ### Deploy the Receiver Contract ```bash -forge create --rpc-url myblockchain --private-key $PK src/0-send-receive/receiverOnSubnet.sol:ReceiverOnSubnet +forge create --rpc-url myblockchain --private-key $PK src/1-send-roundtrip/receiverOnSubnet.sol:ReceiverOnSubnet +``` +``` +[⠊] Compiling... +[⠢] Compiling 1 files with Solc 0.8.18 +[⠆] Solc 0.8.18 finished in 101.71ms +Compiler run successful! +Deployer: 0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC +Deployed to: 0x17aB05351fC94a1a67Bf3f56DdbB941aE6c63E25 // [!code highlight] +Transaction hash: 0x11df9e14bdae4af60a618a900faa955d75e0ce7dd0f2ccc1ea6a764c149ef805 ``` @@ -31,10 +33,9 @@ forge create --rpc-url myblockchain --private-key $PK src/0-send-receive/receive ### Update the Receiver Address -Then save the receiver contract address in an environment variable: - +Update the `RECEIVER_ADDRESS` environment variable with the new address: ```bash -export RECEIVER_ADDRESS="0x123..." +export RECEIVER_ADDRESS=0x17aB05351fC94a1a67Bf3f56DdbB941aE6c63E25 ``` diff --git a/content/course/interchain-messaging/05-two-way-communication/06-send-a-roundtrip-message.mdx b/content/course/interchain-messaging/05-two-way-communication/06-send-a-roundtrip-message.mdx index de6e762d..729c982f 100644 --- a/content/course/interchain-messaging/05-two-way-communication/06-send-a-roundtrip-message.mdx +++ b/content/course/interchain-messaging/05-two-way-communication/06-send-a-roundtrip-message.mdx @@ -27,6 +27,10 @@ To check whether the message has been received, we can call the `roundtripMessag ```bash cast call --rpc-url local-c $SENDER_ADDRESS "roundtripMessage()(string)" ``` +If successful, you should see the following output: +```bash +"Hello World!" +``` @@ -39,5 +43,6 @@ To understand in more detail what happened, check out the relayer logs: avalanche teleporter relayer logs ``` + diff --git a/content/course/interchain-messaging/06-invoking-functions/02-encoding-multiple-values.mdx b/content/course/interchain-messaging/06-invoking-functions/02-encoding-multiple-values.mdx index 32d84cdd..16346e0a 100644 --- a/content/course/interchain-messaging/06-invoking-functions/02-encoding-multiple-values.mdx +++ b/content/course/interchain-messaging/06-invoking-functions/02-encoding-multiple-values.mdx @@ -20,7 +20,7 @@ bytes message = abi.encode( ); ``` -We can see here in how we use the function `abi.encode()` to turn multiple values `(someString, someNumber & someAddress)` of various types `(string, uint & address)` into a single value of the type bytes called `message`. This bytearray can then be sent to the destination chain using the Teleporter. +Here we can see how the function `abi.encode()` is used to turn multiple values `(someString, someNumber & someAddress)` of various types `(string, uint & address)` into a single value of the type bytes called `message`. This bytearray can then be sent to the destination chain using the Teleporter. ```solidity function sendMessage(address destinationAddress) external returns (uint256 messageID) { @@ -81,7 +81,7 @@ function _someFunction(string someString, uint256 someNumber, address someAddres ``` -Here we are using `abi.decode()` to unpack the three values `(someString, someNumber & someAddress)` from the parameter `message` of the type `bytes`. As you can see in here, we do need to provide the message as well as the types of the values encoded in the message in the same order as parameters to `abi.decode()`. +Here we are using `abi.decode()` to unpack the three values `(someString, someNumber & someAddress)` from the parameter `message` of the type `bytes`. As you can see, we need to provide the message as well as the types of values encoded in the message. It is important to note the types must be the same order as parameters to `abi.decode()`. ```solidity ( diff --git a/content/course/interchain-messaging/06-invoking-functions/03-create-simple-calculator-sender.mdx b/content/course/interchain-messaging/06-invoking-functions/03-create-simple-calculator-sender.mdx index cb9503a7..e559c62c 100644 --- a/content/course/interchain-messaging/06-invoking-functions/03-create-simple-calculator-sender.mdx +++ b/content/course/interchain-messaging/06-invoking-functions/03-create-simple-calculator-sender.mdx @@ -8,14 +8,14 @@ icon: Terminal import { Step, Steps } from 'fumadocs-ui/components/steps'; -Now, our goal is to create a dApp that works as a cross-Avalanche L1 Calculator, receiving multiple parameters and using those for a calculation. For now our calculator will only have the Sum function. +Now, our goal is to create a dApp that works as a cross-Avalanche L1 Calculator, receiving multiple parameters and using those for a calculation. For now our calculator will only have the `Sum` function. ### Create Sender Contract -On the Local C-Chain, we need to create the sender part of our cross-chain calculator. This will send two numbers (uint) to the receiver contract on your Avalanche L1. +On the local C-Chain, we need to create the sender part of our cross-chain calculator. This will send two numbers (uint) to the receiver contract on your Avalanche L1. ```solidity title="src/02a-encoding-multiple-paramters/SimpleCalculatorSenderOnCChain.sol" pragma solidity ^0.8.18; @@ -55,7 +55,7 @@ To increase the readability of the code, we have created a helper function `enco ### Replace `destinationBlockchainID` - + @@ -67,16 +67,24 @@ Deploy the sender contract on the Local C-Chain: ```bash forge create --rpc-url local-c --private-key $PK src/2a-invoking-functions/SimpleCalculatorSenderOnCChain.sol:SimpleCalculatorSenderOnCChain ``` - +``` +[⠊] Compiling... +[⠒] Compiling 1 files with Solc 0.8.18 +[⠢] Solc 0.8.18 finished in 84.20ms +Compiler run successful! +Deployer: 0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC +Deployed to: 0x789a5FDac2b37FCD290fb2924382297A6AE65860 // [!code highlight] +Transaction hash: 0xd6cb47dd4ff38e4447711ebbec8b646b93f492f48e80b51719f860984cc25413 +``` ### Save the Sender Contract Address -Then save the sender contract address (displayed in `Deployed To:`) in an environment variable: +Overwrite the `SENDER_ADDRESS` environment variable with the new address: ```bash -export SENDER_ADDRESS=0x123... +export SENDER_ADDRESS=0x789a5FDac2b37FCD290fb2924382297A6AE65860 ``` diff --git a/content/course/interchain-messaging/06-invoking-functions/04-create-simple-calulcator-receiver.mdx b/content/course/interchain-messaging/06-invoking-functions/04-create-simple-calulcator-receiver.mdx index 303db22f..162da17d 100644 --- a/content/course/interchain-messaging/06-invoking-functions/04-create-simple-calulcator-receiver.mdx +++ b/content/course/interchain-messaging/06-invoking-functions/04-create-simple-calulcator-receiver.mdx @@ -15,13 +15,13 @@ On our Avalanche L1, we need to create the receiver part of our cross-chain calc ### Create Receiver Contract -```solidity title="src/02a-encoding-multiple-paramters/SimpleCalculatorReceiverOnAvalanche L1.sol" +```solidity title="src/02a-encoding-multiple-paramters/SimpleCalculatorReceiverOnSubnet.sol" pragma solidity ^0.8.18; import "@teleporter/ITeleporterMessenger.sol"; import "@teleporter/ITeleporterReceiver.sol"; -contract SimpleCalculatorReceiverOnAvalanche L1 is ITeleporterReceiver { +contract SimpleCalculatorReceiverOnSubnet is ITeleporterReceiver { ITeleporterMessenger public immutable teleporterMessenger = ITeleporterMessenger(0x253b2784c75e510dD0fF1da844684a1aC0aa5fcf); @@ -30,7 +30,7 @@ contract SimpleCalculatorReceiverOnAvalanche L1 is ITeleporterReceiver { function receiveTeleporterMessage(bytes32, address, bytes calldata message) external { // Only the Interchain Messaging receiver can deliver a message. require( - msg.sender == address(teleporterMessenger), "CalculatorReceiverOnAvalanche L1: unauthorized TeleporterMessenger" + msg.sender == address(teleporterMessenger), "CalculatorReceiverOnSubnet: unauthorized TeleporterMessenger" ); (uint256 a, uint256 b) = abi.decode(message, (uint256, uint256)); // [!code highlight:2] @@ -52,7 +52,17 @@ contract SimpleCalculatorReceiverOnAvalanche L1 is ITeleporterReceiver { Deploy the receiver contract on your Avalanche L1: ```bash -forge create --rpc-url myblockchain --private-key $PK src/2a-invoking-functions/SimpleCalculatorReceiverOnAvalanche L1.sol:SimpleCalculatorReceiverOnAvalanche L1 +forge create --rpc-url myblockchain --private-key $PK src/2a-invoking-functions/SimpleCalculatorReceiverOnSubnet.sol:SimpleCalculatorReceiverOnSubnet +``` + +``` +[⠊] Compiling... +[⠒] Compiling 1 files with Solc 0.8.18 +[⠢] Solc 0.8.18 finished in 44.12ms +Compiler run successful! +Deployer: 0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC +Deployed to: 0x5aa01B3b5877255cE50cc55e8986a7a5fe29C70e // [!code highlight] +Transaction hash: 0x2d40c53b493556463a28c458e40bc455a248df69a10679bef84145974b7424f3 ``` @@ -60,10 +70,10 @@ forge create --rpc-url myblockchain --private-key $PK src/2a-invoking-functions/ ### Save the Receiver Contract Address -Then save the sender contract address (displayed in `Deployed To:`) in an environment variable: +Overwrite the `RECEIVER_ADDRESS` environment variable with the new address: ```bash -export RECEIVER_ADDRESS=0x123... +export RECEIVER_ADDRESS=0x5aa01B3b5877255cE50cc55e8986a7a5fe29C70e ``` diff --git a/content/course/interchain-messaging/06-invoking-functions/05-call-simple-calculator.mdx b/content/course/interchain-messaging/06-invoking-functions/05-call-simple-calculator.mdx index bd2a38f0..b5ac360f 100644 --- a/content/course/interchain-messaging/06-invoking-functions/05-call-simple-calculator.mdx +++ b/content/course/interchain-messaging/06-invoking-functions/05-call-simple-calculator.mdx @@ -19,18 +19,24 @@ Alright, now let's call our Calculators: cast send --rpc-url local-c --private-key $PK $SENDER_ADDRESS "sendAddMessage(address, uint256, uint256)" $RECEIVER_ADDRESS 2 3 ``` -We need to call the `sendAddMessage` function on the sender contract with the address of the receiver contract and the two numbers we want to add. +We need to call the `sendAddMessage` function on the sender contract with the address of the receiver contract and the two numbers we want to add. + +For this example we will add 2 + 3. ### Verify Message Receipt +To check wether the message has been received, we can call the `result_num()` function on the `Receiver` contract. + ```bash cast call --rpc-url myblockchain $RECEIVER_ADDRESS "result_num()(uint)" ``` -To check wether the message has been received, we can call the `result_num()` function on the `Receiver` contract. - +```bash +5 +``` +2 + 3 = 5. Our cross-chain calculation was successful! diff --git a/content/course/interchain-messaging/06-invoking-functions/06-encoding-function-name.mdx b/content/course/interchain-messaging/06-invoking-functions/06-encoding-function-name.mdx index 0f866c47..f447fb99 100644 --- a/content/course/interchain-messaging/06-invoking-functions/06-encoding-function-name.mdx +++ b/content/course/interchain-messaging/06-invoking-functions/06-encoding-function-name.mdx @@ -55,6 +55,7 @@ contract CalculatorSenderOnCChain { function sendConcatenateMessage(address destinationAddress, string memory text1, string memory text2) external { teleporterMessenger.sendCrossChainMessage( TeleporterMessageInput({ + // Replace with chain id of your Avalanche L1 (see instructions in Readme) destinationBlockchainID: 0x382d2a20c299b03b638dd4d42b96e7401f6c3e88209b764abce83cf71c0c30cd, destinationAddress: destinationAddress, feeInfo: TeleporterFeeInfo({feeTokenAddress: address(0), amount: 0}), @@ -84,14 +85,14 @@ As you can see here we are calling `abi.encode` twice in the encode helpers. The Let's now look at the receiver: -```solidity title="src/2b-invoking-functions/CalculatorReceiverOnAvalanche L1.sol" +```solidity title="src/2b-invoking-functions/CalculatorReceiverOnSubnet.sol" pragma solidity ^0.8.18; import "@teleporter/ITeleporterMessenger.sol"; import "@teleporter/ITeleporterReceiver.sol"; import "./CalculatorActions.sol"; -contract CalculatorReceiverOnAvalanche L1 is ITeleporterReceiver { +contract CalculatorReceiverOnSubnet is ITeleporterReceiver { ITeleporterMessenger public immutable teleporterMessenger = ITeleporterMessenger(0x253b2784c75e510dD0fF1da844684a1aC0aa5fcf); uint256 public result_num; @@ -100,7 +101,7 @@ contract CalculatorReceiverOnAvalanche L1 is ITeleporterReceiver { function receiveTeleporterMessage(bytes32, address, bytes calldata message) external { // Only the Interchain Messaging receiver can deliver a message. require( - msg.sender == address(teleporterMessenger), "CalculatorReceiverOnAvalanche L1: unauthorized TeleporterMessenger" + msg.sender == address(teleporterMessenger), "CalculatorReceiverOnSubnet: unauthorized TeleporterMessenger" ); // Decoding the Action type: // [!code highlight:2] @@ -114,7 +115,7 @@ contract CalculatorReceiverOnAvalanche L1 is ITeleporterReceiver { (string memory text1, string memory text2) = abi.decode(paramsData, (string, string)); _calculatorConcatenateStrings(text1, text2); } else { - revert("CalculatorReceiverOnAvalanche L1: invalid action"); + revert("CalculatorReceiverOnSubnet: invalid action"); } } @@ -160,7 +161,7 @@ if (actionType == CalculatorAction.add) { (string memory text1, string memory text2) = abi.decode(paramsData, (string, string)); // [!code highlight] _calculatorConcatenateStrings(text1, text2); } else { - revert("CalculatorReceiverOnAvalanche L1: invalid action"); + revert("CalculatorReceiverOnSubnet: invalid action"); } ``` @@ -175,9 +176,20 @@ Deploy the sender and receiver contracts and try out the `add` and `concatenate` ### Deploy the Sender Contract + + ```bash forge create --rpc-url local-c --private-key $PK src/2b-invoking-functions/CalculatorSenderOnCChain.sol:CalculatorSenderOnCChain ``` +``` +[⠃] Compiling... +[⠆] Compiling 2 files with Solc 0.8.18 +[⠰] Solc 0.8.18 finished in 240.23ms +Compiler run successful! +Deployer: 0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC +Deployed to: 0x8B3BC4270BE2abbB25BC04717830bd1Cc493a461 // [!code highlight] +Transaction hash: 0xf9cce28a714764bb265bba7522bfd10d620fa0cb0f5dae26de2ac773b0a878ee +``` @@ -185,7 +197,7 @@ forge create --rpc-url local-c --private-key $PK src/2b-invoking-functions/Calcu ### Save the Sender Address: ```bash -export SENDER_ADDRESS=0x123... +export SENDER_ADDRESS=0x8B3BC4270BE2abbB25BC04717830bd1Cc493a461 ``` @@ -194,16 +206,24 @@ export SENDER_ADDRESS=0x123... ### Deploy the Receiver Contract: ```bash -forge create --rpc-url myblockchain --private-key $PK src/2b-invoking-functions/CalculatorReceiverOnAvalanche L1.sol:CalculatorReceiverOnAvalanche L1 +forge create --rpc-url myblockchain --private-key $PK src/2b-invoking-functions/CalculatorReceiverOnSubnet.sol:CalculatorReceiverOnSubnet +``` +``` +[⠊] Compiling... +[⠢] Compiling 1 files with Solc 0.8.18 +[⠆] Solc 0.8.18 finished in 148.40ms +Compiler run successful! +Deployer: 0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC +Deployed to: 0x5DB9A7629912EBF95876228C24A848de0bfB43A9 // [!code highlight] +Transaction hash: 0xa8efb88abfef486d2caba30cb4146b1dc56a0ee88c7fb4c46adccdf1414ae39e ``` - ### Save the Receiver address: ```bash -export RECEIVER_ADDRESS=0x123... +export RECEIVER_ADDRESS=0x5DB9A7629912EBF95876228C24A848de0bfB43A9 ``` @@ -214,7 +234,7 @@ export RECEIVER_ADDRESS=0x123... Now you can call the `sendAddMessage` and `sendConcatenateMessage` functions on the sender contract and see the results on the receiver contract. ```bash -cast send --rpc-url local-c --private-key $PK $SENDER_ADDRESS "sendAddMessage(uint, uint)" 1 2 +cast send --rpc-url local-c --private-key $PK $SENDER_ADDRESS "sendAddMessage(address, uint, uint)" $RECEIVER_ADDRESS 1 2 ``` diff --git a/content/course/interchain-messaging/06-invoking-functions/07-extend-calculator.mdx b/content/course/interchain-messaging/06-invoking-functions/07-extend-calculator.mdx index 8cb2eb90..72ae754e 100644 --- a/content/course/interchain-messaging/06-invoking-functions/07-extend-calculator.mdx +++ b/content/course/interchain-messaging/06-invoking-functions/07-extend-calculator.mdx @@ -6,12 +6,12 @@ authors: [martineckardt] icon: Terminal --- -Now let's add a third feature to the calculator: adding three numbers. We want you to practice handling different amounts of parameters depending on the action to perform, so your task will be to add a tripleSum function that sums up three values of the type uint. +Now let's add a third feature to the calculator: adding three numbers. We want you to practice handling different amounts of parameters depending on the action to perform, so your task will be to add a `tripleSum` function that sums up three values of the type uint. You will need to: -- Add the trippleSum action to the enum file +- Add the `trippleSum` action to the enum file - Add a new encode helper and send function to the sender contract -- Add a new route to the receiver and implement the tripleSum function +- Add a new route to the receiver and implement the `tripleSum` function Check out the solution under `/src/2c-invoking-functions` on the Avalanche-Starter-Kit diff --git a/content/course/interchain-messaging/07-icm-registry/02-how-the-icm-registry-works.mdx b/content/course/interchain-messaging/07-icm-registry/02-how-the-icm-registry-works.mdx index bbf9a554..b5b71d1e 100644 --- a/content/course/interchain-messaging/07-icm-registry/02-how-the-icm-registry-works.mdx +++ b/content/course/interchain-messaging/07-icm-registry/02-how-the-icm-registry-works.mdx @@ -31,7 +31,7 @@ contract TeleporterRegistry { // ... } ``` -In the TeleporterRegistry contract, the latestVersion state variable returns the highest version number that has been registered in the registry. The getLatestTeleporter function returns the ITeleporterMessenger that is registered with the corresponding version. Version zero is an invalid version, and is used to indicate that a TeleporterMessenger contract has not been registered yet. +In the `TeleporterRegistry` contract, the `latestVersion` state variable returns the highest version number that has been registered in the registry. The `getLatestTeleporter` function returns the `ITeleporterMessenger` that is registered with the corresponding version. Version zero is an invalid version, and is used to indicate that a `TeleporterMessenger` contract has not been registered yet. ```solidity title="/lib/teleporter/contracts/src/Teleporter/upgrades/TeleporterRegistry.sol" contract TeleporterRegistry { @@ -58,7 +58,7 @@ contract TeleporterRegistry { } ``` -If a cross-Avalanche L1 dApps prefers a specific version, it can also call directly the getAddressFromVersion function: +If a cross-Avalanche L1 dApps prefers a specific version, it can also call directly the `getAddressFromVersion` function: ```solidity title="/lib/teleporter/contracts/src/Teleporter/upgrades/TeleporterRegistry.sol" contract TeleporterRegistry { diff --git a/content/course/interchain-messaging/07-icm-registry/03-interact-with-the-registry.mdx b/content/course/interchain-messaging/07-icm-registry/03-interact-with-the-registry.mdx index 162c4f56..86f425f4 100644 --- a/content/course/interchain-messaging/07-icm-registry/03-interact-with-the-registry.mdx +++ b/content/course/interchain-messaging/07-icm-registry/03-interact-with-the-registry.mdx @@ -19,6 +19,40 @@ Let's start by interacting with the registry. Registry is deployed on specific a avalanche primary describe ``` +``` + _____ _____ _ _ _____ + / ____| / ____| | (_) | __ \ + | | ______| | | |__ __ _ _ _ __ | |__) |_ _ _ __ __ _ _ __ ___ ___ + | | |______| | | '_ \ / _ | | '_ \ | ___/ _ | '__/ _ | '_ _ \/ __| + | |____ | |____| | | | (_| | | | | | | | | (_| | | | (_| | | | | | \__ \ + \_____| \_____|_| |_|\__,_|_|_| |_| |_| \__,_|_| \__,_|_| |_| |_|___/ ++------------------------------+--------------------------------------------------------------------------+ +| PARAMETER | VALUE | ++------------------------------+--------------------------------------------------------------------------+ +| RPC URL | http://127.0.0.1:9650/ext/bc/C/rpc | ++------------------------------+--------------------------------------------------------------------------+ +| Codespace RPC URL | https://opulent-giggle-rxwwq774w553wq7p-9650.app.github.dev/ext/bc/C/rpc | ++------------------------------+--------------------------------------------------------------------------+ +| EVM Chain ID | 43112 | ++------------------------------+--------------------------------------------------------------------------+ +| TOKEN SYMBOL | AVAX | ++------------------------------+--------------------------------------------------------------------------+ +| Address | 0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC | ++------------------------------+--------------------------------------------------------------------------+ +| Balance | 49999478.838561118 | ++------------------------------+--------------------------------------------------------------------------+ +| Private Key | 56289e99c94b6912bfc12adc093c9b51124f0dc54ac7a766b2bc5ccf558d8027 | ++------------------------------+--------------------------------------------------------------------------+ +| BlockchainID (CB58) | NeA134STyTVwife7gYeNQ6Hwi5GPGC2X7aUFvWsnusnpM2do6 | ++------------------------------+--------------------------------------------------------------------------+ +| BlockchainID (HEX) | 0x31233cae135e3974afa396e90f465aa28027de5f97f729238c310d2ed2f71902 | ++------------------------------+--------------------------------------------------------------------------+ +| Teleporter Messenger Address | 0x253b2784c75e510dD0fF1da844684a1aC0aa5fcf | ++------------------------------+--------------------------------------------------------------------------+ +| Teleporter Registry Address | 0x17aB05351fC94a1a67Bf3f56DdbB941aE6c63E25 | // [!code highlight] ++------------------------------+--------------------------------------------------------------------------+ +``` + @@ -27,7 +61,7 @@ avalanche primary describe Let's put the address of the registry in an environment variable: ```bash -export C_CHAIN_REGISTRY_ADDRESS=0x1234... +export C_CHAIN_REGISTRY_ADDRESS=0x17aB05351fC94a1a67Bf3f56DdbB941aE6c63E25 ``` @@ -36,16 +70,24 @@ export C_CHAIN_REGISTRY_ADDRESS=0x1234... ### Get L1 Registry Address ```bash -avalanche subnet describe myblockchain +avalanche blockchain describe myblockchain +``` +``` ++-------------------------------------------------------------------------------------------+ +| TELEPORTER | ++---------------+------------------------------+--------------------------------------------+ +| Local Network | Teleporter Messenger Address | 0x253b2784c75e510dD0fF1da844684a1aC0aa5fcf | +| +------------------------------+--------------------------------------------+ +| | Teleporter Registry Address | 0x98F9971D3832B94241A2FbBC39712d6e13D8Df99 | // [!code highlight] ++---------------+------------------------------+--------------------------------------------+ ``` - ### Save L1 Registry Address ```bash -export MYBLOCKCHAIN_REGISTRY_ADDRESS=0x5678... +export MYBLOCKCHAIN_REGISTRY_ADDRESS=0x98F9971D3832B94241A2FbBC39712d6e13D8Df99 ``` diff --git a/content/course/interchain-messaging/07-icm-registry/04-retrieving-icm-from-registry.mdx b/content/course/interchain-messaging/07-icm-registry/04-retrieving-icm-from-registry.mdx index 88484838..d16e6fe5 100644 --- a/content/course/interchain-messaging/07-icm-registry/04-retrieving-icm-from-registry.mdx +++ b/content/course/interchain-messaging/07-icm-registry/04-retrieving-icm-from-registry.mdx @@ -6,7 +6,7 @@ authors: [martineckardt] icon: BookOpen --- -Alright, so let's now integrate the registry into a smart contract. Let's go back to the very simple string sending contract from the beginning: +Let's now integrate the registry into a smart contract. Let's go back to the very simple string sending contract from the beginning: ```solidity title="src/3-registry/SenderOnCChainWithRegistry.sol" pragma solidity ^0.8.18; @@ -39,10 +39,10 @@ contract SenderOnCChain { } ``` - + The key things to understand: -- We are also importing the ITeleporterRegistry.sol +- We are importing the `ITeleporterRegistry.sol` interface - We have a variable for the registry address instead of the messenger address - Before sending the message we get the latest version from the registry diff --git a/content/course/interchain-messaging/08-securing-cross-chain-communication/01-securing-cross-chain-communication.mdx b/content/course/interchain-messaging/08-securing-cross-chain-communication/01-securing-cross-chain-communication.mdx index a2bd77cb..3290e1d7 100644 --- a/content/course/interchain-messaging/08-securing-cross-chain-communication/01-securing-cross-chain-communication.mdx +++ b/content/course/interchain-messaging/08-securing-cross-chain-communication/01-securing-cross-chain-communication.mdx @@ -1,6 +1,6 @@ --- title: Securing Cross-Chain Communication -description: TBD +description: Learn about Avalanche Warp Messaging and how it ensures secure communication between blockchains. updated: 2024-05-31 authors: [martineckardt] icon: Book diff --git a/content/course/interchain-messaging/08-securing-cross-chain-communication/02-signature-schemes.mdx b/content/course/interchain-messaging/08-securing-cross-chain-communication/02-signature-schemes.mdx index 045a6b97..30a571d2 100644 --- a/content/course/interchain-messaging/08-securing-cross-chain-communication/02-signature-schemes.mdx +++ b/content/course/interchain-messaging/08-securing-cross-chain-communication/02-signature-schemes.mdx @@ -1,6 +1,6 @@ --- title: Signature Schemes -description: TBD +description: Learn how BLS Signature Schemes work and how they can be used to secure cross-chain communication. updated: 2024-05-31 authors: [martineckardt] icon: BookOpen diff --git a/content/course/interchain-messaging/08-securing-cross-chain-communication/04-multi-signature-schemes.mdx b/content/course/interchain-messaging/08-securing-cross-chain-communication/04-multi-signature-schemes.mdx index 29a188bc..b5aa4f18 100644 --- a/content/course/interchain-messaging/08-securing-cross-chain-communication/04-multi-signature-schemes.mdx +++ b/content/course/interchain-messaging/08-securing-cross-chain-communication/04-multi-signature-schemes.mdx @@ -1,6 +1,6 @@ --- title: Multi-Signature Schemes -description: TBD +description: Learn how multiple signatures can help secure cross-chain communication. updated: 2024-05-31 authors: [martineckardt] icon: BookOpen diff --git a/content/course/interchain-messaging/08-securing-cross-chain-communication/05-signature-aggregation.mdx b/content/course/interchain-messaging/08-securing-cross-chain-communication/05-signature-aggregation.mdx index 3829837c..9e057ff1 100644 --- a/content/course/interchain-messaging/08-securing-cross-chain-communication/05-signature-aggregation.mdx +++ b/content/course/interchain-messaging/08-securing-cross-chain-communication/05-signature-aggregation.mdx @@ -1,6 +1,6 @@ --- title: Signature & Key Aggregation -description: TBD +description: Learn about signature and key aggregation and how it can be used to secure cross-chain communication. updated: 2024-05-31 authors: [martineckardt] icon: BookOpen diff --git a/content/course/interchain-messaging/08-securing-cross-chain-communication/07-trusted-third-parties.mdx b/content/course/interchain-messaging/08-securing-cross-chain-communication/07-trusted-third-parties.mdx index c028b91f..a8772cd8 100644 --- a/content/course/interchain-messaging/08-securing-cross-chain-communication/07-trusted-third-parties.mdx +++ b/content/course/interchain-messaging/08-securing-cross-chain-communication/07-trusted-third-parties.mdx @@ -1,6 +1,6 @@ --- title: Trusted Third Parties -description: TBD +description: Learn about the challenges of cross-chain communication. updated: 2024-05-31 authors: [martineckardt] icon: BookOpen diff --git a/content/course/interchain-messaging/09-avalanche-warp-messaging/04-awm-relayer.mdx b/content/course/interchain-messaging/09-avalanche-warp-messaging/04-awm-relayer.mdx index e4db1bc2..3c5c602b 100644 --- a/content/course/interchain-messaging/09-avalanche-warp-messaging/04-awm-relayer.mdx +++ b/content/course/interchain-messaging/09-avalanche-warp-messaging/04-awm-relayer.mdx @@ -6,7 +6,9 @@ authors: [martineckardt] icon: BookOpen --- -The AWM Relayer is an application run independently of the blockchain clients. Anyone can run their own AWM Relayer to create a communication channel between two Avalanche L1s, and there can be multiple relayers for the same communication channel. There is an open source implementation anyone can use [here](https://github.com/ava-labs/awm-relayer). Soon, AvaCloud will offer hosted relayers. +The AWM Relayer is an application run independently of the blockchain clients. Anyone can run their own AWM Relayer to create a communication channel between two Avalanche L1s, and there can be multiple relayers for the same communication channel. There is an open source implementation anyone can use [here](https://github.com/ava-labs/awm-relayer). + +[AvaCloud](https://www.avacloud.io) also offers their own hosted relayers. ![AWM Relayer data flow](/course-images/teleporter/teleporter-source-destination-with-relayer.png) diff --git a/content/course/interchain-messaging/09-avalanche-warp-messaging/07-message-delivery.mdx b/content/course/interchain-messaging/09-avalanche-warp-messaging/07-message-delivery.mdx index c0b57f23..52524e63 100644 --- a/content/course/interchain-messaging/09-avalanche-warp-messaging/07-message-delivery.mdx +++ b/content/course/interchain-messaging/09-avalanche-warp-messaging/07-message-delivery.mdx @@ -20,7 +20,7 @@ When the validators verify the transaction, they perform the following steps: ### Query the P-Chain: -The verifying validators of the destination L1 each query the validator set of the source Avalanche L1 with its stake weights and BLS Public Keys +The verifying validators of the destination L1 each query the validator set of the source Avalanche L1 with its stake weights and BLS Public Keys. diff --git a/content/course/interchain-messaging/09-avalanche-warp-messaging/09-trust-assumption-of-awm.mdx b/content/course/interchain-messaging/09-avalanche-warp-messaging/09-trust-assumption-of-awm.mdx index 95ccbaac..9a1ff1b5 100644 --- a/content/course/interchain-messaging/09-avalanche-warp-messaging/09-trust-assumption-of-awm.mdx +++ b/content/course/interchain-messaging/09-avalanche-warp-messaging/09-trust-assumption-of-awm.mdx @@ -6,8 +6,8 @@ authors: [martineckardt] icon: BookOpen --- -Avalanche Warp Messaging uses a trick: The trusted third party is the validator set of the source Subnet. We are already trusting them, or else we wouldn't communicate with that Subnet. +Avalanche Warp Messaging uses a trick: The trusted third party is the validator set of the source L1. We are already trusting them, or else we wouldn't communicate with that L1. -The only thing that needs to be ensured is that there is always an AWM Relayer doing the signature aggregation and delivery of the warp message. Since it will have to pay gas on the destination chain, the sender needs to make sure it has enough incentives to do so. Either those incentives come from the sender itself, or from the receiving Subnet if it has an inherent interest to onboard users to its chain. You will learn how users can incentivize AWM Relayers with ERC20 tokens with Interchain Messaging in following chapters. +The only thing that needs to be ensured is that there is always an AWM Relayer doing the signature aggregation and delivery of the warp message. Since it will have to pay gas on the destination chain, the sender needs to make sure it has enough incentives to do so. Either those incentives come from the sender itself, or from the receiving L1 if it has an inherent interest to onboard users to its chain. You will learn how users can incentivize AWM Relayers with ERC20 tokens with Interchain Messaging in following chapters. Generally, if there were no relayer available, anyone could run a AWM Relayer and deliver their own messages. \ No newline at end of file diff --git a/content/course/interchain-messaging/10-running-a-relayer/01-running-a-relayer.mdx b/content/course/interchain-messaging/10-running-a-relayer/01-running-a-relayer.mdx index 35cb1207..09ab3370 100644 --- a/content/course/interchain-messaging/10-running-a-relayer/01-running-a-relayer.mdx +++ b/content/course/interchain-messaging/10-running-a-relayer/01-running-a-relayer.mdx @@ -6,11 +6,11 @@ authors: [martineckardt] icon: Book --- -As you know now Interchain Messaging requires a running relayer to deliver the warp messages underlying it. So far we just assumed a relayer is running and in fact Avalanche CLI automatically configures and runs a relayer for you if you deploy your Subnet on a local network. However, in a production environment, you will either need to run a relayer yourself or have someone else run it for you. +As you now know Interchain Messaging requires a running relayer to deliver the warp messages underlying it. So far we just assumed a relayer is running and in fact Avalanche CLI automatically configures and runs a relayer for you if you deploy your L1 on a local network. However, in a production environment, you will either need to run a relayer yourself or have someone else run it for you. ![AWM Relayer data flow](/course-images/teleporter/teleporter-source-destination-with-relayer.png) -In this section you will learn how to run a relayer for Avalanche Warp Messaging. As discussed in the section on AWM, the relayer is responsible for checking for outgoing warp messages on the source Subnet, aggregate the signatures and deliver it with a transaction on the destination Subnet. +In this section you will learn how to run a relayer for Avalanche Warp Messaging. As discussed in the section on AWM, the relayer is responsible for checking for outgoing warp messages on the source L1, aggregate the signatures and deliver it with a transaction on the destination L1. This chapter utilizes the reference relayer implementation created by Ava Labs. In this case the relayer is a standalone application written in Go. There may be different implementations in the future that are adapted to special use cases. Anyone can build and run a relayer. @@ -22,5 +22,5 @@ In this section, you will go through the following topics: - **Relayer Config:** Here, you will understand how to configure the relayer by creating a relayer config file. This file serves as a blueprint for the relayer's functionality and behavior. - **Wallet:** Create a wallet for the relayer, fund it with testnet tokens and add the wallet parameter to the relayer config. - **Run the Relayer:** Now you will execute the AWM Relayer with your configuration -- **Send Message:** Next you will issue a transaction triggering a cross-Subnet message, so we can observe how the message is delivered by the relayer. +- **Send Message:** Next you will issue a transaction triggering a cross-Avalanche L1 message, so we can observe how the message is delivered by the relayer. - **Verify Message Delivery:** You will learn how you can track the message delivery \ No newline at end of file diff --git a/content/course/interchain-messaging/10-running-a-relayer/02-control-the-avalanche-cli-relayer.mdx b/content/course/interchain-messaging/10-running-a-relayer/02-control-the-avalanche-cli-relayer.mdx index fbc9064b..17edf789 100644 --- a/content/course/interchain-messaging/10-running-a-relayer/02-control-the-avalanche-cli-relayer.mdx +++ b/content/course/interchain-messaging/10-running-a-relayer/02-control-the-avalanche-cli-relayer.mdx @@ -13,7 +13,7 @@ When you deploy your own chain using Avalanche CLI in the Avalanche Starter-kit If you want to stop the relayer, you can use the following command: ```bash -avalanche Interchain Messaging relayer stop +avalanche teleporter relayer stop ``` ## Starting the Relayer @@ -21,5 +21,5 @@ avalanche Interchain Messaging relayer stop If you want to start the relayer, you can use the following command: ```bash -avalanche Interchain Messaging relayer start +avalanche teleporter relayer start ``` \ No newline at end of file diff --git a/content/course/interchain-messaging/10-running-a-relayer/03-install-relayer.mdx b/content/course/interchain-messaging/10-running-a-relayer/03-install-relayer.mdx index dc1a0c0d..478815e3 100644 --- a/content/course/interchain-messaging/10-running-a-relayer/03-install-relayer.mdx +++ b/content/course/interchain-messaging/10-running-a-relayer/03-install-relayer.mdx @@ -15,5 +15,5 @@ The binary for the Avalanche Warp Messaging (AWM) relayer can be acquired in mul When using the [Avalanche Starter Kit](https://github.com/ava-labs/avalanche-starter-kit) the relayer is already included in the Dev Container. You can start the relayer by running the following command: ```bash -avalanche Interchain Messaging relayer start +avalanche teleporter relayer start ``` \ No newline at end of file diff --git a/content/course/interchain-messaging/10-running-a-relayer/04-relayer-configuration.mdx b/content/course/interchain-messaging/10-running-a-relayer/04-relayer-configuration.mdx index 0befe6dc..55905632 100644 --- a/content/course/interchain-messaging/10-running-a-relayer/04-relayer-configuration.mdx +++ b/content/course/interchain-messaging/10-running-a-relayer/04-relayer-configuration.mdx @@ -6,8 +6,8 @@ authors: [martineckardt] icon: BookOpen --- -A relayer is configured to relayer messages between certain source and destination Subnets. Therefore, the configuration consists of three parts: -- **General Config:** Configuration independent of the source and destination Subnets concerning the network as a whole +A relayer is configured to relayer messages between certain source and destination L1s. Therefore, the configuration consists of three parts: +- **General Config:** Configuration independent of the source and destination L1s concerning the network as a whole - **Source Blockchain Configs:** All parameters necessary for the relayer to pick up the messages - **Destination Blockchain Configs:** All parameters necessary to deliver the messages @@ -87,30 +87,30 @@ Next is the configuration for our source blockchain. This is the configuration o } ``` -- **subnet-id:** The Subnet ID of the Subnet that the source blockchain is part of. In this example this is the Subnet ID of the Primary Network. +- **subnet-id:** The Blockchain ID of the L1 that the source blockchain is part of. In this example this is the Blockchain ID of the Primary Network. - **blockchain-id:** The blockchain ID of the source. In this example this is the blockchain ID of Fuji's C-Chain. -- **vm:** A string specifying the virtual machine of the destination Subnet's blockchain. Currently, only the EVM is supported, but this field has been added in anticipation of communication between blockchains powered by different virtual machines in the future. +- **vm:** A string specifying the virtual machine of the destination L1's blockchain. Currently, only the EVM is supported, but this field has been added in anticipation of communication between blockchains powered by different virtual machines in the future. - **rpc-endpoint:** An API Config containing:
-- **base-url:** RPC endpoint of the destination subnet's API node. +- **base-url:** RPC endpoint of the destination L1's API node. - **query-parameters:** Additional query parameters to include in the API requests - **http-headers:** Additional HTTP headers to include in the API requests
- **wss-endpoint:** An API Config containing:
-- **base-url**: The WebSocket endpoint of the source subnet's API node +- **base-url**: The WebSocket endpoint of the source L1's API node - **query-parameters:** Additional query parameters to include in the API requests - **http-headers:** Additional HTTP headers to include in the API requests
- **message-contracts:** A map of contract addresses to the config options of the protocol (e.g. Teleporter) at that address. Each MessageProtocolConfig consists of a unique message-format name, and the raw JSON settings. "0x253b2784c75e510dD0fF1da844684a1aC0aa5fcf" is the address of the TeleporterMessenger on the Fuji C-Chain.
- **message-format:** should be set to Teleporter. Additional message formats next to Interchain Messaging may be developed in the future -- **settings > reward-address:** The address that will be rewarded if a Subnet is incentivizing relayers to send messages on it's behalf. This is the address of the wallet you will create for this relayer. +- **settings > reward-address:** The address that will be rewarded if a L1 is incentivizing relayers to send messages on it's behalf. This is the address of the wallet you will create for this relayer.
## Destination Blockchains -Next is the configuration for our source blockchain. This is the configuration of the blockchain where messages will be initiated and picked up. The relayer will aggregate the signatures of the validators of that Subnet. +Next is the configuration for our source blockchain. This is the configuration of the blockchain where messages will be initiated and picked up. The relayer will aggregate the signatures of the validators of that L1. ```json { "destination-blockchains": [ @@ -131,15 +131,15 @@ Next is the configuration for our source blockchain. This is the configuration o } ``` -For each destination Subnet, the relayer has the following config parameter: +For each destination L1, the relayer has the following config parameter: -- **subnet-id:** The ID of the Subnet that the destination blockchain is part of. -- **blockchain-id:** The blockchain ID of the destination blockchain. This is the Blockchain ID of Fuji's Dispatch Subnet. -- **vm:** A string specifying the virtual machine of the destination Subnet's blockchain. Currently, only the EVM is supported, but this field has been added in anticipation of communication between blockchains powered by different virtual machines in the future. -- **rpc-endpoint:** The RPC endpoint of the destination subnet's API node. Used in favor of api-node-host, api-node-port, and encrypt-connection when constructing the endpoint. +- **subnet-id:** The ID of the L1 that the destination blockchain is part of. +- **blockchain-id:** The blockchain ID of the destination blockchain. This is the Blockchain ID of Fuji's Dispatch L1. +- **vm:** A string specifying the virtual machine of the destination L1's blockchain. Currently, only the EVM is supported, but this field has been added in anticipation of communication between blockchains powered by different virtual machines in the future. +- **rpc-endpoint:** The RPC endpoint of the destination L1's API node. Used in favor of api-node-host, api-node-port, and encrypt-connection when constructing the endpoint. - **kms-key-id:** The ID of the KMS key to use for signing transactions on the destination blockchain. Only one of account-private-key or kms-key-id should be provided. If kms-key-id is provided, then kms-aws-region is required. Please note that the private key in KMS should be exclusive to the relayer. - **kms-aws-region:** The AWS region in which the KMS key is located. Required if kms-key-id is provided. -- **account-private-key:** A private key for a wallet that holds gas tokens on the destination Subnet. This is required so the relayer can sign the transaction that delivers the warp message. +- **account-private-key:** A private key for a wallet that holds gas tokens on the destination L1. This is required so the relayer can sign the transaction that delivers the warp message. If you have been following all the course up to this point with the Avalanche-starter-kit and Avalanche-CLI will provide you with a relayer already funded to perform transactions between the local C-chain and your own chain diff --git a/content/course/interchain-messaging/10-running-a-relayer/05-analyze-relayer-logs.mdx b/content/course/interchain-messaging/10-running-a-relayer/05-analyze-relayer-logs.mdx index 734c301d..ac25f479 100644 --- a/content/course/interchain-messaging/10-running-a-relayer/05-analyze-relayer-logs.mdx +++ b/content/course/interchain-messaging/10-running-a-relayer/05-analyze-relayer-logs.mdx @@ -9,7 +9,7 @@ icon: BookOpen To analyze the relayer activity you can check the relayer logs. If you're using the Avalanche CLI, you can access them with the following command: ```bash -avalanche Interchain Messaging relayer logs +avalanche teleporter relayer logs ``` Alternatively the JSON logs can be located under "~/.avalanche-cli/runs/awm-relayer.log". Let's take a look at them: diff --git a/content/course/interchain-messaging/11-restricting-the-relayer/01-restricting-the-relayer.mdx b/content/course/interchain-messaging/11-restricting-the-relayer/01-restricting-the-relayer.mdx index ba50b6cd..d8410098 100644 --- a/content/course/interchain-messaging/11-restricting-the-relayer/01-restricting-the-relayer.mdx +++ b/content/course/interchain-messaging/11-restricting-the-relayer/01-restricting-the-relayer.mdx @@ -6,7 +6,7 @@ authors: [martineckardt] icon: Book --- -In this segment, we'll delve into the mechanisms of restricting relayers for transmitting messages across Subnets. While the security in AWM and Interchain Messaging doesn't rely at all on the Relayer, there might be some reasons why you would want to restrict the delivery of the message to certain Relayers. +In this segment, we'll delve into the mechanisms of restricting relayers for transmitting messages across Avalanche L1s. While the security in AWM and Interchain Messaging doesn't rely at all on the Relayer, there might be some reasons why you would want to restrict the delivery of the message to certain Relayers. The more obvious one is when you run your own Relayer, and don't want to incentivize any other to ensure your message gets to the destination. On following sections you will learn how to run your own Relayer so you can restrict the messages to your own. @@ -14,5 +14,5 @@ The more obvious one is when you run your own Relayer, and don't want to incenti In this section, you will go through the following topics: -- **Allowed Relayers:** Learn how to restrict the relayer for transmitting messages across Subnets +- **Allowed Relayers:** Learn how to restrict the relayer for transmitting messages across Avalanche L1s - **Dynamically update the allowed Relayers:** Understand how to update the allowed relayers dynamically \ No newline at end of file diff --git a/content/course/interchain-messaging/11-restricting-the-relayer/02-allowed-relayers.mdx b/content/course/interchain-messaging/11-restricting-the-relayer/02-allowed-relayers.mdx index c22b0195..cee333c3 100644 --- a/content/course/interchain-messaging/11-restricting-the-relayer/02-allowed-relayers.mdx +++ b/content/course/interchain-messaging/11-restricting-the-relayer/02-allowed-relayers.mdx @@ -6,11 +6,11 @@ authors: [martineckardt] icon: BookOpen --- -In this segment, we'll delve into the mechanisms of restricting relayers for transmitting messages across Subnets. While the security in AWM and Interchain Messaging doesn't rely at all on the Relayer, there might be some reasons why you would want to restrict the delivery of the message to certain Relayers. +In this segment, we'll delve into the mechanisms of restricting relayers for transmitting messages across Avalanche L1s. While the security in AWM and Interchain Messaging doesn't rely at all on the Relayer, there might be some reasons why you would want to restrict the delivery of the message to certain Relayers. The more obvious one is when you run your own Relayer, and don't want to incentivize any other to ensure your message gets to the destination. On following sections you will learn how to run your own Relayer so you can restrict the messages to your own. -Let's look at the TeleporterMessageInput structure included when we call the sendCrossChainMessage one more time. +Let's look at the `TeleporterMessageInput` structure included when we call the `sendCrossChainMessage` one more time. ```solidity struct TeleporterMessageInput { @@ -29,7 +29,7 @@ interface ITeleporterMessenger { } ``` -As you can see the `TeleporterMessageInput` allows you to specify an array of addresses for the allowed relayers. Previously we have set that do an empty array, which means that any relayer can pick up the message. +As you can see the `TeleporterMessageInput` allows you to specify an array of addresses for the allowed relayers. Previously we have set that to an empty array, which means that any relayer can pick up the message. ```solidity messenger.sendCrossChainMessage( diff --git a/content/course/interchain-messaging/12-incentivizing-a-relayer/01-incentivizing-a-relayer.mdx b/content/course/interchain-messaging/12-incentivizing-a-relayer/01-incentivizing-a-relayer.mdx index d574d29c..90258111 100644 --- a/content/course/interchain-messaging/12-incentivizing-a-relayer/01-incentivizing-a-relayer.mdx +++ b/content/course/interchain-messaging/12-incentivizing-a-relayer/01-incentivizing-a-relayer.mdx @@ -18,4 +18,4 @@ Relayer fees are an optional way to incentivize relayers to deliver a Interchain ## Excersises -In this section you will apply the learned knowledge by calculating and adding fees to our basic send-receive contracts used in the Interchain Messaging Basics chapter. \ No newline at end of file +In this section you will apply the learned knowledge by calculating and adding fees to our basic send-receive contracts used in the [Interchain Messaging Basics chapter](/course/interchain-messaging/04-icm-basics/01-icm-basics). \ No newline at end of file diff --git a/content/course/interchain-messaging/12-incentivizing-a-relayer/02-fee-data-flow.mdx b/content/course/interchain-messaging/12-incentivizing-a-relayer/02-fee-data-flow.mdx index 37afeaf3..fa0477d4 100644 --- a/content/course/interchain-messaging/12-incentivizing-a-relayer/02-fee-data-flow.mdx +++ b/content/course/interchain-messaging/12-incentivizing-a-relayer/02-fee-data-flow.mdx @@ -16,8 +16,11 @@ We are using the following emoji guide to show the actors of each action: **👩 User** + **📜 Cross-Chain dApp** + **👾 TeleporterMessenger** + **🛸 Relayer** ### Previous to Sending the Message: @@ -30,20 +33,20 @@ We are using the following emoji guide to show the actors of each action: - 📜 Fee funds (previously approved) are transferred from the user's wallet to the Cross-Chain dApp. - 📜 Cross-Chain dApp approves the Interchain Messaging Contract to spend the ERC20 fee tokens. - 👾 Fee tokens are transferred into the Interchain Messaging Contract. -- 👾Interchain Messagingassigns a unique ID to the Message and keeps track of the fee Info. +- 👾 Interchain Messaging assigns a unique ID to the Message and keeps track of the fee Info. - 🛸 Relayer can now pick and deliver the Message. ### Message Delivered in the Destination Chain: -- 👾Interchain Messagingin the Destination Chain generates a receipt with the messageID and Relayer address who delivered the message. +- 👾 Interchain Messaging in the Destination Chain generates a receipt with the `messageID` and Relayer address who delivered the message. - Receipt is sent back to the Source Chain. - 🛸 Relayers can send the receipts back to the Source Chain themselves or wait until a new (unrelated) message is sent now from the once Destination Chain to the former Source chain. Messages include up to 5 pending receipts in a message. ### Once Message is Received in the Source Chain: -- 👾 The Interchain Messaging marks the messageID as received and increases the Relayer redeemable reward. +- 👾 The Interchain Messaging marks the `messageID` as received and increases the Relayer redeemable reward. - 🛸 The relayer can now claim its unlocked rewards. -As you can see, there are just a few actions you as a Cross-Chain dApp developer need to implement so dApp works smoothly with fees, everything else is being done by the Interchain Messaging contract and the Relayer. +As you can see, there are just a few actions you as a cross-chain dApp developer need to implement so dApp works smoothly with fees, everything else is being done by the Interchain Messaging contract and the Relayer. If you run your own relayer, you don't have to attach any fees. \ No newline at end of file diff --git a/content/course/interchain-messaging/12-incentivizing-a-relayer/03-determining-the-fee-amount.mdx b/content/course/interchain-messaging/12-incentivizing-a-relayer/03-determining-the-fee-amount.mdx index 52c05b46..f9980a28 100644 --- a/content/course/interchain-messaging/12-incentivizing-a-relayer/03-determining-the-fee-amount.mdx +++ b/content/course/interchain-messaging/12-incentivizing-a-relayer/03-determining-the-fee-amount.mdx @@ -12,13 +12,15 @@ icon: BookOpen The first question to address is: How much should you pay a Relayer to ensure they are incentivized to deliver the message? The answer is straightforward but requires some analysis. The incentive should at least cover the expenses the Relayer will incur by delivering your message. -As mentioned in previous lessons, a message will be considered delivered in the destination Chain if the Relayer sends at least the requiredGasLimit stated in the message, regardless of whether the execution succeeds or fails. Thus, the associated cost in $USD (or another asset like AVAX) that the Relayer will face to deliver your message is: +As mentioned in previous lessons, a message will be considered delivered in the destination Chain if the Relayer sends at least the `requiredGasLimit` stated in the message, regardless of whether the execution succeeds or fails. Thus, the associated cost in $USD (or another asset like AVAX) that the Relayer will face to deliver your message is: + *Cost = requiredGasLimit * gas_price_in_native_token * native_token_price* While the income the Relayer will be paid for delivering your message is: + *Income = Fee_Amount * ERC20_Price* -Excluding the Relayer's hosting costs, any Fee amount where *Costs < Income* will be profitable for the Relayer. Different types of messages or actions available in a Cross-Chain dApp may require different amounts of gas to deliver successfully. For instance, in a Cross-Chain ERC20 minter, creating the token contract is more expensive than minting new tokens, simply because creation requires deploying a new contract. Thus, it makes sense to reward the Relayer with a higher amount for delivering a Creation message compared to a minting message (assuming both requiredGasLimit are set accordingly). +Excluding the Relayer's hosting costs, any Fee amount where *Costs < Income* will be profitable for the Relayer. Different types of messages or actions available in a cross-chain dApp may require different amounts of gas to deliver successfully. For instance, in a cross-chain ERC20 minter, creating the token contract is more expensive than minting new tokens, simply because creation requires deploying a new contract. Thus, it makes sense to reward the Relayer with a higher amount for delivering a creation message compared to a minting message (assuming both `requiredGasLimit` are set accordingly). ### Example Calculation @@ -30,24 +32,29 @@ To simplify, consider the following assumptions: - DIS is the fee token in Bulletin. - Assume *DIS_price = TLP_price*. - Relayer will only take your message if it can make at least 10% profit. -- The requiredGasLimit for sending our message is 10,000 gas units. +- The `requiredGasLimit` for sending our message is 10,000 gas units. - Gas price in Dispatch = 50 nDIS (DIS * 10^-9). ### Calculating the Fee The cost of relaying this message will be: + *Cost = 10,000 * 50 * DIS_price* The Relayer will take your message only if it can make a 10% profit: + *Income = 1.1 * Cost* Therefore: + *TLP_price * Amount = 1.1 * 10,000 * 50 * DIS_price* Knowing that *TLP_price = DIS_price*: + *Amount = 1.1 * 10,000 * 50* Then: + *Amount = 550,000 nTLP* *Amount = 550,000,000,000,000 weiTLP* diff --git a/content/course/interchain-messaging/12-incentivizing-a-relayer/04-setting-incentives.mdx b/content/course/interchain-messaging/12-incentivizing-a-relayer/04-setting-incentives.mdx index 40328f2f..664b143b 100644 --- a/content/course/interchain-messaging/12-incentivizing-a-relayer/04-setting-incentives.mdx +++ b/content/course/interchain-messaging/12-incentivizing-a-relayer/04-setting-incentives.mdx @@ -6,7 +6,9 @@ authors: [andyvargtz] icon: BookOpen --- -As we studied in previous lessons, the sendCrossChainMessage function takes TeleporterMessageInput struct as an input. The fields feeInfo in the TeleporterMessageInput will be a TeleporterFeeInfo struct formed by the ERC20 contract address in which the fee will be paid, as well as the amount of tokens to incentivize the relayer. This amount needs to be set in wei units. Let's take a look at it: +As we studied in previous lessons, the `sendCrossChainMessage` function takes `TeleporterMessageInput` struct as an input. The fields feeInfo in the `TeleporterMessageInput` will be a `TeleporterFeeInfo` struct formed by the ERC20 contract address in which the fee will be paid, as well as the amount of tokens to incentivize the relayer. This amount needs to be set in wei units. + +Let's take a look at it: ```solidity // (c) 2023, Ava Labs, Inc. All rights reserved. @@ -19,15 +21,15 @@ pragma solidity 0.8.18; struct TeleporterMessageInput { bytes32 destinationBlockchainID; address destinationAddress; - TeleporterFeeInfo feeInfo; //[!code highlight] + TeleporterFeeInfo feeInfo; // [!code highlight] uint256 requiredGasLimit; address[] allowedRelayerAddresses; bytes message; } struct TeleporterFeeInfo { - address contractAddress; //[!code highlight] - uint256 amount; //[!code highlight] + address contractAddress; // [!code highlight] + uint256 amount; // [!code highlight] } interface ITeleporterMessenger { @@ -36,6 +38,6 @@ interface ITeleporterMessenger { returns (bytes32); } ``` -As you can see, the TeleporterMessageInput now needs to include the ERC20 address that will pay the incentives and the amount, all this as part of the TeleporterFeeInfo +As you can see, the `TeleporterMessageInput` now needs to include the ERC20 address that will pay the incentives and the amount, all this as part of the `TeleporterFeeInfo` diff --git a/content/course/interchain-messaging/12-incentivizing-a-relayer/05-deploy-fee-token-contract.mdx b/content/course/interchain-messaging/12-incentivizing-a-relayer/05-deploy-fee-token-contract.mdx index a6a8d9d5..6331a702 100644 --- a/content/course/interchain-messaging/12-incentivizing-a-relayer/05-deploy-fee-token-contract.mdx +++ b/content/course/interchain-messaging/12-incentivizing-a-relayer/05-deploy-fee-token-contract.mdx @@ -10,7 +10,7 @@ import { Steps, Step } from 'fumadocs-ui/components/steps'; To add incentives for a relayer we need to specify the ERC20 contract we will be incentivizing with. Since we are working with an almost clean network deployed locally, we will need to first deploy this contract to later use it as the incentive token. -Incentives are set with ERC20 tokens deployed on the Source chain, in this case our local C-chain. While this token can be a wrapped version of the native token, for this example we will be using just a simple ERC20 included as demo in the Avalanche-CLI. Let's deploy and mint some of these FEE tokens to later be used to incentivize the relayer. +Incentives are set with ERC20 tokens deployed on the Source chain, in this case our local C-Chain. While this token can be a wrapped version of the native token, for this example we will be using just a simple ERC20 included as demo in the Avalanche-CLI. Let's deploy and mint some of these FEE tokens to later be used to incentivize the relayer. @@ -24,13 +24,26 @@ avalanche contract deploy erc20 This command will deploy a demo ERC20. Add the following configuration ```bash +✔ Local Network +✔ C-Chain + +A private key is needed to pay for the contract deploy fees. +It will also be considered the owner address of the contract, beign able to call +the contract methods only available to owners. + ✔ Use the private key of the Genesis Allocated address 0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC + Which is the token symbol? Token symbol: FEE Which is the total token supply? Token supply: 100000 Which address should receive the supply? + ✔ Use the Genesis Allocated address 0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC + +Token Address: 0x768AF58E63775354938e9F3FEdB764F601c038b4 + +ERC20 Contract Successfully Deployed! ``` @@ -39,7 +52,7 @@ Which address should receive the supply? ### Save the ERC20 Address ```bash -export ERC20_fee_address=0x... +export ERC20_fee_address=0x768AF58E63775354938e9F3FEdB764F601c038b4 ``` diff --git a/content/course/interchain-messaging/12-incentivizing-a-relayer/06-incentivize-an-awm-relayer.mdx b/content/course/interchain-messaging/12-incentivizing-a-relayer/06-incentivize-an-awm-relayer.mdx index a4dc2e8f..187227bd 100644 --- a/content/course/interchain-messaging/12-incentivizing-a-relayer/06-incentivize-an-awm-relayer.mdx +++ b/content/course/interchain-messaging/12-incentivizing-a-relayer/06-incentivize-an-awm-relayer.mdx @@ -10,7 +10,7 @@ icon: Terminal Now that we have an ERC20 token deployed and some of those tokens in our account to incentivize our relayer, let's include the incentive in our Sender contract. -In the following contract, make sure to update destinationBlockchainID with your current deployment +In the following contract, make sure to update `destinationBlockchainID` with your current deployment ```solidity title="src/9-incentivize-relayer/senderWithFees.sol" // (c) 2023, Ava Labs, Inc. All rights reserved. @@ -21,7 +21,7 @@ In the following contract, make sure to update destinationBlockchainID with your pragma solidity ^0.8.18; import "@teleporter/ITeleporterMessenger.sol"; -import {IERC20} from "@openzeppelin/contracts@4/token/ERC20/IERC20.sol"; //[!code highlight] +import {IERC20} from "@openzeppelin/contracts@4/token/ERC20/IERC20.sol"; // [!code highlight] contract SenderWithFeesOnCChain { ITeleporterMessenger public immutable messenger = ITeleporterMessenger(0x253b2784c75e510dD0fF1da844684a1aC0aa5fcf); @@ -29,17 +29,17 @@ contract SenderWithFeesOnCChain { * @dev Sends a message to another chain. */ function sendMessage(address destinationAddress, string calldata message, address feeAddress) external { - IERC20 feeContract = IERC20(feeAddress); //[!code highlight] - uint256 feeAmount = 500000000000000; //[!code highlight] - feeContract.transferFrom(msg.sender, address(this), feeAmount);//[!code highlight] - feeContract.approve(address(teleporterMessenger),feeAmount); //[!code highlight] + IERC20 feeContract = IERC20(feeAddress); // [!code highlight] + uint256 feeAmount = 500000000000000; // [!code highlight] + feeContract.transferFrom(msg.sender, address(this), feeAmount);// [!code highlight] + feeContract.approve(address(teleporterMessenger),feeAmount); // [!code highlight] messenger.sendCrossChainMessage( TeleporterMessageInput({ - // Replace with blockchainID of your Subnet (see instructions in Readme) + // Replace with blockchainID of your L1 (see instructions in Readme) destinationBlockchainID: 0x108ce15038973062d8628fd20c8c657effe993dd8324297353e350dfc05dacad, destinationAddress: destinationAddress, - feeInfo: TeleporterFeeInfo({feeTokenAddress: feeAddress, amount: feeAmount}), //[!code highlight] + feeInfo: TeleporterFeeInfo({feeTokenAddress: feeAddress, amount: feeAmount}), // [!code highlight] requiredGasLimit: 100000, allowedRelayerAddresses: new address[](0), message: abi.encode(message) @@ -51,8 +51,8 @@ contract SenderWithFeesOnCChain { Notice, our contract implementing Fees now needs to include the functionality we described in the fee flow section: -- Import IERC20 and create the fee contract interface instance -- 📜The Cross-Subnet dApp transfers the ERC20 fee amount to the control of the Cross-Chain dApp contract. -- 📜Cross-Subnet dApp needs to implement the approval for the Interchain Messaging contract of these ERC20 tokens. -- Include the TeleporterFeeInfo struct in the message. +- Import `IERC20` and create the fee contract interface instance +- 📜The Cross-Avalanche L1 dApp transfers the ERC20 fee amount to the control of the Cross-Chain dApp contract. +- 📜Cross-Avalanche L1 dApp needs to implement the approval for the Interchain Messaging contract of these ERC20 tokens. +- Include the `TeleporterFeeInfo` struct in the message. diff --git a/content/course/interchain-messaging/12-incentivizing-a-relayer/07-interaction-flow-with-fees.mdx b/content/course/interchain-messaging/12-incentivizing-a-relayer/07-interaction-flow-with-fees.mdx index 6f5c490e..8d6d1f10 100644 --- a/content/course/interchain-messaging/12-incentivizing-a-relayer/07-interaction-flow-with-fees.mdx +++ b/content/course/interchain-messaging/12-incentivizing-a-relayer/07-interaction-flow-with-fees.mdx @@ -7,10 +7,10 @@ icon: Terminal --- import { Step, Steps } from 'fumadocs-ui/components/steps'; -We have all the Smart Contract 📜 set we can start sending incentivized Cross-Chain messages. Now let complete the flow +Now we have all the Smart Contract 📜 set we can start sending incentivized cross-chain messages. Now let complete the flow -- Deploy sender contract on C-chain -- Deploy receiver contract on myblockchain +- Deploy sender contract on C-Chain +- Deploy receiver contract on `myblockchain` - Approve the sender contract to spend ERC20 funds from the message sender address - Send the message @@ -22,7 +22,16 @@ We have all the Smart Contract 📜 set we can start sending incentivized Cross- To deploy the sender contract run: ```bash -forge create --rpc-url myblockchain --private-key $PK src/9-incentivize-relayer/senderWithFees.sol:SenderWithFeesOnCChain +forge create --rpc-url local-c --private-key $PK src/9-incentivize-relayer/senderWithFees.sol:SenderWithFeesOnCChain +``` +``` +[⠊] Compiling... +[⠒] Compiling 2 files with Solc 0.8.18 +[⠢] Solc 0.8.18 finished in 92.98ms +Compiler run successful! +Deployer: 0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC +Deployed to: 0xa4DfF80B4a1D748BF28BC4A271eD834689Ea3407 // [!code highlight] +Transaction hash: 0xb0ff20527818fcc0836944a13ddb3b336b95047d434bb52f6c064ab407950166 ``` @@ -30,7 +39,7 @@ forge create --rpc-url myblockchain --private-key $PK src/9-incentivize-relayer/ ### Save the Sender Contract Address ```bash -export SENDER_ADDRESS=0x... +export SENDER_ADDRESS=0xa4DfF80B4a1D748BF28BC4A271eD834689Ea3407 ``` @@ -41,7 +50,16 @@ export SENDER_ADDRESS=0x... Now, deploy the receiver contract. ```bash -forge create --rpc-url myblockchain --private-key $PK src/9-incentivize-relayer/receiverWithFees.sol:receiverWithFeesOnCChain +forge create --rpc-url myblockchain --private-key $PK src/9-incentivize-relayer/receiverWithFees.sol:ReceiverOnSubnet +``` +``` +[⠊] Compiling... +[⠢] Compiling 1 files with Solc 0.8.18 +[⠆] Solc 0.8.18 finished in 105.36ms +Compiler run successful! +Deployer: 0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC +Deployed to: 0xe336d36FacA76840407e6836d26119E1EcE0A2b4 // [!code highlight] +Transaction hash: 0x379f0a4b875effc9b80a33f039d9a49404514e7aabaef4490f57b56fb4818f65 ``` @@ -50,7 +68,7 @@ forge create --rpc-url myblockchain --private-key $PK src/9-incentivize-relayer/ ### Save the Receiver Contract Address ```bash -export RECEIVER_ADDRESS=0x... +export RECEIVER_ADDRESS=0xe336d36FacA76840407e6836d26119E1EcE0A2b4 ``` @@ -61,7 +79,7 @@ export RECEIVER_ADDRESS=0x... 👩 The Message Sender (User) requires to approve the Cross-Avalanche L1 dApp as a spender on the ERC20 contract to be used as fee. To do that lets use the function "approve" on our deployed FEE contract. ```bash -cast send --rpc-url local-c --private-key $PK ERC20_fee_address "approve(address,uint256)" SENDER_ADDRESS 500000000000000 +cast send --rpc-url local-c --private-key $PK $ERC20_fee_address "approve(address,uint256)" $SENDER_ADDRESS 500000000000000 ``` @@ -70,7 +88,7 @@ cast send --rpc-url local-c --private-key $PK ERC20_fee_address "approve(address ### Send an incentivized message ```bash -cast send --rpc-url local-c --private-key $PK SENDER_ADDRESS "sendMessage(address, string, address)" $RECEIVER_ADDRESS, "Hello", $ERC20_fee_address +cast send --rpc-url local-c --private-key $PK $SENDER_ADDRESS "sendMessage(address, string, address)" $RECEIVER_ADDRESS "Hello" $ERC20_fee_address ``` @@ -79,8 +97,13 @@ cast send --rpc-url local-c --private-key $PK SENDER_ADDRESS "sendMessage(addres ### Verify message was received on Avalanche L1 ```bash -cast call --rpc-url local-c RECEIVER_ADDRESS "lastMessage()(string)" +cast call --rpc-url myblockchain $RECEIVER_ADDRESS "lastMessage()(string)" ``` +```bash +"Hello" +``` + +**Success!** The message was received on the destination chain while incentivizing the Relayer. \ No newline at end of file