diff --git a/.github/workflows/abi_bindings_checker.yml b/.github/workflows/abi_bindings_checker.yml index 3d490c806..1fad9aeb8 100644 --- a/.github/workflows/abi_bindings_checker.yml +++ b/.github/workflows/abi_bindings_checker.yml @@ -8,25 +8,28 @@ on: branches: - "*" -env: - GO_VERSION: "1.20.10" - jobs: abi_binding: name: abi_binding runs-on: ubuntu-20.04 steps: - - name: Setup Go - uses: actions/setup-go@v4 - with: - go-version: ${{ env.GO_VERSION }} - name: Checkout Teleporter repository uses: actions/checkout@v4 with: submodules: recursive + - name: Set Go version + run: | + source ./scripts/versions.sh + GO_VERSION=$GO_VERSION >> $GITHUB_ENV + + - name: Setup Go + uses: actions/setup-go@v4 + with: + go-version: ${{ env.GO_VERSION }} + - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 with: @@ -49,16 +52,21 @@ jobs: runs-on: ubuntu-20.04 steps: - - name: Setup Go - uses: actions/setup-go@v4 - with: - go-version: ${{ env.GO_VERSION }} - - name: Checkout repositories and submodules uses: actions/checkout@v4 with: submodules: recursive + - name: Set Go version + run: | + source ./scripts/versions.sh + GO_VERSION=$GO_VERSION >> $GITHUB_ENV + + - name: Setup Go + uses: actions/setup-go@v4 + with: + go-version: ${{ env.GO_VERSION }} + - name: Run ABI Binding Unit Tests run: | source scripts/constants.sh diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index beab04840..1fe2468d4 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -11,9 +11,6 @@ on: branches: - "*" -env: - GO_VERSION: "1.20.10" - jobs: e2e_tests: name: e2e_tests @@ -25,6 +22,11 @@ jobs: with: submodules: recursive + - name: Set Go version + run: | + source ./scripts/versions.sh + GO_VERSION=$GO_VERSION >> $GITHUB_ENV + - name: Setup Go uses: actions/setup-go@v4 with: @@ -40,9 +42,6 @@ jobs: cd subnet-evm ./scripts/build.sh /tmp/e2e-test/avalanchego/plugins/srEXiWaHuhNyGwPUi444Tu47ZEDwxTWrbQiuD7FmgSAQ6X7Dy - - name: Checkout teleporter repository - uses: actions/checkout@v4 - - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 with: diff --git a/.github/workflows/gomod_checker.yml b/.github/workflows/gomod_checker.yml new file mode 100644 index 000000000..831258703 --- /dev/null +++ b/.github/workflows/gomod_checker.yml @@ -0,0 +1,31 @@ +name: go.mod Check + +on: + push: + branches: + - main + pull_request: + branches: + - "*" + +jobs: + gomod_check: + name: Check go.mod + runs-on: ubuntu-20.04 + + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - run: | + source ./scripts/versions.sh + GO_VERSION=$GO_VERSION >> $GITHUB_ENV + + - uses: actions/setup-go@v4 + with: + go-version: ${{ env.GO_VERSION }} + + - run: go mod tidy + - run: git --no-pager diff -- go.mod go.sum # This prints the diff + - run: git --no-pager diff --quiet -- go.mod go.sum # This errors if there is a diff \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3520c30f3..94e3e7580 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,9 +8,6 @@ on: branches: - "*" -env: - RELAYER_VERSION: v0.2.4 - jobs: teleporter-integration-test: runs-on: ubuntu-20.04 @@ -25,7 +22,8 @@ jobs: - name: Download awm-relayer image run: | - docker pull avaplatform/awm-relayer:${RELAYER_VERSION} + source ./scripts/versions.sh + docker pull avaplatform/awm-relayer:${AWM_RELAYER_VERSION} - name: Teleporter Integration Tests run: | diff --git a/abi-bindings/go/CrossChainApplications/ExampleMessenger/ExampleCrossChainMessenger/ExampleCrossChainMessenger.go b/abi-bindings/go/CrossChainApplications/ExampleMessenger/ExampleCrossChainMessenger/ExampleCrossChainMessenger.go index eb04ec76a..2397a5078 100644 --- a/abi-bindings/go/CrossChainApplications/ExampleMessenger/ExampleCrossChainMessenger/ExampleCrossChainMessenger.go +++ b/abi-bindings/go/CrossChainApplications/ExampleMessenger/ExampleCrossChainMessenger/ExampleCrossChainMessenger.go @@ -31,7 +31,7 @@ var ( // ExampleCrossChainMessengerMetaData contains all meta data concerning the ExampleCrossChainMessenger contract. var ExampleCrossChainMessengerMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"teleporterRegistryAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"oldMinTeleporterVersion\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"newMinTeleporterVersion\",\"type\":\"uint256\"}],\"name\":\"MinTeleporterVersionUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"originChainID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originSenderAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"ReceiveMessage\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"feeAsset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"feeAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"SendMessage\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"originChainID\",\"type\":\"bytes32\"}],\"name\":\"getCurrentMessage\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"minTeleporterVersion\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"originChainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"originSenderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"receiveTeleporterMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"feeContractAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"feeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"sendMessage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"teleporterRegistry\",\"outputs\":[{\"internalType\":\"contractTeleporterRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"updateMinTeleporterVersion\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"teleporterRegistryAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"oldMinTeleporterVersion\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"newMinTeleporterVersion\",\"type\":\"uint256\"}],\"name\":\"MinTeleporterVersionUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"originChainID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"originSenderAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"ReceiveMessage\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"feeTokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"feeAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"SendMessage\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"originChainID\",\"type\":\"bytes32\"}],\"name\":\"getCurrentMessage\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"minTeleporterVersion\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"originChainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"originSenderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"receiveTeleporterMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"feeTokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"feeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"sendMessage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"teleporterRegistry\",\"outputs\":[{\"internalType\":\"contractTeleporterRegistry\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"updateMinTeleporterVersion\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", } // ExampleCrossChainMessengerABI is the input ABI used to generate the binding from. @@ -349,23 +349,23 @@ func (_ExampleCrossChainMessenger *ExampleCrossChainMessengerTransactorSession) // SendMessage is a paid mutator transaction binding the contract method 0xf63d09d7. // -// Solidity: function sendMessage(bytes32 destinationChainID, address destinationAddress, address feeContractAddress, uint256 feeAmount, uint256 requiredGasLimit, string message) returns(uint256) -func (_ExampleCrossChainMessenger *ExampleCrossChainMessengerTransactor) SendMessage(opts *bind.TransactOpts, destinationChainID [32]byte, destinationAddress common.Address, feeContractAddress common.Address, feeAmount *big.Int, requiredGasLimit *big.Int, message string) (*types.Transaction, error) { - return _ExampleCrossChainMessenger.contract.Transact(opts, "sendMessage", destinationChainID, destinationAddress, feeContractAddress, feeAmount, requiredGasLimit, message) +// Solidity: function sendMessage(bytes32 destinationChainID, address destinationAddress, address feeTokenAddress, uint256 feeAmount, uint256 requiredGasLimit, string message) returns(uint256) +func (_ExampleCrossChainMessenger *ExampleCrossChainMessengerTransactor) SendMessage(opts *bind.TransactOpts, destinationChainID [32]byte, destinationAddress common.Address, feeTokenAddress common.Address, feeAmount *big.Int, requiredGasLimit *big.Int, message string) (*types.Transaction, error) { + return _ExampleCrossChainMessenger.contract.Transact(opts, "sendMessage", destinationChainID, destinationAddress, feeTokenAddress, feeAmount, requiredGasLimit, message) } // SendMessage is a paid mutator transaction binding the contract method 0xf63d09d7. // -// Solidity: function sendMessage(bytes32 destinationChainID, address destinationAddress, address feeContractAddress, uint256 feeAmount, uint256 requiredGasLimit, string message) returns(uint256) -func (_ExampleCrossChainMessenger *ExampleCrossChainMessengerSession) SendMessage(destinationChainID [32]byte, destinationAddress common.Address, feeContractAddress common.Address, feeAmount *big.Int, requiredGasLimit *big.Int, message string) (*types.Transaction, error) { - return _ExampleCrossChainMessenger.Contract.SendMessage(&_ExampleCrossChainMessenger.TransactOpts, destinationChainID, destinationAddress, feeContractAddress, feeAmount, requiredGasLimit, message) +// Solidity: function sendMessage(bytes32 destinationChainID, address destinationAddress, address feeTokenAddress, uint256 feeAmount, uint256 requiredGasLimit, string message) returns(uint256) +func (_ExampleCrossChainMessenger *ExampleCrossChainMessengerSession) SendMessage(destinationChainID [32]byte, destinationAddress common.Address, feeTokenAddress common.Address, feeAmount *big.Int, requiredGasLimit *big.Int, message string) (*types.Transaction, error) { + return _ExampleCrossChainMessenger.Contract.SendMessage(&_ExampleCrossChainMessenger.TransactOpts, destinationChainID, destinationAddress, feeTokenAddress, feeAmount, requiredGasLimit, message) } // SendMessage is a paid mutator transaction binding the contract method 0xf63d09d7. // -// Solidity: function sendMessage(bytes32 destinationChainID, address destinationAddress, address feeContractAddress, uint256 feeAmount, uint256 requiredGasLimit, string message) returns(uint256) -func (_ExampleCrossChainMessenger *ExampleCrossChainMessengerTransactorSession) SendMessage(destinationChainID [32]byte, destinationAddress common.Address, feeContractAddress common.Address, feeAmount *big.Int, requiredGasLimit *big.Int, message string) (*types.Transaction, error) { - return _ExampleCrossChainMessenger.Contract.SendMessage(&_ExampleCrossChainMessenger.TransactOpts, destinationChainID, destinationAddress, feeContractAddress, feeAmount, requiredGasLimit, message) +// Solidity: function sendMessage(bytes32 destinationChainID, address destinationAddress, address feeTokenAddress, uint256 feeAmount, uint256 requiredGasLimit, string message) returns(uint256) +func (_ExampleCrossChainMessenger *ExampleCrossChainMessengerTransactorSession) SendMessage(destinationChainID [32]byte, destinationAddress common.Address, feeTokenAddress common.Address, feeAmount *big.Int, requiredGasLimit *big.Int, message string) (*types.Transaction, error) { + return _ExampleCrossChainMessenger.Contract.SendMessage(&_ExampleCrossChainMessenger.TransactOpts, destinationChainID, destinationAddress, feeTokenAddress, feeAmount, requiredGasLimit, message) } // TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. @@ -941,7 +941,7 @@ func (it *ExampleCrossChainMessengerSendMessageIterator) Close() error { type ExampleCrossChainMessengerSendMessage struct { DestinationChainID [32]byte DestinationAddress common.Address - FeeAsset common.Address + FeeTokenAddress common.Address FeeAmount *big.Int RequiredGasLimit *big.Int Message string @@ -950,7 +950,7 @@ type ExampleCrossChainMessengerSendMessage struct { // FilterSendMessage is a free log retrieval operation binding the contract event 0xa06eff1edd0c66b8dc96d086dda7ba263edf88d7417e6cb15073b5e7bff8a8ca. // -// Solidity: event SendMessage(bytes32 indexed destinationChainID, address indexed destinationAddress, address feeAsset, uint256 feeAmount, uint256 requiredGasLimit, string message) +// Solidity: event SendMessage(bytes32 indexed destinationChainID, address indexed destinationAddress, address feeTokenAddress, uint256 feeAmount, uint256 requiredGasLimit, string message) func (_ExampleCrossChainMessenger *ExampleCrossChainMessengerFilterer) FilterSendMessage(opts *bind.FilterOpts, destinationChainID [][32]byte, destinationAddress []common.Address) (*ExampleCrossChainMessengerSendMessageIterator, error) { var destinationChainIDRule []interface{} @@ -971,7 +971,7 @@ func (_ExampleCrossChainMessenger *ExampleCrossChainMessengerFilterer) FilterSen // WatchSendMessage is a free log subscription operation binding the contract event 0xa06eff1edd0c66b8dc96d086dda7ba263edf88d7417e6cb15073b5e7bff8a8ca. // -// Solidity: event SendMessage(bytes32 indexed destinationChainID, address indexed destinationAddress, address feeAsset, uint256 feeAmount, uint256 requiredGasLimit, string message) +// Solidity: event SendMessage(bytes32 indexed destinationChainID, address indexed destinationAddress, address feeTokenAddress, uint256 feeAmount, uint256 requiredGasLimit, string message) func (_ExampleCrossChainMessenger *ExampleCrossChainMessengerFilterer) WatchSendMessage(opts *bind.WatchOpts, sink chan<- *ExampleCrossChainMessengerSendMessage, destinationChainID [][32]byte, destinationAddress []common.Address) (event.Subscription, error) { var destinationChainIDRule []interface{} @@ -1017,7 +1017,7 @@ func (_ExampleCrossChainMessenger *ExampleCrossChainMessengerFilterer) WatchSend // ParseSendMessage is a log parse operation binding the contract event 0xa06eff1edd0c66b8dc96d086dda7ba263edf88d7417e6cb15073b5e7bff8a8ca. // -// Solidity: event SendMessage(bytes32 indexed destinationChainID, address indexed destinationAddress, address feeAsset, uint256 feeAmount, uint256 requiredGasLimit, string message) +// Solidity: event SendMessage(bytes32 indexed destinationChainID, address indexed destinationAddress, address feeTokenAddress, uint256 feeAmount, uint256 requiredGasLimit, string message) func (_ExampleCrossChainMessenger *ExampleCrossChainMessengerFilterer) ParseSendMessage(log types.Log) (*ExampleCrossChainMessengerSendMessage, error) { event := new(ExampleCrossChainMessengerSendMessage) if err := _ExampleCrossChainMessenger.contract.UnpackLog(event, "SendMessage", log); err != nil { diff --git a/abi-bindings/go/Teleporter/TeleporterMessenger/TeleporterMessenger.go b/abi-bindings/go/Teleporter/TeleporterMessenger/TeleporterMessenger.go index e19df2481..ab0c1327c 100644 --- a/abi-bindings/go/Teleporter/TeleporterMessenger/TeleporterMessenger.go +++ b/abi-bindings/go/Teleporter/TeleporterMessenger/TeleporterMessenger.go @@ -31,7 +31,7 @@ var ( // TeleporterFeeInfo is an auto generated low-level Go binding around an user-defined struct. type TeleporterFeeInfo struct { - ContractAddress common.Address + FeeTokenAddress common.Address Amount *big.Int } @@ -65,7 +65,7 @@ type TeleporterMessageReceipt struct { // TeleporterMessengerMetaData contains all meta data concerning the TeleporterMessenger contract. var TeleporterMessengerMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"contractAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"structTeleporterFeeInfo\",\"name\":\"updatedFeeInfo\",\"type\":\"tuple\"}],\"name\":\"AddFeeAmount\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"originChainID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"}],\"name\":\"MessageExecuted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"originChainID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"allowedRelayerAddresses\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"receivedMessageID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"relayerRewardAddress\",\"type\":\"address\"}],\"internalType\":\"structTeleporterMessageReceipt[]\",\"name\":\"receipts\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"structTeleporterMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"MessageExecutionFailed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"originChainID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"deliverer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"rewardRedeemer\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"allowedRelayerAddresses\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"receivedMessageID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"relayerRewardAddress\",\"type\":\"address\"}],\"internalType\":\"structTeleporterMessageReceipt[]\",\"name\":\"receipts\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"structTeleporterMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"ReceiveCrossChainMessage\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"redeemer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RelayerRewardsRedeemed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"allowedRelayerAddresses\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"receivedMessageID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"relayerRewardAddress\",\"type\":\"address\"}],\"internalType\":\"structTeleporterMessageReceipt[]\",\"name\":\"receipts\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"structTeleporterMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"contractAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"structTeleporterFeeInfo\",\"name\":\"feeInfo\",\"type\":\"tuple\"}],\"name\":\"SendCrossChainMessage\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"WARP_MESSENGER\",\"outputs\":[{\"internalType\":\"contractIWarpMessenger\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"feeContractAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"additionalFeeAmount\",\"type\":\"uint256\"}],\"name\":\"addFeeAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"blockchainID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"feeAsset\",\"type\":\"address\"}],\"name\":\"checkRelayerRewardAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"}],\"name\":\"getFeeInfo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"}],\"name\":\"getMessageHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"chainID\",\"type\":\"bytes32\"}],\"name\":\"getNextMessageID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"chainID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getReceiptAtIndex\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"receivedMessageID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"relayerRewardAddress\",\"type\":\"address\"}],\"internalType\":\"structTeleporterMessageReceipt\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"chainID\",\"type\":\"bytes32\"}],\"name\":\"getReceiptQueueSize\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"originChainID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"}],\"name\":\"getRelayerRewardAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"}],\"name\":\"latestMessageIDs\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"originChainID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"}],\"name\":\"messageReceived\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"sourceChainID\",\"type\":\"bytes32\"}],\"name\":\"receiptQueues\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"first\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"last\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"messageIndex\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"relayerRewardAddress\",\"type\":\"address\"}],\"name\":\"receiveCrossChainMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"sourceChainID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"}],\"name\":\"receivedFailedMessageHashes\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"messageHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"feeAsset\",\"type\":\"address\"}],\"name\":\"redeemRelayerRewards\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"originChainID\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"allowedRelayerAddresses\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"receivedMessageID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"relayerRewardAddress\",\"type\":\"address\"}],\"internalType\":\"structTeleporterMessageReceipt[]\",\"name\":\"receipts\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"internalType\":\"structTeleporterMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"retryMessageExecution\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"allowedRelayerAddresses\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"receivedMessageID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"relayerRewardAddress\",\"type\":\"address\"}],\"internalType\":\"structTeleporterMessageReceipt[]\",\"name\":\"receipts\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"internalType\":\"structTeleporterMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"retrySendCrossChainMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"contractAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structTeleporterFeeInfo\",\"name\":\"feeInfo\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"allowedRelayerAddresses\",\"type\":\"address[]\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"internalType\":\"structTeleporterMessageInput\",\"name\":\"messageInput\",\"type\":\"tuple\"}],\"name\":\"sendCrossChainMessage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"originChainID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256[]\",\"name\":\"messageIDs\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"contractAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structTeleporterFeeInfo\",\"name\":\"feeInfo\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"allowedRelayerAddresses\",\"type\":\"address[]\"}],\"name\":\"sendSpecifiedReceipts\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"}],\"name\":\"sentMessageInfo\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"messageHash\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"contractAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structTeleporterFeeInfo\",\"name\":\"feeInfo\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"feeTokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"structTeleporterFeeInfo\",\"name\":\"updatedFeeInfo\",\"type\":\"tuple\"}],\"name\":\"AddFeeAmount\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"originChainID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"}],\"name\":\"MessageExecuted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"originChainID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"allowedRelayerAddresses\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"receivedMessageID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"relayerRewardAddress\",\"type\":\"address\"}],\"internalType\":\"structTeleporterMessageReceipt[]\",\"name\":\"receipts\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"structTeleporterMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"MessageExecutionFailed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"originChainID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"deliverer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"rewardRedeemer\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"allowedRelayerAddresses\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"receivedMessageID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"relayerRewardAddress\",\"type\":\"address\"}],\"internalType\":\"structTeleporterMessageReceipt[]\",\"name\":\"receipts\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"structTeleporterMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"ReceiveCrossChainMessage\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"redeemer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RelayerRewardsRedeemed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"allowedRelayerAddresses\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"receivedMessageID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"relayerRewardAddress\",\"type\":\"address\"}],\"internalType\":\"structTeleporterMessageReceipt[]\",\"name\":\"receipts\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"structTeleporterMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"feeTokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"structTeleporterFeeInfo\",\"name\":\"feeInfo\",\"type\":\"tuple\"}],\"name\":\"SendCrossChainMessage\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"WARP_MESSENGER\",\"outputs\":[{\"internalType\":\"contractIWarpMessenger\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"feeTokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"additionalFeeAmount\",\"type\":\"uint256\"}],\"name\":\"addFeeAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"blockchainID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"feeAsset\",\"type\":\"address\"}],\"name\":\"checkRelayerRewardAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"}],\"name\":\"getFeeInfo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"}],\"name\":\"getMessageHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"chainID\",\"type\":\"bytes32\"}],\"name\":\"getNextMessageID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"chainID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getReceiptAtIndex\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"receivedMessageID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"relayerRewardAddress\",\"type\":\"address\"}],\"internalType\":\"structTeleporterMessageReceipt\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"chainID\",\"type\":\"bytes32\"}],\"name\":\"getReceiptQueueSize\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"originChainID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"}],\"name\":\"getRelayerRewardAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"}],\"name\":\"latestMessageIDs\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"originChainID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"}],\"name\":\"messageReceived\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"sourceChainID\",\"type\":\"bytes32\"}],\"name\":\"receiptQueues\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"first\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"last\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"messageIndex\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"relayerRewardAddress\",\"type\":\"address\"}],\"name\":\"receiveCrossChainMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"sourceChainID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"}],\"name\":\"receivedFailedMessageHashes\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"messageHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"feeAsset\",\"type\":\"address\"}],\"name\":\"redeemRelayerRewards\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"originChainID\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"allowedRelayerAddresses\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"receivedMessageID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"relayerRewardAddress\",\"type\":\"address\"}],\"internalType\":\"structTeleporterMessageReceipt[]\",\"name\":\"receipts\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"internalType\":\"structTeleporterMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"retryMessageExecution\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"allowedRelayerAddresses\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"receivedMessageID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"relayerRewardAddress\",\"type\":\"address\"}],\"internalType\":\"structTeleporterMessageReceipt[]\",\"name\":\"receipts\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"internalType\":\"structTeleporterMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"retrySendCrossChainMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"feeTokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structTeleporterFeeInfo\",\"name\":\"feeInfo\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"allowedRelayerAddresses\",\"type\":\"address[]\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"internalType\":\"structTeleporterMessageInput\",\"name\":\"messageInput\",\"type\":\"tuple\"}],\"name\":\"sendCrossChainMessage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"originChainID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256[]\",\"name\":\"messageIDs\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"feeTokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structTeleporterFeeInfo\",\"name\":\"feeInfo\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"allowedRelayerAddresses\",\"type\":\"address[]\"}],\"name\":\"sendSpecifiedReceipts\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"destinationChainID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"messageID\",\"type\":\"uint256\"}],\"name\":\"sentMessageInfo\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"messageHash\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"feeTokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structTeleporterFeeInfo\",\"name\":\"feeInfo\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", } // TeleporterMessengerABI is the input ABI used to generate the binding from. @@ -679,23 +679,23 @@ func (_TeleporterMessenger *TeleporterMessengerCallerSession) SentMessageInfo(de // AddFeeAmount is a paid mutator transaction binding the contract method 0x19570c74. // -// Solidity: function addFeeAmount(bytes32 destinationChainID, uint256 messageID, address feeContractAddress, uint256 additionalFeeAmount) returns() -func (_TeleporterMessenger *TeleporterMessengerTransactor) AddFeeAmount(opts *bind.TransactOpts, destinationChainID [32]byte, messageID *big.Int, feeContractAddress common.Address, additionalFeeAmount *big.Int) (*types.Transaction, error) { - return _TeleporterMessenger.contract.Transact(opts, "addFeeAmount", destinationChainID, messageID, feeContractAddress, additionalFeeAmount) +// Solidity: function addFeeAmount(bytes32 destinationChainID, uint256 messageID, address feeTokenAddress, uint256 additionalFeeAmount) returns() +func (_TeleporterMessenger *TeleporterMessengerTransactor) AddFeeAmount(opts *bind.TransactOpts, destinationChainID [32]byte, messageID *big.Int, feeTokenAddress common.Address, additionalFeeAmount *big.Int) (*types.Transaction, error) { + return _TeleporterMessenger.contract.Transact(opts, "addFeeAmount", destinationChainID, messageID, feeTokenAddress, additionalFeeAmount) } // AddFeeAmount is a paid mutator transaction binding the contract method 0x19570c74. // -// Solidity: function addFeeAmount(bytes32 destinationChainID, uint256 messageID, address feeContractAddress, uint256 additionalFeeAmount) returns() -func (_TeleporterMessenger *TeleporterMessengerSession) AddFeeAmount(destinationChainID [32]byte, messageID *big.Int, feeContractAddress common.Address, additionalFeeAmount *big.Int) (*types.Transaction, error) { - return _TeleporterMessenger.Contract.AddFeeAmount(&_TeleporterMessenger.TransactOpts, destinationChainID, messageID, feeContractAddress, additionalFeeAmount) +// Solidity: function addFeeAmount(bytes32 destinationChainID, uint256 messageID, address feeTokenAddress, uint256 additionalFeeAmount) returns() +func (_TeleporterMessenger *TeleporterMessengerSession) AddFeeAmount(destinationChainID [32]byte, messageID *big.Int, feeTokenAddress common.Address, additionalFeeAmount *big.Int) (*types.Transaction, error) { + return _TeleporterMessenger.Contract.AddFeeAmount(&_TeleporterMessenger.TransactOpts, destinationChainID, messageID, feeTokenAddress, additionalFeeAmount) } // AddFeeAmount is a paid mutator transaction binding the contract method 0x19570c74. // -// Solidity: function addFeeAmount(bytes32 destinationChainID, uint256 messageID, address feeContractAddress, uint256 additionalFeeAmount) returns() -func (_TeleporterMessenger *TeleporterMessengerTransactorSession) AddFeeAmount(destinationChainID [32]byte, messageID *big.Int, feeContractAddress common.Address, additionalFeeAmount *big.Int) (*types.Transaction, error) { - return _TeleporterMessenger.Contract.AddFeeAmount(&_TeleporterMessenger.TransactOpts, destinationChainID, messageID, feeContractAddress, additionalFeeAmount) +// Solidity: function addFeeAmount(bytes32 destinationChainID, uint256 messageID, address feeTokenAddress, uint256 additionalFeeAmount) returns() +func (_TeleporterMessenger *TeleporterMessengerTransactorSession) AddFeeAmount(destinationChainID [32]byte, messageID *big.Int, feeTokenAddress common.Address, additionalFeeAmount *big.Int) (*types.Transaction, error) { + return _TeleporterMessenger.Contract.AddFeeAmount(&_TeleporterMessenger.TransactOpts, destinationChainID, messageID, feeTokenAddress, additionalFeeAmount) } // ReceiveCrossChainMessage is a paid mutator transaction binding the contract method 0xccb5f809. diff --git a/contracts/src/CrossChainApplications/ERC20Bridge/ERC20Bridge.sol b/contracts/src/CrossChainApplications/ERC20Bridge/ERC20Bridge.sol index 90caa500b..d03fe764a 100644 --- a/contracts/src/CrossChainApplications/ERC20Bridge/ERC20Bridge.sol +++ b/contracts/src/CrossChainApplications/ERC20Bridge/ERC20Bridge.sol @@ -229,7 +229,7 @@ contract ERC20Bridge is destinationChainID: destinationChainID, destinationAddress: destinationBridgeAddress, feeInfo: TeleporterFeeInfo({ - contractAddress: messageFeeAsset, + feeTokenAddress: messageFeeAsset, amount: adjustedFeeAmount }), requiredGasLimit: CREATE_BRIDGE_TOKENS_REQUIRED_GAS, @@ -598,7 +598,7 @@ contract ERC20Bridge is destinationChainID: destinationChainID, destinationAddress: destinationBridgeAddress, feeInfo: TeleporterFeeInfo({ - contractAddress: nativeContractAddress, + feeTokenAddress: nativeContractAddress, amount: feeAmount }), requiredGasLimit: MINT_BRIDGE_TOKENS_REQUIRED_GAS, @@ -692,7 +692,7 @@ contract ERC20Bridge is destinationChainID: nativeChainID, destinationAddress: nativeBridgeAddress, feeInfo: TeleporterFeeInfo({ - contractAddress: wrappedTransferInfo.wrappedContractAddress, + feeTokenAddress: wrappedTransferInfo.wrappedContractAddress, amount: adjustedPrimaryFeeAmount }), requiredGasLimit: TRANSFER_BRIDGE_TOKENS_REQUIRED_GAS, diff --git a/contracts/src/CrossChainApplications/ERC20Bridge/tests/ERC20BridgeTests.t.sol b/contracts/src/CrossChainApplications/ERC20Bridge/tests/ERC20BridgeTests.t.sol index d25f5cceb..b6714079d 100644 --- a/contracts/src/CrossChainApplications/ERC20Bridge/tests/ERC20BridgeTests.t.sol +++ b/contracts/src/CrossChainApplications/ERC20Bridge/tests/ERC20BridgeTests.t.sol @@ -206,7 +206,7 @@ contract ERC20BridgeTest is Test { destinationChainID: _DEFAULT_OTHER_CHAIN_ID, destinationAddress: _DEFAULT_OTHER_BRIDGE_ADDRESS, feeInfo: TeleporterFeeInfo({ - contractAddress: address(mockERC20), + feeTokenAddress: address(mockERC20), amount: 0 }), requiredGasLimit: erc20Bridge.MINT_BRIDGE_TOKENS_REQUIRED_GAS(), @@ -321,7 +321,7 @@ contract ERC20BridgeTest is Test { destinationChainID: _DEFAULT_OTHER_CHAIN_ID, destinationAddress: _DEFAULT_OTHER_BRIDGE_ADDRESS, feeInfo: TeleporterFeeInfo({ - contractAddress: address(mockERC20), + feeTokenAddress: address(mockERC20), amount: feeAmount }), requiredGasLimit: erc20Bridge.MINT_BRIDGE_TOKENS_REQUIRED_GAS(), @@ -424,7 +424,7 @@ contract ERC20BridgeTest is Test { destinationChainID: _DEFAULT_OTHER_CHAIN_ID, destinationAddress: _DEFAULT_OTHER_BRIDGE_ADDRESS, feeInfo: TeleporterFeeInfo({ - contractAddress: address(mockERC20), + feeTokenAddress: address(mockERC20), amount: bridgeFeeAmount }), requiredGasLimit: erc20Bridge.MINT_BRIDGE_TOKENS_REQUIRED_GAS(), @@ -705,7 +705,7 @@ contract ERC20BridgeTest is Test { destinationChainID: destinationChainID, destinationAddress: destinationBridgeAddress, feeInfo: TeleporterFeeInfo({ - contractAddress: address(0), + feeTokenAddress: address(0), amount: 0 }), requiredGasLimit: erc20Bridge diff --git a/contracts/src/CrossChainApplications/ExampleMessenger/ExampleCrossChainMessenger.sol b/contracts/src/CrossChainApplications/ExampleMessenger/ExampleCrossChainMessenger.sol index 8e1714dee..dced22e3e 100644 --- a/contracts/src/CrossChainApplications/ExampleMessenger/ExampleCrossChainMessenger.sol +++ b/contracts/src/CrossChainApplications/ExampleMessenger/ExampleCrossChainMessenger.sol @@ -37,7 +37,7 @@ contract ExampleCrossChainMessenger is event SendMessage( bytes32 indexed destinationChainID, address indexed destinationAddress, - address feeAsset, + address feeTokenAddress, uint256 feeAmount, uint256 requiredGasLimit, string message @@ -79,7 +79,7 @@ contract ExampleCrossChainMessenger is function sendMessage( bytes32 destinationChainID, address destinationAddress, - address feeContractAddress, + address feeTokenAddress, uint256 feeAmount, uint256 requiredGasLimit, string calldata message @@ -91,10 +91,10 @@ contract ExampleCrossChainMessenger is uint256 adjustedFeeAmount = 0; if (feeAmount > 0) { adjustedFeeAmount = SafeERC20TransferFrom.safeTransferFrom( - IERC20(feeContractAddress), + IERC20(feeTokenAddress), feeAmount ); - IERC20(feeContractAddress).safeIncreaseAllowance( + IERC20(feeTokenAddress).safeIncreaseAllowance( address(teleporterMessenger), adjustedFeeAmount ); @@ -103,7 +103,7 @@ contract ExampleCrossChainMessenger is emit SendMessage({ destinationChainID: destinationChainID, destinationAddress: destinationAddress, - feeAsset: feeContractAddress, + feeTokenAddress: feeTokenAddress, feeAmount: adjustedFeeAmount, requiredGasLimit: requiredGasLimit, message: message @@ -114,7 +114,7 @@ contract ExampleCrossChainMessenger is destinationChainID: destinationChainID, destinationAddress: destinationAddress, feeInfo: TeleporterFeeInfo({ - contractAddress: feeContractAddress, + feeTokenAddress: feeTokenAddress, amount: adjustedFeeAmount }), requiredGasLimit: requiredGasLimit, diff --git a/contracts/src/CrossChainApplications/README.md b/contracts/src/CrossChainApplications/README.md index 01bf8a3a8..9caec5b35 100644 --- a/contracts/src/CrossChainApplications/README.md +++ b/contracts/src/CrossChainApplications/README.md @@ -68,7 +68,7 @@ To start, create the function declarations for `sendMessage`, which will send st function sendMessage( bytes32 destinationChainID, address destinationAddress, - address feeContractAddress, + address feeTokenAddress, uint256 feeAmount, uint256 requiredGasLimit, string calldata message @@ -86,19 +86,19 @@ function receiveTeleporterMessage( ) external {} ``` -Now it's time to implement the methods, starting with `sendMessage`. First, import OpenZeppelin's `IERC20` contract, then in `sendMessage` check whether `feeAmount` is greater than zero. If it is, transfer and approve the amount of IERC20 asset at `feeContractAddress` to the Teleporter Messenger saved as a state variable. Relayer fees are an optional way to incentive relayers to deliver a Teleporter message to its destination. They are not strictly necessary, and may be omitted if a relayer is willing to relay messages with no fee, such as with a self-hosted relayer. +Now it's time to implement the methods, starting with `sendMessage`. First, import OpenZeppelin's `IERC20` contract, then in `sendMessage` check whether `feeAmount` is greater than zero. If it is, transfer and approve the amount of IERC20 asset at `feeTokenAddress` to the Teleporter Messenger saved as a state variable. Relayer fees are an optional way to incentive relayers to deliver a Teleporter message to its destination. They are not strictly necessary, and may be omitted if a relayer is willing to relay messages with no fee, such as with a self-hosted relayer. ```solidity // For non-zero fee amounts, transfer the fee into the control of this contract first, and then // allow the Teleporter contract to spend it. if (feeAmount > 0) { - IERC20 feeAsset = IERC20(feeContractAddress); + IERC20 feeToken = IERC20(feeTokenAddress); require( - feeAsset.transferFrom(msg.sender, address(this), feeAmount), + feeToken.transferFrom(msg.sender, address(this), feeAmount), "Failed to transfer fee amount" ); require( - feeAsset.approve(address(teleporterMessenger), feeAmount), + feeToken.approve(address(teleporterMessenger), feeAmount), "Failed to approve fee amount" ); } @@ -116,7 +116,7 @@ return destinationChainID: destinationChainID, destinationAddress: destinationAddress, feeInfo: TeleporterFeeInfo({ - contractAddress: feeContractAddress, + feeTokenAddress: feeTokenAddress, amount: feeAmount }), requiredGasLimit: requiredGasLimit, diff --git a/contracts/src/CrossChainApplications/VerifiedBlockHash/BlockHashPublisher.sol b/contracts/src/CrossChainApplications/VerifiedBlockHash/BlockHashPublisher.sol index dc6fb9c94..88405ea00 100644 --- a/contracts/src/CrossChainApplications/VerifiedBlockHash/BlockHashPublisher.sol +++ b/contracts/src/CrossChainApplications/VerifiedBlockHash/BlockHashPublisher.sol @@ -64,7 +64,7 @@ contract BlockHashPublisher { destinationChainID: destinationChainID, destinationAddress: destinationAddress, feeInfo: TeleporterFeeInfo({ - contractAddress: address(0), + feeTokenAddress: address(0), amount: 0 }), requiredGasLimit: RECEIVE_BLOCK_HASH_REQUIRED_GAS_LIMIT, diff --git a/contracts/src/Teleporter/ITeleporterMessenger.sol b/contracts/src/Teleporter/ITeleporterMessenger.sol index cbc40df61..ea7faf58d 100644 --- a/contracts/src/Teleporter/ITeleporterMessenger.sol +++ b/contracts/src/Teleporter/ITeleporterMessenger.sol @@ -42,7 +42,7 @@ struct TeleporterMessage { // The contract address is the asset contract the fee will be paid in, and // the amount is the amount of that specified asset. struct TeleporterFeeInfo { - address contractAddress; + address feeTokenAddress; uint256 amount; } @@ -140,14 +140,14 @@ interface ITeleporterMessenger { * @dev Adds the additional fee amount to the amount to be paid to the relayer that delivers * the given message ID to the destination chain. * - * The fee contract address must be the same asset type as the fee asset specified in the original + * The fee token address must be the same asset type as the fee asset specified in the original * call to sendCrossChainMessage. Reverts if the message doesn't exist or there is already * receipt of delivery of the message. */ function addFeeAmount( bytes32 destinationChainID, uint256 messageID, - address feeContractAddress, + address feeTokenAddress, uint256 additionalFeeAmount ) external; @@ -194,7 +194,7 @@ interface ITeleporterMessenger { /** * @dev Sends any fee amount rewards for the given fee asset out to the caller. */ - function redeemRelayerRewards(address feeAsset) external; + function redeemRelayerRewards(address feeTokenAddress) external; /** * @dev Gets the hash of a given message stored in the EVM state, if the message exists. @@ -230,12 +230,12 @@ interface ITeleporterMessenger { */ function checkRelayerRewardAmount( address relayer, - address feeAsset + address feeTokenAddress ) external view returns (uint256); /** - * @dev Gets the fee asset and amount for a given message. - * @return The fee asset address and fee amount for a the given message. + * @dev Gets the fee token address and amount for a given message. + * @return The fee token address and fee amount for a the given message. */ function getFeeInfo( bytes32 destinationChainID, diff --git a/contracts/src/Teleporter/TeleporterMessenger.sol b/contracts/src/Teleporter/TeleporterMessenger.sol index dacf929c1..dfb8397dc 100644 --- a/contracts/src/Teleporter/TeleporterMessenger.sol +++ b/contracts/src/Teleporter/TeleporterMessenger.sol @@ -108,7 +108,7 @@ contract TeleporterMessenger is ITeleporterMessenger, ReentrancyGuards { * Requirements: * * - `message` must have been previously sent to the given `destinationChainID`. - * - `message` encoding mush match previously sent message. + * - `message` encoding must match previously sent message. */ function retrySendCrossChainMessage( bytes32 destinationChainID, @@ -153,12 +153,12 @@ contract TeleporterMessenger is ITeleporterMessenger, ReentrancyGuards { * * - `additionalFeeAmount` must be non-zero. * - `message` must exist and not have been delivered yet. - * - `feeContractAddress` must match the fee asset contract address used in the original call to `sendCrossChainMessage`. + * - `feeTokenAddress` must match the fee asset contract address used in the original call to `sendCrossChainMessage`. */ function addFeeAmount( bytes32 destinationChainID, uint256 messageID, - address feeContractAddress, + address feeTokenAddress, uint256 additionalFeeAmount ) external senderNonReentrant { // The additional fee amount must be non-zero. @@ -169,7 +169,7 @@ contract TeleporterMessenger is ITeleporterMessenger, ReentrancyGuards { // Do not allow adding a fee asset with contract address zero. require( - feeContractAddress != address(0), + feeTokenAddress != address(0), "TeleporterMessenger: zero fee asset contract address" ); @@ -190,13 +190,13 @@ contract TeleporterMessenger is ITeleporterMessenger, ReentrancyGuards { require( sentMessageInfo[destinationChainID][messageID] .feeInfo - .contractAddress == feeContractAddress, + .feeTokenAddress == feeTokenAddress, "TeleporterMessenger: invalid fee asset contract address" ); // Transfer the additional fee amount to this Teleporter instance. uint256 adjustedAmount = SafeERC20TransferFrom.safeTransferFrom( - IERC20(feeContractAddress), + IERC20(feeTokenAddress), additionalFeeAmount ); @@ -269,7 +269,7 @@ contract TeleporterMessenger is ITeleporterMessenger, ReentrancyGuards { "TeleporterMessenger: invalid destination chain ID" ); - // Check the message has not been delivered previously. + // Require that the message has not been delivered previously. require( !_messageReceived( warpMessage.sourceChainID, @@ -303,7 +303,7 @@ contract TeleporterMessenger is ITeleporterMessenger, ReentrancyGuards { // Process the receipts that were included in the teleporter message by paying the // fee for the messages are reward to the given relayers. uint256 length = teleporterMessage.receipts.length; - for (uint256 i = 0; i < length; ++i) { + for (uint256 i; i < length; ++i) { TeleporterMessageReceipt memory receipt = teleporterMessage .receipts[i]; _markReceipt( @@ -426,7 +426,7 @@ contract TeleporterMessenger is ITeleporterMessenger, ReentrancyGuards { memory receiptsToSend = new TeleporterMessageReceipt[]( messageIDs.length ); - for (uint256 i = 0; i < messageIDs.length; i++) { + for (uint256 i; i < messageIDs.length; ++i) { uint256 receivedMessageID = messageIDs[i]; // Get the relayer reward address for the message. address relayerRewardAddress = _relayerRewardAddresses[ @@ -530,7 +530,7 @@ contract TeleporterMessenger is ITeleporterMessenger, ReentrancyGuards { TeleporterFeeInfo memory feeInfo = sentMessageInfo[destinationChainID][ messageID ].feeInfo; - return (feeInfo.contractAddress, feeInfo.amount); + return (feeInfo.feeTokenAddress, feeInfo.amount); } /** @@ -583,7 +583,7 @@ contract TeleporterMessenger is ITeleporterMessenger, ReentrancyGuards { } // Otherwise, the deliverer address must be included in allowedRelayers. - for (uint256 i = 0; i < allowedRelayers.length; ++i) { + for (uint256 i; i < allowedRelayers.length; ++i) { if (allowedRelayers[i] == delivererAddress) { return true; } @@ -625,16 +625,16 @@ contract TeleporterMessenger is ITeleporterMessenger, ReentrancyGuards { // The fee is allowed to be 0 because it's possible for someone to run their own relayer and deliver their own messages, // which does not require further incentivization. They still must pay the transaction fee to submit the message, so // this is not a DOS vector in terms of being able to submit zero-fee messages. - uint256 adjustedFeeAmount = 0; + uint256 adjustedFeeAmount; if (messageInput.feeInfo.amount > 0) { // If the fee amount is non-zero, check that the contract address is not address(0) require( - messageInput.feeInfo.contractAddress != address(0), + messageInput.feeInfo.feeTokenAddress != address(0), "TeleporterMessenger: zero fee asset contract address" ); adjustedFeeAmount = SafeERC20TransferFrom.safeTransferFrom( - IERC20(messageInput.feeInfo.contractAddress), + IERC20(messageInput.feeInfo.feeTokenAddress), messageInput.feeInfo.amount ); } @@ -642,7 +642,7 @@ contract TeleporterMessenger is ITeleporterMessenger, ReentrancyGuards { // Store the fee asset and amount to be paid to the relayer of this message upon receiving the receipt. // Also store the message hash so that it can be retried until a receipt of its delivery is received back. TeleporterFeeInfo memory adjustedFeeInfo = TeleporterFeeInfo({ - contractAddress: messageInput.feeInfo.contractAddress, + feeTokenAddress: messageInput.feeInfo.feeTokenAddress, amount: adjustedFeeAmount }); sentMessageInfo[messageInput.destinationChainID][ @@ -666,7 +666,7 @@ contract TeleporterMessenger is ITeleporterMessenger, ReentrancyGuards { } /** - * @dev Records the receival of a receipt for a message previsouly sent to the `destinationChainID` with the given `messageID`. + * @dev Records the receival of a receipt for a message previously sent to the `destinationChainID` with the given `messageID`. * * Returns early if a receipt was already previously received for this message, or if the message never existed. Otherwise, deletes * the message information from `sentMessageInfo` and increments the reward redeemable by the specified relayer reward address. @@ -695,7 +695,7 @@ contract TeleporterMessenger is ITeleporterMessenger, ReentrancyGuards { // Increment the fee/reward amount owed to the relayer for having delivered // the message identified in this receipt. _relayerRewardAmounts[relayerRewardAddress][ - messageInfo.feeInfo.contractAddress + messageInfo.feeInfo.feeTokenAddress ] += messageInfo.feeInfo.amount; } @@ -704,7 +704,7 @@ contract TeleporterMessenger is ITeleporterMessenger, ReentrancyGuards { * * Only revert in the event that the message deliverer (relayer) did not provide enough gas to handle the execution * (including possibly storing a failed message in state). All execution specific errors (i.e. invalid call data, etc) - * that are not in the relayers control are caught and handled properly. + * that are not in the relayer's control are caught and handled properly. * * Emits a {MessageExecuted} event if the call on destination address is successful. * Emits a {MessageExecutionFailed} event if the call on destination address fails with formatted call data. @@ -752,7 +752,7 @@ contract TeleporterMessenger is ITeleporterMessenger, ReentrancyGuards { // If the execution failed, store a hash of the message in state such that its // execution can be retried again in the future with a higher gas limit (paid by whoever - // retries).Either way, the message will now be considered "delivered" since the relayer + // retries). Either way, the message will now be considered "delivered" since the relayer // provided enough gas to meet the required gas limit. if (!success) { _storeFailedMessageExecution(originChainID, message); @@ -771,7 +771,7 @@ contract TeleporterMessenger is ITeleporterMessenger, ReentrancyGuards { // // Assembly is used for the low-level call to avoid unnecessary expansion of the return data in memory. // This prevents possible "return bomb" vectors where the external contract could force the caller - // to use an arbitrary amount of gas. See Soldity issue here: https://github.com/ethereum/solidity/issues/12306 + // to use an arbitrary amount of gas. See Solidity issue here: https://github.com/ethereum/solidity/issues/12306 bool success; // solhint-disable-next-line no-inline-assembly assembly { diff --git a/contracts/src/Teleporter/tests/AddFeeAmountTests.t.sol b/contracts/src/Teleporter/tests/AddFeeAmountTests.t.sol index 0fa2924ac..6186d65c6 100644 --- a/contracts/src/Teleporter/tests/AddFeeAmountTests.t.sol +++ b/contracts/src/Teleporter/tests/AddFeeAmountTests.t.sol @@ -42,7 +42,7 @@ contract AddFeeAmountTest is TeleporterMessengerTest { DEFAULT_DESTINATION_CHAIN_ID, messageID, TeleporterFeeInfo({ - contractAddress: address(_mockFeeAsset), + feeTokenAddress: address(_mockFeeAsset), amount: totalFeeAmount }) ); diff --git a/contracts/src/Teleporter/tests/GetNextMessageIdTests.t.sol b/contracts/src/Teleporter/tests/GetNextMessageIdTests.t.sol index 36a7ec1a0..0dfa0fc31 100644 --- a/contracts/src/Teleporter/tests/GetNextMessageIdTests.t.sol +++ b/contracts/src/Teleporter/tests/GetNextMessageIdTests.t.sol @@ -37,7 +37,7 @@ contract GetNextMessageIDTest is TeleporterMessengerTest { destinationChainID: chainID, destinationAddress: address(0), feeInfo: TeleporterFeeInfo({ - contractAddress: address(0), + feeTokenAddress: address(0), amount: uint256(0) }), requiredGasLimit: 1e6, @@ -69,7 +69,7 @@ contract GetNextMessageIDTest is TeleporterMessengerTest { destinationChainID: chainID, destinationAddress: address(0), feeInfo: TeleporterFeeInfo({ - contractAddress: address(0), + feeTokenAddress: address(0), amount: uint256(0) }), requiredGasLimit: 1e6, diff --git a/contracts/src/Teleporter/tests/SendCrossChainMessageTests.t.sol b/contracts/src/Teleporter/tests/SendCrossChainMessageTests.t.sol index e7d7f8027..490c0b70c 100644 --- a/contracts/src/Teleporter/tests/SendCrossChainMessageTests.t.sol +++ b/contracts/src/Teleporter/tests/SendCrossChainMessageTests.t.sol @@ -118,7 +118,7 @@ contract SendCrossChainMessageTest is TeleporterMessengerTest { // Expect the ERC20 contract transferFrom method to be called to transfer the fee. vm.expectCall( - messageInput.feeInfo.contractAddress, + messageInput.feeInfo.feeTokenAddress, abi.encodeCall( IERC20.transferFrom, ( diff --git a/contracts/src/Teleporter/tests/SendSpecifiedReceiptsTests.t.sol b/contracts/src/Teleporter/tests/SendSpecifiedReceiptsTests.t.sol index b26f63d8b..247eee942 100644 --- a/contracts/src/Teleporter/tests/SendSpecifiedReceiptsTests.t.sol +++ b/contracts/src/Teleporter/tests/SendSpecifiedReceiptsTests.t.sol @@ -205,7 +205,7 @@ contract SendSpecifiedReceiptsTest is TeleporterMessengerTest { } TeleporterFeeInfo memory feeInfo = TeleporterFeeInfo({ - contractAddress: feeAddress, + feeTokenAddress: feeAddress, amount: feeAmount }); diff --git a/contracts/src/Teleporter/tests/TeleporterMessengerTest.t.sol b/contracts/src/Teleporter/tests/TeleporterMessengerTest.t.sol index cdbcd1edf..1b9ce1e74 100644 --- a/contracts/src/Teleporter/tests/TeleporterMessengerTest.t.sol +++ b/contracts/src/Teleporter/tests/TeleporterMessengerTest.t.sol @@ -129,7 +129,7 @@ contract TeleporterMessengerTest is Test { feeAsset = address(_mockFeeAsset); } TeleporterFeeInfo memory feeInfo = TeleporterFeeInfo({ - contractAddress: feeAsset, + feeTokenAddress: feeAsset, amount: feeAmount }); diff --git a/docker/Dockerfile b/docker/Dockerfile index c56917f75..11ddf3a92 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -11,6 +11,8 @@ ARG DEBIAN_FRONTEND=noninteractive # configured using either docker --build-arg flag or docker composer yaml service.build.args ARG ARCH=amd64 +ARG GO_VERSION + # defaults to grep running in a container. ENV grepcmd=grep @@ -24,8 +26,8 @@ RUN apt-get install -y wget curl git python3 make gcc build-essential # Install Golang RUN apt-get install -y bison -RUN wget https://go.dev/dl/go1.20.10.linux-${ARCH}.tar.gz -RUN rm -rf /usr/local/go && tar -C /usr/local -xzf go1.20.10.linux-${ARCH}.tar.gz +RUN wget https://go.dev/dl/go${GO_VERSION}.linux-${ARCH}.tar.gz +RUN rm -rf /usr/local/go && tar -C /usr/local -xzf go${GO_VERSION}.linux-${ARCH}.tar.gz ENV PATH $PATH:/usr/local/go/bin ENV GOPATH $HOME/go ENV GOROOT /usr/local/go diff --git a/docker/docker-compose-run-local-template.yml b/docker/docker-compose-run-local-template.yml index db3dc38d6..880743230 100644 --- a/docker/docker-compose-run-local-template.yml +++ b/docker/docker-compose-run-local-template.yml @@ -9,6 +9,7 @@ services: dockerfile: ./docker/Dockerfile args: ARCH: ${ARCH} # set by run.sh + GO_VERSION: ${GO_VERSION} # set by run.sh container_name: local_network_run init: true working_dir: /code diff --git a/docker/docker-compose-run.yml b/docker/docker-compose-run.yml index 87dd099d4..a16b4857e 100644 --- a/docker/docker-compose-run.yml +++ b/docker/docker-compose-run.yml @@ -9,6 +9,7 @@ services: dockerfile: ./docker/Dockerfile args: ARCH: ${ARCH} # set by run.sh + GO_VERSION: ${GO_VERSION} # set by run.sh container_name: local_network_run init: true working_dir: /code diff --git a/docker/docker-compose-test-local-template.yml b/docker/docker-compose-test-local-template.yml index 39ced67c6..c3119c394 100644 --- a/docker/docker-compose-test-local-template.yml +++ b/docker/docker-compose-test-local-template.yml @@ -10,6 +10,7 @@ services: dockerfile: ./docker/Dockerfile args: ARCH: ${ARCH} # set by test.sh + GO_VERSION: ${GO_VERSION} # set by test.sh container_name: local_network_test init: true working_dir: /code @@ -38,6 +39,7 @@ services: dockerfile: ./docker/Dockerfile args: ARCH: ${ARCH} # set by test.sh + GO_VERSION: ${GO_VERSION} # set by test.sh container_name: test_runner init: true working_dir: /code diff --git a/docker/docker-compose-test.yml b/docker/docker-compose-test.yml index ca8becfc8..a4c65fdb3 100644 --- a/docker/docker-compose-test.yml +++ b/docker/docker-compose-test.yml @@ -10,6 +10,7 @@ services: dockerfile: ./docker/Dockerfile args: ARCH: ${ARCH} # set by test.sh + GO_VERSION: ${GO_VERSION} # set by test.sh container_name: local_network_test init: true working_dir: /code @@ -37,6 +38,7 @@ services: dockerfile: ./docker/Dockerfile args: ARCH: ${ARCH} # set by test.sh + GO_VERSION: ${GO_VERSION} # set by test.sh container_name: test_runner init: true working_dir: /code diff --git a/go.mod b/go.mod index 1b07ef4f4..a4e2fcb51 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,6 @@ module github.com/ava-labs/teleporter +// Patch version for go is set in versions.sh go 1.20 require ( diff --git a/scripts/abi_bindings.sh b/scripts/abi_bindings.sh index 477e9e17a..f9155a809 100755 --- a/scripts/abi_bindings.sh +++ b/scripts/abi_bindings.sh @@ -11,6 +11,7 @@ TELEPORTER_PATH=$( source $TELEPORTER_PATH/scripts/constants.sh source $TELEPORTER_PATH/scripts/utils.sh +source $TELEPORTER_PATH/scripts/versions.sh setARCH diff --git a/scripts/local/run.sh b/scripts/local/run.sh index 648ff9a7e..d0ba1d77d 100755 --- a/scripts/local/run.sh +++ b/scripts/local/run.sh @@ -5,6 +5,7 @@ set -e # Stop on first error source ./scripts/utils.sh +source ./scripts/versions.sh LOCAL_RELAYER_IMAGE= RUN_STOP_FLAG="-c" diff --git a/scripts/local/test.sh b/scripts/local/test.sh index 39658c9d6..4048e329a 100755 --- a/scripts/local/test.sh +++ b/scripts/local/test.sh @@ -4,6 +4,7 @@ set -e # Stop on first error source ./scripts/utils.sh +source ./scripts/versions.sh TEST_TARGET= LOCAL_RELAYER_IMAGE= diff --git a/scripts/versions.sh b/scripts/versions.sh index 50cc1c28c..a5be5e19f 100755 --- a/scripts/versions.sh +++ b/scripts/versions.sh @@ -2,9 +2,29 @@ # Copyright (C) 2023, Ava Labs, Inc. All rights reserved. # See the file LICENSE for licensing terms. -# Set up the versions to be used -AWM_RELAYER_VERSION=${AWM_RELAYER_VERSION:-'v0.2.4'} -SUBNET_EVM_VERSION=${SUBNET_EVM_VERSION:-'v0.5.8'} +set -e +set -o pipefail + +# The go version for this project is set from a combination of major.minor from go.mod and the patch version set here. +GO_PATCH_VERSION=10 + +TELEPORTER_PATH=$( + cd "$(dirname "${BASH_SOURCE[0]}")" + cd .. && pwd +) + +# Pass in the full name of the dependency. +# Parses go.mod for a matching entry and extracts the version number. +function getDepVersion() { + grep -m1 "^\s*$1" $TELEPORTER_PATH/go.mod | cut -d ' ' -f2 +} + +# AWM_RELAYER_VERSION is needed for the docker run setup, but is not a go module dependency. +AWM_RELAYER_VERSION=${AWM_RELAYER_VERSION:-'v0.2.3'} + +# This needs to be exported to be picked up by the dockerfile. +export GO_VERSION=${GO_VERSION:-$(getDepVersion go).$GO_PATCH_VERSION} + # Don't export them as they're used in the context of other calls -AVALANCHE_VERSION=${AVALANCHE_VERSION:-'v1.10.14'} -GINKGO_VERSION=${GINKGO_VERSION:-'v2.2.0'} +AVALANCHE_VERSION=${AVALANCHE_VERSION:-$(getDepVersion github.com/ava-labs/avalanchego)} +GINKGO_VERSION=${GINKGO_VERSION:-$(getDepVersion github.com/onsi/ginkgo/v2)} diff --git a/tests/basic_one_way_send.go b/tests/basic_one_way_send.go index 39c136894..c35e42b91 100644 --- a/tests/basic_one_way_send.go +++ b/tests/basic_one_way_send.go @@ -36,7 +36,7 @@ func BasicOneWaySend() { DestinationChainID: subnetBInfo.BlockchainID, DestinationAddress: fundedAddress, FeeInfo: teleportermessenger.TeleporterFeeInfo{ - ContractAddress: fundedAddress, + FeeTokenAddress: fundedAddress, Amount: big.NewInt(0), }, RequiredGasLimit: big.NewInt(1),