Work with multiple functions in a single Cross-Chain dApp
Great work. We can now pack multiple values into a message. In this section, we will learn how to encode the function name and depending on that its parameters in the message. Let's imagine a more advanced calculator that not only has a single add function but also a concatenate function, that lets you concatenate two strings.
For the add function we need to encode two numbers. For the concatenate function we need to encode two strings. How can we go about this? The concept is easy: It's like packing an envelope into another envelope:
pragma solidity ^0.8.18;import "@teleporter/ITeleporterMessenger.sol";import "./CalculatorActions.sol";contract CalculatorSenderOnCChain { ITeleporterMessenger public immutable teleporterMessenger = ITeleporterMessenger(0x253b2784c75e510dD0fF1da844684a1aC0aa5fcf); function sendAddMessage(address destinationAddress, uint256 num1, uint256 num2) external { teleporterMessenger.sendCrossChainMessage( TeleporterMessageInput({ // Replace with chain id of your Avalanche L1 (see instructions in Readme) destinationBlockchainID: 0x92756d698399805f0088fc07fc42af47c67e1d38c576667ac6c7031b8df05293, destinationAddress: destinationAddress, feeInfo: TeleporterFeeInfo({feeTokenAddress: address(0), amount: 0}), requiredGasLimit: 100000, allowedRelayerAddresses: new address[](0), message: encodeAddData(num1, num2) }) ); } 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}), requiredGasLimit: 100000, allowedRelayerAddresses: new address[](0), message: encodeConcatenateData(text1, text2) }) ); } // Encode helpers function encodeAddData(uint256 a, uint256 b) public pure returns (bytes memory) { bytes memory paramsData = abi.encode(a, b); return abi.encode(CalculatorAction.add, paramsData); } function encodeConcatenateData(string memory a, string memory b) public pure returns (bytes memory) { bytes memory paramsData = abi.encode(a, b); return abi.encode(CalculatorAction.concatenate, paramsData); }}
As you can see here we are calling abi.encode twice in the encode helpers. The first time we encode the function paramters and the second time we encode the function name with the byte array containing paramters.
Then based on the function name we decide how to unpack the paramters
// Route to the appropriate function.if (actionType == CalculatorAction.add) { (uint256 a, uint256 b) = abi.decode(paramsData, (uint256, uint256)); _calculatorAdd(a, b);} else if (actionType == ...) { (string memory text1, string memory text2) = abi.decode(paramsData, (string, string)); _calculatorConcatenateStrings(text1, text2);} else { revert("CalculatorReceiverOnSubnet: invalid action");}
For the add function we decode two numbers and for the concatenate function we decode two strings. After the decoding we call the appropriate internal function.