diff --git a/.github/workflows/abi_go_bindings_checker.yml b/.github/workflows/abi_bindings_checker.yml similarity index 66% rename from .github/workflows/abi_go_bindings_checker.yml rename to .github/workflows/abi_bindings_checker.yml index 3eece84ba..ed1d721e5 100644 --- a/.github/workflows/abi_go_bindings_checker.yml +++ b/.github/workflows/abi_bindings_checker.yml @@ -36,7 +36,26 @@ jobs: export GOPATH=$HOME/go export PATH="$PATH:$BASE_DIR/.foundry/bin" export PATH="$PATH:$GOPATH/bin" - ./scripts/abi_go_bindings.sh + ./scripts/abi_bindings.sh - name: Check for clean branch run: .github/workflows/check_clean_branch.sh + unit_tests: + name: Unit tests + 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: Run ABI Binding Unit Tests + run: | + cd abi-bindings/go + go test ./... diff --git a/abi-bindings/README.md b/abi-bindings/README.md new file mode 100644 index 000000000..a38697b47 --- /dev/null +++ b/abi-bindings/README.md @@ -0,0 +1,3 @@ +## ABI Bindings + +This directory contains ABI bindings for the Solidity contracts in the `contracts/src/CrossChainApplications` and `contracts/src/Teleporter` directories. The files with the same name as the Solidity source files are automatically generated by the `scripts/abi_bindings.sh` script. Other files in this directory (such as the packing utilities) are manually created and maintained. \ No newline at end of file diff --git a/abi-bindings/CrossChainApplications/ERC20Bridge/BridgeToken/BridgeToken.go b/abi-bindings/go/CrossChainApplications/ERC20Bridge/BridgeToken/BridgeToken.go similarity index 100% rename from abi-bindings/CrossChainApplications/ERC20Bridge/BridgeToken/BridgeToken.go rename to abi-bindings/go/CrossChainApplications/ERC20Bridge/BridgeToken/BridgeToken.go diff --git a/abi-bindings/CrossChainApplications/ERC20Bridge/ERC20Bridge/ERC20Bridge.go b/abi-bindings/go/CrossChainApplications/ERC20Bridge/ERC20Bridge/ERC20Bridge.go similarity index 100% rename from abi-bindings/CrossChainApplications/ERC20Bridge/ERC20Bridge/ERC20Bridge.go rename to abi-bindings/go/CrossChainApplications/ERC20Bridge/ERC20Bridge/ERC20Bridge.go diff --git a/abi-bindings/CrossChainApplications/ExampleMessenger/ExampleCrossChainMessenger/ExampleCrossChainMessenger.go b/abi-bindings/go/CrossChainApplications/ExampleMessenger/ExampleCrossChainMessenger/ExampleCrossChainMessenger.go similarity index 100% rename from abi-bindings/CrossChainApplications/ExampleMessenger/ExampleCrossChainMessenger/ExampleCrossChainMessenger.go rename to abi-bindings/go/CrossChainApplications/ExampleMessenger/ExampleCrossChainMessenger/ExampleCrossChainMessenger.go diff --git a/abi-bindings/CrossChainApplications/VerifiedBlockHash/BlockHashPublisher/BlockHashPublisher.go b/abi-bindings/go/CrossChainApplications/VerifiedBlockHash/BlockHashPublisher/BlockHashPublisher.go similarity index 100% rename from abi-bindings/CrossChainApplications/VerifiedBlockHash/BlockHashPublisher/BlockHashPublisher.go rename to abi-bindings/go/CrossChainApplications/VerifiedBlockHash/BlockHashPublisher/BlockHashPublisher.go diff --git a/abi-bindings/CrossChainApplications/VerifiedBlockHash/BlockHashReceiver/BlockHashReceiver.go b/abi-bindings/go/CrossChainApplications/VerifiedBlockHash/BlockHashReceiver/BlockHashReceiver.go similarity index 100% rename from abi-bindings/CrossChainApplications/VerifiedBlockHash/BlockHashReceiver/BlockHashReceiver.go rename to abi-bindings/go/CrossChainApplications/VerifiedBlockHash/BlockHashReceiver/BlockHashReceiver.go diff --git a/abi-bindings/Teleporter/TeleporterMessenger/TeleporterMessenger.go b/abi-bindings/go/Teleporter/TeleporterMessenger/TeleporterMessenger.go similarity index 100% rename from abi-bindings/Teleporter/TeleporterMessenger/TeleporterMessenger.go rename to abi-bindings/go/Teleporter/TeleporterMessenger/TeleporterMessenger.go diff --git a/abi-bindings/go/Teleporter/TeleporterMessenger/packing.go b/abi-bindings/go/Teleporter/TeleporterMessenger/packing.go new file mode 100644 index 000000000..018811ad2 --- /dev/null +++ b/abi-bindings/go/Teleporter/TeleporterMessenger/packing.go @@ -0,0 +1,119 @@ +package teleportermessenger + +import ( + "fmt" + "math/big" + + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/subnet-evm/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/pkg/errors" +) + +var teleporterMessageType abi.Type + +func init() { + // Create an ABI binding for TeleporterMessage, defined in ITeleporterMessenger.sol + // abigen does not support ABI bindings for standalone structs, only methods and events, + // so we must manually keep this up-to-date with the struct defined in the contract. + var err error + teleporterMessageType, err = abi.NewType("tuple", "struct Overloader.F", []abi.ArgumentMarshaling{ + {Name: "messageID", Type: "uint256"}, + {Name: "senderAddress", Type: "address"}, + {Name: "destinationAddress", Type: "address"}, + {Name: "requiredGasLimit", Type: "uint256"}, + {Name: "allowedRelayerAddresses", Type: "address[]"}, + {Name: "receipts", Type: "tuple[]", Components: []abi.ArgumentMarshaling{ + {Name: "receivedMessageID", Type: "uint256"}, + {Name: "relayerRewardAddress", Type: "address"}, + }}, + {Name: "message", Type: "bytes"}, + }) + if err != nil { + panic(fmt.Sprintf("failed to create TeleporterMessage ABI type: %v", err)) + } +} + +func UnpackTeleporterMessage(messageBytes []byte) (*TeleporterMessage, error) { + args := abi.Arguments{ + { + Name: "teleporterMessage", + Type: teleporterMessageType, + }, + } + unpacked, err := args.Unpack(messageBytes) + if err != nil { + return nil, fmt.Errorf("failed to unpack to teleporter message with err: %v", err) + } + type teleporterMessageArg struct { + TeleporterMessage TeleporterMessage `json:"teleporterMessage"` + } + var teleporterMessage teleporterMessageArg + err = args.Copy(&teleporterMessage, unpacked) + if err != nil { + return nil, err + } + return &teleporterMessage.TeleporterMessage, nil +} + +func PackSendCrossChainMessage(input TeleporterMessageInput) ([]byte, error) { + abi, err := TeleporterMessengerMetaData.GetAbi() + if err != nil { + return nil, errors.Wrap(err, "failed to get abi") + } + + return abi.Pack("sendCrossChainMessage", input) +} + +// PackReceiveCrossChainMessage packs a ReceiveCrossChainMessageInput to form a call to the receiveCrossChainMessage function +func PackReceiveCrossChainMessage(messageIndex uint32, relayerRewardAddress common.Address) ([]byte, error) { + abi, err := TeleporterMessengerMetaData.GetAbi() + if err != nil { + return nil, errors.Wrap(err, "failed to get abi") + } + + return abi.Pack("receiveCrossChainMessage", messageIndex, relayerRewardAddress) +} + +// PackMessageReceived packs a MessageReceivedInput to form a call to the messageReceived function +func PackMessageReceived(originChainID ids.ID, messageID *big.Int) ([]byte, error) { + abi, err := TeleporterMessengerMetaData.GetAbi() + if err != nil { + return nil, errors.Wrap(err, "failed to get abi") + } + return abi.Pack("messageReceived", originChainID, messageID) +} + +// UnpackMessageReceivedResult attempts to unpack result bytes to a bool indicating whether the message was received +func UnpackMessageReceivedResult(result []byte) (bool, error) { + abi, err := TeleporterMessengerMetaData.GetAbi() + if err != nil { + return false, errors.Wrap(err, "failed to get abi") + } + + var success bool + err = abi.UnpackIntoInterface(&success, "messageReceived", result) + return success, err +} + +func PackMessageReceivedOutput(success bool) ([]byte, error) { + abi, err := TeleporterMessengerMetaData.GetAbi() + if err != nil { + return nil, errors.Wrap(err, "failed to get abi") + } + + return abi.PackOutput("messageReceived", success) +} + +// CAUTION: PackEvent is documented as not supporting struct types, so this should only be used for testing purposes. +// In a real setting, the Teleporter contract should pack the event. +// PackSendCrossChainMessageEvent packs the SendCrossChainMessage event type. +func PackSendCrossChainMessageEvent(destinationChainID common.Hash, message TeleporterMessage, feeInfo TeleporterFeeInfo) ([]byte, error) { + abi, err := TeleporterMessengerMetaData.GetAbi() + if err != nil { + return nil, errors.Wrap(err, "failed to get abi") + } + + _, hashes, err := abi.PackEvent("SendCrossChainMessage", destinationChainID, message.MessageID, message, feeInfo) + return hashes, err +} diff --git a/abi-bindings/go/Teleporter/TeleporterMessenger/packing_test.go b/abi-bindings/go/Teleporter/TeleporterMessenger/packing_test.go new file mode 100644 index 000000000..81766bb07 --- /dev/null +++ b/abi-bindings/go/Teleporter/TeleporterMessenger/packing_test.go @@ -0,0 +1,66 @@ +// Copyright (C) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package teleportermessenger + +import ( + "bytes" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +func createTestTeleporterMessage(messageID int64) TeleporterMessage { + m := TeleporterMessage{ + MessageID: big.NewInt(messageID), + SenderAddress: common.HexToAddress("0x0123456789abcdef0123456789abcdef01234567"), + DestinationAddress: common.HexToAddress("0x0123456789abcdef0123456789abcdef01234567"), + RequiredGasLimit: big.NewInt(2), + AllowedRelayerAddresses: []common.Address{ + common.HexToAddress("0x0123456789abcdef0123456789abcdef01234567"), + }, + Receipts: []TeleporterMessageReceipt{ + { + ReceivedMessageID: big.NewInt(1), + RelayerRewardAddress: common.HexToAddress("0x0123456789abcdef0123456789abcdef01234567"), + }, + }, + Message: []byte{1, 2, 3, 4}, + } + return m +} + +func TestPackUnpackTeleporterMessage(t *testing.T) { + var ( + messageID int64 = 4 + ) + message := createTestTeleporterMessage(messageID) + + b, err := PackSendCrossChainMessageEvent(common.HexToHash("0x03"), message, TeleporterFeeInfo{ + ContractAddress: common.HexToAddress("0x0123456789abcdef0123456789abcdef01234567"), + Amount: big.NewInt(1), + }) + if err != nil { + t.Errorf("failed to pack teleporter message: %v", err) + t.FailNow() + } + + unpacked, err := UnpackTeleporterMessage(b) + if err != nil { + t.Errorf("failed to unpack teleporter message: %v", err) + t.FailNow() + } + + for i := 0; i < len(message.AllowedRelayerAddresses); i++ { + require.Equal(t, unpacked.AllowedRelayerAddresses[i], message.AllowedRelayerAddresses[i]) + } + + for i := 0; i < len(message.Receipts); i++ { + require.Equal(t, message.Receipts[i].ReceivedMessageID, unpacked.Receipts[i].ReceivedMessageID) + require.Equal(t, message.Receipts[i].RelayerRewardAddress, unpacked.Receipts[i].RelayerRewardAddress) + } + + require.True(t, bytes.Equal(message.Message, unpacked.Message)) +} diff --git a/docker/run_setup.sh b/docker/run_setup.sh index 8950c27a9..02844aa55 100755 --- a/docker/run_setup.sh +++ b/docker/run_setup.sh @@ -94,7 +94,7 @@ if [ ! -e $dir_prefix/NETWORK_RUNNING ]; then cd contracts forge build cd .. - go run contract-deployment/contractDeploymentTools.go constructKeylessTx contracts/out/TeleporterMessenger.sol/TeleporterMessenger.json + go run utils/contract-deployment/contractDeploymentTools.go constructKeylessTx contracts/out/TeleporterMessenger.sol/TeleporterMessenger.json teleporter_deploy_address=$(cat UniversalTeleporterDeployerAddress.txt) teleporter_deploy_tx=$(cat UniversalTeleporterDeployerTransaction.txt) teleporter_contract_address=$(cat UniversalTeleporterMessengerContractAddress.txt) diff --git a/go.mod b/go.mod index 7d767b8fc..5b50d28e8 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,6 @@ require ( require ( github.com/ava-labs/avalanche-network-runner v1.7.2 - github.com/ava-labs/awm-relayer v0.2.2 github.com/ava-labs/subnet-evm v0.5.6 github.com/ethereum/go-ethereum v1.12.0 github.com/onsi/ginkgo/v2 v2.13.0 diff --git a/go.sum b/go.sum index 8a05f6d5f..ef69c8b66 100644 --- a/go.sum +++ b/go.sum @@ -63,8 +63,6 @@ github.com/ava-labs/avalanche-network-runner v1.7.2 h1:XFad/wZfYzDnqbLzPAPPRYU3a github.com/ava-labs/avalanche-network-runner v1.7.2/go.mod h1:naLveusSrP7YgTAqRykD1SyLOAUilCp9jGjk3MDxoPI= github.com/ava-labs/avalanchego v1.10.10 h1:EYX4LVotcfdtIQ0nJSBTcoisubx/Bzk2tM1aP3yiYiw= github.com/ava-labs/avalanchego v1.10.10/go.mod h1:6UA0nxxTvvpyuCbP2DSzx9+7uWQfQx9DPApK8JptLiE= -github.com/ava-labs/awm-relayer v0.2.2 h1:TW/cJr13bVMHL5NjBF9aTTJQTyjpwbRMH6ffX78DFmo= -github.com/ava-labs/awm-relayer v0.2.2/go.mod h1:UIc0Nl/ZIRVm5fBmUWDxWahNsQWZoSfJb3ei25q5ZlQ= github.com/ava-labs/coreth v0.12.5-rc.6 h1:OajGUyKkO5Q82XSuMa8T5UD6QywtCHUiZ4Tv3RFmRBU= github.com/ava-labs/coreth v0.12.5-rc.6/go.mod h1:s5wVyy+5UCCk2m0Tq3jVmy0UqOpKBDYqRE13gInCJVs= github.com/ava-labs/subnet-evm v0.5.6 h1:u+xBvEExOa362Up02hgSgeF+aqDona57whhRIeEIim8= diff --git a/scripts/abi_go_bindings.sh b/scripts/abi_bindings.sh similarity index 91% rename from scripts/abi_go_bindings.sh rename to scripts/abi_bindings.sh index e69f0ab9e..cfaaa6138 100755 --- a/scripts/abi_go_bindings.sh +++ b/scripts/abi_bindings.sh @@ -26,7 +26,7 @@ while [ $# -gt 0 ]; do done if [ "$HELP" = true ]; then - echo "Usage: ./scripts/abi_go_bindings.sh [OPTIONS]" + echo "Usage: ./scripts/abi_bindings.sh [OPTIONS]" echo "Build contracts and generate Go bindings" echo "" echo "Options:" @@ -71,11 +71,12 @@ do fi echo "Generating Go bindings for $contract_name..." - mkdir -p $TELEPORTER_PATH/abi-bindings/$dir/$contract_name + gen_path=$TELEPORTER_PATH/abi-bindings/go/$dir/$contract_name + mkdir -p $gen_path $GOPATH/bin/abigen --abi $abi_file \ --pkg $(convertToLower $contract_name) \ --type $contract_name \ - --out $TELEPORTER_PATH/abi-bindings/$dir/$contract_name/$contract_name.go + --out $gen_path/$contract_name.go echo "Done generating Go bindings for $contract_name." done diff --git a/tests/basic_one_way_send.go b/tests/basic_one_way_send.go index 496f94b0b..1f727e81d 100644 --- a/tests/basic_one_way_send.go +++ b/tests/basic_one_way_send.go @@ -4,9 +4,8 @@ import ( "context" "math/big" - "github.com/ava-labs/awm-relayer/messages/teleporter" "github.com/ava-labs/subnet-evm/interfaces" - teleportermessenger "github.com/ava-labs/teleporter/abi-bindings/Teleporter/TeleporterMessenger" + teleportermessenger "github.com/ava-labs/teleporter/abi-bindings/go/Teleporter/TeleporterMessenger" "github.com/ava-labs/teleporter/tests/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" @@ -33,10 +32,10 @@ func BasicOneWaySend() { // ctx := context.Background() - sendCrossChainMessageInput := utils.SendCrossChainMessageInput{ + sendCrossChainMessageInput := teleportermessenger.TeleporterMessageInput{ DestinationChainID: subnetBInfo.BlockchainID, DestinationAddress: fundedAddress, - FeeInfo: utils.FeeInfo{ + FeeInfo: teleportermessenger.TeleporterFeeInfo{ ContractAddress: fundedAddress, Amount: big.NewInt(0), }, @@ -66,10 +65,7 @@ func BasicOneWaySend() { // // Check Teleporter message received on the destination // - data, err := teleporter.PackMessageReceived(teleporter.MessageReceivedInput{ - OriginChainID: subnetAInfo.BlockchainID, - MessageID: teleporterMessageID, - }) + data, err := teleportermessenger.PackMessageReceived(subnetAInfo.BlockchainID, teleporterMessageID) Expect(err).Should(BeNil()) callMessage := interfaces.CallMsg{ To: &teleporterContractAddress, @@ -79,7 +75,7 @@ func BasicOneWaySend() { Expect(err).Should(BeNil()) // check the contract call result - delivered, err := teleporter.UnpackMessageReceivedResult(result) + delivered, err := teleportermessenger.UnpackMessageReceivedResult(result) Expect(err).Should(BeNil()) Expect(delivered).Should(BeTrue()) } diff --git a/tests/e2e_test.go b/tests/e2e_test.go index fde110e1e..79730c7e5 100644 --- a/tests/e2e_test.go +++ b/tests/e2e_test.go @@ -7,8 +7,8 @@ import ( "os" "testing" - deploymentUtils "github.com/ava-labs/teleporter/contract-deployment/utils" testUtils "github.com/ava-labs/teleporter/tests/utils" + deploymentUtils "github.com/ava-labs/teleporter/utils/deployment-utils" "github.com/ethereum/go-ethereum/log" "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" diff --git a/tests/utils/network_setup.go b/tests/utils/network_setup.go index 1ee6b16f3..2c1594649 100644 --- a/tests/utils/network_setup.go +++ b/tests/utils/network_setup.go @@ -9,12 +9,12 @@ import ( "github.com/ava-labs/avalanche-network-runner/rpcpb" "github.com/ava-labs/avalanchego/ids" - relayerEvm "github.com/ava-labs/awm-relayer/vms/evm" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/ethclient" "github.com/ava-labs/subnet-evm/plugin/evm" "github.com/ava-labs/subnet-evm/rpc" "github.com/ava-labs/subnet-evm/tests/utils/runner" + gasUtils "github.com/ava-labs/teleporter/utils/gas-utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" @@ -222,8 +222,8 @@ func DeployTeleporterContracts(transactionBytes []byte, deployerAddress common.A Expect(err).Should(BeNil()) baseFee, err := client.EstimateBaseFee(context.Background()) Expect(err).Should(BeNil()) - gasFeeCap := baseFee.Mul(baseFee, big.NewInt(relayerEvm.BaseFeeFactor)) - gasFeeCap.Add(gasFeeCap, big.NewInt(relayerEvm.MaxPriorityFeePerGas)) + gasFeeCap := baseFee.Mul(baseFee, big.NewInt(gasUtils.BaseFeeFactor)) + gasFeeCap.Add(gasFeeCap, big.NewInt(gasUtils.MaxPriorityFeePerGas)) // Fund the deployer address { value := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(10)) // 10eth diff --git a/tests/utils/utils.go b/tests/utils/utils.go index 6f9f5a366..6cd01f002 100644 --- a/tests/utils/utils.go +++ b/tests/utils/utils.go @@ -15,9 +15,9 @@ import ( "github.com/ava-labs/avalanchego/ids" avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" warpBackend "github.com/ava-labs/subnet-evm/warp" - teleportermessenger "github.com/ava-labs/teleporter/abi-bindings/Teleporter/TeleporterMessenger" + teleportermessenger "github.com/ava-labs/teleporter/abi-bindings/go/Teleporter/TeleporterMessenger" + gasUtils "github.com/ava-labs/teleporter/utils/gas-utils" - "github.com/ava-labs/awm-relayer/messages/teleporter" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/ethclient" "github.com/ava-labs/subnet-evm/interfaces" @@ -39,33 +39,6 @@ var ( DefaultTeleporterTransactionValue = common.Big0 ) -type SendCrossChainMessageEvent struct { - DestinationChainID ids.ID - MessageID *big.Int - Message teleporter.TeleporterMessage -} - -type ReceiveCrossChainMessageEvent struct { - OriginChainID ids.ID - MessageID *big.Int - Message teleporter.TeleporterMessage -} - -// Teleporter contract sendCrossChainMessage input type -type SendCrossChainMessageInput struct { - DestinationChainID ids.ID - DestinationAddress common.Address - FeeInfo FeeInfo - RequiredGasLimit *big.Int - Message []byte - AllowedRelayerAddresses []common.Address -} - -type FeeInfo struct { - ContractAddress common.Address - Amount *big.Int -} - // // Test utility functions // @@ -132,15 +105,12 @@ func GetURIHostAndPort(uri string) (string, uint32, error) { func CreateSendCrossChainMessageTransaction( ctx context.Context, source SubnetTestInfo, - input SendCrossChainMessageInput, + input teleportermessenger.TeleporterMessageInput, fundedAddress common.Address, fundedKey *ecdsa.PrivateKey, teleporterContractAddress common.Address, ) *types.Transaction { - data, err := teleporter.EVMTeleporterContractABI.Pack( - "sendCrossChainMessage", - input, - ) + data, err := teleportermessenger.PackSendCrossChainMessage(input) Expect(err).Should(BeNil()) gasFeeCap, gasTipCap, nonce := calculateTxParams(ctx, source.ChainWSClient, fundedAddress) @@ -180,13 +150,10 @@ func CreateReceiveCrossChainMessageTransaction( numSigners, err := signedMessage.Signature.NumSigners() Expect(err).Should(BeNil()) - gasLimit, err := teleporter.CalculateReceiveMessageGasLimit(numSigners, requiredGasLimit) + gasLimit, err := gasUtils.CalculateReceiveMessageGasLimit(numSigners, requiredGasLimit) Expect(err).Should(BeNil()) - callData, err := teleporter.PackReceiveCrossChainMessage(teleporter.ReceiveCrossChainMessageInput{ - MessageIndex: 0, - RelayerRewardAddress: fundedAddress, - }) + callData, err := teleportermessenger.PackReceiveCrossChainMessage(0, fundedAddress) Expect(err).Should(BeNil()) gasFeeCap, gasTipCap, nonce := calculateTxParams(ctx, wsClient, fundedAddress) diff --git a/contract-deployment/README.md b/utils/contract-deployment/README.md similarity index 100% rename from contract-deployment/README.md rename to utils/contract-deployment/README.md diff --git a/contract-deployment/contractDeploymentTools.go b/utils/contract-deployment/contractDeploymentTools.go similarity index 95% rename from contract-deployment/contractDeploymentTools.go rename to utils/contract-deployment/contractDeploymentTools.go index 7a21eef6c..bf7fbe26e 100644 --- a/contract-deployment/contractDeploymentTools.go +++ b/utils/contract-deployment/contractDeploymentTools.go @@ -9,7 +9,7 @@ import ( "os" "strconv" - deploymentUtils "github.com/ava-labs/teleporter/contract-deployment/utils" + deploymentUtils "github.com/ava-labs/teleporter/utils/deployment-utils" "github.com/ethereum/go-ethereum/common" ) diff --git a/contract-deployment/utils/deployment_utils.go b/utils/deployment-utils/deployment_utils.go similarity index 100% rename from contract-deployment/utils/deployment_utils.go rename to utils/deployment-utils/deployment_utils.go diff --git a/utils/gas-utils/gas_utils.go b/utils/gas-utils/gas_utils.go new file mode 100644 index 000000000..f2bd6b49d --- /dev/null +++ b/utils/gas-utils/gas_utils.go @@ -0,0 +1,46 @@ +package utils + +import ( + "errors" + "math/big" + + "github.com/ava-labs/avalanchego/utils/math" +) + +const ( + ReceiveCrossChainMessageStaticGasCost uint64 = 2_000_000 + ReceiveCrossChainMessageGasCostPerAggregatedKey uint64 = 1_000 + ReceiveMessageGasLimitBufferAmount uint64 = 100_000 + + BaseFeeFactor = 2 + MaxPriorityFeePerGas = 2500000000 // 2.5 gwei +) + +// CalculateReceiveMessageGasLimit calculates the estimated gas amount used by a single call +// to receiveCrossChainMessage for the given message and validator bit vector. The result amount +// depends on the required limit for the message execution, the number of validator signatures +// included in the aggregate signature, the static gas cost defined by the precompile, and an +// extra buffer amount defined here to ensure the call doesn't run out of gas. +func CalculateReceiveMessageGasLimit(numSigners int, executionRequiredGasLimit *big.Int) (uint64, error) { + if !executionRequiredGasLimit.IsUint64() { + return 0, errors.New("required gas limit too high") + } + + gasAmounts := []uint64{ + executionRequiredGasLimit.Uint64(), + ReceiveCrossChainMessageStaticGasCost, + uint64(numSigners) * ReceiveCrossChainMessageGasCostPerAggregatedKey, + ReceiveMessageGasLimitBufferAmount, + } + + res := gasAmounts[0] + var err error + for i := 1; i < len(gasAmounts); i++ { + res, err = math.Add64(res, gasAmounts[i]) + if err != nil { + return 0, err + } + } + + return res, nil +}