diff --git a/.github/workflows/abi_bindings_checker.yml b/.github/workflows/abi_bindings_checker.yml index 99604edb6..bc65c93a7 100644 --- a/.github/workflows/abi_bindings_checker.yml +++ b/.github/workflows/abi_bindings_checker.yml @@ -30,7 +30,7 @@ jobs: - name: Install solc run: | source ./scripts/versions.sh - wget https://github.com/ethereum/solidity/releases/download/v$SOLIDITY_VERSION/solc-static-linux + wget https://github.com/ethereum/solidity/releases/download/v$AVALANCHE_SOLIDITY_VERSION/solc-static-linux chmod +x solc-static-linux sudo mv solc-static-linux /usr/local/bin/solc diff --git a/.gitmodules b/.gitmodules index 79d879e32..1642167f3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,10 +1,13 @@ -[submodule "lib/forge-std"] +[submodule "avalanche/lib/forge-std"] branch = v1 - path = lib/forge-std + path = avalanche/lib/forge-std url = https://github.com/foundry-rs/forge-std -[submodule "lib/openzeppelin-contracts-upgradeable"] - path = lib/openzeppelin-contracts-upgradeable +[submodule "avalanche/lib/openzeppelin-contracts-upgradeable"] + path = avalanche/lib/openzeppelin-contracts-upgradeable url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable -[submodule "lib/subnet-evm"] - path = lib/subnet-evm +[submodule "avalanche/lib/subnet-evm"] + path = avalanche/lib/subnet-evm url = https://github.com/ava-labs/subnet-evm +[submodule "ethereum/lib/forge-std"] + path = ethereum/lib/forge-std + url = https://github.com/foundry-rs/forge-std diff --git a/abi-bindings/go/AvalancheValidatorSetRegistry/AvalancheValidatorSetRegistry.go b/abi-bindings/go/AvalancheValidatorSetRegistry/AvalancheValidatorSetRegistry.go new file mode 100644 index 000000000..ae2c4cb12 --- /dev/null +++ b/abi-bindings/go/AvalancheValidatorSetRegistry/AvalancheValidatorSetRegistry.go @@ -0,0 +1,865 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package avalanchevalidatorsetregistry + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ava-labs/libevm" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/types" + "github.com/ava-labs/libevm/event" + "github.com/ava-labs/subnet-evm/accounts/abi" + "github.com/ava-labs/subnet-evm/accounts/abi/bind" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// ICMMessage is an auto generated low-level Go binding around an user-defined struct. +type ICMMessage struct { + UnsignedMessage ICMUnsignedMessage + UnsignedMessageBytes []byte + Signature ICMSignature +} + +// ICMSignature is an auto generated low-level Go binding around an user-defined struct. +type ICMSignature struct { + Signers []byte + Signature []byte +} + +// ICMUnsignedMessage is an auto generated low-level Go binding around an user-defined struct. +type ICMUnsignedMessage struct { + AvalancheNetworkID uint32 + AvalancheSourceBlockchainID [32]byte + Payload []byte +} + +// Validator is an auto generated low-level Go binding around an user-defined struct. +type Validator struct { + BlsPublicKey []byte + Weight uint64 +} + +// ValidatorSet is an auto generated low-level Go binding around an user-defined struct. +type ValidatorSet struct { + AvalancheBlockchainID [32]byte + Validators []Validator + TotalWeight uint64 + PChainHeight uint64 + PChainTimestamp uint64 +} + +// AvalancheValidatorSetRegistryMetaData contains all meta data concerning the AvalancheValidatorSetRegistry contract. +var AvalancheValidatorSetRegistryMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_avalancheNetworkID\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"_avalancheBlockChainID\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"validatorSetID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"avalancheBlockchainID\",\"type\":\"bytes32\"}],\"name\":\"ValidatorSetRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"validatorSetID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"avalancheBlockchainID\",\"type\":\"bytes32\"}],\"name\":\"ValidatorSetUpdated\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"avalancheBlockChainID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"avalancheNetworkID\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAvalancheNetworkID\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentValidatorSet\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"avalancheBlockchainID\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"blsPublicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structValidator[]\",\"name\":\"validators\",\"type\":\"tuple[]\"},{\"internalType\":\"uint64\",\"name\":\"totalWeight\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"pChainHeight\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"pChainTimestamp\",\"type\":\"uint64\"}],\"internalType\":\"structValidatorSet\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentValidatorSetID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"validatorSetID\",\"type\":\"uint256\"}],\"name\":\"getValidatorSet\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"avalancheBlockchainID\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"blsPublicKey\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structValidator[]\",\"name\":\"validators\",\"type\":\"tuple[]\"},{\"internalType\":\"uint64\",\"name\":\"totalWeight\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"pChainHeight\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"pChainTimestamp\",\"type\":\"uint64\"}],\"internalType\":\"structValidatorSet\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nextValidatorSetID\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"avalancheNetworkID\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"avalancheSourceBlockchainID\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"internalType\":\"structICMUnsignedMessage\",\"name\":\"unsignedMessage\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"unsignedMessageBytes\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"signers\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structICMSignature\",\"name\":\"signature\",\"type\":\"tuple\"}],\"internalType\":\"structICMMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"validatorBytes\",\"type\":\"bytes\"}],\"name\":\"registerValidatorSet\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"validatorSetID\",\"type\":\"uint256\"},{\"components\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"avalancheNetworkID\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"avalancheSourceBlockchainID\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"internalType\":\"structICMUnsignedMessage\",\"name\":\"unsignedMessage\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"unsignedMessageBytes\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"signers\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structICMSignature\",\"name\":\"signature\",\"type\":\"tuple\"}],\"internalType\":\"structICMMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"validatorBytes\",\"type\":\"bytes\"}],\"name\":\"updateValidatorSet\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"avalancheNetworkID\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"avalancheSourceBlockchainID\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"internalType\":\"structICMUnsignedMessage\",\"name\":\"unsignedMessage\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"unsignedMessageBytes\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"signers\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structICMSignature\",\"name\":\"signature\",\"type\":\"tuple\"}],\"internalType\":\"structICMMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"verifyICMMessage\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"validatorSetID\",\"type\":\"uint256\"},{\"components\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"avalancheNetworkID\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"avalancheSourceBlockchainID\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"internalType\":\"structICMUnsignedMessage\",\"name\":\"unsignedMessage\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"unsignedMessageBytes\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"signers\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structICMSignature\",\"name\":\"signature\",\"type\":\"tuple\"}],\"internalType\":\"structICMMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"verifyICMMessageWithID\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x60c0346100ae57601f61331f38819003918201601f19168301916001600160401b038311848410176100b25780849260409485528339810103126100ae5780519063ffffffff821682036100ae57602001519063ffffffff195f54165f5560805260a05260405161325890816100c782396080518181816102700152818161049f015281816106270152610822015260a05181818161024b0152818161047d0152818161068a01526107fd0152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe60806040526004361015610011575f80fd5b5f3560e01c80630209fdd0146100bf57806338153622146100ba57806339f56451146100b55780634095a588146100b057806368531ed0146100ab57806382366d05146100ab578063a04e8293146100a6578063b490c333146100a1578063b7f4a51f1461009c578063c8f3c751146100975763fd94b8ea14610092575f80fd5b610726565b6106e4565b6106ad565b610673565b61064b565b61060b565b6103cc565b61020b565b6101db565b6101ac565b6020815260c08101918051602083015260208101519260a06040840152835180915260e0830190602060e08260051b8601019501915f905b82821061014f57505050509060a060808361012a604061014c96015160608601906001600160401b03169052565b60608101516001600160401b03168483015201516001600160401b0316910152565b90565b90919295602080606060019360df198a8203018652826001600160401b03818d518051604086528051948591826040890152018787015e5f85850187015201511684830152601f01601f19160101980194939190910191016100fc565b346101d7575f3660031901126101d7576101d36101c7610b52565b604051918291826100c4565b0390f35b5f80fd5b346101d7575f3660031901126101d757602063ffffffff5f5416604051908152f35b908160609103126101d75790565b346101d75760203660031901126101d7576004356001600160401b0381116101d75761029c61024060209236906004016101fd565b610248610b52565b907f0000000000000000000000000000000000000000000000000000000000000000906102977f0000000000000000000000000000000000000000000000000000000000000000913690610be5565b6111c8565b6040519015158152f35b634e487b7160e01b5f52604160045260245ffd5b60a081019081106001600160401b038211176102d557604052565b6102a6565b604081019081106001600160401b038211176102d557604052565b606081019081106001600160401b038211176102d557604052565b90601f801991011681019081106001600160401b038211176102d557604052565b6040519061034060a083610310565b565b60405190610340604083610310565b60405190610340608083610310565b6001600160401b0381116102d557601f01601f191660200190565b92919261038782610360565b916103956040519384610310565b8294818452818301116101d7578281602093845f960137010152565b9080601f830112156101d75781602061014c9335910161037b565b346101d75760603660031901126101d7576004356024356001600160401b0381116101d7576103ff9036906004016101fd565b6044356001600160401b0381116101d7576105bc6105cc6104ce61042a6105e39436906004016103b1565b61044e61044761043e5f5463ffffffff1690565b63ffffffff1690565b8810610cb0565b610460875f52600160205260405f2090565b956104c96104c46104713684610be5565b61047a8a6109c3565b907f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000906111c8565b610cfc565b61151c565b939091956104df8751825414610d3e565b6105ac602088019561052860026104fd89516001600160401b031690565b940154936001600160401b03610520604087901c82165b6001600160401b031690565b911611610d83565b61056760408a01936001600160401b0361055f61051461054f88516001600160401b031690565b9360801c6001600160401b031690565b911611610df5565b61058b61057d8a5198516001600160401b031690565b93516001600160401b031690565b94610594610331565b97885260208801526001600160401b03166040870152565b6001600160401b03166060850152565b6001600160401b03166080830152565b6105de845f52600160205260405f2090565b610fe7565b51907fd48741f16bef6492997e28d107c7a13b06376de704072bdb37a9b02e502ea1f95f80a3005b346101d7575f3660031901126101d757602060405163ffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346101d75760203660031901126101d7576101d36101c760043561066d6108cc565b506115d0565b346101d7575f3660031901126101d75760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346101d7575f3660031901126101d757602063ffffffff6106db815f54166106d68115156108f7565b610957565b16604051908152f35b346101d75760403660031901126101d7576004356024356001600160401b0381116101d75760209161024861072061029c9336906004016101fd565b916115d0565b346101d75760403660031901126101d7576004356001600160401b0381116101d7576107569036906004016101fd565b6024356001600160401b0381116101d7576104c46107fb6107876107816108499436906004016103b1565b8561151c565b6107eb839492979351946107db6107b660406001600160401b036020850151169301516001600160401b031690565b936107bf610331565b9a8b988952602089015260408801906001600160401b03169052565b6001600160401b03166060860152565b6001600160401b03166080840152565b7f0000000000000000000000000000000000000000000000000000000000000000906102977f0000000000000000000000000000000000000000000000000000000000000000913690610be5565b63ffffffff61085c5f5463ffffffff1690565b61087c610868826111b1565b63ffffffff1663ffffffff195f5416175f55565b1690610894816105de845f52600160205260405f2090565b516101d3604051928392817fe93e9f47e7810153341664fc2050adcb29c88899748615c477d17b712d6215835f80a382526020820190565b604051906108d9826102ba565b5f608083828152606060208201528260408201528260608201520152565b156108fe57565b60405162461bcd60e51b815260206004820152601760248201527f4e6f2076616c696461746f7220736574732065786973740000000000000000006044820152606490fd5b634e487b7160e01b5f52601160045260245ffd5b63ffffffff5f199116019063ffffffff821161096f57565b610943565b6001600160401b0381116102d55760051b60200190565b90600182811c921680156109b9575b60208310146109a557565b634e487b7160e01b5f52602260045260245ffd5b91607f169161099a565b906040516109d0816102ba565b809280548252600181018054906109e682610974565b916109f46040519384610310565b80835260208301915f5260205f205f925b828410610a7a5750505050610a6c6002849360809360206103409701520154610a47610a37826001600160401b031690565b6001600160401b03166040860152565b610a5d604082901c6001600160401b03166107db565b60801c6001600160401b031690565b6001600160401b0316910152565b604051610a86816102da565b6040515f8454610a958161098b565b8084529060018116908115610b2f5750600114610af8575b509260029282610ac36020946001970382610310565b8152610aea610adb868801546001600160401b031690565b6001600160401b031682850152565b815201920193019290610a05565b5f868152602081209092505b818310610b1957505081016020016002610aad565b6001816020925483868801015201920191610b04565b60ff191660208086019190915291151560051b8401909101915060029050610aad565b610b5a6108cc565b5063ffffffff610b72815f54166106d68115156108f7565b165f52600160205261014c60405f206109c3565b91906040838203126101d75760405190610b9f826102da565b819380356001600160401b0381116101d75782610bbd9183016103b1565b83526020810135916001600160401b0383116101d757602092610be092016103b1565b910152565b91906060838203126101d75760405190610bfe826102f5565b819380356001600160401b0381116101d75781016060818403126101d75760405190610c29826102f5565b803563ffffffff811681036101d7578252602081013560208301526040810135906001600160401b0382116101d757610c64918591016103b1565b6040820152835260208101356001600160401b0381116101d75782610c8a9183016103b1565b60208401526040810135916001600160401b0383116101d757604092610be09201610b86565b15610cb757565b60405162461bcd60e51b815260206004820152601c60248201527f56616c696461746f722073657420646f6573206e6f74206578697374000000006044820152606490fd5b15610d0357565b60405162461bcd60e51b8152602060048201526013602482015272496e76616c69642049434d206d65737361676560681b6044820152606490fd5b15610d4557565b60405162461bcd60e51b8152602060048201526016602482015275084d8dec6d6c6d0c2d2dc40928840dad2e6dac2e8c6d60531b6044820152606490fd5b15610d8a57565b60405162461bcd60e51b815260206004820152603d60248201527f502d436861696e20686569676874206d7573742062652067726561746572207460448201527f68616e207468652063757272656e742076616c696461746f72207365740000006064820152608490fd5b15610dfc57565b608460405162461bcd60e51b815260206004820152604060248201527f502d436861696e2074696d657374616d70206d7573742062652067726561746560448201527f72207468616e207468652063757272656e742076616c696461746f72207365746064820152fd5b908160031b918083046008149015171561096f57565b818110610e87575050565b5f8155600101610e7c565b9190601f8111610ea157505050565b610340925f5260205f20906020601f840160051c83019310610ecb575b601f0160051c0190610e7c565b9091508190610ebe565b91909182519283516001600160401b0381116102d557610eff81610ef9855461098b565b85610e92565b6020601f8211600114610f7357600192610f3a83610f4b94602094610340999a5f92610f68575b50508160011b915f199060031b1c19161790565b85555b01516001600160401b031690565b9101906001600160401b03166001600160401b0319825416179055565b015190505f80610f26565b601f19821695610f86855f5260205f2090565b965f5b818110610fcf575083610340979860209460019794610f4b97899510610fb7575b505050811b018555610f3d565b01515f1960f88460031b161c191690555f8080610faa565b83830151895560019098019760209384019301610f89565b81518155600181016020830151908151916801000000000000000083116102d5578154838355808410611106575b5060206110279101915f5260205f2090565b5f915b8383106110e85750505050906110c06080600261034094019261107761105a60408301516001600160401b031690565b855467ffffffffffffffff19166001600160401b03909116178555565b610f3d61108e60608301516001600160401b031690565b85546fffffffffffffffff0000000000000000191660409190911b6fffffffffffffffff000000000000000016178555565b815467ffffffffffffffff60801b191660809190911b67ffffffffffffffff60801b16179055565b60026020826110fa6001945186610ed5565b0192019201919061102a565b6001600160ff1b038116810361096f576001600160ff1b038416840361096f57825f5260205f209060011b8101908460011b015b8181106111475750611015565b806111546002925461098b565b80611167575b505f60018201550161113a565b601f811160011461117d57505f81555b5f61115a565b6111a0906001601f611192855f5260205f2090565b920160051c82019101610e7c565b5f8181526020812081835555611177565b63ffffffff1663ffffffff811461096f5760010190565b92919063ffffffff806111e1865163ffffffff90511690565b9216911603611318578151036112c4576040820191611235611231604061122b61121a61120f885151611771565b602088015190611928565b92909601516001600160401b031690565b90611a0a565b1590565b61128e5760208061124c9451015191015191611a40565b80156112555790565b60405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b6044820152606490fd5b60405162461bcd60e51b815260206004820152600e60248201526d125b9d985b1a59081dd95a59da1d60921b6044820152606490fd5b60405162461bcd60e51b815260206004820152602660248201527f496e76616c6964206176616c616e63686520736f7572636520626c6f636b6368604482015265185a5b88125160d21b6064820152608490fd5b60405162461bcd60e51b815260206004820152601c60248201527f496e76616c6964206176616c616e636865206e6574776f726b204944000000006044820152606490fd5b60405190608082018281106001600160401b038211176102d5576040525f6060838281528260208201528260408201520152565b903590601e19813603018212156101d757018035906001600160401b0382116101d7576020019181360383136101d757565b156113ca57565b60405162461bcd60e51b815260206004820152601c60248201527f536f757263652061646472657373206d75737420626520656d707479000000006044820152606490fd5b805191908290602001825e015f815290565b6040513d5f823e3d90fd5b1561143357565b60405162461bcd60e51b815260206004820152601b60248201527f56616c696461746f72207365742068617368206d69736d6174636800000000006044820152606490fd5b1561147f57565b60405162461bcd60e51b815260206004820152601d60248201527f56616c696461746f72207365742063616e6e6f7420626520656d7074790000006044820152606490fd5b156114cb57565b60405162461bcd60e51b815260206004820152602360248201527f546f74616c20776569676874206d75737420626520677265617465722074686160448201526206e20360ec1b6064820152608490fd5b91909161152761135d565b508035605e19823603018112156101d75761155f61155a61155360209361157295016040810190611391565b369161037b565b611c7f565b61156b815151156113c3565b0151611e14565b9160608301519060205f6040518061158a818661140f565b039060025afa156115cb576115a46115a9925f511461142c565b612151565b90916103406001600160401b03836115c386511515611478565b1615156114c4565b611421565b6115d86108cc565b506115eb63ffffffff5f54168210610cb0565b5f52600160205261014c60405f206109c3565b634e487b7160e01b5f52603260045260245ffd5b80511561161f5760200190565b6115fe565b80516001101561161f5760210190565b90815181101561161f570160200190565b1561164c57565b60405162461bcd60e51b815260206004820152600f60248201526e125b9d985b1a5908189a5d081cd95d608a1b6044820152606490fd5b5f19811461096f5760010190565b600703906007821161096f57565b5f1981019190821161096f57565b9190820391821161096f57565b906116c482610974565b6116d16040519182610310565b82815280926116e2601f1991610974565b0190602036910137565b80516001101561161f5760400190565b80516002101561161f5760600190565b80516003101561161f5760800190565b80516004101561161f5760a00190565b80516005101561161f5760c00190565b80516006101561161f5760e00190565b80516007101561161f576101000190565b805182101561161f5760209160051b010190565b8051151580611873575b61178490611645565b6117a76117a161179383611612565b516001600160f81b03191690565b60f81c90565b905f916080905b60ff82821616156118515750506117d66117d1836117cc8451610e66565b6116ad565b6116ba565b5f905f5b8351811015611849578061184357845b600881106117fb57506001016117da565b9261183c60019161183760ff6118176117a1611793888c611634565b856118218a611691565b1b16161515611830838861175d565b9015159052565b611683565b93016117ea565b5f6117ea565b509250505090565b909261186b61186160ff92611683565b9460011c607f1690565b9190506117ae565b506117846001600160f81b031961188c61179384611612565b161515905061177b565b1561189d57565b60405162461bcd60e51b815260206004820152603e60248201527f5369676e657273206c656e677468206d757374206265206c657373207468616e60448201527f206f7220657175616c20746f2076616c696461746f7273206c656e67746800006064820152608490fd5b906001600160401b03809116911601906001600160401b03821161096f57565b9190611938835182511015611896565b6060905f905f5b8151811015611a025785518181811091826119d5575b5050611964575b60010161193f565b9161196f838361175d565b51936001600160401b038216156119b5576001916119a660206119976119ac94895190612302565b9701516001600160401b031690565b90611908565b925b905061195c565b505060016119cf602085519501516001600160401b031690565b926119ae565b6119fb92506119ea6119f5926119ef926116ad565b61169f565b8861175d565b51151590565b815f611955565b505092509190565b906001600160401b0316908160430291604383040361096f576001600160401b0316908160640291606483040361096f57111590565b9160405191611a50606084610310565b602b83527f424c535f5349475f424c53313233383147325f584d443a5348412d3235365f5360208401526a5357555f524f5f504f505f60a81b60408401526080845103611b2b57600193611aea611afe83611af0611ac0611b27985f98611abb60c08b9a5114612398565b612ad2565b91611aea611ad5611acf6123e4565b92612d18565b91604051968795611aea60208801809b61140f565b9061140f565b03601f198101835282610310565b5190600f5afa611b15611b0f612287565b91612471565b611b2260208251146124bd565b612515565b1490565b60405162461bcd60e51b815260206004820152601960248201527f496e76616c6964207075626c6963206b6579206c656e677468000000000000006044820152606490fd5b60405190611b7d826102da565b60606020838281520152565b15611b9057565b60405162461bcd60e51b815260206004820152601060248201526f125b9d985b1a590818dbd91958c8125160821b6044820152606490fd5b80516020909101516001600160e01b0319811692919060048210611bea575050565b6001600160e01b031960049290920360031b82901b16169150565b15611c0c57565b60405162461bcd60e51b815260206004820152601760248201527f496e76616c6964207061796c6f616420747970652049440000000000000000006044820152606490fd5b63ffffffff16600a019063ffffffff821161096f57565b63ffffffff16600e019063ffffffff821161096f57565b611c87611b70565b50611c9181611612565b516001600160f81b0319161580611d42575b611cac90611b89565b611cd7600163ffffffff611cd0611cca611cc586612537565b611bc8565b60e01c90565b1614611c05565b611d2f611ce9611cca611cc5846125cf565b91611cfa63ffffffff841682612622565b9263ffffffff611d2761043e611d21611cca611cc5611d1b61043e88611c51565b8861267d565b93611c68565b9116916128c8565b611d37610342565b918252602082015290565b50611cac611d62611d5561179384611624565b6001600160f81b03191690565b159050611ca3565b15611d7157565b60405162461bcd60e51b815260206004820152602960248201527f496e76616c69642056616c696461746f725365745374617465207061796c6f6160448201526819081d1e5c1948125160ba1b6064820152608490fd5b908160209103126101d7575190565b80516020909101516001600160c01b0319811692919060088210611df9575050565b6001600160c01b031960089290920360031b82901b16169150565b611e1c61135d565b506001600160f81b0319611e3261179383611612565b161580611eef575b611e4390611b89565b611e63600463ffffffff611e5c611cca611cc586612537565b1614611d6a565b611e7e611e6f826126d2565b60208082518301019101611dc8565b90611ee7611e9c611e96611e9184612725565b611dd7565b60c01c90565b91611ed7611ebb611e6f611eb5611e96611e9186612778565b936127cb565b93611ec4610351565b9586526001600160401b03166020860152565b6001600160401b03166040840152565b606082015290565b50611e43611f02611d5561179384611624565b159050611e3a565b90611f1482610974565b611f216040519182610310565b8281528092611f32601f1991610974565b01905f5b828110611f4257505050565b602090604051611f51816102da565b606081525f8382015282828501015201611f36565b60405160809190611f778382610310565b6060815291601f1901366020840137565b60405160a09190611f998382610310565b6080815291601f1901366020840137565b6040516101009190610120611fbf8183610310565b8382526001600160401b038294116102d557601f190190369060200137565b90611fe882610360565b611ff56040519182610310565b82815280926116e2601f1991610360565b1561200d57565b60405162461bcd60e51b815260206004820152603960248201527f424c53207075626c6963206b6579206d7573742062652067726561746572207460448201527f68616e20746865206c6174657374207075626c6963206b6579000000000000006064820152608490fd5b906060820180921161096f57565b906068820180921161096f57565b601001908160101161096f57565b906030820180921161096f57565b605001908160501161096f57565b906090820180921161096f57565b609001908160901161096f57565b60d001908160d01161096f57565b9190820180921161096f57565b156120fc57565b60405162461bcd60e51b815260206004820152602760248201527f56616c696461746f7220776569676874206d75737420626520677265617465726044820152660207468616e20360cc1b6064820152608490fd5b906001600160f81b031961216761179384611612565b16158061226c575b61217890611b89565b63ffffffff61218c611cca611cc585612537565b1661219681611f0a565b925f916006946121a4611f66565b925f945b63ffffffff861684811015612260576122566122508763ffffffff9461224a60019561221f8f611e96611e916121ff836121fa8f6121f46121ed612205985f9361281e565b9c8d612923565b13612006565b612078565b8d612873565b9461221a6001600160401b03871615156120f5565b612a09565b612227610342565b9081526001600160401b0385166020820152612243828c61175d565b528961175d565b50611908565b99612086565b96011694966121a8565b50965050925050509190565b5061217861227f611d5561179385611624565b15905061216f565b3d156122b1573d9061229882610360565b916122a66040519384610310565b82523d5f602084013e565b606090565b156122bd57565b60405162461bcd60e51b815260206004820152601760248201527f4661696c656420746f2061646420473120706f696e74730000000000000000006044820152606490fd5b9060808251148061238d575b15612348575f91611af06123318493604051928391611aea60208401809761140f565b5190600b5afa61014c612342612287565b916122b6565b60405162461bcd60e51b815260206004820152601760248201527f496e76616c696420473120706f696e74206c656e6774680000000000000000006044820152606490fd5b50608081511461230e565b1561239f57565b60405162461bcd60e51b815260206004820152601860248201527f496e76616c6964207369676e6174757265206c656e67746800000000000000006044820152606490fd5b604051906123f360a083610310565b608082527f67816aef1db507c96655b9d5caac42364e6f38ba0ecb751bad54dcd6b939c2ca6080836f17f1d3a73197d7942695638c4fa9ac0f60208201527fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb60408201526f114d1d6855d545a8aa7d76c8cf2e21f260608201520152565b1561247857565b60405162461bcd60e51b815260206004820152601f60248201527f4661696c656420746f20706572666f726d2070616972696e6720636865636b006044820152606490fd5b156124c457565b60405162461bcd60e51b815260206004820152602360248201527f496e76616c69642070616972696e6720636865636b206f7574707574206c656e6044820152620cee8d60eb1b6064820152608490fd5b602081519101519060208110612529575090565b5f199060200360031b1b1690565b90600682511061258a5761254b6004611fde565b9160025f5b6004811061255d57505050565b8082019081831161096f5761257761179360019386611634565b5f1a6125838288611634565b5301612550565b60405162461bcd60e51b815260206004820152601960248201527f42797465536c696365723a206f7574206f6620626f756e6473000000000000006044820152606490fd5b90600a82511061258a576125e36004611fde565b9160065f5b600481106125f557505050565b8082019081831161096f5761260f61179360019386611634565b5f1a61261b8288611634565b53016125e8565b9190825181600a019081600a1161096f571061258a5761264181611fde565b925f5b82811061265057505050565b8061266a611793612664600194600a6120e8565b85611634565b5f1a6126768288611634565b5301612644565b91908251600482019081831161096f571061258a5761269c6004611fde565b925f5b600481106126ac57505050565b806126bf611793612664600194876120e8565b5f1a6126cb8288611634565b530161269f565b90602682511061258a576126e66020611fde565b9160065f5b602081106126f857505050565b8082019081831161096f5761271261179360019386611634565b5f1a61271e8288611634565b53016126eb565b90602e82511061258a576127396008611fde565b9160265f5b6008811061274b57505050565b8082019081831161096f5761276561179360019386611634565b5f1a6127718288611634565b530161273e565b90603682511061258a5761278c6008611fde565b91602e5f5b6008811061279e57505050565b8082019081831161096f576127b861179360019386611634565b5f1a6127c48288611634565b5301612791565b90605682511061258a576127df6020611fde565b9160365f5b602081106127f157505050565b8082019081831161096f5761280b61179360019386611634565b5f1a6128178288611634565b53016127e4565b91908251606082019081831161096f571061258a5761283d6060611fde565b925f5b6060811061284d57505050565b80612860611793612664600194876120e8565b5f1a61286c8288611634565b5301612840565b91908251600882019081831161096f571061258a576128926008611fde565b925f5b600881106128a257505050565b806128b5611793612664600194876120e8565b5f1a6128c18288611634565b5301612895565b9291909280518285019081861161096f571061258a576128e782611fde565b935f5b8381106128f75750505050565b8061291061179361290a600194866120e8565b86611634565b5f1a61291c8289611634565b53016128ea565b805180158080612a00575b6129f8576129f057825180156129d757808210156129e957505b5f5b8181106129735750505190519081811061296c5711612967575f90565b600190565b50505f1990565b6129806117938285611634565b612990611d556117938488611634565b6001600160f81b0319909116106129e0576129ae6117938285611634565b6129be611d556117938488611634565b6001600160f81b0319909116116129d75760010161294a565b50505050600190565b505050505f1990565b9050612948565b505050600190565b505050505f90565b5083511561292e565b906060825103612a8d57612a1b611f88565b5f5b60308110612a6a57505f5b60308110612a3557509150565b80612a4d611793612a476001946120a2565b87611634565b612a63612a59836120b0565b915f1a9185611634565b5301612a28565b80612a7a61179360019387611634565b612a86612a5983612094565b5301612a1d565b60405162461bcd60e51b815260206004820152601f60248201527f496e76616c696420696e707574207075626c6963206b6579206c656e677468006044820152606490fd5b90612adb612df0565b50612b5a612b4c612b0c612b05612b00612af6610100612fd4565b60051c6107ff1690565b612fe8565b61ffff1690565b92612b1a60ff851115612ffc565b612b2860ff82511115613052565b612b46612b36825160ff1690565b60f81b6001600160f81b03191690565b9061308d565b928390600160f81b906130c0565b9160205f612b77612b6a856116ba565b956040519182809261140f565b039060025afa156115cb575f5160205f612ba0612b948585613113565b6040519182809261140f565b039060025afa156115cb575f51612bb685611612565b5260025b8360ff82161115612c6757505050508061014c9150612c61612c5a612bdd612df0565b612bfa612be985611612565b51612bf3866116ec565b5190613192565b815152612c13612c09856116fc565b51612bf38661170c565b602082510152612c4e612c32612c288661171c565b51612bf38761172c565b946020830195865152612bf3612c478261173c565b519161174c565b60208551015251612e51565b9151612e51565b90612f3c565b60205f612ca183612b94612c8c612c86612c808461314d565b60ff1690565b8b61175d565b518718611af089604051948593898501613172565b039060025afa156115cb57612cc7905f51612cc16119ef612c8084613160565b5261313c565b612bba565b15612cd357565b60405162461bcd60e51b815260206004820152601e60248201527f496e76616c696420696e707574207369676e6174757265206c656e67746800006044820152606490fd5b90612d2660c0835114612ccc565b612d2e611faa565b5f5b60308110612dcb57505f5b60308110612da857505f5b60308110612d8357505f5b60308110612d5e57509150565b80612d70611793612a47600194612078565b612d7c612a59836120da565b5301612d51565b80612d95611793612a476001946120be565b612da1612a59836120cc565b5301612d46565b80612db861179360019387611634565b612dc4612a59836120b0565b5301612d3b565b80612ddd611793612a476001946120a2565b612de9612a5983612094565b5301612d30565b6040908151612dff8382610310565b91604090835f5b838110612e135750505050565b6020908351612e21816102da565b8451612e2d8682610310565b8536823781528451612e3f8682610310565b85368237838201528184015201612e06565b5f80918051519060208082510151910160208151519151015190604051926020840194855260408401526060830152608082015260808152612e9460a082610310565b519060115afa612ea2612287565b9015612eab5790565b60405162461bcd60e51b815260206004820152601760248201527f4661696c656420746f206d61702046703220746f2047320000000000000000006044820152606490fd5b15612ef757565b60405162461bcd60e51b815260206004820152601760248201527f4661696c656420746f2061646420473220706f696e74730000000000000000006044820152606490fd5b9061010082511480612fc8575b15612f83575f91611af0612f6c8493604051928391611aea60208401809761140f565b5190600d5afa61014c612f7d612287565b91612ef0565b60405162461bcd60e51b815260206004820152601760248201527f496e76616c696420473220706f696e74206c656e6774680000000000000000006044820152606490fd5b50610100815114612f49565b61ffff5f199116019061ffff821161096f57565b61ffff60019116019061ffff821161096f57565b1561300357565b60405162461bcd60e51b815260206004820152602160248201527f6c656e5f696e5f627974657320746f6f206c6172676520666f722073686132356044820152601b60f91b6064820152608490fd5b1561305957565b60405162461bcd60e51b815260206004820152600c60248201526b64737420746f6f206c6f6e6760a01b6044820152606490fd5b6001610340916130a89493604051958692602084019061140f565b9060ff60f81b16815203601e19810185520183610310565b6131056130ea94936003610340946040519788955f60208801525f6040880152606087019061140f565b6001600160f01b031990911681525f6002820152019061140f565b03601f198101845283610310565b610340909291926131056040519485926020840152600160f81b6040840152604183019061140f565b60ff1660ff811461096f5760010190565b60ff6001199116019060ff821161096f57565b60ff5f199116019060ff821161096f57565b61014c9392602192825260ff60f81b9060f81b166020820152019061140f565b9190916040928380516131a58282610310565b3690378351908482526020808301528482019285845260608301526080820152600160a08201526f1a0111ea397fe69a4b1ba7b6434bacd760c08201527f64774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab60e08201528381610100816005610545195a01fa15613220579252565bfefea264697066735822122023c06432722695e94fe25aac46ef4d9b290a938cb0af66a953e95e1a7f557f0864736f6c634300081e0033", +} + +// AvalancheValidatorSetRegistryABI is the input ABI used to generate the binding from. +// Deprecated: Use AvalancheValidatorSetRegistryMetaData.ABI instead. +var AvalancheValidatorSetRegistryABI = AvalancheValidatorSetRegistryMetaData.ABI + +// AvalancheValidatorSetRegistryBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use AvalancheValidatorSetRegistryMetaData.Bin instead. +var AvalancheValidatorSetRegistryBin = AvalancheValidatorSetRegistryMetaData.Bin + +// DeployAvalancheValidatorSetRegistry deploys a new Ethereum contract, binding an instance of AvalancheValidatorSetRegistry to it. +func DeployAvalancheValidatorSetRegistry(auth *bind.TransactOpts, backend bind.ContractBackend, _avalancheNetworkID uint32, _avalancheBlockChainID [32]byte) (common.Address, *types.Transaction, *AvalancheValidatorSetRegistry, error) { + parsed, err := AvalancheValidatorSetRegistryMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(AvalancheValidatorSetRegistryBin), backend, _avalancheNetworkID, _avalancheBlockChainID) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &AvalancheValidatorSetRegistry{AvalancheValidatorSetRegistryCaller: AvalancheValidatorSetRegistryCaller{contract: contract}, AvalancheValidatorSetRegistryTransactor: AvalancheValidatorSetRegistryTransactor{contract: contract}, AvalancheValidatorSetRegistryFilterer: AvalancheValidatorSetRegistryFilterer{contract: contract}}, nil +} + +// AvalancheValidatorSetRegistry is an auto generated Go binding around an Ethereum contract. +type AvalancheValidatorSetRegistry struct { + AvalancheValidatorSetRegistryCaller // Read-only binding to the contract + AvalancheValidatorSetRegistryTransactor // Write-only binding to the contract + AvalancheValidatorSetRegistryFilterer // Log filterer for contract events +} + +// AvalancheValidatorSetRegistryCaller is an auto generated read-only Go binding around an Ethereum contract. +type AvalancheValidatorSetRegistryCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AvalancheValidatorSetRegistryTransactor is an auto generated write-only Go binding around an Ethereum contract. +type AvalancheValidatorSetRegistryTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AvalancheValidatorSetRegistryFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type AvalancheValidatorSetRegistryFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AvalancheValidatorSetRegistrySession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type AvalancheValidatorSetRegistrySession struct { + Contract *AvalancheValidatorSetRegistry // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// AvalancheValidatorSetRegistryCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type AvalancheValidatorSetRegistryCallerSession struct { + Contract *AvalancheValidatorSetRegistryCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// AvalancheValidatorSetRegistryTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type AvalancheValidatorSetRegistryTransactorSession struct { + Contract *AvalancheValidatorSetRegistryTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// AvalancheValidatorSetRegistryRaw is an auto generated low-level Go binding around an Ethereum contract. +type AvalancheValidatorSetRegistryRaw struct { + Contract *AvalancheValidatorSetRegistry // Generic contract binding to access the raw methods on +} + +// AvalancheValidatorSetRegistryCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type AvalancheValidatorSetRegistryCallerRaw struct { + Contract *AvalancheValidatorSetRegistryCaller // Generic read-only contract binding to access the raw methods on +} + +// AvalancheValidatorSetRegistryTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type AvalancheValidatorSetRegistryTransactorRaw struct { + Contract *AvalancheValidatorSetRegistryTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewAvalancheValidatorSetRegistry creates a new instance of AvalancheValidatorSetRegistry, bound to a specific deployed contract. +func NewAvalancheValidatorSetRegistry(address common.Address, backend bind.ContractBackend) (*AvalancheValidatorSetRegistry, error) { + contract, err := bindAvalancheValidatorSetRegistry(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &AvalancheValidatorSetRegistry{AvalancheValidatorSetRegistryCaller: AvalancheValidatorSetRegistryCaller{contract: contract}, AvalancheValidatorSetRegistryTransactor: AvalancheValidatorSetRegistryTransactor{contract: contract}, AvalancheValidatorSetRegistryFilterer: AvalancheValidatorSetRegistryFilterer{contract: contract}}, nil +} + +// NewAvalancheValidatorSetRegistryCaller creates a new read-only instance of AvalancheValidatorSetRegistry, bound to a specific deployed contract. +func NewAvalancheValidatorSetRegistryCaller(address common.Address, caller bind.ContractCaller) (*AvalancheValidatorSetRegistryCaller, error) { + contract, err := bindAvalancheValidatorSetRegistry(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &AvalancheValidatorSetRegistryCaller{contract: contract}, nil +} + +// NewAvalancheValidatorSetRegistryTransactor creates a new write-only instance of AvalancheValidatorSetRegistry, bound to a specific deployed contract. +func NewAvalancheValidatorSetRegistryTransactor(address common.Address, transactor bind.ContractTransactor) (*AvalancheValidatorSetRegistryTransactor, error) { + contract, err := bindAvalancheValidatorSetRegistry(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &AvalancheValidatorSetRegistryTransactor{contract: contract}, nil +} + +// NewAvalancheValidatorSetRegistryFilterer creates a new log filterer instance of AvalancheValidatorSetRegistry, bound to a specific deployed contract. +func NewAvalancheValidatorSetRegistryFilterer(address common.Address, filterer bind.ContractFilterer) (*AvalancheValidatorSetRegistryFilterer, error) { + contract, err := bindAvalancheValidatorSetRegistry(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &AvalancheValidatorSetRegistryFilterer{contract: contract}, nil +} + +// bindAvalancheValidatorSetRegistry binds a generic wrapper to an already deployed contract. +func bindAvalancheValidatorSetRegistry(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := AvalancheValidatorSetRegistryMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AvalancheValidatorSetRegistry.Contract.AvalancheValidatorSetRegistryCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AvalancheValidatorSetRegistry.Contract.AvalancheValidatorSetRegistryTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AvalancheValidatorSetRegistry.Contract.AvalancheValidatorSetRegistryTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AvalancheValidatorSetRegistry.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AvalancheValidatorSetRegistry.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AvalancheValidatorSetRegistry.Contract.contract.Transact(opts, method, params...) +} + +// AvalancheBlockChainID is a free data retrieval call binding the contract method 0xb490c333. +// +// Solidity: function avalancheBlockChainID() view returns(bytes32) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryCaller) AvalancheBlockChainID(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _AvalancheValidatorSetRegistry.contract.Call(opts, &out, "avalancheBlockChainID") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// AvalancheBlockChainID is a free data retrieval call binding the contract method 0xb490c333. +// +// Solidity: function avalancheBlockChainID() view returns(bytes32) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistrySession) AvalancheBlockChainID() ([32]byte, error) { + return _AvalancheValidatorSetRegistry.Contract.AvalancheBlockChainID(&_AvalancheValidatorSetRegistry.CallOpts) +} + +// AvalancheBlockChainID is a free data retrieval call binding the contract method 0xb490c333. +// +// Solidity: function avalancheBlockChainID() view returns(bytes32) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryCallerSession) AvalancheBlockChainID() ([32]byte, error) { + return _AvalancheValidatorSetRegistry.Contract.AvalancheBlockChainID(&_AvalancheValidatorSetRegistry.CallOpts) +} + +// AvalancheNetworkID is a free data retrieval call binding the contract method 0x68531ed0. +// +// Solidity: function avalancheNetworkID() view returns(uint32) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryCaller) AvalancheNetworkID(opts *bind.CallOpts) (uint32, error) { + var out []interface{} + err := _AvalancheValidatorSetRegistry.contract.Call(opts, &out, "avalancheNetworkID") + + if err != nil { + return *new(uint32), err + } + + out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32) + + return out0, err + +} + +// AvalancheNetworkID is a free data retrieval call binding the contract method 0x68531ed0. +// +// Solidity: function avalancheNetworkID() view returns(uint32) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistrySession) AvalancheNetworkID() (uint32, error) { + return _AvalancheValidatorSetRegistry.Contract.AvalancheNetworkID(&_AvalancheValidatorSetRegistry.CallOpts) +} + +// AvalancheNetworkID is a free data retrieval call binding the contract method 0x68531ed0. +// +// Solidity: function avalancheNetworkID() view returns(uint32) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryCallerSession) AvalancheNetworkID() (uint32, error) { + return _AvalancheValidatorSetRegistry.Contract.AvalancheNetworkID(&_AvalancheValidatorSetRegistry.CallOpts) +} + +// GetAvalancheNetworkID is a free data retrieval call binding the contract method 0x82366d05. +// +// Solidity: function getAvalancheNetworkID() view returns(uint32) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryCaller) GetAvalancheNetworkID(opts *bind.CallOpts) (uint32, error) { + var out []interface{} + err := _AvalancheValidatorSetRegistry.contract.Call(opts, &out, "getAvalancheNetworkID") + + if err != nil { + return *new(uint32), err + } + + out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32) + + return out0, err + +} + +// GetAvalancheNetworkID is a free data retrieval call binding the contract method 0x82366d05. +// +// Solidity: function getAvalancheNetworkID() view returns(uint32) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistrySession) GetAvalancheNetworkID() (uint32, error) { + return _AvalancheValidatorSetRegistry.Contract.GetAvalancheNetworkID(&_AvalancheValidatorSetRegistry.CallOpts) +} + +// GetAvalancheNetworkID is a free data retrieval call binding the contract method 0x82366d05. +// +// Solidity: function getAvalancheNetworkID() view returns(uint32) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryCallerSession) GetAvalancheNetworkID() (uint32, error) { + return _AvalancheValidatorSetRegistry.Contract.GetAvalancheNetworkID(&_AvalancheValidatorSetRegistry.CallOpts) +} + +// GetCurrentValidatorSet is a free data retrieval call binding the contract method 0x0209fdd0. +// +// Solidity: function getCurrentValidatorSet() view returns((bytes32,(bytes,uint64)[],uint64,uint64,uint64)) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryCaller) GetCurrentValidatorSet(opts *bind.CallOpts) (ValidatorSet, error) { + var out []interface{} + err := _AvalancheValidatorSetRegistry.contract.Call(opts, &out, "getCurrentValidatorSet") + + if err != nil { + return *new(ValidatorSet), err + } + + out0 := *abi.ConvertType(out[0], new(ValidatorSet)).(*ValidatorSet) + + return out0, err + +} + +// GetCurrentValidatorSet is a free data retrieval call binding the contract method 0x0209fdd0. +// +// Solidity: function getCurrentValidatorSet() view returns((bytes32,(bytes,uint64)[],uint64,uint64,uint64)) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistrySession) GetCurrentValidatorSet() (ValidatorSet, error) { + return _AvalancheValidatorSetRegistry.Contract.GetCurrentValidatorSet(&_AvalancheValidatorSetRegistry.CallOpts) +} + +// GetCurrentValidatorSet is a free data retrieval call binding the contract method 0x0209fdd0. +// +// Solidity: function getCurrentValidatorSet() view returns((bytes32,(bytes,uint64)[],uint64,uint64,uint64)) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryCallerSession) GetCurrentValidatorSet() (ValidatorSet, error) { + return _AvalancheValidatorSetRegistry.Contract.GetCurrentValidatorSet(&_AvalancheValidatorSetRegistry.CallOpts) +} + +// GetCurrentValidatorSetID is a free data retrieval call binding the contract method 0xb7f4a51f. +// +// Solidity: function getCurrentValidatorSetID() view returns(uint256) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryCaller) GetCurrentValidatorSetID(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _AvalancheValidatorSetRegistry.contract.Call(opts, &out, "getCurrentValidatorSetID") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetCurrentValidatorSetID is a free data retrieval call binding the contract method 0xb7f4a51f. +// +// Solidity: function getCurrentValidatorSetID() view returns(uint256) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistrySession) GetCurrentValidatorSetID() (*big.Int, error) { + return _AvalancheValidatorSetRegistry.Contract.GetCurrentValidatorSetID(&_AvalancheValidatorSetRegistry.CallOpts) +} + +// GetCurrentValidatorSetID is a free data retrieval call binding the contract method 0xb7f4a51f. +// +// Solidity: function getCurrentValidatorSetID() view returns(uint256) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryCallerSession) GetCurrentValidatorSetID() (*big.Int, error) { + return _AvalancheValidatorSetRegistry.Contract.GetCurrentValidatorSetID(&_AvalancheValidatorSetRegistry.CallOpts) +} + +// GetValidatorSet is a free data retrieval call binding the contract method 0xa04e8293. +// +// Solidity: function getValidatorSet(uint256 validatorSetID) view returns((bytes32,(bytes,uint64)[],uint64,uint64,uint64)) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryCaller) GetValidatorSet(opts *bind.CallOpts, validatorSetID *big.Int) (ValidatorSet, error) { + var out []interface{} + err := _AvalancheValidatorSetRegistry.contract.Call(opts, &out, "getValidatorSet", validatorSetID) + + if err != nil { + return *new(ValidatorSet), err + } + + out0 := *abi.ConvertType(out[0], new(ValidatorSet)).(*ValidatorSet) + + return out0, err + +} + +// GetValidatorSet is a free data retrieval call binding the contract method 0xa04e8293. +// +// Solidity: function getValidatorSet(uint256 validatorSetID) view returns((bytes32,(bytes,uint64)[],uint64,uint64,uint64)) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistrySession) GetValidatorSet(validatorSetID *big.Int) (ValidatorSet, error) { + return _AvalancheValidatorSetRegistry.Contract.GetValidatorSet(&_AvalancheValidatorSetRegistry.CallOpts, validatorSetID) +} + +// GetValidatorSet is a free data retrieval call binding the contract method 0xa04e8293. +// +// Solidity: function getValidatorSet(uint256 validatorSetID) view returns((bytes32,(bytes,uint64)[],uint64,uint64,uint64)) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryCallerSession) GetValidatorSet(validatorSetID *big.Int) (ValidatorSet, error) { + return _AvalancheValidatorSetRegistry.Contract.GetValidatorSet(&_AvalancheValidatorSetRegistry.CallOpts, validatorSetID) +} + +// NextValidatorSetID is a free data retrieval call binding the contract method 0x38153622. +// +// Solidity: function nextValidatorSetID() view returns(uint32) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryCaller) NextValidatorSetID(opts *bind.CallOpts) (uint32, error) { + var out []interface{} + err := _AvalancheValidatorSetRegistry.contract.Call(opts, &out, "nextValidatorSetID") + + if err != nil { + return *new(uint32), err + } + + out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32) + + return out0, err + +} + +// NextValidatorSetID is a free data retrieval call binding the contract method 0x38153622. +// +// Solidity: function nextValidatorSetID() view returns(uint32) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistrySession) NextValidatorSetID() (uint32, error) { + return _AvalancheValidatorSetRegistry.Contract.NextValidatorSetID(&_AvalancheValidatorSetRegistry.CallOpts) +} + +// NextValidatorSetID is a free data retrieval call binding the contract method 0x38153622. +// +// Solidity: function nextValidatorSetID() view returns(uint32) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryCallerSession) NextValidatorSetID() (uint32, error) { + return _AvalancheValidatorSetRegistry.Contract.NextValidatorSetID(&_AvalancheValidatorSetRegistry.CallOpts) +} + +// VerifyICMMessage is a free data retrieval call binding the contract method 0x39f56451. +// +// Solidity: function verifyICMMessage(((uint32,bytes32,bytes),bytes,(bytes,bytes)) message) view returns(bool) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryCaller) VerifyICMMessage(opts *bind.CallOpts, message ICMMessage) (bool, error) { + var out []interface{} + err := _AvalancheValidatorSetRegistry.contract.Call(opts, &out, "verifyICMMessage", message) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// VerifyICMMessage is a free data retrieval call binding the contract method 0x39f56451. +// +// Solidity: function verifyICMMessage(((uint32,bytes32,bytes),bytes,(bytes,bytes)) message) view returns(bool) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistrySession) VerifyICMMessage(message ICMMessage) (bool, error) { + return _AvalancheValidatorSetRegistry.Contract.VerifyICMMessage(&_AvalancheValidatorSetRegistry.CallOpts, message) +} + +// VerifyICMMessage is a free data retrieval call binding the contract method 0x39f56451. +// +// Solidity: function verifyICMMessage(((uint32,bytes32,bytes),bytes,(bytes,bytes)) message) view returns(bool) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryCallerSession) VerifyICMMessage(message ICMMessage) (bool, error) { + return _AvalancheValidatorSetRegistry.Contract.VerifyICMMessage(&_AvalancheValidatorSetRegistry.CallOpts, message) +} + +// VerifyICMMessageWithID is a free data retrieval call binding the contract method 0xc8f3c751. +// +// Solidity: function verifyICMMessageWithID(uint256 validatorSetID, ((uint32,bytes32,bytes),bytes,(bytes,bytes)) message) view returns(bool) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryCaller) VerifyICMMessageWithID(opts *bind.CallOpts, validatorSetID *big.Int, message ICMMessage) (bool, error) { + var out []interface{} + err := _AvalancheValidatorSetRegistry.contract.Call(opts, &out, "verifyICMMessageWithID", validatorSetID, message) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// VerifyICMMessageWithID is a free data retrieval call binding the contract method 0xc8f3c751. +// +// Solidity: function verifyICMMessageWithID(uint256 validatorSetID, ((uint32,bytes32,bytes),bytes,(bytes,bytes)) message) view returns(bool) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistrySession) VerifyICMMessageWithID(validatorSetID *big.Int, message ICMMessage) (bool, error) { + return _AvalancheValidatorSetRegistry.Contract.VerifyICMMessageWithID(&_AvalancheValidatorSetRegistry.CallOpts, validatorSetID, message) +} + +// VerifyICMMessageWithID is a free data retrieval call binding the contract method 0xc8f3c751. +// +// Solidity: function verifyICMMessageWithID(uint256 validatorSetID, ((uint32,bytes32,bytes),bytes,(bytes,bytes)) message) view returns(bool) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryCallerSession) VerifyICMMessageWithID(validatorSetID *big.Int, message ICMMessage) (bool, error) { + return _AvalancheValidatorSetRegistry.Contract.VerifyICMMessageWithID(&_AvalancheValidatorSetRegistry.CallOpts, validatorSetID, message) +} + +// RegisterValidatorSet is a paid mutator transaction binding the contract method 0xfd94b8ea. +// +// Solidity: function registerValidatorSet(((uint32,bytes32,bytes),bytes,(bytes,bytes)) message, bytes validatorBytes) returns(uint256) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryTransactor) RegisterValidatorSet(opts *bind.TransactOpts, message ICMMessage, validatorBytes []byte) (*types.Transaction, error) { + return _AvalancheValidatorSetRegistry.contract.Transact(opts, "registerValidatorSet", message, validatorBytes) +} + +// RegisterValidatorSet is a paid mutator transaction binding the contract method 0xfd94b8ea. +// +// Solidity: function registerValidatorSet(((uint32,bytes32,bytes),bytes,(bytes,bytes)) message, bytes validatorBytes) returns(uint256) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistrySession) RegisterValidatorSet(message ICMMessage, validatorBytes []byte) (*types.Transaction, error) { + return _AvalancheValidatorSetRegistry.Contract.RegisterValidatorSet(&_AvalancheValidatorSetRegistry.TransactOpts, message, validatorBytes) +} + +// RegisterValidatorSet is a paid mutator transaction binding the contract method 0xfd94b8ea. +// +// Solidity: function registerValidatorSet(((uint32,bytes32,bytes),bytes,(bytes,bytes)) message, bytes validatorBytes) returns(uint256) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryTransactorSession) RegisterValidatorSet(message ICMMessage, validatorBytes []byte) (*types.Transaction, error) { + return _AvalancheValidatorSetRegistry.Contract.RegisterValidatorSet(&_AvalancheValidatorSetRegistry.TransactOpts, message, validatorBytes) +} + +// UpdateValidatorSet is a paid mutator transaction binding the contract method 0x4095a588. +// +// Solidity: function updateValidatorSet(uint256 validatorSetID, ((uint32,bytes32,bytes),bytes,(bytes,bytes)) message, bytes validatorBytes) returns() +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryTransactor) UpdateValidatorSet(opts *bind.TransactOpts, validatorSetID *big.Int, message ICMMessage, validatorBytes []byte) (*types.Transaction, error) { + return _AvalancheValidatorSetRegistry.contract.Transact(opts, "updateValidatorSet", validatorSetID, message, validatorBytes) +} + +// UpdateValidatorSet is a paid mutator transaction binding the contract method 0x4095a588. +// +// Solidity: function updateValidatorSet(uint256 validatorSetID, ((uint32,bytes32,bytes),bytes,(bytes,bytes)) message, bytes validatorBytes) returns() +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistrySession) UpdateValidatorSet(validatorSetID *big.Int, message ICMMessage, validatorBytes []byte) (*types.Transaction, error) { + return _AvalancheValidatorSetRegistry.Contract.UpdateValidatorSet(&_AvalancheValidatorSetRegistry.TransactOpts, validatorSetID, message, validatorBytes) +} + +// UpdateValidatorSet is a paid mutator transaction binding the contract method 0x4095a588. +// +// Solidity: function updateValidatorSet(uint256 validatorSetID, ((uint32,bytes32,bytes),bytes,(bytes,bytes)) message, bytes validatorBytes) returns() +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryTransactorSession) UpdateValidatorSet(validatorSetID *big.Int, message ICMMessage, validatorBytes []byte) (*types.Transaction, error) { + return _AvalancheValidatorSetRegistry.Contract.UpdateValidatorSet(&_AvalancheValidatorSetRegistry.TransactOpts, validatorSetID, message, validatorBytes) +} + +// AvalancheValidatorSetRegistryValidatorSetRegisteredIterator is returned from FilterValidatorSetRegistered and is used to iterate over the raw logs and unpacked data for ValidatorSetRegistered events raised by the AvalancheValidatorSetRegistry contract. +type AvalancheValidatorSetRegistryValidatorSetRegisteredIterator struct { + Event *AvalancheValidatorSetRegistryValidatorSetRegistered // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AvalancheValidatorSetRegistryValidatorSetRegisteredIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AvalancheValidatorSetRegistryValidatorSetRegistered) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AvalancheValidatorSetRegistryValidatorSetRegistered) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AvalancheValidatorSetRegistryValidatorSetRegisteredIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AvalancheValidatorSetRegistryValidatorSetRegisteredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AvalancheValidatorSetRegistryValidatorSetRegistered represents a ValidatorSetRegistered event raised by the AvalancheValidatorSetRegistry contract. +type AvalancheValidatorSetRegistryValidatorSetRegistered struct { + ValidatorSetID *big.Int + AvalancheBlockchainID [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterValidatorSetRegistered is a free log retrieval operation binding the contract event 0xe93e9f47e7810153341664fc2050adcb29c88899748615c477d17b712d621583. +// +// Solidity: event ValidatorSetRegistered(uint256 indexed validatorSetID, bytes32 indexed avalancheBlockchainID) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryFilterer) FilterValidatorSetRegistered(opts *bind.FilterOpts, validatorSetID []*big.Int, avalancheBlockchainID [][32]byte) (*AvalancheValidatorSetRegistryValidatorSetRegisteredIterator, error) { + + var validatorSetIDRule []interface{} + for _, validatorSetIDItem := range validatorSetID { + validatorSetIDRule = append(validatorSetIDRule, validatorSetIDItem) + } + var avalancheBlockchainIDRule []interface{} + for _, avalancheBlockchainIDItem := range avalancheBlockchainID { + avalancheBlockchainIDRule = append(avalancheBlockchainIDRule, avalancheBlockchainIDItem) + } + + logs, sub, err := _AvalancheValidatorSetRegistry.contract.FilterLogs(opts, "ValidatorSetRegistered", validatorSetIDRule, avalancheBlockchainIDRule) + if err != nil { + return nil, err + } + return &AvalancheValidatorSetRegistryValidatorSetRegisteredIterator{contract: _AvalancheValidatorSetRegistry.contract, event: "ValidatorSetRegistered", logs: logs, sub: sub}, nil +} + +// WatchValidatorSetRegistered is a free log subscription operation binding the contract event 0xe93e9f47e7810153341664fc2050adcb29c88899748615c477d17b712d621583. +// +// Solidity: event ValidatorSetRegistered(uint256 indexed validatorSetID, bytes32 indexed avalancheBlockchainID) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryFilterer) WatchValidatorSetRegistered(opts *bind.WatchOpts, sink chan<- *AvalancheValidatorSetRegistryValidatorSetRegistered, validatorSetID []*big.Int, avalancheBlockchainID [][32]byte) (event.Subscription, error) { + + var validatorSetIDRule []interface{} + for _, validatorSetIDItem := range validatorSetID { + validatorSetIDRule = append(validatorSetIDRule, validatorSetIDItem) + } + var avalancheBlockchainIDRule []interface{} + for _, avalancheBlockchainIDItem := range avalancheBlockchainID { + avalancheBlockchainIDRule = append(avalancheBlockchainIDRule, avalancheBlockchainIDItem) + } + + logs, sub, err := _AvalancheValidatorSetRegistry.contract.WatchLogs(opts, "ValidatorSetRegistered", validatorSetIDRule, avalancheBlockchainIDRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AvalancheValidatorSetRegistryValidatorSetRegistered) + if err := _AvalancheValidatorSetRegistry.contract.UnpackLog(event, "ValidatorSetRegistered", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseValidatorSetRegistered is a log parse operation binding the contract event 0xe93e9f47e7810153341664fc2050adcb29c88899748615c477d17b712d621583. +// +// Solidity: event ValidatorSetRegistered(uint256 indexed validatorSetID, bytes32 indexed avalancheBlockchainID) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryFilterer) ParseValidatorSetRegistered(log types.Log) (*AvalancheValidatorSetRegistryValidatorSetRegistered, error) { + event := new(AvalancheValidatorSetRegistryValidatorSetRegistered) + if err := _AvalancheValidatorSetRegistry.contract.UnpackLog(event, "ValidatorSetRegistered", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// AvalancheValidatorSetRegistryValidatorSetUpdatedIterator is returned from FilterValidatorSetUpdated and is used to iterate over the raw logs and unpacked data for ValidatorSetUpdated events raised by the AvalancheValidatorSetRegistry contract. +type AvalancheValidatorSetRegistryValidatorSetUpdatedIterator struct { + Event *AvalancheValidatorSetRegistryValidatorSetUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AvalancheValidatorSetRegistryValidatorSetUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AvalancheValidatorSetRegistryValidatorSetUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AvalancheValidatorSetRegistryValidatorSetUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AvalancheValidatorSetRegistryValidatorSetUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AvalancheValidatorSetRegistryValidatorSetUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AvalancheValidatorSetRegistryValidatorSetUpdated represents a ValidatorSetUpdated event raised by the AvalancheValidatorSetRegistry contract. +type AvalancheValidatorSetRegistryValidatorSetUpdated struct { + ValidatorSetID *big.Int + AvalancheBlockchainID [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterValidatorSetUpdated is a free log retrieval operation binding the contract event 0xd48741f16bef6492997e28d107c7a13b06376de704072bdb37a9b02e502ea1f9. +// +// Solidity: event ValidatorSetUpdated(uint256 indexed validatorSetID, bytes32 indexed avalancheBlockchainID) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryFilterer) FilterValidatorSetUpdated(opts *bind.FilterOpts, validatorSetID []*big.Int, avalancheBlockchainID [][32]byte) (*AvalancheValidatorSetRegistryValidatorSetUpdatedIterator, error) { + + var validatorSetIDRule []interface{} + for _, validatorSetIDItem := range validatorSetID { + validatorSetIDRule = append(validatorSetIDRule, validatorSetIDItem) + } + var avalancheBlockchainIDRule []interface{} + for _, avalancheBlockchainIDItem := range avalancheBlockchainID { + avalancheBlockchainIDRule = append(avalancheBlockchainIDRule, avalancheBlockchainIDItem) + } + + logs, sub, err := _AvalancheValidatorSetRegistry.contract.FilterLogs(opts, "ValidatorSetUpdated", validatorSetIDRule, avalancheBlockchainIDRule) + if err != nil { + return nil, err + } + return &AvalancheValidatorSetRegistryValidatorSetUpdatedIterator{contract: _AvalancheValidatorSetRegistry.contract, event: "ValidatorSetUpdated", logs: logs, sub: sub}, nil +} + +// WatchValidatorSetUpdated is a free log subscription operation binding the contract event 0xd48741f16bef6492997e28d107c7a13b06376de704072bdb37a9b02e502ea1f9. +// +// Solidity: event ValidatorSetUpdated(uint256 indexed validatorSetID, bytes32 indexed avalancheBlockchainID) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryFilterer) WatchValidatorSetUpdated(opts *bind.WatchOpts, sink chan<- *AvalancheValidatorSetRegistryValidatorSetUpdated, validatorSetID []*big.Int, avalancheBlockchainID [][32]byte) (event.Subscription, error) { + + var validatorSetIDRule []interface{} + for _, validatorSetIDItem := range validatorSetID { + validatorSetIDRule = append(validatorSetIDRule, validatorSetIDItem) + } + var avalancheBlockchainIDRule []interface{} + for _, avalancheBlockchainIDItem := range avalancheBlockchainID { + avalancheBlockchainIDRule = append(avalancheBlockchainIDRule, avalancheBlockchainIDItem) + } + + logs, sub, err := _AvalancheValidatorSetRegistry.contract.WatchLogs(opts, "ValidatorSetUpdated", validatorSetIDRule, avalancheBlockchainIDRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AvalancheValidatorSetRegistryValidatorSetUpdated) + if err := _AvalancheValidatorSetRegistry.contract.UnpackLog(event, "ValidatorSetUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseValidatorSetUpdated is a log parse operation binding the contract event 0xd48741f16bef6492997e28d107c7a13b06376de704072bdb37a9b02e502ea1f9. +// +// Solidity: event ValidatorSetUpdated(uint256 indexed validatorSetID, bytes32 indexed avalancheBlockchainID) +func (_AvalancheValidatorSetRegistry *AvalancheValidatorSetRegistryFilterer) ParseValidatorSetUpdated(log types.Log) (*AvalancheValidatorSetRegistryValidatorSetUpdated, error) { + event := new(AvalancheValidatorSetRegistryValidatorSetUpdated) + if err := _AvalancheValidatorSetRegistry.contract.UnpackLog(event, "ValidatorSetUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/abi-bindings/go/EthWarp/EthWarp.go b/abi-bindings/go/EthWarp/EthWarp.go new file mode 100644 index 000000000..1d49bbe06 --- /dev/null +++ b/abi-bindings/go/EthWarp/EthWarp.go @@ -0,0 +1,651 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package ethwarp + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ava-labs/libevm" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/types" + "github.com/ava-labs/libevm/event" + "github.com/ava-labs/subnet-evm/accounts/abi" + "github.com/ava-labs/subnet-evm/accounts/abi/bind" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// ICMMessage is an auto generated low-level Go binding around an user-defined struct. +type ICMMessage struct { + UnsignedMessage ICMUnsignedMessage + UnsignedMessageBytes []byte + Signature ICMSignature +} + +// ICMSignature is an auto generated low-level Go binding around an user-defined struct. +type ICMSignature struct { + Signers []byte + Signature []byte +} + +// ICMUnsignedMessage is an auto generated low-level Go binding around an user-defined struct. +type ICMUnsignedMessage struct { + AvalancheNetworkID uint32 + AvalancheSourceBlockchainID [32]byte + Payload []byte +} + +// WarpBlockHash is an auto generated low-level Go binding around an user-defined struct. +type WarpBlockHash struct { + SourceChainID [32]byte + BlockHash [32]byte +} + +// WarpMessage is an auto generated low-level Go binding around an user-defined struct. +type WarpMessage struct { + SourceChainID [32]byte + OriginSenderAddress common.Address + Payload []byte +} + +// EthWarpMetaData contains all meta data concerning the EthWarp contract. +var EthWarpMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockChainId\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"_warpSourceChainID\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"SendWarpMessage\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"blockchainID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBlockchainID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"avalancheNetworkID\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"avalancheSourceBlockchainID\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"internalType\":\"structICMUnsignedMessage\",\"name\":\"unsignedMessage\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"unsignedMessageBytes\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"signers\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structICMSignature\",\"name\":\"signature\",\"type\":\"tuple\"}],\"internalType\":\"structICMMessage\",\"name\":\"icmMessage\",\"type\":\"tuple\"}],\"name\":\"getVerifiedICMMessage\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"sourceChainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"originSenderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"internalType\":\"structWarpMessage\",\"name\":\"warpMessage\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"index\",\"type\":\"uint32\"}],\"name\":\"getVerifiedWarpBlockHash\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"sourceChainID\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"internalType\":\"structWarpBlockHash\",\"name\":\"\",\"type\":\"tuple\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"index\",\"type\":\"uint32\"}],\"name\":\"getVerifiedWarpMessage\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"sourceChainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"originSenderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"internalType\":\"structWarpMessage\",\"name\":\"\",\"type\":\"tuple\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"avaBlockchainId\",\"type\":\"bytes32\"}],\"name\":\"isChainRegistered\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"avaBlockchainId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"verifyWarpMessage\",\"type\":\"address\"}],\"name\":\"registerChain\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"sendWarpMessage\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"warpSourceChainID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x608034605657601f610de538819003918201601f19168301916001600160401b03831184841017605a57808492604094855283398101031260565760208151910151905f55600155604051610d76908161006f8239f35b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe6080806040526004361015610012575f80fd5b5f905f3560e01c9081634213cf7814610b9857508063559f29f514610b7b5780635eb13d5c14610a875780636f825350146109ed57806385a88ca1146109b3578063b1b731c8146101d2578063ce7f592914610161578063d127dc9b146101445763ee5b48eb14610081575f80fd5b346101395760203660031901126101395760043567ffffffffffffffff8111610140573660238201121561014057806004013567ffffffffffffffff811161013c57369101602401116101395760405162461bcd60e51b815260206004820152603e60248201527f53656e64696e672057617270206d657373616765732066726f6d20457468657260448201527f65756d206973206e6f742063757272656e746c7920737570706f7274656400006064820152608490fd5b80fd5b8280fd5b5080fd5b503461013957806003193601126101395760209054604051908152f35b50346101395760203660031901126101395761017b610bb1565b5060405162461bcd60e51b815260206004820152602860248201527f54686973206d6574686f642063616e6e6f742062652063616c6c6564206f6e20604482015267457468657265756d60c01b6064820152608490fd5b346108a75760203660031901126108a75760043567ffffffffffffffff81116108a75780600401908036039060606003198301126108a757610212610c95565b5061024060206102228580610cb4565b01355f908152600260205260409020546001600160a01b0316151590565b156109365760206102518480610cb4565b01355f52600260205260018060a01b0360405f20541691604051926339f5645160e01b845260206004850152843560621983018112156108a7576102db6102ca856102fa930160446004820191606060248b015263ffffffff6102b384610bc4565b1660848b0152602481013560a48b01520190610bd5565b606060c489015260e4880191610c07565b6102e86024860188610bd5565b87830360231901604489015290610c07565b604484013592604219018312156108a7578461035e8194926020968394019061035160048301602319868403016064870152602461034961033b8380610bd5565b604087526040870191610c07565b940190610bd5565b9189818503910152610c07565b03915afa90811561092b575f916108f0575b50156108ab578061038091610cb4565b600154906060813603126108a7576040519061039b82610c27565b6103a481610bc4565b82526020810135602083015260408101359067ffffffffffffffff82116108a7570136601f820112156108a7578035916103dd83610cc9565b926103eb6040519485610c73565b80845236602082850101116108a7576020815f928260409601838801378501015201908152610418610c95565b5051906060602060405161042b81610c57565b82815201528151156108935760208201516001600160f81b0319161580610873575b1561083b5781519060068092106106c8576104686004610cc9565b6104756040519182610c73565b60048152601f196104866004610cc9565b013660208301375f5b6004811061080257506104a3600191610cf6565b60e01c036107bd57825191600a8093106106c8576104c16004610cc9565b906104cf6040519283610c73565b60048252601f196104e06004610cc9565b013660208401375f5b600481106107865750506104fc90610cf6565b60e01c9183518382019081831161070d5781116106c85761051c84610cc9565b9161052a6040519384610c73565b848352601f1961053986610cc9565b013660208501375f5b85811061074f57505063ffffffff811161070d5763ffffffff168451600482019081831161070d57106106c8576105796004610cc9565b906105876040519283610c73565b60048252601f196105986004610cc9565b013660208401375f5b600481106107215750506105b490610cf6565b60e01c92600e0163ffffffff811161070d5763ffffffff169284516105d98286610d33565b116106c8576105e781610cc9565b936105f56040519586610c73565b818552601f1961060483610cc9565b013660208701375f5b828110610694578560a086826020886040519061062982610c57565b815201526040519061063a82610c27565b81526020808201935f8552604083019081526040519485938385525183850152600180861b039051166040840152516060808401528051918291826080860152018484015e5f828201840152601f01601f19168101030190f35b6001906001600160f81b03196106b36106ad8386610d33565b8a610ce5565b51165f1a6106c18289610ce5565b530161060d565b60405162461bcd60e51b815260206004820152601960248201527f42797465536c696365723a206f7574206f6620626f756e6473000000000000006044820152606490fd5b634e487b7160e01b5f52601160045260245ffd5b6001906001600160f81b031961073a6106ad8386610d33565b51165f1a6107488286610ce5565b53016105a1565b8082019081831161070d576001916001600160f81b031990610771908a610ce5565b51165f1a61077f8287610ce5565b5301610542565b8082019081831161070d576001916001600160f81b0319906107a89089610ce5565b51165f1a6107b68286610ce5565b53016104e9565b60405162461bcd60e51b815260206004820152601760248201527f496e76616c6964207061796c6f616420747970652049440000000000000000006044820152606490fd5b80600201908160021161070d576001916001600160f81b0319906108269088610ce5565b51165f1a6108348285610ce5565b530161048f565b60405162461bcd60e51b815260206004820152601060248201526f125b9d985b1a590818dbd91958c8125160821b6044820152606490fd5b508151600110156108935760218201516001600160f81b0319161561044d565b634e487b7160e01b5f52603260045260245ffd5b5f80fd5b60405162461bcd60e51b815260206004820152601f60248201527f526563656976656420616e20696e76616c69642049434d206d657373616765006044820152606490fd5b90506020813d602011610923575b8161090b60209383610c73565b810103126108a7575180151581036108a75782610370565b3d91506108fe565b6040513d5f823e3d90fd5b60405162461bcd60e51b815260206004820152604960248201527f43616e6e6f74207265636569766520612057617270206d65737361676520667260448201527f6f6d206120636861696e2077686f73652076616c696461746f7220736574206960648201526839903ab735b737bbb760b91b608482015260a490fd5b346108a75760203660031901126108a7576004355f908152600260209081526040909120546001600160a01b031615156040519015158152f35b346108a75760203660031901126108a757610a06610bb1565b5060405162461bcd60e51b815260206004820152604c60248201527f54686973206d6574686f642063616e27742062652063616c6c6564206f6e204560448201527f7468657265756d2c207573652060676574566572696669656449434d4d65737360648201526b1859d958081a5b9cdd19585960a21b608482015260a490fd5b346108a75760403660031901126108a7576024356001600160a01b03811690600435908290036108a7575f818152600260205260409020546001600160a01b0316610b37578115610af2575f90815260026020526040902080546001600160a01b0319169091179055005b60405162461bcd60e51b815260206004820152601f60248201527f50726f7669646564206164647265737320646f6573206e6f74206578697374006044820152606490fd5b606460405162461bcd60e51b815260206004820152602060248201527f5468697320636861696e20697320616c726561647920726567697374657265646044820152fd5b346108a7575f3660031901126108a7576020600154604051908152f35b346108a7575f3660031901126108a7576020905f548152f35b6004359063ffffffff821682036108a757565b359063ffffffff821682036108a757565b9035601e19823603018112156108a757016020813591019167ffffffffffffffff82116108a75781360383136108a757565b908060209392818452848401375f828201840152601f01601f1916010190565b6060810190811067ffffffffffffffff821117610c4357604052565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff821117610c4357604052565b90601f8019910116810190811067ffffffffffffffff821117610c4357604052565b60405190610ca282610c27565b60606040835f81525f60208201520152565b903590605e19813603018212156108a7570190565b67ffffffffffffffff8111610c4357601f01601f191660200190565b908151811015610893570160200190565b80516020909101516001600160e01b0319811692919060048210610d18575050565b6001600160e01b031960049290920360031b82901b16169150565b9190820180921161070d5756fea2646970667358221220279983b4c4045dc7b7b5f4915bf372ebe8cb7ea118fe32906d1caecd8cec21ea64736f6c634300081e0033", +} + +// EthWarpABI is the input ABI used to generate the binding from. +// Deprecated: Use EthWarpMetaData.ABI instead. +var EthWarpABI = EthWarpMetaData.ABI + +// EthWarpBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use EthWarpMetaData.Bin instead. +var EthWarpBin = EthWarpMetaData.Bin + +// DeployEthWarp deploys a new Ethereum contract, binding an instance of EthWarp to it. +func DeployEthWarp(auth *bind.TransactOpts, backend bind.ContractBackend, blockChainId *big.Int, _warpSourceChainID [32]byte) (common.Address, *types.Transaction, *EthWarp, error) { + parsed, err := EthWarpMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(EthWarpBin), backend, blockChainId, _warpSourceChainID) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &EthWarp{EthWarpCaller: EthWarpCaller{contract: contract}, EthWarpTransactor: EthWarpTransactor{contract: contract}, EthWarpFilterer: EthWarpFilterer{contract: contract}}, nil +} + +// EthWarp is an auto generated Go binding around an Ethereum contract. +type EthWarp struct { + EthWarpCaller // Read-only binding to the contract + EthWarpTransactor // Write-only binding to the contract + EthWarpFilterer // Log filterer for contract events +} + +// EthWarpCaller is an auto generated read-only Go binding around an Ethereum contract. +type EthWarpCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// EthWarpTransactor is an auto generated write-only Go binding around an Ethereum contract. +type EthWarpTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// EthWarpFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type EthWarpFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// EthWarpSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type EthWarpSession struct { + Contract *EthWarp // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// EthWarpCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type EthWarpCallerSession struct { + Contract *EthWarpCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// EthWarpTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type EthWarpTransactorSession struct { + Contract *EthWarpTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// EthWarpRaw is an auto generated low-level Go binding around an Ethereum contract. +type EthWarpRaw struct { + Contract *EthWarp // Generic contract binding to access the raw methods on +} + +// EthWarpCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type EthWarpCallerRaw struct { + Contract *EthWarpCaller // Generic read-only contract binding to access the raw methods on +} + +// EthWarpTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type EthWarpTransactorRaw struct { + Contract *EthWarpTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewEthWarp creates a new instance of EthWarp, bound to a specific deployed contract. +func NewEthWarp(address common.Address, backend bind.ContractBackend) (*EthWarp, error) { + contract, err := bindEthWarp(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &EthWarp{EthWarpCaller: EthWarpCaller{contract: contract}, EthWarpTransactor: EthWarpTransactor{contract: contract}, EthWarpFilterer: EthWarpFilterer{contract: contract}}, nil +} + +// NewEthWarpCaller creates a new read-only instance of EthWarp, bound to a specific deployed contract. +func NewEthWarpCaller(address common.Address, caller bind.ContractCaller) (*EthWarpCaller, error) { + contract, err := bindEthWarp(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &EthWarpCaller{contract: contract}, nil +} + +// NewEthWarpTransactor creates a new write-only instance of EthWarp, bound to a specific deployed contract. +func NewEthWarpTransactor(address common.Address, transactor bind.ContractTransactor) (*EthWarpTransactor, error) { + contract, err := bindEthWarp(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &EthWarpTransactor{contract: contract}, nil +} + +// NewEthWarpFilterer creates a new log filterer instance of EthWarp, bound to a specific deployed contract. +func NewEthWarpFilterer(address common.Address, filterer bind.ContractFilterer) (*EthWarpFilterer, error) { + contract, err := bindEthWarp(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &EthWarpFilterer{contract: contract}, nil +} + +// bindEthWarp binds a generic wrapper to an already deployed contract. +func bindEthWarp(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := EthWarpMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_EthWarp *EthWarpRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _EthWarp.Contract.EthWarpCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_EthWarp *EthWarpRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _EthWarp.Contract.EthWarpTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_EthWarp *EthWarpRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _EthWarp.Contract.EthWarpTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_EthWarp *EthWarpCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _EthWarp.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_EthWarp *EthWarpTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _EthWarp.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_EthWarp *EthWarpTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _EthWarp.Contract.contract.Transact(opts, method, params...) +} + +// BlockchainID is a free data retrieval call binding the contract method 0xd127dc9b. +// +// Solidity: function blockchainID() view returns(bytes32) +func (_EthWarp *EthWarpCaller) BlockchainID(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _EthWarp.contract.Call(opts, &out, "blockchainID") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// BlockchainID is a free data retrieval call binding the contract method 0xd127dc9b. +// +// Solidity: function blockchainID() view returns(bytes32) +func (_EthWarp *EthWarpSession) BlockchainID() ([32]byte, error) { + return _EthWarp.Contract.BlockchainID(&_EthWarp.CallOpts) +} + +// BlockchainID is a free data retrieval call binding the contract method 0xd127dc9b. +// +// Solidity: function blockchainID() view returns(bytes32) +func (_EthWarp *EthWarpCallerSession) BlockchainID() ([32]byte, error) { + return _EthWarp.Contract.BlockchainID(&_EthWarp.CallOpts) +} + +// GetBlockchainID is a free data retrieval call binding the contract method 0x4213cf78. +// +// Solidity: function getBlockchainID() view returns(bytes32) +func (_EthWarp *EthWarpCaller) GetBlockchainID(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _EthWarp.contract.Call(opts, &out, "getBlockchainID") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetBlockchainID is a free data retrieval call binding the contract method 0x4213cf78. +// +// Solidity: function getBlockchainID() view returns(bytes32) +func (_EthWarp *EthWarpSession) GetBlockchainID() ([32]byte, error) { + return _EthWarp.Contract.GetBlockchainID(&_EthWarp.CallOpts) +} + +// GetBlockchainID is a free data retrieval call binding the contract method 0x4213cf78. +// +// Solidity: function getBlockchainID() view returns(bytes32) +func (_EthWarp *EthWarpCallerSession) GetBlockchainID() ([32]byte, error) { + return _EthWarp.Contract.GetBlockchainID(&_EthWarp.CallOpts) +} + +// GetVerifiedICMMessage is a free data retrieval call binding the contract method 0xb1b731c8. +// +// Solidity: function getVerifiedICMMessage(((uint32,bytes32,bytes),bytes,(bytes,bytes)) icmMessage) view returns((bytes32,address,bytes) warpMessage) +func (_EthWarp *EthWarpCaller) GetVerifiedICMMessage(opts *bind.CallOpts, icmMessage ICMMessage) (WarpMessage, error) { + var out []interface{} + err := _EthWarp.contract.Call(opts, &out, "getVerifiedICMMessage", icmMessage) + + if err != nil { + return *new(WarpMessage), err + } + + out0 := *abi.ConvertType(out[0], new(WarpMessage)).(*WarpMessage) + + return out0, err + +} + +// GetVerifiedICMMessage is a free data retrieval call binding the contract method 0xb1b731c8. +// +// Solidity: function getVerifiedICMMessage(((uint32,bytes32,bytes),bytes,(bytes,bytes)) icmMessage) view returns((bytes32,address,bytes) warpMessage) +func (_EthWarp *EthWarpSession) GetVerifiedICMMessage(icmMessage ICMMessage) (WarpMessage, error) { + return _EthWarp.Contract.GetVerifiedICMMessage(&_EthWarp.CallOpts, icmMessage) +} + +// GetVerifiedICMMessage is a free data retrieval call binding the contract method 0xb1b731c8. +// +// Solidity: function getVerifiedICMMessage(((uint32,bytes32,bytes),bytes,(bytes,bytes)) icmMessage) view returns((bytes32,address,bytes) warpMessage) +func (_EthWarp *EthWarpCallerSession) GetVerifiedICMMessage(icmMessage ICMMessage) (WarpMessage, error) { + return _EthWarp.Contract.GetVerifiedICMMessage(&_EthWarp.CallOpts, icmMessage) +} + +// GetVerifiedWarpBlockHash is a free data retrieval call binding the contract method 0xce7f5929. +// +// Solidity: function getVerifiedWarpBlockHash(uint32 index) pure returns((bytes32,bytes32), bool) +func (_EthWarp *EthWarpCaller) GetVerifiedWarpBlockHash(opts *bind.CallOpts, index uint32) (WarpBlockHash, bool, error) { + var out []interface{} + err := _EthWarp.contract.Call(opts, &out, "getVerifiedWarpBlockHash", index) + + if err != nil { + return *new(WarpBlockHash), *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(WarpBlockHash)).(*WarpBlockHash) + out1 := *abi.ConvertType(out[1], new(bool)).(*bool) + + return out0, out1, err + +} + +// GetVerifiedWarpBlockHash is a free data retrieval call binding the contract method 0xce7f5929. +// +// Solidity: function getVerifiedWarpBlockHash(uint32 index) pure returns((bytes32,bytes32), bool) +func (_EthWarp *EthWarpSession) GetVerifiedWarpBlockHash(index uint32) (WarpBlockHash, bool, error) { + return _EthWarp.Contract.GetVerifiedWarpBlockHash(&_EthWarp.CallOpts, index) +} + +// GetVerifiedWarpBlockHash is a free data retrieval call binding the contract method 0xce7f5929. +// +// Solidity: function getVerifiedWarpBlockHash(uint32 index) pure returns((bytes32,bytes32), bool) +func (_EthWarp *EthWarpCallerSession) GetVerifiedWarpBlockHash(index uint32) (WarpBlockHash, bool, error) { + return _EthWarp.Contract.GetVerifiedWarpBlockHash(&_EthWarp.CallOpts, index) +} + +// GetVerifiedWarpMessage is a free data retrieval call binding the contract method 0x6f825350. +// +// Solidity: function getVerifiedWarpMessage(uint32 index) pure returns((bytes32,address,bytes), bool) +func (_EthWarp *EthWarpCaller) GetVerifiedWarpMessage(opts *bind.CallOpts, index uint32) (WarpMessage, bool, error) { + var out []interface{} + err := _EthWarp.contract.Call(opts, &out, "getVerifiedWarpMessage", index) + + if err != nil { + return *new(WarpMessage), *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(WarpMessage)).(*WarpMessage) + out1 := *abi.ConvertType(out[1], new(bool)).(*bool) + + return out0, out1, err + +} + +// GetVerifiedWarpMessage is a free data retrieval call binding the contract method 0x6f825350. +// +// Solidity: function getVerifiedWarpMessage(uint32 index) pure returns((bytes32,address,bytes), bool) +func (_EthWarp *EthWarpSession) GetVerifiedWarpMessage(index uint32) (WarpMessage, bool, error) { + return _EthWarp.Contract.GetVerifiedWarpMessage(&_EthWarp.CallOpts, index) +} + +// GetVerifiedWarpMessage is a free data retrieval call binding the contract method 0x6f825350. +// +// Solidity: function getVerifiedWarpMessage(uint32 index) pure returns((bytes32,address,bytes), bool) +func (_EthWarp *EthWarpCallerSession) GetVerifiedWarpMessage(index uint32) (WarpMessage, bool, error) { + return _EthWarp.Contract.GetVerifiedWarpMessage(&_EthWarp.CallOpts, index) +} + +// IsChainRegistered is a free data retrieval call binding the contract method 0x85a88ca1. +// +// Solidity: function isChainRegistered(bytes32 avaBlockchainId) view returns(bool) +func (_EthWarp *EthWarpCaller) IsChainRegistered(opts *bind.CallOpts, avaBlockchainId [32]byte) (bool, error) { + var out []interface{} + err := _EthWarp.contract.Call(opts, &out, "isChainRegistered", avaBlockchainId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsChainRegistered is a free data retrieval call binding the contract method 0x85a88ca1. +// +// Solidity: function isChainRegistered(bytes32 avaBlockchainId) view returns(bool) +func (_EthWarp *EthWarpSession) IsChainRegistered(avaBlockchainId [32]byte) (bool, error) { + return _EthWarp.Contract.IsChainRegistered(&_EthWarp.CallOpts, avaBlockchainId) +} + +// IsChainRegistered is a free data retrieval call binding the contract method 0x85a88ca1. +// +// Solidity: function isChainRegistered(bytes32 avaBlockchainId) view returns(bool) +func (_EthWarp *EthWarpCallerSession) IsChainRegistered(avaBlockchainId [32]byte) (bool, error) { + return _EthWarp.Contract.IsChainRegistered(&_EthWarp.CallOpts, avaBlockchainId) +} + +// WarpSourceChainID is a free data retrieval call binding the contract method 0x559f29f5. +// +// Solidity: function warpSourceChainID() view returns(bytes32) +func (_EthWarp *EthWarpCaller) WarpSourceChainID(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _EthWarp.contract.Call(opts, &out, "warpSourceChainID") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// WarpSourceChainID is a free data retrieval call binding the contract method 0x559f29f5. +// +// Solidity: function warpSourceChainID() view returns(bytes32) +func (_EthWarp *EthWarpSession) WarpSourceChainID() ([32]byte, error) { + return _EthWarp.Contract.WarpSourceChainID(&_EthWarp.CallOpts) +} + +// WarpSourceChainID is a free data retrieval call binding the contract method 0x559f29f5. +// +// Solidity: function warpSourceChainID() view returns(bytes32) +func (_EthWarp *EthWarpCallerSession) WarpSourceChainID() ([32]byte, error) { + return _EthWarp.Contract.WarpSourceChainID(&_EthWarp.CallOpts) +} + +// RegisterChain is a paid mutator transaction binding the contract method 0x5eb13d5c. +// +// Solidity: function registerChain(bytes32 avaBlockchainId, address verifyWarpMessage) returns() +func (_EthWarp *EthWarpTransactor) RegisterChain(opts *bind.TransactOpts, avaBlockchainId [32]byte, verifyWarpMessage common.Address) (*types.Transaction, error) { + return _EthWarp.contract.Transact(opts, "registerChain", avaBlockchainId, verifyWarpMessage) +} + +// RegisterChain is a paid mutator transaction binding the contract method 0x5eb13d5c. +// +// Solidity: function registerChain(bytes32 avaBlockchainId, address verifyWarpMessage) returns() +func (_EthWarp *EthWarpSession) RegisterChain(avaBlockchainId [32]byte, verifyWarpMessage common.Address) (*types.Transaction, error) { + return _EthWarp.Contract.RegisterChain(&_EthWarp.TransactOpts, avaBlockchainId, verifyWarpMessage) +} + +// RegisterChain is a paid mutator transaction binding the contract method 0x5eb13d5c. +// +// Solidity: function registerChain(bytes32 avaBlockchainId, address verifyWarpMessage) returns() +func (_EthWarp *EthWarpTransactorSession) RegisterChain(avaBlockchainId [32]byte, verifyWarpMessage common.Address) (*types.Transaction, error) { + return _EthWarp.Contract.RegisterChain(&_EthWarp.TransactOpts, avaBlockchainId, verifyWarpMessage) +} + +// SendWarpMessage is a paid mutator transaction binding the contract method 0xee5b48eb. +// +// Solidity: function sendWarpMessage(bytes payload) returns(bytes32) +func (_EthWarp *EthWarpTransactor) SendWarpMessage(opts *bind.TransactOpts, payload []byte) (*types.Transaction, error) { + return _EthWarp.contract.Transact(opts, "sendWarpMessage", payload) +} + +// SendWarpMessage is a paid mutator transaction binding the contract method 0xee5b48eb. +// +// Solidity: function sendWarpMessage(bytes payload) returns(bytes32) +func (_EthWarp *EthWarpSession) SendWarpMessage(payload []byte) (*types.Transaction, error) { + return _EthWarp.Contract.SendWarpMessage(&_EthWarp.TransactOpts, payload) +} + +// SendWarpMessage is a paid mutator transaction binding the contract method 0xee5b48eb. +// +// Solidity: function sendWarpMessage(bytes payload) returns(bytes32) +func (_EthWarp *EthWarpTransactorSession) SendWarpMessage(payload []byte) (*types.Transaction, error) { + return _EthWarp.Contract.SendWarpMessage(&_EthWarp.TransactOpts, payload) +} + +// EthWarpSendWarpMessageIterator is returned from FilterSendWarpMessage and is used to iterate over the raw logs and unpacked data for SendWarpMessage events raised by the EthWarp contract. +type EthWarpSendWarpMessageIterator struct { + Event *EthWarpSendWarpMessage // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *EthWarpSendWarpMessageIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(EthWarpSendWarpMessage) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(EthWarpSendWarpMessage) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *EthWarpSendWarpMessageIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *EthWarpSendWarpMessageIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// EthWarpSendWarpMessage represents a SendWarpMessage event raised by the EthWarp contract. +type EthWarpSendWarpMessage struct { + Sender common.Address + MessageID [32]byte + Message []byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterSendWarpMessage is a free log retrieval operation binding the contract event 0x56600c567728a800c0aa927500f831cb451df66a7af570eb4df4dfbf4674887d. +// +// Solidity: event SendWarpMessage(address indexed sender, bytes32 indexed messageID, bytes message) +func (_EthWarp *EthWarpFilterer) FilterSendWarpMessage(opts *bind.FilterOpts, sender []common.Address, messageID [][32]byte) (*EthWarpSendWarpMessageIterator, error) { + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + var messageIDRule []interface{} + for _, messageIDItem := range messageID { + messageIDRule = append(messageIDRule, messageIDItem) + } + + logs, sub, err := _EthWarp.contract.FilterLogs(opts, "SendWarpMessage", senderRule, messageIDRule) + if err != nil { + return nil, err + } + return &EthWarpSendWarpMessageIterator{contract: _EthWarp.contract, event: "SendWarpMessage", logs: logs, sub: sub}, nil +} + +// WatchSendWarpMessage is a free log subscription operation binding the contract event 0x56600c567728a800c0aa927500f831cb451df66a7af570eb4df4dfbf4674887d. +// +// Solidity: event SendWarpMessage(address indexed sender, bytes32 indexed messageID, bytes message) +func (_EthWarp *EthWarpFilterer) WatchSendWarpMessage(opts *bind.WatchOpts, sink chan<- *EthWarpSendWarpMessage, sender []common.Address, messageID [][32]byte) (event.Subscription, error) { + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + var messageIDRule []interface{} + for _, messageIDItem := range messageID { + messageIDRule = append(messageIDRule, messageIDItem) + } + + logs, sub, err := _EthWarp.contract.WatchLogs(opts, "SendWarpMessage", senderRule, messageIDRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(EthWarpSendWarpMessage) + if err := _EthWarp.contract.UnpackLog(event, "SendWarpMessage", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseSendWarpMessage is a log parse operation binding the contract event 0x56600c567728a800c0aa927500f831cb451df66a7af570eb4df4dfbf4674887d. +// +// Solidity: event SendWarpMessage(address indexed sender, bytes32 indexed messageID, bytes message) +func (_EthWarp *EthWarpFilterer) ParseSendWarpMessage(log types.Log) (*EthWarpSendWarpMessage, error) { + event := new(EthWarpSendWarpMessage) + if err := _EthWarp.contract.UnpackLog(event, "SendWarpMessage", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/abi-bindings/go/teleporter/TeleporterMessenger/TeleporterMessenger.go b/abi-bindings/go/teleporter/TeleporterMessenger/TeleporterMessenger.go index 3ca975d13..9649cb6fc 100644 --- a/abi-bindings/go/teleporter/TeleporterMessenger/TeleporterMessenger.go +++ b/abi-bindings/go/teleporter/TeleporterMessenger/TeleporterMessenger.go @@ -29,6 +29,26 @@ var ( _ = abi.ConvertType ) +// ICMMessage is an auto generated low-level Go binding around an user-defined struct. +type ICMMessage struct { + UnsignedMessage ICMUnsignedMessage + UnsignedMessageBytes []byte + Signature ICMSignature +} + +// ICMSignature is an auto generated low-level Go binding around an user-defined struct. +type ICMSignature struct { + Signers []byte + Signature []byte +} + +// ICMUnsignedMessage is an auto generated low-level Go binding around an user-defined struct. +type ICMUnsignedMessage struct { + AvalancheNetworkID uint32 + AvalancheSourceBlockchainID [32]byte + Payload []byte +} + // TeleporterFeeInfo is an auto generated low-level Go binding around an user-defined struct. type TeleporterFeeInfo struct { FeeTokenAddress common.Address @@ -65,8 +85,8 @@ type TeleporterMessageReceipt struct { // TeleporterMessengerMetaData contains all meta data concerning the TeleporterMessenger contract. var TeleporterMessengerMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"},{\"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\":\"blockchainID\",\"type\":\"bytes32\"}],\"name\":\"BlockchainIDInitialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"sourceBlockchainID\",\"type\":\"bytes32\"}],\"name\":\"MessageExecuted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"sourceBlockchainID\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"messageNonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"originSenderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"destinationBlockchainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"allowedRelayerAddresses\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"receivedMessageNonce\",\"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\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"destinationBlockchainID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayerRewardAddress\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"feeTokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"structTeleporterFeeInfo\",\"name\":\"feeInfo\",\"type\":\"tuple\"}],\"name\":\"ReceiptReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"sourceBlockchainID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"deliverer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"rewardRedeemer\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"messageNonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"originSenderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"destinationBlockchainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"allowedRelayerAddresses\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"receivedMessageNonce\",\"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\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"destinationBlockchainID\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"messageNonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"originSenderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"destinationBlockchainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"allowedRelayerAddresses\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"receivedMessageNonce\",\"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\":\"messageID\",\"type\":\"bytes32\"},{\"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\":\"bytes32\",\"name\":\"sourceBlockchainID\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destinationBlockchainID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"name\":\"calculateMessageID\",\"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\":\"messageID\",\"type\":\"bytes32\"}],\"name\":\"getFeeInfo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"}],\"name\":\"getMessageHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"destinationBlockchainID\",\"type\":\"bytes32\"}],\"name\":\"getNextMessageID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"sourceBlockchainID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getReceiptAtIndex\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"receivedMessageNonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"relayerRewardAddress\",\"type\":\"address\"}],\"internalType\":\"structTeleporterMessageReceipt\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"sourceBlockchainID\",\"type\":\"bytes32\"}],\"name\":\"getReceiptQueueSize\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"}],\"name\":\"getRelayerRewardAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initializeBlockchainID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messageNonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"}],\"name\":\"messageReceived\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"sourceBlockchainID\",\"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\":\"messageID\",\"type\":\"bytes32\"}],\"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\":\"sourceBlockchainID\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"messageNonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"originSenderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"destinationBlockchainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"allowedRelayerAddresses\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"receivedMessageNonce\",\"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\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"messageNonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"originSenderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"destinationBlockchainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"allowedRelayerAddresses\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"receivedMessageNonce\",\"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\":\"destinationBlockchainID\",\"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\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"sourceBlockchainID\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32[]\",\"name\":\"messageIDs\",\"type\":\"bytes32[]\"},{\"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\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"}],\"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\"}]", - Bin: "0x6080604052348015600e575f80fd5b5060015f8190558055613142806100245f395ff3fe608060405234801561000f575f80fd5b5060043610610148575f3560e01c8063a8898181116100bf578063df20e8bc11610079578063df20e8bc14610331578063e69d606a14610344578063e6e67bd5146103ab578063ebc3b1ba146103e6578063ecc7042814610409578063fc2d619714610412575f80fd5b8063a8898181146102a9578063a9a85614146102bc578063b771b3bc146102cf578063c473eef8146102dd578063ccb5f80914610315578063d127dc9b14610328575f80fd5b8063399b77da11610110578063399b77da1461021257806362448850146102315780638245a1b014610244578063860a3b0614610257578063892bf412146102765780638ac0fd0414610296575f80fd5b80630af5b4ff1461014c57806322296c3a146101675780632bc8b0bf1461017c5780632ca40f551461018f5780632e27c223146101e7575b5f80fd5b610154610425565b6040519081526020015b60405180910390f35b61017a610175366004612138565b6104f3565b005b61015461018a366004612153565b6105e6565b6101d961019d366004612153565b600560209081525f9182526040918290208054835180850190945260018201546001600160a01b03168452600290910154918301919091529082565b60405161015e92919061216a565b6101fa6101f5366004612153565b610602565b6040516001600160a01b03909116815260200161015e565b610154610220366004612153565b5f9081526005602052604090205490565b61015461023f366004612191565b610689565b61017a6102523660046121de565b6106e2565b610154610265366004612153565b60066020525f908152604090205481565b61028961028436600461220f565b610885565b60405161015e919061222f565b61017a6102a436600461224f565b6108b6565b6101546102b7366004612284565b610aed565b6101546102ca3660046122f4565b610b2f565b6101fa6005600160991b0181565b6101546102eb366004612385565b6001600160a01b039182165f90815260096020908152604080832093909416825291909152205490565b61017a6103233660046123bc565b610dc1565b61015460025481565b61015461033f366004612153565b6111e3565b61038c610352366004612153565b5f90815260056020908152604091829020825180840190935260018101546001600160a01b03168084526002909101549290910182905291565b604080516001600160a01b03909316835260208301919091520161015e565b6103d16103b9366004612153565b60046020525f90815260409020805460019091015482565b6040805192835260208301919091520161015e565b6103f96103f4366004612153565b61122a565b604051901515815260200161015e565b61015460035481565b61017a6104203660046123e0565b61123f565b6002545f90806104ee576005600160991b016001600160a01b0316634213cf786040518163ffffffff1660e01b8152600401602060405180830381865afa158015610472573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104969190612423565b9050806104be5760405162461bcd60e51b81526004016104b59061243a565b60405180910390fd5b600281905560405181907f1eac640109dc937d2a9f42735a05f794b39a5e3759d681951d671aabbce4b104905f90a25b919050565b335f9081526009602090815260408083206001600160a01b0385168452909152902054806105745760405162461bcd60e51b815260206004820152602860248201527f54656c65706f727465724d657373656e6765723a206e6f2072657761726420746044820152676f2072656465656d60c01b60648201526084016104b5565b335f8181526009602090815260408083206001600160a01b03871680855290835281842093909355518481529192917f3294c84e5b0f29d9803655319087207bc94f4db29f7927846944822773780b88910160405180910390a36105e26001600160a01b0383163383611494565b5050565b5f8181526004602052604081206105fc906114f8565b92915050565b5f8181526007602052604081205461066e5760405162461bcd60e51b815260206004820152602960248201527f54656c65706f727465724d657373656e6765723a206d657373616765206e6f74604482015268081c9958d95a5d995960ba1b60648201526084016104b5565b505f908152600860205260409020546001600160a01b031690565b5f60015f54146106ab5760405162461bcd60e51b81526004016104b590612481565b60025f556106d86106bb836126b8565b83355f9081526004602052604090206106d39061150a565b611604565b60015f5592915050565b60015f54146107035760405162461bcd60e51b81526004016104b590612481565b60025f818155905461071b9060408401358435610aed565b5f818152600560209081526040918290208251808401845281548152835180850190945260018201546001600160a01b0316845260029091015483830152908101919091528051919250906107825760405162461bcd60e51b81526004016104b590612757565b5f8360405160200161079491906129d6565b60408051601f19818403018152919052825181516020830120919250146107cd5760405162461bcd60e51b81526004016104b5906129e8565b8360400135837f2a211ad4a59ab9d003852404f9c57c690704ee755f3c79d2c2812ad32da99df8868560200151604051610808929190612a31565b60405180910390a360405163ee5b48eb60e01b81526005600160991b019063ee5b48eb9061083a908490600401612ab2565b6020604051808303815f875af1158015610856573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061087a9190612423565b505060015f55505050565b604080518082019091525f80825260208201525f8381526004602052604090206108af9083611837565b9392505050565b60015f54146108d75760405162461bcd60e51b81526004016104b590612481565b60025f5560018054146108fc5760405162461bcd60e51b81526004016104b590612ac4565b6002600155806109665760405162461bcd60e51b815260206004820152602f60248201527f54656c65706f727465724d657373656e6765723a207a65726f2061646469746960448201526e1bdb985b0819995948185b5bdd5b9d608a1b60648201526084016104b5565b6001600160a01b03821661098c5760405162461bcd60e51b81526004016104b590612b09565b5f838152600560205260409020546109b65760405162461bcd60e51b81526004016104b590612757565b5f838152600560205260409020600101546001600160a01b03838116911614610a475760405162461bcd60e51b815260206004820152603760248201527f54656c65706f727465724d657373656e6765723a20696e76616c69642066656560448201527f20617373657420636f6e7472616374206164647265737300000000000000000060648201526084016104b5565b5f610a5283836118f8565b5f85815260056020526040812060020180549293508392909190610a77908490612b71565b90915550505f8481526005602052604090819020905185917fc1bfd1f1208927dfbd414041dcb5256e6c9ad90dd61aec3249facbd34ff7b3e191610ad8916001019081546001600160a01b0316815260019190910154602082015260400190565b60405180910390a2505060018080555f555050565b6040805130602082015290810184905260608101839052608081018290525f9060a0016040516020818303038152906040528051906020012090509392505050565b5f60015f5414610b515760405162461bcd60e51b81526004016104b590612481565b60025f818155905490866001600160401b03811115610b7257610b726124c4565b604051908082528060200260200182016040528015610bb657816020015b604080518082019091525f8082526020820152815260200190600190039081610b905790505b509050865f5b81811015610d2e575f8a8a83818110610bd757610bd7612b84565b9050602002013590505f60075f8381526020019081526020015f20549050805f03610c535760405162461bcd60e51b815260206004820152602660248201527f54656c65706f727465724d657373656e6765723a2072656365697074206e6f7460448201526508199bdd5b9960d21b60648201526084016104b5565b610c5e8d8783610aed565b8214610cd25760405162461bcd60e51b815260206004820152603a60248201527f54656c65706f727465724d657373656e6765723a206d6573736167652049442060448201527f6e6f742066726f6d20736f7572636520626c6f636b636861696e00000000000060648201526084016104b5565b5f828152600860209081526040918290205482518084019093528383526001600160a01b03169082018190528651909190879086908110610d1557610d15612b84565b6020026020010181905250505050806001019050610bbc565b506040805160c0810182528b81525f6020820152610daf918101610d57368b90038b018b612b98565b81526020015f81526020018888808060200260200160405190810160405280939291908181526020018383602002808284375f9201829052509385525050604080519283526020808401909152909201525083611604565b60015f559a9950505050505050505050565b6001805414610de25760405162461bcd60e51b81526004016104b590612ac4565b60026001556040516306f8253560e41b815263ffffffff831660048201525f9081906005600160991b0190636f825350906024015f60405180830381865afa158015610e30573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610e579190810190612c0e565b9150915080610eba5760405162461bcd60e51b815260206004820152602960248201527f54656c65706f727465724d657373656e6765723a20696e76616c69642077617260448201526870206d65737361676560b81b60648201526084016104b5565b60208201516001600160a01b03163014610f315760405162461bcd60e51b815260206004820152603260248201527f54656c65706f727465724d657373656e6765723a20696e76616c6964206f726960448201527167696e2073656e646572206164647265737360701b60648201526084016104b5565b5f8260400151806020019051810190610f4a9190612da2565b90505f610f55610425565b905080826040015114610fc45760405162461bcd60e51b815260206004820152603160248201527f54656c65706f727465724d657373656e6765723a20696e76616c6964206465736044820152701d1a5b985d1a5bdb8818da185a5b881251607a1b60648201526084016104b5565b835182515f91610fd5918490610aed565b5f81815260076020526040902054909150156110495760405162461bcd60e51b815260206004820152602d60248201527f54656c65706f727465724d657373656e6765723a206d65737361676520616c7260448201526c1958591e481c9958d95a5d9959609a1b60648201526084016104b5565b611057338460a00151611904565b6110b55760405162461bcd60e51b815260206004820152602960248201527f54656c65706f727465724d657373656e6765723a20756e617574686f72697a6560448201526832103932b630bcb2b960b91b60648201526084016104b5565b6110c281845f0151611970565b6001600160a01b038616156110f8575f81815260086020526040902080546001600160a01b0319166001600160a01b0388161790555b60c0830151515f5b8181101561113b5761113384885f01518760c00151848151811061112657611126612b84565b60200260200101516119e0565b600101611100565b50604080518082018252855181526001600160a01b03891660208083019190915288515f90815260049091529190912061117491611b04565b336001600160a01b0316865f0151837f292ee90bbaf70b5d4936025e09d56ba08f3e421156b6a568cf3c2840d9343e348a886040516111b4929190612fb1565b60405180910390a460e084015151156111d5576111d582875f015186611b5e565b505060018055505050505050565b6002545f90806112055760405162461bcd60e51b81526004016104b59061243a565b5f60035460016112159190612b71565b9050611222828583610aed565b949350505050565b5f8181526007602052604081205415156105fc565b60018054146112605760405162461bcd60e51b81526004016104b590612ac4565b60026001819055545f906112779084908435610aed565b5f81815260066020526040902054909150806112a55760405162461bcd60e51b81526004016104b590612757565b80836040516020016112b791906129d6565b60405160208183030381529060405280519060200120146112ea5760405162461bcd60e51b81526004016104b5906129e8565b5f6112fb6080850160608601612138565b6001600160a01b03163b1161136f5760405162461bcd60e51b815260206004820152603460248201527f54656c65706f727465724d657373656e6765723a2064657374696e6174696f6e604482015273206164647265737320686173206e6f20636f646560601b60648201526084016104b5565b604051849083907f34795cc6b122b9a0ae684946319f1e14a577b4e8f9b3dda9ac94c21a54d3188c905f90a35f82815260066020908152604080832083905586916113be918701908701612138565b6113cb60e0870187612fd4565b6040516024016113de9493929190613016565b60408051601f198184030181529190526020810180516001600160e01b031663643477d560e11b17905290505f61142561141e6080870160608801612138565b5a84611c8d565b9050806114885760405162461bcd60e51b815260206004820152602b60248201527f54656c65706f727465724d657373656e6765723a20726574727920657865637560448201526a1d1a5bdb8819985a5b195960aa1b60648201526084016104b5565b50506001805550505050565b6040516001600160a01b038381166024830152604482018390526114f391859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050611ca4565b505050565b805460018201545f916105fc91613040565b60605f611520600561151b856114f8565b611d05565b9050805f0361156c57604080515f8082526020820190925290611564565b604080518082019091525f808252602082015281526020019060019003908161153e5790505b509392505050565b5f816001600160401b03811115611585576115856124c4565b6040519080825280602002602001820160405280156115c957816020015b604080518082019091525f80825260208201528152602001906001900390816115a35790505b5090505f5b82811015611564576115df85611d1a565b8282815181106115f1576115f1612b84565b60209081029190910101526001016115ce565b5f8061160e610425565b90505f60035f815461161f90613053565b91905081905590505f61163683875f015184610aed565b90505f604051806101000160405280848152602001336001600160a01b03168152602001885f0151815260200188602001516001600160a01b0316815260200188606001518152602001886080015181526020018781526020018860a0015181525090505f816040516020016116ac919061306b565b60405160208183030381529060405290505f808960400151602001511115611713576040890151516001600160a01b03166116f95760405162461bcd60e51b81526004016104b590612b09565b6040890151805160209091015161171091906118f8565b90505b6040805180820182528a820151516001600160a01b03908116825260208083018590528351808501855286518783012081528082018481525f8a815260058452869020915182555180516001830180546001600160a01b03191691909516179093559101516002909101558a51915190919086907f2a211ad4a59ab9d003852404f9c57c690704ee755f3c79d2c2812ad32da99df8906117b6908890869061307d565b60405180910390a360405163ee5b48eb60e01b81526005600160991b019063ee5b48eb906117e8908690600401612ab2565b6020604051808303815f875af1158015611804573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118289190612423565b50939998505050505050505050565b604080518082019091525f8082526020820152611853836114f8565b82106118ab5760405162461bcd60e51b815260206004820152602160248201527f5265636569707451756575653a20696e646578206f7574206f6620626f756e646044820152607360f81b60648201526084016104b5565b826002015f83855f01546118bf9190612b71565b815260208082019290925260409081015f20815180830190925280548252600101546001600160a01b0316918101919091529392505050565b5f6108af833384611de4565b5f81515f03611915575060016105fc565b81515f5b8181101561196657846001600160a01b031684828151811061193d5761193d612b84565b60200260200101516001600160a01b03160361195e576001925050506105fc565b600101611919565b505f949350505050565b805f036119cf5760405162461bcd60e51b815260206004820152602760248201527f54656c65706f727465724d657373656e6765723a207a65726f206d657373616760448201526665206e6f6e636560c81b60648201526084016104b5565b5f9182526007602052604090912055565b5f6119ef8484845f0151610aed565b5f818152600560209081526040918290208251808401845281548152835180850190945260018201546001600160a01b031684526002909101548383015290810191909152805191925090611a45575050505050565b5f8281526005602090815260408083208381556001810180546001600160a01b03191690556002018390558382018051830151878401516001600160a01b0390811686526009855283862092515116855292528220805491929091611aab908490612b71565b9250508190555082602001516001600160a01b031684837fd13a7935f29af029349bed0a2097455b91fd06190a30478c575db3f31e00bf578460200151604051611af5919061308f565b60405180910390a45050505050565b600182018054829160028501915f9182611b1d83613053565b9091555081526020808201929092526040015f2082518155910151600190910180546001600160a01b0319166001600160a01b039092169190911790555050565b80608001515a1015611bc05760405162461bcd60e51b815260206004820152602560248201527f54656c65706f727465724d657373656e6765723a20696e73756666696369656e604482015264742067617360d81b60648201526084016104b5565b80606001516001600160a01b03163b5f03611be0576114f3838383611f47565b602081015160e08201516040515f92611bfd9286926024016130af565b60408051601f198184030181529190526020810180516001600160e01b031663643477d560e11b179052606083015160808401519192505f91611c41919084611c8d565b905080611c5a57611c53858585611f47565b5050505050565b604051849086907f34795cc6b122b9a0ae684946319f1e14a577b4e8f9b3dda9ac94c21a54d3188c905f90a35050505050565b5f805f808451602086015f8989f195945050505050565b5f611cb86001600160a01b03841683611fbb565b905080515f14158015611cdc575080806020019051810190611cda91906130d8565b155b156114f357604051635274afe760e01b81526001600160a01b03841660048201526024016104b5565b5f818310611d1357816108af565b5090919050565b604080518082019091525f808252602082015281546001830154819003611d835760405162461bcd60e51b815260206004820152601960248201527f5265636569707451756575653a20656d7074792071756575650000000000000060448201526064016104b5565b5f8181526002840160208181526040808420815180830190925280548252600180820180546001600160a01b03811685870152888852959094529490556001600160a01b0319909216905590611dda908390612b71565b9093555090919050565b6040516370a0823160e01b81523060048201525f9081906001600160a01b038616906370a0823190602401602060405180830381865afa158015611e2a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e4e9190612423565b9050611e656001600160a01b038616853086611fc8565b6040516370a0823160e01b81523060048201525f906001600160a01b038716906370a0823190602401602060405180830381865afa158015611ea9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ecd9190612423565b9050818111611f335760405162461bcd60e51b815260206004820152602c60248201527f5361666545524332305472616e7366657246726f6d3a2062616c616e6365206e60448201526b1bdd081a5b98dc99585cd95960a21b60648201526084016104b5565b611f3d8282613040565b9695505050505050565b80604051602001611f58919061306b565b60408051601f1981840301815282825280516020918201205f878152600690925291902055829084907f4619adc1017b82e02eaefac01a43d50d6d8de4460774bc370c3ff0210d40c98590611fae90859061306b565b60405180910390a3505050565b60606108af83835f612007565b6040516001600160a01b0384811660248301528381166044830152606482018390526120019186918216906323b872dd906084016114c1565b50505050565b60608147101561202c5760405163cd78605960e01b81523060048201526024016104b5565b5f80856001600160a01b0316848660405161204791906130f1565b5f6040518083038185875af1925050503d805f8114612081576040519150601f19603f3d011682016040523d82523d5f602084013e612086565b606091505b5091509150611f3d8683836060826120a6576120a1826120ed565b6108af565b81511580156120bd57506001600160a01b0384163b155b156120e657604051639996b31560e01b81526001600160a01b03851660048201526024016104b5565b50806108af565b8051156120fd5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b50565b6001600160a01b0381168114612116575f80fd5b80356104ee81612119565b5f60208284031215612148575f80fd5b81356108af81612119565b5f60208284031215612163575f80fd5b5035919050565b828152606081016108af602083018480516001600160a01b03168252602090810151910152565b5f602082840312156121a1575f80fd5b81356001600160401b038111156121b6575f80fd5b820160e081850312156108af575f80fd5b5f61010082840312156121d8575f80fd5b50919050565b5f602082840312156121ee575f80fd5b81356001600160401b03811115612203575f80fd5b611222848285016121c7565b5f8060408385031215612220575f80fd5b50508035926020909101359150565b815181526020808301516001600160a01b031690820152604081016105fc565b5f805f60608486031215612261575f80fd5b83359250602084013561227381612119565b929592945050506040919091013590565b5f805f60608486031215612296575f80fd5b505081359360208301359350604090920135919050565b5f8083601f8401126122bd575f80fd5b5081356001600160401b038111156122d3575f80fd5b6020830191508360208260051b85010111156122ed575f80fd5b9250929050565b5f805f805f8086880360a081121561230a575f80fd5b8735965060208801356001600160401b0380821115612327575f80fd5b6123338b838c016122ad565b90985096508691506040603f198401121561234c575f80fd5b60408a01955060808a0135925080831115612365575f80fd5b505061237389828a016122ad565b979a9699509497509295939492505050565b5f8060408385031215612396575f80fd5b82356123a181612119565b915060208301356123b181612119565b809150509250929050565b5f80604083850312156123cd575f80fd5b823563ffffffff811681146123a1575f80fd5b5f80604083850312156123f1575f80fd5b8235915060208301356001600160401b0381111561240d575f80fd5b612419858286016121c7565b9150509250929050565b5f60208284031215612433575f80fd5b5051919050565b60208082526027908201527f54656c65706f727465724d657373656e6765723a207a65726f20626c6f636b636040820152661a185a5b88125160ca1b606082015260800190565b60208082526023908201527f5265656e7472616e63794775617264733a2073656e646572207265656e7472616040820152626e637960e81b606082015260800190565b634e487b7160e01b5f52604160045260245ffd5b604080519081016001600160401b03811182821017156124fa576124fa6124c4565b60405290565b60405160c081016001600160401b03811182821017156124fa576124fa6124c4565b60405161010081016001600160401b03811182821017156124fa576124fa6124c4565b604051601f8201601f191681016001600160401b038111828210171561256d5761256d6124c4565b604052919050565b5f60408284031215612585575f80fd5b61258d6124d8565b9050813561259a81612119565b808252506020820135602082015292915050565b5f6001600160401b038211156125c6576125c66124c4565b5060051b60200190565b5f82601f8301126125df575f80fd5b813560206125f46125ef836125ae565b612545565b8083825260208201915060208460051b870101935086841115612615575f80fd5b602086015b8481101561263a57803561262d81612119565b835291830191830161261a565b509695505050505050565b5f6001600160401b0382111561265d5761265d6124c4565b50601f01601f191660200190565b5f82601f83011261267a575f80fd5b81356126886125ef82612645565b81815284602083860101111561269c575f80fd5b816020850160208301375f918101602001919091529392505050565b5f60e082360312156126c8575f80fd5b6126d0612500565b823581526126e06020840161212d565b60208201526126f23660408501612575565b60408201526080830135606082015260a08301356001600160401b038082111561271a575f80fd5b612726368387016125d0565b608084015260c085013591508082111561273e575f80fd5b5061274b3682860161266b565b60a08301525092915050565b60208082526026908201527f54656c65706f727465724d657373656e6765723a206d657373616765206e6f7460408201526508199bdd5b9960d21b606082015260800190565b5f808335601e198436030181126127b2575f80fd5b83016020810192503590506001600160401b038111156127d0575f80fd5b8060051b36038213156122ed575f80fd5b8183525f60208085019450825f5b8581101561281d57813561280281612119565b6001600160a01b0316875295820195908201906001016127ef565b509495945050505050565b5f808335601e1984360301811261283d575f80fd5b83016020810192503590506001600160401b0381111561285b575f80fd5b8060061b36038213156122ed575f80fd5b8183525f60208085019450825f5b8581101561281d57813587528282013561289381612119565b6001600160a01b031687840152604096870196919091019060010161287a565b5f808335601e198436030181126128c8575f80fd5b83016020810192503590506001600160401b038111156128e6575f80fd5b8036038213156122ed575f80fd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b5f61010082358452602083013561293281612119565b6001600160a01b03166020850152604083810135908501526129566060840161212d565b6001600160a01b031660608501526080838101359085015261297b60a084018461279d565b8260a087015261298e83870182846127e1565b9250505061299f60c0840184612828565b85830360c08701526129b283828461286c565b925050506129c360e08401846128b3565b85830360e0870152611f3d8382846128f4565b602081525f6108af602083018461291c565b60208082526029908201527f54656c65706f727465724d657373656e6765723a20696e76616c6964206d65736040820152680e6c2ceca40d0c2e6d60bb1b606082015260800190565b606081525f612a43606083018561291c565b90506108af602083018480516001600160a01b03168252602090810151910152565b5f5b83811015612a7f578181015183820152602001612a67565b50505f910152565b5f8151808452612a9e816020860160208601612a65565b601f01601f19169290920160200192915050565b602081525f6108af6020830184612a87565b60208082526025908201527f5265656e7472616e63794775617264733a207265636569766572207265656e7460408201526472616e637960d81b606082015260800190565b60208082526034908201527f54656c65706f727465724d657373656e6765723a207a65726f2066656520617360408201527373657420636f6e7472616374206164647265737360601b606082015260800190565b634e487b7160e01b5f52601160045260245ffd5b808201808211156105fc576105fc612b5d565b634e487b7160e01b5f52603260045260245ffd5b5f60408284031215612ba8575f80fd5b6108af8383612575565b80516104ee81612119565b5f82601f830112612bcc575f80fd5b8151612bda6125ef82612645565b818152846020838601011115612bee575f80fd5b611222826020830160208701612a65565b805180151581146104ee575f80fd5b5f8060408385031215612c1f575f80fd5b82516001600160401b0380821115612c35575f80fd5b9084019060608287031215612c48575f80fd5b604051606081018181108382111715612c6357612c636124c4565b604052825181526020830151612c7881612119565b6020820152604083015182811115612c8e575f80fd5b612c9a88828601612bbd565b6040830152509350612cb191505060208401612bff565b90509250929050565b5f82601f830112612cc9575f80fd5b81516020612cd96125ef836125ae565b8083825260208201915060208460051b870101935086841115612cfa575f80fd5b602086015b8481101561263a578051612d1281612119565b8352918301918301612cff565b5f82601f830112612d2e575f80fd5b81516020612d3e6125ef836125ae565b82815260069290921b84018101918181019086841115612d5c575f80fd5b8286015b8481101561263a5760408189031215612d77575f80fd5b612d7f6124d8565b8151815284820151612d9081612119565b81860152835291830191604001612d60565b5f60208284031215612db2575f80fd5b81516001600160401b0380821115612dc8575f80fd5b908301906101008286031215612ddc575f80fd5b612de4612522565b82518152612df460208401612bb2565b602082015260408301516040820152612e0f60608401612bb2565b60608201526080830151608082015260a083015182811115612e2f575f80fd5b612e3b87828601612cba565b60a08301525060c083015182811115612e52575f80fd5b612e5e87828601612d1f565b60c08301525060e083015182811115612e75575f80fd5b612e8187828601612bbd565b60e08301525095945050505050565b5f815180845260208085019450602084015f5b8381101561281d5781516001600160a01b031687529582019590820190600101612ea3565b5f815180845260208085019450602084015f5b8381101561281d57612f01878351805182526020908101516001600160a01b0316910152565b6040969096019590820190600101612edb565b5f6101008251845260018060a01b036020840151166020850152604083015160408501526060830151612f5260608601826001600160a01b03169052565b506080830151608085015260a08301518160a0860152612f7482860182612e90565b91505060c083015184820360c0860152612f8e8282612ec8565b91505060e083015184820360e0860152612fa88282612a87565b95945050505050565b6001600160a01b03831681526040602082018190525f9061122290830184612f14565b5f808335601e19843603018112612fe9575f80fd5b8301803591506001600160401b03821115613002575f80fd5b6020019150368190038213156122ed575f80fd5b8481526001600160a01b03841660208201526060604082018190525f90611f3d90830184866128f4565b818103818111156105fc576105fc612b5d565b5f6001820161306457613064612b5d565b5060010190565b602081525f6108af6020830184612f14565b606081525f612a436060830185612f14565b81516001600160a01b0316815260208083015190820152604081016105fc565b8381526001600160a01b03831660208201526060604082018190525f90612fa890830184612a87565b5f602082840312156130e8575f80fd5b6108af82612bff565b5f8251613102818460208701612a65565b919091019291505056fea2646970667358221220bebf51c222d80d785ed2e04260277fb1153341348da1e46892572ee118e254b364736f6c63430008190033", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"},{\"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\":\"blockchainID\",\"type\":\"bytes32\"}],\"name\":\"BlockchainIDInitialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"sourceBlockchainID\",\"type\":\"bytes32\"}],\"name\":\"MessageExecuted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"sourceBlockchainID\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"messageNonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"originSenderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"destinationBlockchainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"allowedRelayerAddresses\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"receivedMessageNonce\",\"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\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"destinationBlockchainID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayerRewardAddress\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"feeTokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"structTeleporterFeeInfo\",\"name\":\"feeInfo\",\"type\":\"tuple\"}],\"name\":\"ReceiptReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"sourceBlockchainID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"deliverer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"rewardRedeemer\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"messageNonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"originSenderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"destinationBlockchainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"allowedRelayerAddresses\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"receivedMessageNonce\",\"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\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"destinationBlockchainID\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"messageNonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"originSenderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"destinationBlockchainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"allowedRelayerAddresses\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"receivedMessageNonce\",\"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\":\"VERSION\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"},{\"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\":\"bytes32\",\"name\":\"sourceBlockchainID\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destinationBlockchainID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"name\":\"calculateMessageID\",\"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\":\"messageID\",\"type\":\"bytes32\"}],\"name\":\"getFeeInfo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"}],\"name\":\"getMessageHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"destinationBlockchainID\",\"type\":\"bytes32\"}],\"name\":\"getNextMessageID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"sourceBlockchainID\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getReceiptAtIndex\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"receivedMessageNonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"relayerRewardAddress\",\"type\":\"address\"}],\"internalType\":\"structTeleporterMessageReceipt\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"sourceBlockchainID\",\"type\":\"bytes32\"}],\"name\":\"getReceiptQueueSize\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"}],\"name\":\"getRelayerRewardAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"warpContract\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initializeBlockchainID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messageNonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"}],\"name\":\"messageReceived\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"sourceBlockchainID\",\"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\":[{\"components\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"avalancheNetworkID\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"avalancheSourceBlockchainID\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"internalType\":\"structICMUnsignedMessage\",\"name\":\"unsignedMessage\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"unsignedMessageBytes\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"signers\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structICMSignature\",\"name\":\"signature\",\"type\":\"tuple\"}],\"internalType\":\"structICMMessage\",\"name\":\"icmMessage\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"relayerRewardAddress\",\"type\":\"address\"}],\"name\":\"receiveInterChainMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"}],\"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\":\"sourceBlockchainID\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"messageNonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"originSenderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"destinationBlockchainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"allowedRelayerAddresses\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"receivedMessageNonce\",\"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\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"messageNonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"originSenderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"destinationBlockchainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"requiredGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"allowedRelayerAddresses\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"receivedMessageNonce\",\"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\":\"destinationBlockchainID\",\"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\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"sourceBlockchainID\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32[]\",\"name\":\"messageIDs\",\"type\":\"bytes32[]\"},{\"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\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"}],\"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\"}]", + Bin: "0x6080604052348015600e575f80fd5b5060015f8190558055613511806100245f395ff3fe608060405234801561000f575f80fd5b506004361061016d575f3560e01c8063a8898181116100d9578063df20e8bc11610093578063ebc3b1ba1161006e578063ebc3b1ba14610423578063ecc7042814610446578063fc2d61971461044f578063ffa1ad7414610462575f80fd5b8063df20e8bc1461036e578063e69d606a14610381578063e6e67bd5146103e8575f80fd5b8063a8898181146102e1578063a9a85614146102f4578063c473eef814610307578063c4d66de81461033f578063ccb5f80914610352578063d127dc9b14610365575f80fd5b8063624488501161012a5780636244885014610256578063807c0be0146102695780638245a1b01461027c578063860a3b061461028f578063892bf412146102ae5780638ac0fd04146102ce575f80fd5b80630af5b4ff1461017157806322296c3a1461018c5780632bc8b0bf146101a15780632ca40f55146101b45780632e27c2231461020c578063399b77da14610237575b5f80fd5b610179610490565b6040519081526020015b60405180910390f35b61019f61019a36600461233a565b61056b565b005b6101796101af366004612355565b61065e565b6101fe6101c2366004612355565b600760209081525f9182526040918290208054835180850190945260018201546001600160a01b03168452600290910154918301919091529082565b60405161018392919061236c565b61021f61021a366004612355565b61067a565b6040516001600160a01b039091168152602001610183565b610179610245366004612355565b5f9081526007602052604090205490565b610179610264366004612393565b610701565b61019f6102773660046123c9565b61075a565b61019f61028a366004612432565b610806565b61017961029d366004612355565b60086020525f908152604090205481565b6102c16102bc366004612463565b6109b0565b6040516101839190612483565b61019f6102dc3660046124a3565b6109e1565b6101796102ef3660046124d8565b610c18565b610179610302366004612548565b610c69565b6101796103153660046125d9565b6001600160a01b039182165f908152600b6020908152604080832093909416825291909152205490565b61019f61034d36600461233a565b610efc565b61019f610360366004612608565b610f3b565b61017960045481565b61017961037c366004612355565b6110c5565b6103c961038f366004612355565b5f90815260076020908152604091829020825180840190935260018101546001600160a01b03168084526002909101549290910182905291565b604080516001600160a01b039093168352602083019190915201610183565b61040e6103f6366004612355565b60066020525f90815260409020805460019091015482565b60408051928352602083019190915201610183565b610436610431366004612355565b61110c565b6040519015158152602001610183565b61017960055481565b61019f61045d366004612622565b611121565b610483604051806040016040528060028152602001612b1960f11b81525081565b60405161018391906126b2565b6004545f90806105665760035f9054906101000a90046001600160a01b03166001600160a01b0316634213cf786040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104ea573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061050e91906126c4565b9050806105365760405162461bcd60e51b815260040161052d906126db565b60405180910390fd5b600481905560405181907f1eac640109dc937d2a9f42735a05f794b39a5e3759d681951d671aabbce4b104905f90a25b919050565b335f908152600b602090815260408083206001600160a01b0385168452909152902054806105ec5760405162461bcd60e51b815260206004820152602860248201527f54656c65706f727465724d657373656e6765723a206e6f2072657761726420746044820152676f2072656465656d60c01b606482015260840161052d565b335f818152600b602090815260408083206001600160a01b03871680855290835281842093909355518481529192917f3294c84e5b0f29d9803655319087207bc94f4db29f7927846944822773780b88910160405180910390a361065a6001600160a01b0383163383611376565b5050565b5f818152600660205260408120610674906113da565b92915050565b5f818152600960205260408120546106e65760405162461bcd60e51b815260206004820152602960248201527f54656c65706f727465724d657373656e6765723a206d657373616765206e6f74604482015268081c9958d95a5d995960ba1b606482015260840161052d565b505f908152600a60205260409020546001600160a01b031690565b5f60015f54146107235760405162461bcd60e51b815260040161052d90612722565b60025f5561075061073383612959565b83355f90815260066020526040902061074b906113ec565b6114e6565b60015f5592915050565b600180541461077b5760405162461bcd60e51b815260040161052d906129f8565b6002600155600354604051631636e63960e31b81525f916001600160a01b03169063b1b731c8906107b0908690600401612b03565b5f60405180830381865afa1580156107ca573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526107f19190810190612c8c565b90506107fd818361162c565b50506001805550565b60015f54146108275760405162461bcd60e51b815260040161052d90612722565b60025f9081556004546108409060408401358435610c18565b5f818152600760209081526040918290208251808401845281548152835180850190945260018201546001600160a01b0316845260029091015483830152908101919091528051919250906108a75760405162461bcd60e51b815260040161052d90612cbd565b5f836040516020016108b99190612ed3565b60408051601f19818403018152919052825181516020830120919250146108f25760405162461bcd60e51b815260040161052d90612ee5565b8360400135837f2a211ad4a59ab9d003852404f9c57c690704ee755f3c79d2c2812ad32da99df886856020015160405161092d929190612f2e565b60405180910390a360035460405163ee5b48eb60e01b81526001600160a01b039091169063ee5b48eb906109659084906004016126b2565b6020604051808303815f875af1158015610981573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109a591906126c4565b505060015f55505050565b604080518082019091525f80825260208201525f8381526006602052604090206109da90836118d8565b9392505050565b60015f5414610a025760405162461bcd60e51b815260040161052d90612722565b60025f556001805414610a275760405162461bcd60e51b815260040161052d906129f8565b600260015580610a915760405162461bcd60e51b815260206004820152602f60248201527f54656c65706f727465724d657373656e6765723a207a65726f2061646469746960448201526e1bdb985b0819995948185b5bdd5b9d608a1b606482015260840161052d565b6001600160a01b038216610ab75760405162461bcd60e51b815260040161052d90612f62565b5f83815260076020526040902054610ae15760405162461bcd60e51b815260040161052d90612cbd565b5f838152600760205260409020600101546001600160a01b03838116911614610b725760405162461bcd60e51b815260206004820152603760248201527f54656c65706f727465724d657373656e6765723a20696e76616c69642066656560448201527f20617373657420636f6e74726163742061646472657373000000000000000000606482015260840161052d565b5f610b7d8383611999565b5f85815260076020526040812060020180549293508392909190610ba2908490612fca565b90915550505f8481526007602052604090819020905185917fc1bfd1f1208927dfbd414041dcb5256e6c9ad90dd61aec3249facbd34ff7b3e191610c03916001019081546001600160a01b0316815260019190910154602082015260400190565b60405180910390a2505060018080555f555050565b5f604051806040016040528060028152602001612b1960f11b815250848484604051602001610c4a9493929190612fdd565b6040516020818303038152906040528051906020012090509392505050565b5f60015f5414610c8b5760405162461bcd60e51b815260040161052d90612722565b60025f90815560045490866001600160401b03811115610cad57610cad612765565b604051908082528060200260200182016040528015610cf157816020015b604080518082019091525f8082526020820152815260200190600190039081610ccb5790505b509050865f5b81811015610e69575f8a8a83818110610d1257610d1261300b565b9050602002013590505f60095f8381526020019081526020015f20549050805f03610d8e5760405162461bcd60e51b815260206004820152602660248201527f54656c65706f727465724d657373656e6765723a2072656365697074206e6f7460448201526508199bdd5b9960d21b606482015260840161052d565b610d998d8783610c18565b8214610e0d5760405162461bcd60e51b815260206004820152603a60248201527f54656c65706f727465724d657373656e6765723a206d6573736167652049442060448201527f6e6f742066726f6d20736f7572636520626c6f636b636861696e000000000000606482015260840161052d565b5f828152600a60209081526040918290205482518084019093528383526001600160a01b03169082018190528651909190879086908110610e5057610e5061300b565b6020026020010181905250505050806001019050610cf7565b506040805160c0810182528b81525f6020820152610eea918101610e92368b90038b018b61301f565b81526020015f81526020018888808060200260200160405190810160405280939291908181526020018383602002808284375f92018290525093855250506040805192835260208084019091529092015250836114e6565b60015f559a9950505050505050505050565b6002546001600160a01b0316610f3857600280546001600160a01b0383166001600160a01b031991821681179092556003805490911690911790555b50565b6001805414610f5c5760405162461bcd60e51b815260040161052d906129f8565b60026001556003546040516306f8253560e41b815263ffffffff841660048201525f9182916001600160a01b0390911690636f825350906024015f60405180830381865afa158015610fb0573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610fd79190810190613048565b915091508061103a5760405162461bcd60e51b815260206004820152602960248201527f54656c65706f727465724d657373656e6765723a20696e76616c69642077617260448201526870206d65737361676560b81b606482015260840161052d565b60208201516001600160a01b031630146110b15760405162461bcd60e51b815260206004820152603260248201527f54656c65706f727465724d657373656e6765723a20696e76616c6964206f726960448201527167696e2073656e646572206164647265737360701b606482015260840161052d565b6110bb828461162c565b5050600180555050565b6004545f90806110e75760405162461bcd60e51b815260040161052d906126db565b5f60055460016110f79190612fca565b9050611104828583610c18565b949350505050565b5f818152600960205260408120541515610674565b60018054146111425760405162461bcd60e51b815260040161052d906129f8565b60026001556004545f906111599084908435610c18565b5f81815260086020526040902054909150806111875760405162461bcd60e51b815260040161052d90612cbd565b80836040516020016111999190612ed3565b60405160208183030381529060405280519060200120146111cc5760405162461bcd60e51b815260040161052d90612ee5565b5f6111dd608085016060860161233a565b6001600160a01b03163b116112515760405162461bcd60e51b815260206004820152603460248201527f54656c65706f727465724d657373656e6765723a2064657374696e6174696f6e604482015273206164647265737320686173206e6f20636f646560601b606482015260840161052d565b604051849083907f34795cc6b122b9a0ae684946319f1e14a577b4e8f9b3dda9ac94c21a54d3188c905f90a35f82815260086020908152604080832083905586916112a091870190870161233a565b6112ad60e0870187613092565b6040516024016112c094939291906130d4565b60408051601f198184030181529190526020810180516001600160e01b031663643477d560e11b17905290505f611307611300608087016060880161233a565b5a846119a5565b90508061136a5760405162461bcd60e51b815260206004820152602b60248201527f54656c65706f727465724d657373656e6765723a20726574727920657865637560448201526a1d1a5bdb8819985a5b195960aa1b606482015260840161052d565b50506001805550505050565b6040516001600160a01b038381166024830152604482018390526113d591859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506119bc565b505050565b805460018201545f91610674916130fe565b60605f61140260056113fd856113da565b611a1d565b9050805f0361144e57604080515f8082526020820190925290611446565b604080518082019091525f80825260208201528152602001906001900390816114205790505b509392505050565b5f816001600160401b0381111561146757611467612765565b6040519080825280602002602001820160405280156114ab57816020015b604080518082019091525f80825260208201528152602001906001900390816114855790505b5090505f5b82811015611446576114c185611a32565b8282815181106114d3576114d361300b565b60209081029190910101526001016114b0565b5f805f806114f48686611afc565b9250925092505f8260405160200161150c9190613229565b60408051808303601f190181528282018252805160208083019190912084528084018681525f89815260078352849020945185555180516001860180546001600160a01b0319166001600160a01b039092169190911790550151600290930192909255885190519192509085907f2a211ad4a59ab9d003852404f9c57c690704ee755f3c79d2c2812ad32da99df8906115a8908790879061323b565b60405180910390a360035460405163ee5b48eb60e01b81526001600160a01b039091169063ee5b48eb906115e09084906004016126b2565b6020604051808303815f875af11580156115fc573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061162091906126c4565b50929695505050505050565b5f82604001518060200190518101906116459190613335565b90505f611650610490565b9050808260400151146116bf5760405162461bcd60e51b815260206004820152603160248201527f54656c65706f727465724d657373656e6765723a20696e76616c6964206465736044820152701d1a5b985d1a5bdb8818da185a5b881251607a1b606482015260840161052d565b835182515f916116d0918490610c18565b5f81815260096020526040902054909150156117445760405162461bcd60e51b815260206004820152602d60248201527f54656c65706f727465724d657373656e6765723a206d65737361676520616c7260448201526c1958591e481c9958d95a5d9959609a1b606482015260840161052d565b611752338460a00151611c60565b6117b05760405162461bcd60e51b815260206004820152602960248201527f54656c65706f727465724d657373656e6765723a20756e617574686f72697a6560448201526832103932b630bcb2b960b91b606482015260840161052d565b6117bd81845f0151611ccc565b6001600160a01b038416156117f3575f818152600a6020526040902080546001600160a01b0319166001600160a01b0386161790555b60c0830151515f5b818110156118365761182e84885f01518760c0015184815181106118215761182161300b565b6020026020010151611d3c565b6001016117fb565b50604080518082018252855181526001600160a01b03871660208083019190915288515f90815260069091529190912061186f91611e60565b336001600160a01b0316865f0151837f292ee90bbaf70b5d4936025e09d56ba08f3e421156b6a568cf3c2840d9343e3488886040516118af929190613423565b60405180910390a460e084015151156118d0576118d082875f015186611eba565b505050505050565b604080518082019091525f80825260208201526118f4836113da565b821061194c5760405162461bcd60e51b815260206004820152602160248201527f5265636569707451756575653a20696e646578206f7574206f6620626f756e646044820152607360f81b606482015260840161052d565b826002015f83855f01546119609190612fca565b815260208082019290925260409081015f20815180830190925280548252600101546001600160a01b0316918101919091529392505050565b5f6109da833384611fe9565b5f805f808451602086015f8989f195945050505050565b5f6119d06001600160a01b0384168361214c565b905080515f141580156119f45750808060200190518101906119f29190613446565b155b156113d557604051635274afe760e01b81526001600160a01b038416600482015260240161052d565b5f818310611a2b57816109da565b5090919050565b604080518082019091525f808252602082015281546001830154819003611a9b5760405162461bcd60e51b815260206004820152601960248201527f5265636569707451756575653a20656d70747920717565756500000000000000604482015260640161052d565b5f8181526002840160208181526040808420815180830190925280548252600180820180546001600160a01b03811685870152888852959094529490556001600160a01b0319909216905590611af2908390612fca565b9093555090919050565b60408051610100810182525f8082526020820181905291810182905260608082018390526080820183905260a0820181905260c0820181905260e0820152604080518082019091525f80825260208201525f611b56610490565b90505f60055f8154611b679061345f565b9190508190559050611b7d82885f015183610c18565b9450604051806101000160405280828152602001336001600160a01b03168152602001885f0151815260200188602001516001600160a01b0316815260200188606001518152602001886080015181526020018781526020018860a0015181525093505f808860400151602001511115611c36576040880151516001600160a01b0316611c1c5760405162461bcd60e51b815260040161052d90612f62565b60408801518051602090910151611c339190611999565b90505b604080518082018252980151516001600160a01b0316885260208801525092959194935090915050565b5f81515f03611c7157506001610674565b81515f5b81811015611cc257846001600160a01b0316848281518110611c9957611c9961300b565b60200260200101516001600160a01b031603611cba57600192505050610674565b600101611c75565b505f949350505050565b805f03611d2b5760405162461bcd60e51b815260206004820152602760248201527f54656c65706f727465724d657373656e6765723a207a65726f206d657373616760448201526665206e6f6e636560c81b606482015260840161052d565b5f9182526009602052604090912055565b5f611d4b8484845f0151610c18565b5f818152600760209081526040918290208251808401845281548152835180850190945260018201546001600160a01b031684526002909101548383015290810191909152805191925090611da1575050505050565b5f8281526007602090815260408083208381556001810180546001600160a01b03191690556002018390558382018051830151878401516001600160a01b039081168652600b855283862092515116855292528220805491929091611e07908490612fca565b9250508190555082602001516001600160a01b031684837fd13a7935f29af029349bed0a2097455b91fd06190a30478c575db3f31e00bf578460200151604051611e519190613477565b60405180910390a45050505050565b600182018054829160028501915f9182611e798361345f565b9091555081526020808201929092526040015f2082518155910151600190910180546001600160a01b0319166001600160a01b039092169190911790555050565b80608001515a1015611f1c5760405162461bcd60e51b815260206004820152602560248201527f54656c65706f727465724d657373656e6765723a20696e73756666696369656e604482015264742067617360d81b606482015260840161052d565b80606001516001600160a01b03163b5f03611f3c576113d5838383612159565b602081015160e08201516040515f92611f59928692602401613497565b60408051601f198184030181529190526020810180516001600160e01b031663643477d560e11b179052606083015160808401519192505f91611f9d9190846119a5565b905080611fb657611faf858585612159565b5050505050565b604051849086907f34795cc6b122b9a0ae684946319f1e14a577b4e8f9b3dda9ac94c21a54d3188c905f90a35050505050565b6040516370a0823160e01b81523060048201525f9081906001600160a01b038616906370a0823190602401602060405180830381865afa15801561202f573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061205391906126c4565b905061206a6001600160a01b0386168530866121cd565b6040516370a0823160e01b81523060048201525f906001600160a01b038716906370a0823190602401602060405180830381865afa1580156120ae573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120d291906126c4565b90508181116121385760405162461bcd60e51b815260206004820152602c60248201527f5361666545524332305472616e7366657246726f6d3a2062616c616e6365206e60448201526b1bdd081a5b98dc99585cd95960a21b606482015260840161052d565b61214282826130fe565b9695505050505050565b60606109da83835f61220c565b8060405160200161216a9190613229565b60408051601f1981840301815282825280516020918201205f878152600890925291902055829084907f4619adc1017b82e02eaefac01a43d50d6d8de4460774bc370c3ff0210d40c985906121c0908590613229565b60405180910390a3505050565b6040516001600160a01b0384811660248301528381166044830152606482018390526122069186918216906323b872dd906084016113a3565b50505050565b6060814710156122315760405163cd78605960e01b815230600482015260240161052d565b5f80856001600160a01b0316848660405161224c91906134c0565b5f6040518083038185875af1925050503d805f8114612286576040519150601f19603f3d011682016040523d82523d5f602084013e61228b565b606091505b50915091506121428683836060826122ab576122a6826122f2565b6109da565b81511580156122c257506001600160a01b0384163b155b156122eb57604051639996b31560e01b81526001600160a01b038516600482015260240161052d565b50806109da565b8051156123025780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6001600160a01b0381168114610f38575f80fd5b80356105668161231b565b5f6020828403121561234a575f80fd5b81356109da8161231b565b5f60208284031215612365575f80fd5b5035919050565b828152606081016109da602083018480516001600160a01b03168252602090810151910152565b5f602082840312156123a3575f80fd5b81356001600160401b038111156123b8575f80fd5b820160e081850312156109da575f80fd5b5f80604083850312156123da575f80fd5b82356001600160401b038111156123ef575f80fd5b830160608186031215612400575f80fd5b915060208301356124108161231b565b809150509250929050565b5f610100828403121561242c575f80fd5b50919050565b5f60208284031215612442575f80fd5b81356001600160401b03811115612457575f80fd5b6111048482850161241b565b5f8060408385031215612474575f80fd5b50508035926020909101359150565b815181526020808301516001600160a01b03169082015260408101610674565b5f805f606084860312156124b5575f80fd5b8335925060208401356124c78161231b565b929592945050506040919091013590565b5f805f606084860312156124ea575f80fd5b505081359360208301359350604090920135919050565b5f8083601f840112612511575f80fd5b5081356001600160401b03811115612527575f80fd5b6020830191508360208260051b8501011115612541575f80fd5b9250929050565b5f805f805f8086880360a081121561255e575f80fd5b8735965060208801356001600160401b038082111561257b575f80fd5b6125878b838c01612501565b90985096508691506040603f19840112156125a0575f80fd5b60408a01955060808a01359250808311156125b9575f80fd5b50506125c789828a01612501565b979a9699509497509295939492505050565b5f80604083850312156125ea575f80fd5b82356124008161231b565b803563ffffffff81168114610566575f80fd5b5f8060408385031215612619575f80fd5b612400836125f5565b5f8060408385031215612633575f80fd5b8235915060208301356001600160401b0381111561264f575f80fd5b61265b8582860161241b565b9150509250929050565b5f5b8381101561267f578181015183820152602001612667565b50505f910152565b5f815180845261269e816020860160208601612665565b601f01601f19169290920160200192915050565b602081525f6109da6020830184612687565b5f602082840312156126d4575f80fd5b5051919050565b60208082526027908201527f54656c65706f727465724d657373656e6765723a207a65726f20626c6f636b636040820152661a185a5b88125160ca1b606082015260800190565b60208082526023908201527f5265656e7472616e63794775617264733a2073656e646572207265656e7472616040820152626e637960e81b606082015260800190565b634e487b7160e01b5f52604160045260245ffd5b604080519081016001600160401b038111828210171561279b5761279b612765565b60405290565b60405160c081016001600160401b038111828210171561279b5761279b612765565b60405161010081016001600160401b038111828210171561279b5761279b612765565b604051601f8201601f191681016001600160401b038111828210171561280e5761280e612765565b604052919050565b5f60408284031215612826575f80fd5b61282e612779565b9050813561283b8161231b565b808252506020820135602082015292915050565b5f6001600160401b0382111561286757612867612765565b5060051b60200190565b5f82601f830112612880575f80fd5b813560206128956128908361284f565b6127e6565b8083825260208201915060208460051b8701019350868411156128b6575f80fd5b602086015b848110156128db5780356128ce8161231b565b83529183019183016128bb565b509695505050505050565b5f6001600160401b038211156128fe576128fe612765565b50601f01601f191660200190565b5f82601f83011261291b575f80fd5b8135612929612890826128e6565b81815284602083860101111561293d575f80fd5b816020850160208301375f918101602001919091529392505050565b5f60e08236031215612969575f80fd5b6129716127a1565b823581526129816020840161232f565b60208201526129933660408501612816565b60408201526080830135606082015260a08301356001600160401b03808211156129bb575f80fd5b6129c736838701612871565b608084015260c08501359150808211156129df575f80fd5b506129ec3682860161290c565b60a08301525092915050565b60208082526025908201527f5265656e7472616e63794775617264733a207265636569766572207265656e7460408201526472616e637960d81b606082015260800190565b5f808335601e19843603018112612a52575f80fd5b83016020810192503590506001600160401b03811115612a70575f80fd5b803603821315612541575f80fd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b5f8235603e19833603018112612aba575f80fd5b90910192915050565b5f612ace8283612a3d565b60408552612ae0604086018284612a7e565b915050612af06020840184612a3d565b8583036020870152612142838284612a7e565b602081525f8235605e19843603018112612b1b575f80fd5b60606020840152830163ffffffff612b32826125f5565b166080840152602081013560a0840152612b4f6040820182612a3d565b9150606060c0850152612b6660e085018383612a7e565b915050612b766020850185612a3d565b601f1980868503016040870152612b8e848385612a7e565b9350612b9d6040880188612aa6565b9250808685030160608701525050612bb58282612ac3565b95945050505050565b80516105668161231b565b5f82601f830112612bd8575f80fd5b8151612be6612890826128e6565b818152846020838601011115612bfa575f80fd5b611104826020830160208701612665565b5f60608284031215612c1b575f80fd5b604051606081016001600160401b038282108183111715612c3e57612c3e612765565b816040528293508451835260208501519150612c598261231b565b8160208401526040850151915080821115612c72575f80fd5b50612c7f85828601612bc9565b6040830152505092915050565b5f60208284031215612c9c575f80fd5b81516001600160401b03811115612cb1575f80fd5b61110484828501612c0b565b60208082526026908201527f54656c65706f727465724d657373656e6765723a206d657373616765206e6f7460408201526508199bdd5b9960d21b606082015260800190565b5f808335601e19843603018112612d18575f80fd5b83016020810192503590506001600160401b03811115612d36575f80fd5b8060051b3603821315612541575f80fd5b8183525f60208085019450825f5b85811015612d83578135612d688161231b565b6001600160a01b031687529582019590820190600101612d55565b509495945050505050565b5f808335601e19843603018112612da3575f80fd5b83016020810192503590506001600160401b03811115612dc1575f80fd5b8060061b3603821315612541575f80fd5b8183525f60208085019450825f5b85811015612d83578135875282820135612df98161231b565b6001600160a01b0316878401526040968701969190910190600101612de0565b5f610100823584526020830135612e2f8161231b565b6001600160a01b0316602085015260408381013590850152612e536060840161232f565b6001600160a01b0316606085015260808381013590850152612e7860a0840184612d03565b8260a0870152612e8b8387018284612d47565b92505050612e9c60c0840184612d8e565b85830360c0870152612eaf838284612dd2565b92505050612ec060e0840184612a3d565b85830360e0870152612142838284612a7e565b602081525f6109da6020830184612e19565b60208082526029908201527f54656c65706f727465724d657373656e6765723a20696e76616c6964206d65736040820152680e6c2ceca40d0c2e6d60bb1b606082015260800190565b606081525f612f406060830185612e19565b90506109da602083018480516001600160a01b03168252602090810151910152565b60208082526034908201527f54656c65706f727465724d657373656e6765723a207a65726f2066656520617360408201527373657420636f6e7472616374206164647265737360601b606082015260800190565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561067457610674612fb6565b608081525f612fef6080830187612687565b6020830195909552506040810192909252606090910152919050565b634e487b7160e01b5f52603260045260245ffd5b5f6040828403121561302f575f80fd5b6109da8383612816565b80518015158114610566575f80fd5b5f8060408385031215613059575f80fd5b82516001600160401b0381111561306e575f80fd5b61307a85828601612c0b565b92505061308960208401613039565b90509250929050565b5f808335601e198436030181126130a7575f80fd5b8301803591506001600160401b038211156130c0575f80fd5b602001915036819003821315612541575f80fd5b8481526001600160a01b03841660208201526060604082018190525f906121429083018486612a7e565b8181038181111561067457610674612fb6565b5f815180845260208085019450602084015f5b83811015612d835781516001600160a01b031687529582019590820190600101613124565b5f815180845260208085019450602084015f5b83811015612d8357613182878351805182526020908101516001600160a01b0316910152565b604096909601959082019060010161315c565b5f6101008251845260018060a01b0360208401511660208501526040830151604085015260608301516131d360608601826001600160a01b03169052565b506080830151608085015260a08301518160a08601526131f582860182613111565b91505060c083015184820360c086015261320f8282613149565b91505060e083015184820360e0860152612bb58282612687565b602081525f6109da6020830184613195565b606081525f612f406060830185613195565b5f82601f83011261325c575f80fd5b8151602061326c6128908361284f565b8083825260208201915060208460051b87010193508684111561328d575f80fd5b602086015b848110156128db5780516132a58161231b565b8352918301918301613292565b5f82601f8301126132c1575f80fd5b815160206132d16128908361284f565b82815260069290921b840181019181810190868411156132ef575f80fd5b8286015b848110156128db576040818903121561330a575f80fd5b613312612779565b81518152848201516133238161231b565b818601528352918301916040016132f3565b5f60208284031215613345575f80fd5b81516001600160401b038082111561335b575f80fd5b90830190610100828603121561336f575f80fd5b6133776127c3565b8251815261338760208401612bbe565b6020820152604083015160408201526133a260608401612bbe565b60608201526080830151608082015260a0830151828111156133c2575f80fd5b6133ce8782860161324d565b60a08301525060c0830151828111156133e5575f80fd5b6133f1878286016132b2565b60c08301525060e083015182811115613408575f80fd5b61341487828601612bc9565b60e08301525095945050505050565b6001600160a01b03831681526040602082018190525f9061110490830184613195565b5f60208284031215613456575f80fd5b6109da82613039565b5f6001820161347057613470612fb6565b5060010190565b81516001600160a01b031681526020808301519082015260408101610674565b8381526001600160a01b03831660208201526060604082018190525f90612bb590830184612687565b5f82516134d1818460208701612665565b919091019291505056fea2646970667358221220fed763b7418a7ba6f934024374554045dcb406260b0d6d3d85ddeff2a2f2c71a64736f6c63430008190033", } // TeleporterMessengerABI is the input ABI used to generate the binding from. @@ -236,35 +256,35 @@ func (_TeleporterMessenger *TeleporterMessengerTransactorRaw) Transact(opts *bin return _TeleporterMessenger.Contract.contract.Transact(opts, method, params...) } -// WARPMESSENGER is a free data retrieval call binding the contract method 0xb771b3bc. +// VERSION is a free data retrieval call binding the contract method 0xffa1ad74. // -// Solidity: function WARP_MESSENGER() view returns(address) -func (_TeleporterMessenger *TeleporterMessengerCaller) WARPMESSENGER(opts *bind.CallOpts) (common.Address, error) { +// Solidity: function VERSION() view returns(string) +func (_TeleporterMessenger *TeleporterMessengerCaller) VERSION(opts *bind.CallOpts) (string, error) { var out []interface{} - err := _TeleporterMessenger.contract.Call(opts, &out, "WARP_MESSENGER") + err := _TeleporterMessenger.contract.Call(opts, &out, "VERSION") if err != nil { - return *new(common.Address), err + return *new(string), err } - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + out0 := *abi.ConvertType(out[0], new(string)).(*string) return out0, err } -// WARPMESSENGER is a free data retrieval call binding the contract method 0xb771b3bc. +// VERSION is a free data retrieval call binding the contract method 0xffa1ad74. // -// Solidity: function WARP_MESSENGER() view returns(address) -func (_TeleporterMessenger *TeleporterMessengerSession) WARPMESSENGER() (common.Address, error) { - return _TeleporterMessenger.Contract.WARPMESSENGER(&_TeleporterMessenger.CallOpts) +// Solidity: function VERSION() view returns(string) +func (_TeleporterMessenger *TeleporterMessengerSession) VERSION() (string, error) { + return _TeleporterMessenger.Contract.VERSION(&_TeleporterMessenger.CallOpts) } -// WARPMESSENGER is a free data retrieval call binding the contract method 0xb771b3bc. +// VERSION is a free data retrieval call binding the contract method 0xffa1ad74. // -// Solidity: function WARP_MESSENGER() view returns(address) -func (_TeleporterMessenger *TeleporterMessengerCallerSession) WARPMESSENGER() (common.Address, error) { - return _TeleporterMessenger.Contract.WARPMESSENGER(&_TeleporterMessenger.CallOpts) +// Solidity: function VERSION() view returns(string) +func (_TeleporterMessenger *TeleporterMessengerCallerSession) VERSION() (string, error) { + return _TeleporterMessenger.Contract.VERSION(&_TeleporterMessenger.CallOpts) } // BlockchainID is a free data retrieval call binding the contract method 0xd127dc9b. @@ -751,6 +771,27 @@ func (_TeleporterMessenger *TeleporterMessengerTransactorSession) AddFeeAmount(m return _TeleporterMessenger.Contract.AddFeeAmount(&_TeleporterMessenger.TransactOpts, messageID, feeTokenAddress, additionalFeeAmount) } +// Initialize is a paid mutator transaction binding the contract method 0xc4d66de8. +// +// Solidity: function initialize(address warpContract) returns() +func (_TeleporterMessenger *TeleporterMessengerTransactor) Initialize(opts *bind.TransactOpts, warpContract common.Address) (*types.Transaction, error) { + return _TeleporterMessenger.contract.Transact(opts, "initialize", warpContract) +} + +// Initialize is a paid mutator transaction binding the contract method 0xc4d66de8. +// +// Solidity: function initialize(address warpContract) returns() +func (_TeleporterMessenger *TeleporterMessengerSession) Initialize(warpContract common.Address) (*types.Transaction, error) { + return _TeleporterMessenger.Contract.Initialize(&_TeleporterMessenger.TransactOpts, warpContract) +} + +// Initialize is a paid mutator transaction binding the contract method 0xc4d66de8. +// +// Solidity: function initialize(address warpContract) returns() +func (_TeleporterMessenger *TeleporterMessengerTransactorSession) Initialize(warpContract common.Address) (*types.Transaction, error) { + return _TeleporterMessenger.Contract.Initialize(&_TeleporterMessenger.TransactOpts, warpContract) +} + // InitializeBlockchainID is a paid mutator transaction binding the contract method 0x0af5b4ff. // // Solidity: function initializeBlockchainID() returns(bytes32) @@ -793,6 +834,27 @@ func (_TeleporterMessenger *TeleporterMessengerTransactorSession) ReceiveCrossCh return _TeleporterMessenger.Contract.ReceiveCrossChainMessage(&_TeleporterMessenger.TransactOpts, messageIndex, relayerRewardAddress) } +// ReceiveInterChainMessage is a paid mutator transaction binding the contract method 0x807c0be0. +// +// Solidity: function receiveInterChainMessage(((uint32,bytes32,bytes),bytes,(bytes,bytes)) icmMessage, address relayerRewardAddress) returns() +func (_TeleporterMessenger *TeleporterMessengerTransactor) ReceiveInterChainMessage(opts *bind.TransactOpts, icmMessage ICMMessage, relayerRewardAddress common.Address) (*types.Transaction, error) { + return _TeleporterMessenger.contract.Transact(opts, "receiveInterChainMessage", icmMessage, relayerRewardAddress) +} + +// ReceiveInterChainMessage is a paid mutator transaction binding the contract method 0x807c0be0. +// +// Solidity: function receiveInterChainMessage(((uint32,bytes32,bytes),bytes,(bytes,bytes)) icmMessage, address relayerRewardAddress) returns() +func (_TeleporterMessenger *TeleporterMessengerSession) ReceiveInterChainMessage(icmMessage ICMMessage, relayerRewardAddress common.Address) (*types.Transaction, error) { + return _TeleporterMessenger.Contract.ReceiveInterChainMessage(&_TeleporterMessenger.TransactOpts, icmMessage, relayerRewardAddress) +} + +// ReceiveInterChainMessage is a paid mutator transaction binding the contract method 0x807c0be0. +// +// Solidity: function receiveInterChainMessage(((uint32,bytes32,bytes),bytes,(bytes,bytes)) icmMessage, address relayerRewardAddress) returns() +func (_TeleporterMessenger *TeleporterMessengerTransactorSession) ReceiveInterChainMessage(icmMessage ICMMessage, relayerRewardAddress common.Address) (*types.Transaction, error) { + return _TeleporterMessenger.Contract.ReceiveInterChainMessage(&_TeleporterMessenger.TransactOpts, icmMessage, relayerRewardAddress) +} + // RedeemRelayerRewards is a paid mutator transaction binding the contract method 0x22296c3a. // // Solidity: function redeemRelayerRewards(address feeAsset) returns() diff --git a/abi-bindings/go/teleporter/TeleporterMessenger/packing.go b/abi-bindings/go/teleporter/TeleporterMessenger/packing.go index ba52b01b8..906d06c29 100644 --- a/abi-bindings/go/teleporter/TeleporterMessenger/packing.go +++ b/abi-bindings/go/teleporter/TeleporterMessenger/packing.go @@ -8,6 +8,7 @@ import ( "math/big" "github.com/ava-labs/avalanchego/ids" + avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/accounts/abi" "github.com/pkg/errors" @@ -91,6 +92,17 @@ func PackReceiveCrossChainMessage(messageIndex uint32, relayerRewardAddress comm return abi.Pack("receiveCrossChainMessage", messageIndex, relayerRewardAddress) } +// PackReceiveInterChainMessage packs a ReceiveInterChainMessageInput to form +// a call to the receiveInterChainMessage function +func PackReceiveInterChainMessage(messagePayload *avalancheWarp.Message, relayerRewardAddress common.Address) ([]byte, error) { + abi, err := TeleporterMessengerMetaData.GetAbi() + if err != nil { + return nil, errors.Wrap(err, "failed to get abi") + } + + return abi.Pack("receiveInterChainMessage", messagePayload, relayerRewardAddress) +} + // PackCalculateMessageID packs input to form a call to the calculateMessageID function func PackCalculateMessageID( sourceBlockchainID [32]byte, diff --git a/abi-bindings/go/teleporter/registry/TeleporterRegistry/TeleporterRegistry.go b/abi-bindings/go/teleporter/registry/TeleporterRegistry/TeleporterRegistry.go index 756477a57..6f981828c 100644 --- a/abi-bindings/go/teleporter/registry/TeleporterRegistry/TeleporterRegistry.go +++ b/abi-bindings/go/teleporter/registry/TeleporterRegistry/TeleporterRegistry.go @@ -38,7 +38,7 @@ type ProtocolRegistryEntry struct { // TeleporterRegistryMetaData contains all meta data concerning the TeleporterRegistry contract. var TeleporterRegistryMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"version\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"protocolAddress\",\"type\":\"address\"}],\"internalType\":\"structProtocolRegistryEntry[]\",\"name\":\"initialEntries\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"version\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"protocolAddress\",\"type\":\"address\"}],\"name\":\"AddProtocolVersion\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"oldVersion\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"newVersion\",\"type\":\"uint256\"}],\"name\":\"LatestVersionUpdated\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"MAX_VERSION_INCREMENT\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VALIDATORS_SOURCE_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"WARP_MESSENGER\",\"outputs\":[{\"internalType\":\"contractIWarpMessenger\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"messageIndex\",\"type\":\"uint32\"}],\"name\":\"addProtocolVersion\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"blockchainID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"version\",\"type\":\"uint256\"}],\"name\":\"getAddressFromVersion\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLatestTeleporter\",\"outputs\":[{\"internalType\":\"contractITeleporterMessenger\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"version\",\"type\":\"uint256\"}],\"name\":\"getTeleporterFromVersion\",\"outputs\":[{\"internalType\":\"contractITeleporterMessenger\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"protocolAddress\",\"type\":\"address\"}],\"name\":\"getVersionFromAddress\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestVersion\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x60a060405234801561000f575f80fd5b50604051610fe0380380610fe083398101604081905261002e916103e2565b7302000000000000000000000000000000000000056001600160a01b0316634213cf786040518163ffffffff1660e01b8152600401602060405180830381865afa15801561007e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100a291906104bc565b60805280515f5b818110156100e1576100d98382815181106100c6576100c66104d3565b60200260200101516100e960201b60201c565b6001016100a9565b50505061050c565b80515f0361013e5760405162461bcd60e51b815260206004820181905260248201527f54656c65706f7274657252656769737472793a207a65726f2076657273696f6e60448201526064015b60405180910390fd5b80515f908152600160205260409020546001600160a01b0316156101b75760405162461bcd60e51b815260206004820152602a60248201527f54656c65706f7274657252656769737472793a2076657273696f6e20616c72656044820152696164792065786973747360b01b6064820152608401610135565b60208101516001600160a01b03166102235760405162461bcd60e51b815260206004820152602960248201527f54656c65706f7274657252656769737472793a207a65726f2070726f746f636f6044820152686c206164647265737360b81b6064820152608401610135565b5f546102316101f4826104e7565b825111156102985760405162461bcd60e51b815260206004820152602e60248201527f54656c65706f7274657252656769737472793a2076657273696f6e20696e637260448201526d0cadacadce840e8dede40d0d2ced60931b6064820152608401610135565b6020828101805184515f90815260018452604080822080546001600160a01b0319166001600160a01b03948516179055925190911681526002909252902054825111156102ff5781516020808401516001600160a01b03165f908152600290915260409020555b602082015182516040516001600160a01b03909216917fa5eed93d951a9603d5f7c0a57de79a299dd3dbd5e51429be209d8053a42ab43a905f90a381518110156103725781515f81815560405183917f30623e953733f6474dabdfbef1103ce15ab73cdc77c6dfad0f9874d167e8a9b091a35b5050565b634e487b7160e01b5f52604160045260245ffd5b604080519081016001600160401b03811182821017156103ac576103ac610376565b60405290565b604051601f8201601f191681016001600160401b03811182821017156103da576103da610376565b604052919050565b5f60208083850312156103f3575f80fd5b82516001600160401b0380821115610409575f80fd5b818501915085601f83011261041c575f80fd5b81518181111561042e5761042e610376565b61043c848260051b016103b2565b818152848101925060069190911b83018401908782111561045b575f80fd5b928401925b818410156104b15760408489031215610477575f80fd5b61047f61038a565b84518152858501516001600160a01b038116811461049b575f80fd5b8187015283526040939093019291840191610460565b979650505050505050565b5f602082840312156104cc575f80fd5b5051919050565b634e487b7160e01b5f52603260045260245ffd5b8082018082111561050657634e487b7160e01b5f52601160045260245ffd5b92915050565b608051610ab561052b5f395f818161014301526102580152610ab55ff3fe608060405234801561000f575f80fd5b506004361061009b575f3560e01c8063ac473ac311610063578063ac473ac31461011f578063b771b3bc14610128578063c07f47d414610136578063d127dc9b1461013e578063d820e64f14610165575f80fd5b80630731775d1461009f578063215abce9146100c357806341f34ed9146100d657806346f9ef49146100eb5780634c1f08ce146100fe575b5f80fd5b6100a65f81565b6040516001600160a01b0390911681526020015b60405180910390f35b6100a66100d13660046107aa565b61016d565b6100e96100e43660046107c1565b61017d565b005b6100a66100f93660046107aa565b6103ec565b61011161010c366004610802565b6104ae565b6040519081526020016100ba565b6101116101f481565b6100a66005600160991b0181565b6101115f5481565b6101117f000000000000000000000000000000000000000000000000000000000000000081565b6100a6610554565b5f610177826103ec565b92915050565b6040516306f8253560e41b815263ffffffff821660048201525f9081906005600160991b0190636f825350906024015f60405180830381865afa1580156101c6573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526101ed919081019061089f565b91509150806102545760405162461bcd60e51b815260206004820152602860248201527f54656c65706f7274657252656769737472793a20696e76616c69642077617270604482015267206d65737361676560c01b60648201526084015b60405180910390fd5b81517f0000000000000000000000000000000000000000000000000000000000000000146102d85760405162461bcd60e51b815260206004820152602b60248201527f54656c65706f7274657252656769737472793a20696e76616c696420736f757260448201526a18d94818da185a5b88125160aa1b606482015260840161024b565b60208201516001600160a01b03161561034d5760405162461bcd60e51b815260206004820152603160248201527f54656c65706f7274657252656769737472793a20696e76616c6964206f726967604482015270696e2073656e646572206164647265737360781b606482015260840161024b565b5f808360400151806020019051810190610367919061099e565b90925090506001600160a01b03811630146103dc5760405162461bcd60e51b815260206004820152602f60248201527f54656c65706f7274657252656769737472793a20696e76616c6964206465737460448201526e696e6174696f6e206164647265737360881b606482015260840161024b565b6103e582610564565b5050505050565b5f815f0361043c5760405162461bcd60e51b815260206004820181905260248201527f54656c65706f7274657252656769737472793a207a65726f2076657273696f6e604482015260640161024b565b5f828152600160205260409020546001600160a01b0316806101775760405162461bcd60e51b815260206004820152602560248201527f54656c65706f7274657252656769737472793a2076657273696f6e206e6f7420604482015264199bdd5b9960da1b606482015260840161024b565b5f6001600160a01b0382166104d55760405162461bcd60e51b815260040161024b90610a17565b6001600160a01b0382165f90815260026020526040812054908190036101775760405162461bcd60e51b815260206004820152602e60248201527f54656c65706f7274657252656769737472793a2070726f746f636f6c2061646460448201526d1c995cdcc81b9bdd08199bdd5b9960921b606482015260840161024b565b5f61055f5f546103ec565b905090565b80515f036105b45760405162461bcd60e51b815260206004820181905260248201527f54656c65706f7274657252656769737472793a207a65726f2076657273696f6e604482015260640161024b565b80515f908152600160205260409020546001600160a01b03161561062d5760405162461bcd60e51b815260206004820152602a60248201527f54656c65706f7274657252656769737472793a2076657273696f6e20616c72656044820152696164792065786973747360b01b606482015260840161024b565b60208101516001600160a01b03166106575760405162461bcd60e51b815260040161024b90610a17565b5f546106656101f482610a60565b825111156106cc5760405162461bcd60e51b815260206004820152602e60248201527f54656c65706f7274657252656769737472793a2076657273696f6e20696e637260448201526d0cadacadce840e8dede40d0d2ced60931b606482015260840161024b565b6020828101805184515f90815260018452604080822080546001600160a01b0319166001600160a01b03948516179055925190911681526002909252902054825111156107335781516020808401516001600160a01b03165f908152600290915260409020555b602082015182516040516001600160a01b03909216917fa5eed93d951a9603d5f7c0a57de79a299dd3dbd5e51429be209d8053a42ab43a905f90a381518110156107a65781515f81815560405183917f30623e953733f6474dabdfbef1103ce15ab73cdc77c6dfad0f9874d167e8a9b091a35b5050565b5f602082840312156107ba575f80fd5b5035919050565b5f602082840312156107d1575f80fd5b813563ffffffff811681146107e4575f80fd5b9392505050565b6001600160a01b03811681146107ff575f80fd5b50565b5f60208284031215610812575f80fd5b81356107e4816107eb565b634e487b7160e01b5f52604160045260245ffd5b6040516060810167ffffffffffffffff811182821017156108545761085461081d565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156108835761088361081d565b604052919050565b8051801515811461089a575f80fd5b919050565b5f80604083850312156108b0575f80fd5b825167ffffffffffffffff808211156108c7575f80fd5b90840190606082870312156108da575f80fd5b6108e2610831565b825181526020808401516108f5816107eb565b8282015260408401518381111561090a575f80fd5b80850194505087601f85011261091e575f80fd5b8351838111156109305761093061081d565b610942601f8201601f1916830161085a565b93508084528882828701011115610957575f80fd5b5f5b81811015610974578581018301518582018401528201610959565b505f8282860101525082604083015281955061099181880161088b565b9450505050509250929050565b5f8082840360608112156109b0575f80fd5b60408112156109bd575f80fd5b506040516040810181811067ffffffffffffffff821117156109e1576109e161081d565b6040528351815260208401516109f6816107eb565b60208201526040840151909250610a0c816107eb565b809150509250929050565b60208082526029908201527f54656c65706f7274657252656769737472793a207a65726f2070726f746f636f6040820152686c206164647265737360b81b606082015260800190565b8082018082111561017757634e487b7160e01b5f52601160045260245ffdfea26469706673582212209162d7e828050fd09c74d7e4669100d88b34c03d1d6e0d9e7ad8152d615fc2e464736f6c63430008190033", + Bin: "0x60a060405234801561000f575f80fd5b50604051610fe0380380610fe083398101604081905261002e916103e2565b7302000000000000000000000000000000000000056001600160a01b0316634213cf786040518163ffffffff1660e01b8152600401602060405180830381865afa15801561007e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100a291906104bc565b60805280515f5b818110156100e1576100d98382815181106100c6576100c66104d3565b60200260200101516100e960201b60201c565b6001016100a9565b50505061050c565b80515f0361013e5760405162461bcd60e51b815260206004820181905260248201527f54656c65706f7274657252656769737472793a207a65726f2076657273696f6e60448201526064015b60405180910390fd5b80515f908152600160205260409020546001600160a01b0316156101b75760405162461bcd60e51b815260206004820152602a60248201527f54656c65706f7274657252656769737472793a2076657273696f6e20616c72656044820152696164792065786973747360b01b6064820152608401610135565b60208101516001600160a01b03166102235760405162461bcd60e51b815260206004820152602960248201527f54656c65706f7274657252656769737472793a207a65726f2070726f746f636f6044820152686c206164647265737360b81b6064820152608401610135565b5f546102316101f4826104e7565b825111156102985760405162461bcd60e51b815260206004820152602e60248201527f54656c65706f7274657252656769737472793a2076657273696f6e20696e637260448201526d0cadacadce840e8dede40d0d2ced60931b6064820152608401610135565b6020828101805184515f90815260018452604080822080546001600160a01b0319166001600160a01b03948516179055925190911681526002909252902054825111156102ff5781516020808401516001600160a01b03165f908152600290915260409020555b602082015182516040516001600160a01b03909216917fa5eed93d951a9603d5f7c0a57de79a299dd3dbd5e51429be209d8053a42ab43a905f90a381518110156103725781515f81815560405183917f30623e953733f6474dabdfbef1103ce15ab73cdc77c6dfad0f9874d167e8a9b091a35b5050565b634e487b7160e01b5f52604160045260245ffd5b604080519081016001600160401b03811182821017156103ac576103ac610376565b60405290565b604051601f8201601f191681016001600160401b03811182821017156103da576103da610376565b604052919050565b5f60208083850312156103f3575f80fd5b82516001600160401b0380821115610409575f80fd5b818501915085601f83011261041c575f80fd5b81518181111561042e5761042e610376565b61043c848260051b016103b2565b818152848101925060069190911b83018401908782111561045b575f80fd5b928401925b818410156104b15760408489031215610477575f80fd5b61047f61038a565b84518152858501516001600160a01b038116811461049b575f80fd5b8187015283526040939093019291840191610460565b979650505050505050565b5f602082840312156104cc575f80fd5b5051919050565b634e487b7160e01b5f52603260045260245ffd5b8082018082111561050657634e487b7160e01b5f52601160045260245ffd5b92915050565b608051610ab561052b5f395f818161014301526102580152610ab55ff3fe608060405234801561000f575f80fd5b506004361061009b575f3560e01c8063ac473ac311610063578063ac473ac31461011f578063b771b3bc14610128578063c07f47d414610136578063d127dc9b1461013e578063d820e64f14610165575f80fd5b80630731775d1461009f578063215abce9146100c357806341f34ed9146100d657806346f9ef49146100eb5780634c1f08ce146100fe575b5f80fd5b6100a65f81565b6040516001600160a01b0390911681526020015b60405180910390f35b6100a66100d13660046107aa565b61016d565b6100e96100e43660046107c1565b61017d565b005b6100a66100f93660046107aa565b6103ec565b61011161010c366004610802565b6104ae565b6040519081526020016100ba565b6101116101f481565b6100a66005600160991b0181565b6101115f5481565b6101117f000000000000000000000000000000000000000000000000000000000000000081565b6100a6610554565b5f610177826103ec565b92915050565b6040516306f8253560e41b815263ffffffff821660048201525f9081906005600160991b0190636f825350906024015f60405180830381865afa1580156101c6573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526101ed919081019061089f565b91509150806102545760405162461bcd60e51b815260206004820152602860248201527f54656c65706f7274657252656769737472793a20696e76616c69642077617270604482015267206d65737361676560c01b60648201526084015b60405180910390fd5b81517f0000000000000000000000000000000000000000000000000000000000000000146102d85760405162461bcd60e51b815260206004820152602b60248201527f54656c65706f7274657252656769737472793a20696e76616c696420736f757260448201526a18d94818da185a5b88125160aa1b606482015260840161024b565b60208201516001600160a01b03161561034d5760405162461bcd60e51b815260206004820152603160248201527f54656c65706f7274657252656769737472793a20696e76616c6964206f726967604482015270696e2073656e646572206164647265737360781b606482015260840161024b565b5f808360400151806020019051810190610367919061099e565b90925090506001600160a01b03811630146103dc5760405162461bcd60e51b815260206004820152602f60248201527f54656c65706f7274657252656769737472793a20696e76616c6964206465737460448201526e696e6174696f6e206164647265737360881b606482015260840161024b565b6103e582610564565b5050505050565b5f815f0361043c5760405162461bcd60e51b815260206004820181905260248201527f54656c65706f7274657252656769737472793a207a65726f2076657273696f6e604482015260640161024b565b5f828152600160205260409020546001600160a01b0316806101775760405162461bcd60e51b815260206004820152602560248201527f54656c65706f7274657252656769737472793a2076657273696f6e206e6f7420604482015264199bdd5b9960da1b606482015260840161024b565b5f6001600160a01b0382166104d55760405162461bcd60e51b815260040161024b90610a17565b6001600160a01b0382165f90815260026020526040812054908190036101775760405162461bcd60e51b815260206004820152602e60248201527f54656c65706f7274657252656769737472793a2070726f746f636f6c2061646460448201526d1c995cdcc81b9bdd08199bdd5b9960921b606482015260840161024b565b5f61055f5f546103ec565b905090565b80515f036105b45760405162461bcd60e51b815260206004820181905260248201527f54656c65706f7274657252656769737472793a207a65726f2076657273696f6e604482015260640161024b565b80515f908152600160205260409020546001600160a01b03161561062d5760405162461bcd60e51b815260206004820152602a60248201527f54656c65706f7274657252656769737472793a2076657273696f6e20616c72656044820152696164792065786973747360b01b606482015260840161024b565b60208101516001600160a01b03166106575760405162461bcd60e51b815260040161024b90610a17565b5f546106656101f482610a60565b825111156106cc5760405162461bcd60e51b815260206004820152602e60248201527f54656c65706f7274657252656769737472793a2076657273696f6e20696e637260448201526d0cadacadce840e8dede40d0d2ced60931b606482015260840161024b565b6020828101805184515f90815260018452604080822080546001600160a01b0319166001600160a01b03948516179055925190911681526002909252902054825111156107335781516020808401516001600160a01b03165f908152600290915260409020555b602082015182516040516001600160a01b03909216917fa5eed93d951a9603d5f7c0a57de79a299dd3dbd5e51429be209d8053a42ab43a905f90a381518110156107a65781515f81815560405183917f30623e953733f6474dabdfbef1103ce15ab73cdc77c6dfad0f9874d167e8a9b091a35b5050565b5f602082840312156107ba575f80fd5b5035919050565b5f602082840312156107d1575f80fd5b813563ffffffff811681146107e4575f80fd5b9392505050565b6001600160a01b03811681146107ff575f80fd5b50565b5f60208284031215610812575f80fd5b81356107e4816107eb565b634e487b7160e01b5f52604160045260245ffd5b6040516060810167ffffffffffffffff811182821017156108545761085461081d565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156108835761088361081d565b604052919050565b8051801515811461089a575f80fd5b919050565b5f80604083850312156108b0575f80fd5b825167ffffffffffffffff808211156108c7575f80fd5b90840190606082870312156108da575f80fd5b6108e2610831565b825181526020808401516108f5816107eb565b8282015260408401518381111561090a575f80fd5b80850194505087601f85011261091e575f80fd5b8351838111156109305761093061081d565b610942601f8201601f1916830161085a565b93508084528882828701011115610957575f80fd5b5f5b81811015610974578581018301518582018401528201610959565b505f8282860101525082604083015281955061099181880161088b565b9450505050509250929050565b5f8082840360608112156109b0575f80fd5b60408112156109bd575f80fd5b506040516040810181811067ffffffffffffffff821117156109e1576109e161081d565b6040528351815260208401516109f6816107eb565b60208201526040840151909250610a0c816107eb565b809150509250929050565b60208082526029908201527f54656c65706f7274657252656769737472793a207a65726f2070726f746f636f6040820152686c206164647265737360b81b606082015260800190565b8082018082111561017757634e487b7160e01b5f52601160045260245ffdfea2646970667358221220597bdd94ad86545bd8dde89fa47d791136e7967c5069ef4b1ae9ade6cee52bf764736f6c63430008190033", } // TeleporterRegistryABI is the input ABI used to generate the binding from. diff --git a/abi-bindings/go/teleporter/tests/TestMessenger/TestMessenger.go b/abi-bindings/go/teleporter/tests/TestMessenger/TestMessenger.go index 0c155a272..fbb4224fa 100644 --- a/abi-bindings/go/teleporter/tests/TestMessenger/TestMessenger.go +++ b/abi-bindings/go/teleporter/tests/TestMessenger/TestMessenger.go @@ -32,7 +32,7 @@ var ( // TestMessengerMetaData contains all meta data concerning the TestMessenger contract. var TestMessengerMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"teleporterRegistryAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"teleporterManager\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minTeleporterVersion\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidInitialization\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"OwnableInvalidOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"OwnableUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrancyGuardReentrantCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"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\":\"sourceBlockchainID\",\"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\":\"destinationBlockchainID\",\"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\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"teleporterAddress\",\"type\":\"address\"}],\"name\":\"TeleporterAddressPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"teleporterAddress\",\"type\":\"address\"}],\"name\":\"TeleporterAddressUnpaused\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"TELEPORTER_REGISTRY_APP_STORAGE_LOCATION\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"sourceBlockchainID\",\"type\":\"bytes32\"}],\"name\":\"getCurrentMessage\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getMinTeleporterVersion\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"teleporterAddress\",\"type\":\"address\"}],\"name\":\"isTeleporterAddressPaused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"teleporterAddress\",\"type\":\"address\"}],\"name\":\"pauseTeleporterAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"sourceBlockchainID\",\"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\":\"destinationBlockchainID\",\"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\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"teleporterAddress\",\"type\":\"address\"}],\"name\":\"unpauseTeleporterAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"version\",\"type\":\"uint256\"}],\"name\":\"updateMinTeleporterVersion\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x608060405234801561000f575f80fd5b50604051611ff4380380611ff483398101604081905261002e9161062e565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff1615906001600160401b03165f811580156100775750825b90505f826001600160401b031660011480156100925750303b155b9050811580156100a0575080155b156100be5760405163f92ee8a960e01b815260040160405180910390fd5b84546001600160401b031916600117855583156100ec57845460ff60401b1916680100000000000000001785555b6100f4610152565b6100ff888888610164565b831561014557845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050505061067e565b61015a610184565b6101626101d2565b565b61016c610184565b6101768382610200565b61017f82610226565b505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff1661016257604051631afcd79f60e31b815260040160405180910390fd5b6101da610184565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b610208610184565b610210610152565b61021861023a565b6102228282610242565b5050565b61022e610184565b610237816103d1565b50565b610162610184565b61024a610184565b6001600160a01b0382166102cb5760405162461bcd60e51b815260206004820152603760248201527f54656c65706f7274657252656769737472794170703a207a65726f2054656c6560448201527f706f72746572207265676973747279206164647265737300000000000000000060648201526084015b60405180910390fd5b5f7fde77a4dc7391f6f8f2d9567915d687d3aee79e7a1fc7300392f2727e9a0f1d0090505f8390505f816001600160a01b031663c07f47d46040518163ffffffff1660e01b8152600401602060405180830381865afa158015610330573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103549190610667565b116103a95760405162461bcd60e51b815260206004820152603260248201525f80516020611fd4833981519152604482015271656c65706f7274657220726567697374727960701b60648201526084016102c2565b81546001600160a01b0319166001600160a01b0382161782556103cb8361040b565b50505050565b6103d9610184565b6001600160a01b03811661040257604051631e4fbdf760e01b81525f60048201526024016102c2565b610237816105a3565b7fde77a4dc7391f6f8f2d9567915d687d3aee79e7a1fc7300392f2727e9a0f1d0080546040805163301fd1f560e21b815290515f926001600160a01b03169163c07f47d49160048083019260209291908290030181865afa158015610472573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104969190610667565b6002830154909150818411156104f55760405162461bcd60e51b815260206004820152603160248201525f80516020611fd483398151915260448201527032b632b837b93a32b9103b32b939b4b7b760791b60648201526084016102c2565b80841161056a5760405162461bcd60e51b815260206004820152603f60248201527f54656c65706f7274657252656769737472794170703a206e6f7420677265617460448201527f6572207468616e2063757272656e74206d696e696d756d2076657273696f6e0060648201526084016102c2565b60028301849055604051849082907fa9a7ef57e41f05b4c15480842f5f0c27edfcbb553fed281f7c4068452cc1c02d905f90a350505050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a3505050565b80516001600160a01b0381168114610629575f80fd5b919050565b5f805f60608486031215610640575f80fd5b61064984610613565b925061065760208501610613565b9150604084015190509250925092565b5f60208284031215610677575f80fd5b5051919050565b6119498061068b5f395ff3fe608060405234801561000f575f80fd5b50600436106100b1575f3560e01c8063973142971161006e5780639731429714610159578063b33fead41461017c578063c868efaa1461019d578063d2cc7a70146101b0578063f2fde38b146101d7578063f63d09d7146101ea575f80fd5b80632b0d8f18146100b55780634511243e146100ca5780635eb99514146100dd578063715018a6146100f05780638da5cb5b146100f8578063909a6ac014610137575b5f80fd5b6100c86100c336600461130a565b6101fd565b005b6100c86100d836600461130a565b6102ff565b6100c86100eb366004611325565b6103ee565b6100c8610402565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546040516001600160a01b0390911681526020015b60405180910390f35b61014b5f805160206118f483398151915281565b60405190815260200161012e565b61016c61016736600461130a565b610415565b604051901515815260200161012e565b61018f61018a366004611325565b610435565b60405161012e929190611389565b6100c86101ab3660046113f9565b610507565b7fde77a4dc7391f6f8f2d9567915d687d3aee79e7a1fc7300392f2727e9a0f1d025461014b565b6100c86101e536600461130a565b6106e5565b61014b6101f8366004611451565b61071f565b5f805160206118f483398151915261021361087b565b6001600160a01b0382166102425760405162461bcd60e51b8152600401610239906114d1565b60405180910390fd5b61024c8183610883565b156102af5760405162461bcd60e51b815260206004820152602d60248201527f54656c65706f7274657252656769737472794170703a2061646472657373206160448201526c1b1c9958591e481c185d5cd959609a1b6064820152608401610239565b6001600160a01b0382165f81815260018381016020526040808320805460ff1916909217909155517f933f93e57a222e6330362af8b376d0a8725b6901e9a2fb86d00f169702b28a4c9190a25050565b5f805160206118f483398151915261031561087b565b6001600160a01b03821661033b5760405162461bcd60e51b8152600401610239906114d1565b6103458183610883565b6103a35760405162461bcd60e51b815260206004820152602960248201527f54656c65706f7274657252656769737472794170703a2061646472657373206e6044820152681bdd081c185d5cd95960ba1b6064820152608401610239565b6001600160a01b0382165f818152600183016020526040808220805460ff19169055517f844e2f3154214672229235858fd029d1dfd543901c6d05931f0bc2480a2d72c39190a25050565b6103f661087b565b6103ff816108a7565b50565b61040a610a3f565b6104135f610a9a565b565b5f5f805160206118f483398151915261042e8184610883565b9392505050565b5f81815260208181526040808320815180830190925280546001600160a01b0316825260018101805460609486949392908401916104729061151f565b80601f016020809104026020016040519081016040528092919081815260200182805461049e9061151f565b80156104e95780601f106104c0576101008083540402835291602001916104e9565b820191905f5260205f20905b8154815290600101906020018083116104cc57829003601f168201915b5050505050815250509050805f015181602001519250925050915091565b61050f610b0a565b5f5f805160206118f483398151915260028101548154919250906001600160a01b0316634c1f08ce336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa15801561057a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061059e9190611557565b10156106055760405162461bcd60e51b815260206004820152603060248201527f54656c65706f7274657252656769737472794170703a20696e76616c6964205460448201526f32b632b837b93a32b91039b2b73232b960811b6064820152608401610239565b61060f8133610883565b156106755760405162461bcd60e51b815260206004820152603060248201527f54656c65706f7274657252656769737472794170703a2054656c65706f72746560448201526f1c881859191c995cdcc81c185d5cd95960821b6064820152608401610239565b6106b5858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250610b5492505050565b506106df60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b50505050565b6106ed610a3f565b6001600160a01b03811661071657604051631e4fbdf760e01b81525f6004820152602401610239565b6103ff81610a9a565b5f610728610b0a565b5f851561073c576107398787610c09565b90505b876001600160a01b0316897fa06eff1edd0c66b8dc96d086dda7ba263edf88d7417e6cb15073b5e7bff8a8ca898489898960405161077e959493929190611596565b60405180910390a36108446040518060c001604052808b81526020018a6001600160a01b0316815260200160405180604001604052808b6001600160a01b031681526020018581525081526020018781526020015f67ffffffffffffffff8111156107eb576107eb6115c3565b604051908082528060200260200182016040528015610814578160200160208202803683370190505b508152602001868660405160200161082d9291906115d7565b604051602081830303815290604052815250610c15565b91505061087060017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b979650505050505050565b610413610a3f565b6001600160a01b0381165f90815260018301602052604090205460ff165b92915050565b5f805160206118f483398151915280546040805163301fd1f560e21b815290515f926001600160a01b03169163c07f47d49160048083019260209291908290030181865afa1580156108fb573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061091f9190611557565b6002830154909150818411156109915760405162461bcd60e51b815260206004820152603160248201527f54656c65706f7274657252656769737472794170703a20696e76616c6964205460448201527032b632b837b93a32b9103b32b939b4b7b760791b6064820152608401610239565b808411610a065760405162461bcd60e51b815260206004820152603f60248201527f54656c65706f7274657252656769737472794170703a206e6f7420677265617460448201527f6572207468616e2063757272656e74206d696e696d756d2076657273696f6e006064820152608401610239565b60028301849055604051849082907fa9a7ef57e41f05b4c15480842f5f0c27edfcbb553fed281f7c4068452cc1c02d905f90a350505050565b33610a717f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b0316146104135760405163118cdaa760e01b8152336004820152602401610239565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a3505050565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00805460011901610b4e57604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b5f81806020019051810190610b6991906115ea565b6040805180820182526001600160a01b03868116825260208083018581525f8a815291829052939020825181546001600160a01b03191692169190911781559151929350916001820190610bbd90826116d2565b50905050826001600160a01b0316847f1f5c800b5f2b573929a7948f82a199c2a212851b53a6c5bd703ece23999d24aa83604051610bfb9190611792565b60405180910390a350505050565b5f61042e833384610d30565b5f80610c1f610e93565b60408401516020015190915015610cc4576040830151516001600160a01b0316610ca15760405162461bcd60e51b815260206004820152602d60248201527f54656c65706f7274657252656769737472794170703a207a65726f206665652060448201526c746f6b656e206164647265737360981b6064820152608401610239565b604083015160208101519051610cc4916001600160a01b03909116908390610f83565b604051630624488560e41b81526001600160a01b03821690636244885090610cf09086906004016117e7565b6020604051808303815f875af1158015610d0c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061042e9190611557565b6040516370a0823160e01b81523060048201525f9081906001600160a01b038616906370a0823190602401602060405180830381865afa158015610d76573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d9a9190611557565b9050610db16001600160a01b03861685308661100a565b6040516370a0823160e01b81523060048201525f906001600160a01b038716906370a0823190602401602060405180830381865afa158015610df5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e199190611557565b9050818111610e7f5760405162461bcd60e51b815260206004820152602c60248201527f5361666545524332305472616e7366657246726f6d3a2062616c616e6365206e60448201526b1bdd081a5b98dc99585cd95960a21b6064820152608401610239565b610e898282611878565b9695505050505050565b5f805160206118f483398151915280546040805163d820e64f60e01b815290515f939284926001600160a01b039091169163d820e64f916004808201926020929091908290030181865afa158015610eed573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f11919061188b565b9050610f1d8282610883565b156108a15760405162461bcd60e51b815260206004820152603060248201527f54656c65706f7274657252656769737472794170703a2054656c65706f72746560448201526f1c881cd95b991a5b99c81c185d5cd95960821b6064820152608401610239565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301525f919085169063dd62ed3e90604401602060405180830381865afa158015610fd0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ff49190611557565b90506106df848461100585856118a6565b611071565b6040516001600160a01b0384811660248301528381166044830152606482018390526106df9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506110fc565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526110c28482611162565b6106df576040516001600160a01b0384811660248301525f60448301526110f691869182169063095ea7b39060640161103f565b6106df84825b5f6111106001600160a01b03841683611203565b905080515f1415801561113457508080602001905181019061113291906118b9565b155b1561115d57604051635274afe760e01b81526001600160a01b0384166004820152602401610239565b505050565b5f805f846001600160a01b03168460405161117d91906118d8565b5f604051808303815f865af19150503d805f81146111b6576040519150601f19603f3d011682016040523d82523d5f602084013e6111bb565b606091505b50915091508180156111e55750805115806111e55750808060200190518101906111e591906118b9565b80156111fa57505f856001600160a01b03163b115b95945050505050565b606061042e83835f845f80856001600160a01b0316848660405161122791906118d8565b5f6040518083038185875af1925050503d805f8114611261576040519150601f19603f3d011682016040523d82523d5f602084013e611266565b606091505b5091509150610e8986838360608261128657611281826112cd565b61042e565b815115801561129d57506001600160a01b0384163b155b156112c657604051639996b31560e01b81526001600160a01b0385166004820152602401610239565b508061042e565b8051156112dd5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6001600160a01b03811681146103ff575f80fd5b5f6020828403121561131a575f80fd5b813561042e816112f6565b5f60208284031215611335575f80fd5b5035919050565b5f5b8381101561135657818101518382015260200161133e565b50505f910152565b5f815180845261137581602086016020860161133c565b601f01601f19169290920160200192915050565b6001600160a01b03831681526040602082018190525f906113ac9083018461135e565b949350505050565b5f8083601f8401126113c4575f80fd5b50813567ffffffffffffffff8111156113db575f80fd5b6020830191508360208285010111156113f2575f80fd5b9250929050565b5f805f806060858703121561140c575f80fd5b84359350602085013561141e816112f6565b9250604085013567ffffffffffffffff811115611439575f80fd5b611445878288016113b4565b95989497509550505050565b5f805f805f805f60c0888a031215611467575f80fd5b873596506020880135611479816112f6565b95506040880135611489816112f6565b9450606088013593506080880135925060a088013567ffffffffffffffff8111156114b2575f80fd5b6114be8a828b016113b4565b989b979a50959850939692959293505050565b6020808252602e908201527f54656c65706f7274657252656769737472794170703a207a65726f2054656c6560408201526d706f72746572206164647265737360901b606082015260800190565b600181811c9082168061153357607f821691505b60208210810361155157634e487b7160e01b5f52602260045260245ffd5b50919050565b5f60208284031215611567575f80fd5b5051919050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b60018060a01b0386168152846020820152836040820152608060608201525f61087060808301848661156e565b634e487b7160e01b5f52604160045260245ffd5b602081525f6113ac60208301848661156e565b5f602082840312156115fa575f80fd5b815167ffffffffffffffff80821115611611575f80fd5b818401915084601f830112611624575f80fd5b815181811115611636576116366115c3565b604051601f8201601f19908116603f0116810190838211818310171561165e5761165e6115c3565b81604052828152876020848701011115611676575f80fd5b61087083602083016020880161133c565b601f82111561115d57805f5260205f20601f840160051c810160208510156116ac5750805b601f840160051c820191505b818110156116cb575f81556001016116b8565b5050505050565b815167ffffffffffffffff8111156116ec576116ec6115c3565b611700816116fa845461151f565b84611687565b602080601f831160018114611733575f841561171c5750858301515b5f19600386901b1c1916600185901b17855561178a565b5f85815260208120601f198616915b8281101561176157888601518255948401946001909101908401611742565b508582101561177e57878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b602081525f61042e602083018461135e565b5f815180845260208085019450602084015f5b838110156117dc5781516001600160a01b0316875295820195908201906001016117b7565b509495945050505050565b60208152815160208201525f602083015160018060a01b03808216604085015260408501519150808251166060850152506020810151608084015250606083015160a0830152608083015160e060c08401526118476101008401826117a4565b905060a0840151601f198483030160e08501526111fa828261135e565b634e487b7160e01b5f52601160045260245ffd5b818103818111156108a1576108a1611864565b5f6020828403121561189b575f80fd5b815161042e816112f6565b808201808211156108a1576108a1611864565b5f602082840312156118c9575f80fd5b8151801515811461042e575f80fd5b5f82516118e981846020870161133c565b919091019291505056fede77a4dc7391f6f8f2d9567915d687d3aee79e7a1fc7300392f2727e9a0f1d00a264697066735822122062fd8850632ccfe83eea1845a044d69129346188301e664b16db39ae9a7db3cb64736f6c6343000819003354656c65706f7274657252656769737472794170703a20696e76616c69642054", + Bin: "0x608060405234801561000f575f80fd5b50604051611ff4380380611ff483398101604081905261002e9161062e565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff1615906001600160401b03165f811580156100775750825b90505f826001600160401b031660011480156100925750303b155b9050811580156100a0575080155b156100be5760405163f92ee8a960e01b815260040160405180910390fd5b84546001600160401b031916600117855583156100ec57845460ff60401b1916680100000000000000001785555b6100f4610152565b6100ff888888610164565b831561014557845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050505061067e565b61015a610184565b6101626101d2565b565b61016c610184565b6101768382610200565b61017f82610226565b505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff1661016257604051631afcd79f60e31b815260040160405180910390fd5b6101da610184565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b610208610184565b610210610152565b61021861023a565b6102228282610242565b5050565b61022e610184565b610237816103d1565b50565b610162610184565b61024a610184565b6001600160a01b0382166102cb5760405162461bcd60e51b815260206004820152603760248201527f54656c65706f7274657252656769737472794170703a207a65726f2054656c6560448201527f706f72746572207265676973747279206164647265737300000000000000000060648201526084015b60405180910390fd5b5f7fde77a4dc7391f6f8f2d9567915d687d3aee79e7a1fc7300392f2727e9a0f1d0090505f8390505f816001600160a01b031663c07f47d46040518163ffffffff1660e01b8152600401602060405180830381865afa158015610330573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103549190610667565b116103a95760405162461bcd60e51b815260206004820152603260248201525f80516020611fd4833981519152604482015271656c65706f7274657220726567697374727960701b60648201526084016102c2565b81546001600160a01b0319166001600160a01b0382161782556103cb8361040b565b50505050565b6103d9610184565b6001600160a01b03811661040257604051631e4fbdf760e01b81525f60048201526024016102c2565b610237816105a3565b7fde77a4dc7391f6f8f2d9567915d687d3aee79e7a1fc7300392f2727e9a0f1d0080546040805163301fd1f560e21b815290515f926001600160a01b03169163c07f47d49160048083019260209291908290030181865afa158015610472573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104969190610667565b6002830154909150818411156104f55760405162461bcd60e51b815260206004820152603160248201525f80516020611fd483398151915260448201527032b632b837b93a32b9103b32b939b4b7b760791b60648201526084016102c2565b80841161056a5760405162461bcd60e51b815260206004820152603f60248201527f54656c65706f7274657252656769737472794170703a206e6f7420677265617460448201527f6572207468616e2063757272656e74206d696e696d756d2076657273696f6e0060648201526084016102c2565b60028301849055604051849082907fa9a7ef57e41f05b4c15480842f5f0c27edfcbb553fed281f7c4068452cc1c02d905f90a350505050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a3505050565b80516001600160a01b0381168114610629575f80fd5b919050565b5f805f60608486031215610640575f80fd5b61064984610613565b925061065760208501610613565b9150604084015190509250925092565b5f60208284031215610677575f80fd5b5051919050565b6119498061068b5f395ff3fe608060405234801561000f575f80fd5b50600436106100b1575f3560e01c8063973142971161006e5780639731429714610159578063b33fead41461017c578063c868efaa1461019d578063d2cc7a70146101b0578063f2fde38b146101d7578063f63d09d7146101ea575f80fd5b80632b0d8f18146100b55780634511243e146100ca5780635eb99514146100dd578063715018a6146100f05780638da5cb5b146100f8578063909a6ac014610137575b5f80fd5b6100c86100c336600461130a565b6101fd565b005b6100c86100d836600461130a565b6102ff565b6100c86100eb366004611325565b6103ee565b6100c8610402565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546040516001600160a01b0390911681526020015b60405180910390f35b61014b5f805160206118f483398151915281565b60405190815260200161012e565b61016c61016736600461130a565b610415565b604051901515815260200161012e565b61018f61018a366004611325565b610435565b60405161012e929190611389565b6100c86101ab3660046113f9565b610507565b7fde77a4dc7391f6f8f2d9567915d687d3aee79e7a1fc7300392f2727e9a0f1d025461014b565b6100c86101e536600461130a565b6106e5565b61014b6101f8366004611451565b61071f565b5f805160206118f483398151915261021361087b565b6001600160a01b0382166102425760405162461bcd60e51b8152600401610239906114d1565b60405180910390fd5b61024c8183610883565b156102af5760405162461bcd60e51b815260206004820152602d60248201527f54656c65706f7274657252656769737472794170703a2061646472657373206160448201526c1b1c9958591e481c185d5cd959609a1b6064820152608401610239565b6001600160a01b0382165f81815260018381016020526040808320805460ff1916909217909155517f933f93e57a222e6330362af8b376d0a8725b6901e9a2fb86d00f169702b28a4c9190a25050565b5f805160206118f483398151915261031561087b565b6001600160a01b03821661033b5760405162461bcd60e51b8152600401610239906114d1565b6103458183610883565b6103a35760405162461bcd60e51b815260206004820152602960248201527f54656c65706f7274657252656769737472794170703a2061646472657373206e6044820152681bdd081c185d5cd95960ba1b6064820152608401610239565b6001600160a01b0382165f818152600183016020526040808220805460ff19169055517f844e2f3154214672229235858fd029d1dfd543901c6d05931f0bc2480a2d72c39190a25050565b6103f661087b565b6103ff816108a7565b50565b61040a610a3f565b6104135f610a9a565b565b5f5f805160206118f483398151915261042e8184610883565b9392505050565b5f81815260208181526040808320815180830190925280546001600160a01b0316825260018101805460609486949392908401916104729061151f565b80601f016020809104026020016040519081016040528092919081815260200182805461049e9061151f565b80156104e95780601f106104c0576101008083540402835291602001916104e9565b820191905f5260205f20905b8154815290600101906020018083116104cc57829003601f168201915b5050505050815250509050805f015181602001519250925050915091565b61050f610b0a565b5f5f805160206118f483398151915260028101548154919250906001600160a01b0316634c1f08ce336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa15801561057a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061059e9190611557565b10156106055760405162461bcd60e51b815260206004820152603060248201527f54656c65706f7274657252656769737472794170703a20696e76616c6964205460448201526f32b632b837b93a32b91039b2b73232b960811b6064820152608401610239565b61060f8133610883565b156106755760405162461bcd60e51b815260206004820152603060248201527f54656c65706f7274657252656769737472794170703a2054656c65706f72746560448201526f1c881859191c995cdcc81c185d5cd95960821b6064820152608401610239565b6106b5858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250610b5492505050565b506106df60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b50505050565b6106ed610a3f565b6001600160a01b03811661071657604051631e4fbdf760e01b81525f6004820152602401610239565b6103ff81610a9a565b5f610728610b0a565b5f851561073c576107398787610c09565b90505b876001600160a01b0316897fa06eff1edd0c66b8dc96d086dda7ba263edf88d7417e6cb15073b5e7bff8a8ca898489898960405161077e959493929190611596565b60405180910390a36108446040518060c001604052808b81526020018a6001600160a01b0316815260200160405180604001604052808b6001600160a01b031681526020018581525081526020018781526020015f67ffffffffffffffff8111156107eb576107eb6115c3565b604051908082528060200260200182016040528015610814578160200160208202803683370190505b508152602001868660405160200161082d9291906115d7565b604051602081830303815290604052815250610c15565b91505061087060017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b979650505050505050565b610413610a3f565b6001600160a01b0381165f90815260018301602052604090205460ff165b92915050565b5f805160206118f483398151915280546040805163301fd1f560e21b815290515f926001600160a01b03169163c07f47d49160048083019260209291908290030181865afa1580156108fb573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061091f9190611557565b6002830154909150818411156109915760405162461bcd60e51b815260206004820152603160248201527f54656c65706f7274657252656769737472794170703a20696e76616c6964205460448201527032b632b837b93a32b9103b32b939b4b7b760791b6064820152608401610239565b808411610a065760405162461bcd60e51b815260206004820152603f60248201527f54656c65706f7274657252656769737472794170703a206e6f7420677265617460448201527f6572207468616e2063757272656e74206d696e696d756d2076657273696f6e006064820152608401610239565b60028301849055604051849082907fa9a7ef57e41f05b4c15480842f5f0c27edfcbb553fed281f7c4068452cc1c02d905f90a350505050565b33610a717f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b0316146104135760405163118cdaa760e01b8152336004820152602401610239565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a3505050565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00805460011901610b4e57604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b5f81806020019051810190610b6991906115ea565b6040805180820182526001600160a01b03868116825260208083018581525f8a815291829052939020825181546001600160a01b03191692169190911781559151929350916001820190610bbd90826116d2565b50905050826001600160a01b0316847f1f5c800b5f2b573929a7948f82a199c2a212851b53a6c5bd703ece23999d24aa83604051610bfb9190611792565b60405180910390a350505050565b5f61042e833384610d30565b5f80610c1f610e93565b60408401516020015190915015610cc4576040830151516001600160a01b0316610ca15760405162461bcd60e51b815260206004820152602d60248201527f54656c65706f7274657252656769737472794170703a207a65726f206665652060448201526c746f6b656e206164647265737360981b6064820152608401610239565b604083015160208101519051610cc4916001600160a01b03909116908390610f83565b604051630624488560e41b81526001600160a01b03821690636244885090610cf09086906004016117e7565b6020604051808303815f875af1158015610d0c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061042e9190611557565b6040516370a0823160e01b81523060048201525f9081906001600160a01b038616906370a0823190602401602060405180830381865afa158015610d76573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d9a9190611557565b9050610db16001600160a01b03861685308661100a565b6040516370a0823160e01b81523060048201525f906001600160a01b038716906370a0823190602401602060405180830381865afa158015610df5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e199190611557565b9050818111610e7f5760405162461bcd60e51b815260206004820152602c60248201527f5361666545524332305472616e7366657246726f6d3a2062616c616e6365206e60448201526b1bdd081a5b98dc99585cd95960a21b6064820152608401610239565b610e898282611878565b9695505050505050565b5f805160206118f483398151915280546040805163d820e64f60e01b815290515f939284926001600160a01b039091169163d820e64f916004808201926020929091908290030181865afa158015610eed573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f11919061188b565b9050610f1d8282610883565b156108a15760405162461bcd60e51b815260206004820152603060248201527f54656c65706f7274657252656769737472794170703a2054656c65706f72746560448201526f1c881cd95b991a5b99c81c185d5cd95960821b6064820152608401610239565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301525f919085169063dd62ed3e90604401602060405180830381865afa158015610fd0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ff49190611557565b90506106df848461100585856118a6565b611071565b6040516001600160a01b0384811660248301528381166044830152606482018390526106df9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506110fc565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526110c28482611162565b6106df576040516001600160a01b0384811660248301525f60448301526110f691869182169063095ea7b39060640161103f565b6106df84825b5f6111106001600160a01b03841683611203565b905080515f1415801561113457508080602001905181019061113291906118b9565b155b1561115d57604051635274afe760e01b81526001600160a01b0384166004820152602401610239565b505050565b5f805f846001600160a01b03168460405161117d91906118d8565b5f604051808303815f865af19150503d805f81146111b6576040519150601f19603f3d011682016040523d82523d5f602084013e6111bb565b606091505b50915091508180156111e55750805115806111e55750808060200190518101906111e591906118b9565b80156111fa57505f856001600160a01b03163b115b95945050505050565b606061042e83835f845f80856001600160a01b0316848660405161122791906118d8565b5f6040518083038185875af1925050503d805f8114611261576040519150601f19603f3d011682016040523d82523d5f602084013e611266565b606091505b5091509150610e8986838360608261128657611281826112cd565b61042e565b815115801561129d57506001600160a01b0384163b155b156112c657604051639996b31560e01b81526001600160a01b0385166004820152602401610239565b508061042e565b8051156112dd5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6001600160a01b03811681146103ff575f80fd5b5f6020828403121561131a575f80fd5b813561042e816112f6565b5f60208284031215611335575f80fd5b5035919050565b5f5b8381101561135657818101518382015260200161133e565b50505f910152565b5f815180845261137581602086016020860161133c565b601f01601f19169290920160200192915050565b6001600160a01b03831681526040602082018190525f906113ac9083018461135e565b949350505050565b5f8083601f8401126113c4575f80fd5b50813567ffffffffffffffff8111156113db575f80fd5b6020830191508360208285010111156113f2575f80fd5b9250929050565b5f805f806060858703121561140c575f80fd5b84359350602085013561141e816112f6565b9250604085013567ffffffffffffffff811115611439575f80fd5b611445878288016113b4565b95989497509550505050565b5f805f805f805f60c0888a031215611467575f80fd5b873596506020880135611479816112f6565b95506040880135611489816112f6565b9450606088013593506080880135925060a088013567ffffffffffffffff8111156114b2575f80fd5b6114be8a828b016113b4565b989b979a50959850939692959293505050565b6020808252602e908201527f54656c65706f7274657252656769737472794170703a207a65726f2054656c6560408201526d706f72746572206164647265737360901b606082015260800190565b600181811c9082168061153357607f821691505b60208210810361155157634e487b7160e01b5f52602260045260245ffd5b50919050565b5f60208284031215611567575f80fd5b5051919050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b60018060a01b0386168152846020820152836040820152608060608201525f61087060808301848661156e565b634e487b7160e01b5f52604160045260245ffd5b602081525f6113ac60208301848661156e565b5f602082840312156115fa575f80fd5b815167ffffffffffffffff80821115611611575f80fd5b818401915084601f830112611624575f80fd5b815181811115611636576116366115c3565b604051601f8201601f19908116603f0116810190838211818310171561165e5761165e6115c3565b81604052828152876020848701011115611676575f80fd5b61087083602083016020880161133c565b601f82111561115d57805f5260205f20601f840160051c810160208510156116ac5750805b601f840160051c820191505b818110156116cb575f81556001016116b8565b5050505050565b815167ffffffffffffffff8111156116ec576116ec6115c3565b611700816116fa845461151f565b84611687565b602080601f831160018114611733575f841561171c5750858301515b5f19600386901b1c1916600185901b17855561178a565b5f85815260208120601f198616915b8281101561176157888601518255948401946001909101908401611742565b508582101561177e57878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b602081525f61042e602083018461135e565b5f815180845260208085019450602084015f5b838110156117dc5781516001600160a01b0316875295820195908201906001016117b7565b509495945050505050565b60208152815160208201525f602083015160018060a01b03808216604085015260408501519150808251166060850152506020810151608084015250606083015160a0830152608083015160e060c08401526118476101008401826117a4565b905060a0840151601f198483030160e08501526111fa828261135e565b634e487b7160e01b5f52601160045260245ffd5b818103818111156108a1576108a1611864565b5f6020828403121561189b575f80fd5b815161042e816112f6565b808201808211156108a1576108a1611864565b5f602082840312156118c9575f80fd5b8151801515811461042e575f80fd5b5f82516118e981846020870161133c565b919091019291505056fede77a4dc7391f6f8f2d9567915d687d3aee79e7a1fc7300392f2727e9a0f1d00a26469706673582212202259d01275adae801579c0498279360343806c65496f6dde468ae9813110963064736f6c6343000819003354656c65706f7274657252656769737472794170703a20696e76616c69642054", } // TestMessengerABI is the input ABI used to generate the binding from. diff --git a/contracts/README.md b/avalanche/contracts/README.md similarity index 100% rename from contracts/README.md rename to avalanche/contracts/README.md diff --git a/contracts/governance/README.md b/avalanche/contracts/governance/README.md similarity index 100% rename from contracts/governance/README.md rename to avalanche/contracts/governance/README.md diff --git a/contracts/governance/ValidatorSetSig.sol b/avalanche/contracts/governance/ValidatorSetSig.sol similarity index 100% rename from contracts/governance/ValidatorSetSig.sol rename to avalanche/contracts/governance/ValidatorSetSig.sol diff --git a/contracts/governance/tests/ValidatorSetSigTests.t.sol b/avalanche/contracts/governance/tests/ValidatorSetSigTests.t.sol similarity index 100% rename from contracts/governance/tests/ValidatorSetSigTests.t.sol rename to avalanche/contracts/governance/tests/ValidatorSetSigTests.t.sol diff --git a/contracts/ictt/README.md b/avalanche/contracts/ictt/README.md similarity index 100% rename from contracts/ictt/README.md rename to avalanche/contracts/ictt/README.md diff --git a/contracts/ictt/TokenHome/ERC20TokenHome.sol b/avalanche/contracts/ictt/TokenHome/ERC20TokenHome.sol similarity index 100% rename from contracts/ictt/TokenHome/ERC20TokenHome.sol rename to avalanche/contracts/ictt/TokenHome/ERC20TokenHome.sol diff --git a/contracts/ictt/TokenHome/ERC20TokenHomeUpgradeable.sol b/avalanche/contracts/ictt/TokenHome/ERC20TokenHomeUpgradeable.sol similarity index 100% rename from contracts/ictt/TokenHome/ERC20TokenHomeUpgradeable.sol rename to avalanche/contracts/ictt/TokenHome/ERC20TokenHomeUpgradeable.sol diff --git a/contracts/ictt/TokenHome/NativeTokenHome.sol b/avalanche/contracts/ictt/TokenHome/NativeTokenHome.sol similarity index 100% rename from contracts/ictt/TokenHome/NativeTokenHome.sol rename to avalanche/contracts/ictt/TokenHome/NativeTokenHome.sol diff --git a/contracts/ictt/TokenHome/NativeTokenHomeUpgradeable.sol b/avalanche/contracts/ictt/TokenHome/NativeTokenHomeUpgradeable.sol similarity index 100% rename from contracts/ictt/TokenHome/NativeTokenHomeUpgradeable.sol rename to avalanche/contracts/ictt/TokenHome/NativeTokenHomeUpgradeable.sol diff --git a/contracts/ictt/TokenHome/TokenHome.sol b/avalanche/contracts/ictt/TokenHome/TokenHome.sol similarity index 100% rename from contracts/ictt/TokenHome/TokenHome.sol rename to avalanche/contracts/ictt/TokenHome/TokenHome.sol diff --git a/contracts/ictt/TokenHome/interfaces/IERC20TokenHome.sol b/avalanche/contracts/ictt/TokenHome/interfaces/IERC20TokenHome.sol similarity index 100% rename from contracts/ictt/TokenHome/interfaces/IERC20TokenHome.sol rename to avalanche/contracts/ictt/TokenHome/interfaces/IERC20TokenHome.sol diff --git a/contracts/ictt/TokenHome/interfaces/INativeTokenHome.sol b/avalanche/contracts/ictt/TokenHome/interfaces/INativeTokenHome.sol similarity index 100% rename from contracts/ictt/TokenHome/interfaces/INativeTokenHome.sol rename to avalanche/contracts/ictt/TokenHome/interfaces/INativeTokenHome.sol diff --git a/contracts/ictt/TokenHome/interfaces/ITokenHome.sol b/avalanche/contracts/ictt/TokenHome/interfaces/ITokenHome.sol similarity index 100% rename from contracts/ictt/TokenHome/interfaces/ITokenHome.sol rename to avalanche/contracts/ictt/TokenHome/interfaces/ITokenHome.sol diff --git a/contracts/ictt/TokenRemote/ERC20TokenRemote.sol b/avalanche/contracts/ictt/TokenRemote/ERC20TokenRemote.sol similarity index 100% rename from contracts/ictt/TokenRemote/ERC20TokenRemote.sol rename to avalanche/contracts/ictt/TokenRemote/ERC20TokenRemote.sol diff --git a/contracts/ictt/TokenRemote/ERC20TokenRemoteUpgradeable.sol b/avalanche/contracts/ictt/TokenRemote/ERC20TokenRemoteUpgradeable.sol similarity index 100% rename from contracts/ictt/TokenRemote/ERC20TokenRemoteUpgradeable.sol rename to avalanche/contracts/ictt/TokenRemote/ERC20TokenRemoteUpgradeable.sol diff --git a/contracts/ictt/TokenRemote/NativeTokenRemote.sol b/avalanche/contracts/ictt/TokenRemote/NativeTokenRemote.sol similarity index 100% rename from contracts/ictt/TokenRemote/NativeTokenRemote.sol rename to avalanche/contracts/ictt/TokenRemote/NativeTokenRemote.sol diff --git a/contracts/ictt/TokenRemote/NativeTokenRemoteUpgradeable.sol b/avalanche/contracts/ictt/TokenRemote/NativeTokenRemoteUpgradeable.sol similarity index 100% rename from contracts/ictt/TokenRemote/NativeTokenRemoteUpgradeable.sol rename to avalanche/contracts/ictt/TokenRemote/NativeTokenRemoteUpgradeable.sol diff --git a/contracts/ictt/TokenRemote/TokenRemote.sol b/avalanche/contracts/ictt/TokenRemote/TokenRemote.sol similarity index 100% rename from contracts/ictt/TokenRemote/TokenRemote.sol rename to avalanche/contracts/ictt/TokenRemote/TokenRemote.sol diff --git a/contracts/ictt/TokenRemote/interfaces/INativeTokenRemote.sol b/avalanche/contracts/ictt/TokenRemote/interfaces/INativeTokenRemote.sol similarity index 100% rename from contracts/ictt/TokenRemote/interfaces/INativeTokenRemote.sol rename to avalanche/contracts/ictt/TokenRemote/interfaces/INativeTokenRemote.sol diff --git a/contracts/ictt/TokenRemote/interfaces/ITokenRemote.sol b/avalanche/contracts/ictt/TokenRemote/interfaces/ITokenRemote.sol similarity index 100% rename from contracts/ictt/TokenRemote/interfaces/ITokenRemote.sol rename to avalanche/contracts/ictt/TokenRemote/interfaces/ITokenRemote.sol diff --git a/contracts/ictt/WrappedNativeToken.sol b/avalanche/contracts/ictt/WrappedNativeToken.sol similarity index 100% rename from contracts/ictt/WrappedNativeToken.sol rename to avalanche/contracts/ictt/WrappedNativeToken.sol diff --git a/contracts/ictt/interfaces/IERC20SendAndCallReceiver.sol b/avalanche/contracts/ictt/interfaces/IERC20SendAndCallReceiver.sol similarity index 100% rename from contracts/ictt/interfaces/IERC20SendAndCallReceiver.sol rename to avalanche/contracts/ictt/interfaces/IERC20SendAndCallReceiver.sol diff --git a/contracts/ictt/interfaces/IERC20TokenTransferrer.sol b/avalanche/contracts/ictt/interfaces/IERC20TokenTransferrer.sol similarity index 100% rename from contracts/ictt/interfaces/IERC20TokenTransferrer.sol rename to avalanche/contracts/ictt/interfaces/IERC20TokenTransferrer.sol diff --git a/contracts/ictt/interfaces/INativeSendAndCallReceiver.sol b/avalanche/contracts/ictt/interfaces/INativeSendAndCallReceiver.sol similarity index 100% rename from contracts/ictt/interfaces/INativeSendAndCallReceiver.sol rename to avalanche/contracts/ictt/interfaces/INativeSendAndCallReceiver.sol diff --git a/contracts/ictt/interfaces/INativeTokenTransferrer.sol b/avalanche/contracts/ictt/interfaces/INativeTokenTransferrer.sol similarity index 100% rename from contracts/ictt/interfaces/INativeTokenTransferrer.sol rename to avalanche/contracts/ictt/interfaces/INativeTokenTransferrer.sol diff --git a/contracts/ictt/interfaces/ITokenTransferrer.sol b/avalanche/contracts/ictt/interfaces/ITokenTransferrer.sol similarity index 100% rename from contracts/ictt/interfaces/ITokenTransferrer.sol rename to avalanche/contracts/ictt/interfaces/ITokenTransferrer.sol diff --git a/contracts/ictt/interfaces/IWrappedNativeToken.sol b/avalanche/contracts/ictt/interfaces/IWrappedNativeToken.sol similarity index 100% rename from contracts/ictt/interfaces/IWrappedNativeToken.sol rename to avalanche/contracts/ictt/interfaces/IWrappedNativeToken.sol diff --git a/contracts/ictt/mocks/ExampleERC20Decimals.sol b/avalanche/contracts/ictt/mocks/ExampleERC20Decimals.sol similarity index 100% rename from contracts/ictt/mocks/ExampleERC20Decimals.sol rename to avalanche/contracts/ictt/mocks/ExampleERC20Decimals.sol diff --git a/contracts/ictt/mocks/MockERC20SendAndCallReceiver.sol b/avalanche/contracts/ictt/mocks/MockERC20SendAndCallReceiver.sol similarity index 100% rename from contracts/ictt/mocks/MockERC20SendAndCallReceiver.sol rename to avalanche/contracts/ictt/mocks/MockERC20SendAndCallReceiver.sol diff --git a/contracts/ictt/mocks/MockNativeSendAndCallReceiver.sol b/avalanche/contracts/ictt/mocks/MockNativeSendAndCallReceiver.sol similarity index 100% rename from contracts/ictt/mocks/MockNativeSendAndCallReceiver.sol rename to avalanche/contracts/ictt/mocks/MockNativeSendAndCallReceiver.sol diff --git a/contracts/ictt/tests/ERC20TokenHomeTests.t.sol b/avalanche/contracts/ictt/tests/ERC20TokenHomeTests.t.sol similarity index 100% rename from contracts/ictt/tests/ERC20TokenHomeTests.t.sol rename to avalanche/contracts/ictt/tests/ERC20TokenHomeTests.t.sol diff --git a/contracts/ictt/tests/ERC20TokenRemoteTests.t.sol b/avalanche/contracts/ictt/tests/ERC20TokenRemoteTests.t.sol similarity index 100% rename from contracts/ictt/tests/ERC20TokenRemoteTests.t.sol rename to avalanche/contracts/ictt/tests/ERC20TokenRemoteTests.t.sol diff --git a/contracts/ictt/tests/ERC20TokenTransferrerTests.t.sol b/avalanche/contracts/ictt/tests/ERC20TokenTransferrerTests.t.sol similarity index 100% rename from contracts/ictt/tests/ERC20TokenTransferrerTests.t.sol rename to avalanche/contracts/ictt/tests/ERC20TokenTransferrerTests.t.sol diff --git a/contracts/ictt/tests/ExampleERC20DecimalsTests.t.sol b/avalanche/contracts/ictt/tests/ExampleERC20DecimalsTests.t.sol similarity index 100% rename from contracts/ictt/tests/ExampleERC20DecimalsTests.t.sol rename to avalanche/contracts/ictt/tests/ExampleERC20DecimalsTests.t.sol diff --git a/contracts/ictt/tests/MockSendAndCallReceiverTest.t.sol b/avalanche/contracts/ictt/tests/MockSendAndCallReceiverTest.t.sol similarity index 100% rename from contracts/ictt/tests/MockSendAndCallReceiverTest.t.sol rename to avalanche/contracts/ictt/tests/MockSendAndCallReceiverTest.t.sol diff --git a/contracts/ictt/tests/NativeTokenHomeTests.t.sol b/avalanche/contracts/ictt/tests/NativeTokenHomeTests.t.sol similarity index 100% rename from contracts/ictt/tests/NativeTokenHomeTests.t.sol rename to avalanche/contracts/ictt/tests/NativeTokenHomeTests.t.sol diff --git a/contracts/ictt/tests/NativeTokenRemoteTests.t.sol b/avalanche/contracts/ictt/tests/NativeTokenRemoteTests.t.sol similarity index 100% rename from contracts/ictt/tests/NativeTokenRemoteTests.t.sol rename to avalanche/contracts/ictt/tests/NativeTokenRemoteTests.t.sol diff --git a/contracts/ictt/tests/NativeTokenTransferrerTests.t.sol b/avalanche/contracts/ictt/tests/NativeTokenTransferrerTests.t.sol similarity index 100% rename from contracts/ictt/tests/NativeTokenTransferrerTests.t.sol rename to avalanche/contracts/ictt/tests/NativeTokenTransferrerTests.t.sol diff --git a/contracts/ictt/tests/StorageSlotTests.t.sol b/avalanche/contracts/ictt/tests/StorageSlotTests.t.sol similarity index 100% rename from contracts/ictt/tests/StorageSlotTests.t.sol rename to avalanche/contracts/ictt/tests/StorageSlotTests.t.sol diff --git a/contracts/ictt/tests/TokenHomeTests.t.sol b/avalanche/contracts/ictt/tests/TokenHomeTests.t.sol similarity index 100% rename from contracts/ictt/tests/TokenHomeTests.t.sol rename to avalanche/contracts/ictt/tests/TokenHomeTests.t.sol diff --git a/contracts/ictt/tests/TokenRemoteTests.t.sol b/avalanche/contracts/ictt/tests/TokenRemoteTests.t.sol similarity index 100% rename from contracts/ictt/tests/TokenRemoteTests.t.sol rename to avalanche/contracts/ictt/tests/TokenRemoteTests.t.sol diff --git a/contracts/ictt/tests/TokenTransferrerTests.t.sol b/avalanche/contracts/ictt/tests/TokenTransferrerTests.t.sol similarity index 100% rename from contracts/ictt/tests/TokenTransferrerTests.t.sol rename to avalanche/contracts/ictt/tests/TokenTransferrerTests.t.sol diff --git a/contracts/ictt/tests/WrappedNativeTokenTests.t.sol b/avalanche/contracts/ictt/tests/WrappedNativeTokenTests.t.sol similarity index 100% rename from contracts/ictt/tests/WrappedNativeTokenTests.t.sol rename to avalanche/contracts/ictt/tests/WrappedNativeTokenTests.t.sol diff --git a/contracts/mocks/ExampleERC20.sol b/avalanche/contracts/mocks/ExampleERC20.sol similarity index 100% rename from contracts/mocks/ExampleERC20.sol rename to avalanche/contracts/mocks/ExampleERC20.sol diff --git a/contracts/mocks/UnitTestMockERC20.sol b/avalanche/contracts/mocks/UnitTestMockERC20.sol similarity index 100% rename from contracts/mocks/UnitTestMockERC20.sol rename to avalanche/contracts/mocks/UnitTestMockERC20.sol diff --git a/contracts/teleporter/ITeleporterMessenger.sol b/avalanche/contracts/teleporter/ITeleporterMessenger.sol similarity index 92% rename from contracts/teleporter/ITeleporterMessenger.sol rename to avalanche/contracts/teleporter/ITeleporterMessenger.sol index 5a062718d..e01af2dbc 100644 --- a/contracts/teleporter/ITeleporterMessenger.sol +++ b/avalanche/contracts/teleporter/ITeleporterMessenger.sol @@ -3,7 +3,7 @@ // SPDX-License-Identifier: LicenseRef-Ecosystem -pragma solidity 0.8.25; +pragma solidity ^0.8.25; // A message receipt identifies the message that was delivered by its nonce, // and the address that can redeem the reward for that message. @@ -26,7 +26,7 @@ struct TeleporterMessageInput { bytes message; } -// Represents a message sent or received by an implementation of {ITeleporterMessenger}. +// Represents a cross-chain message sent or received by an implementation of {ITeleporterMessenger}. struct TeleporterMessage { uint256 messageNonce; address originSenderAddress; @@ -46,6 +46,27 @@ struct TeleporterFeeInfo { uint256 amount; } + +struct ICMSignature { + bytes signers; + bytes signature; +} + + +struct ICMUnsignedMessage { + uint32 avalancheNetworkID; + bytes32 avalancheSourceBlockchainID; + bytes payload; +} + +/// A signed ICM message which carries a Teleporter message +struct ICMMessage { + ICMUnsignedMessage unsignedMessage; + bytes unsignedMessageBytes; + ICMSignature signature; +} + + /** * @dev Interface that describes functionalities for a cross-chain messenger implementing the Teleporter protcol. * @@ -125,6 +146,7 @@ interface ITeleporterMessenger { TeleporterMessageInput calldata messageInput ) external returns (bytes32); + /** * @notice Called by transactions to retry the sending of a cross-chain message. * @@ -160,6 +182,12 @@ interface ITeleporterMessenger { */ function receiveCrossChainMessage(uint32 messageIndex, address relayerRewardAddress) external; + /** + * @notice Receives an inter-chain message, and marks the `relayerRewardAddress` for fee reward for a successful delivery. + * + */ + function receiveInterChainMessage(ICMMessage calldata icmMessage, address relayerRewardAddress) external; + /** * @notice Retries the execution of a previously delivered message by verifying the payload matches * the hash of the payload originally delivered, and calling the destination address again. @@ -187,7 +215,7 @@ interface ITeleporterMessenger { bytes32[] calldata messageIDs, TeleporterFeeInfo calldata feeInfo, address[] calldata allowedRelayerAddresses - ) external returns (bytes32); + ) external returns (bytes32); /** /** * @notice Sends any fee amount rewards for the given fee asset out to the caller. diff --git a/contracts/teleporter/ITeleporterReceiver.sol b/avalanche/contracts/teleporter/ITeleporterReceiver.sol similarity index 100% rename from contracts/teleporter/ITeleporterReceiver.sol rename to avalanche/contracts/teleporter/ITeleporterReceiver.sol diff --git a/avalanche/contracts/teleporter/IWarpExt.sol b/avalanche/contracts/teleporter/IWarpExt.sol new file mode 100644 index 000000000..3d4d48b92 --- /dev/null +++ b/avalanche/contracts/teleporter/IWarpExt.sol @@ -0,0 +1,27 @@ +// (c) 2025, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +// SPDX-License-Identifier: LicenseRef-Ecosystem + +pragma solidity ^0.8.25; + +import { + WarpMessage, + IWarpMessenger +} from "@avalabs/subnet-evm-contracts@1.2.2/contracts/interfaces/IWarpMessenger.sol"; +import {ICMMessage} from "./ITeleporterMessenger.sol"; + +/** + * @dev Interface that allows adapting the Warp interface. This is necessary for external interoperability + * since external chains do not receive Warp messages in their access lists. + */ +interface IWarpExt is IWarpMessenger { + /** + * @notice Depending on the chain this contract is deployed on, dispatch logic for + * getting the actual verified Warp message. + * @return message A verified Warp message. + */ + function getVerifiedICMMessage( + ICMMessage calldata icmMessag3 + ) external view returns (WarpMessage memory message); +} \ No newline at end of file diff --git a/avalanche/contracts/teleporter/NativeWarp.sol b/avalanche/contracts/teleporter/NativeWarp.sol new file mode 100644 index 000000000..58b44065a --- /dev/null +++ b/avalanche/contracts/teleporter/NativeWarp.sol @@ -0,0 +1,47 @@ +// (c) 2025, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +// SPDX-License-Identifier: LicenseRef-Ecosystem + +pragma solidity 0.8.25; + +import { + WarpMessage, + WarpBlockHash, + IWarpMessenger +} from "@avalabs/subnet-evm-contracts@1.2.2/contracts/interfaces/IWarpMessenger.sol"; +import {ICMMessage} from "./ITeleporterMessenger.sol"; +import {IWarpExt} from "./IWarpExt.sol"; + +contract WarpNative is IWarpExt { + /** + * @notice Warp precompile used for sending and receiving Warp messages. + */ + IWarpMessenger public constant WARP_MESSENGER = + IWarpMessenger(0x0200000000000000000000000000000000000005); + + function getVerifiedICMMessage( + ICMMessage calldata icmMessage + ) external view returns (WarpMessage memory message) { + revert("Todo"); + } + + function getVerifiedWarpMessage(uint32 index) external view returns (WarpMessage memory message, bool valid) { + return WARP_MESSENGER.getVerifiedWarpMessage(index); + } + + function sendWarpMessage(bytes calldata payload) external returns (bytes32 messageID) { + return WARP_MESSENGER.sendWarpMessage(payload); + } + + function getVerifiedWarpBlockHash( + uint32 index + ) external view returns (WarpBlockHash memory warpBlockHash, bool valid) { + return WARP_MESSENGER.getVerifiedWarpBlockHash(index); + } + + function getBlockchainID() external view returns (bytes32 blockchainID) { + return WARP_MESSENGER.getBlockchainID(); + } + +} \ No newline at end of file diff --git a/contracts/teleporter/README.md b/avalanche/contracts/teleporter/README.md similarity index 100% rename from contracts/teleporter/README.md rename to avalanche/contracts/teleporter/README.md diff --git a/contracts/teleporter/ReceiptQueue.sol b/avalanche/contracts/teleporter/ReceiptQueue.sol similarity index 100% rename from contracts/teleporter/ReceiptQueue.sol rename to avalanche/contracts/teleporter/ReceiptQueue.sol diff --git a/contracts/teleporter/TeleporterMessenger.sol b/avalanche/contracts/teleporter/TeleporterMessenger.sol similarity index 92% rename from contracts/teleporter/TeleporterMessenger.sol rename to avalanche/contracts/teleporter/TeleporterMessenger.sol index 1e84a6dbf..12c6441c4 100644 --- a/contracts/teleporter/TeleporterMessenger.sol +++ b/avalanche/contracts/teleporter/TeleporterMessenger.sol @@ -8,20 +8,22 @@ pragma solidity 0.8.25; import {IERC20} from "@openzeppelin/contracts@5.0.2/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts@5.0.2/token/ERC20/utils/SafeERC20.sol"; import { - WarpMessage, - IWarpMessenger + WarpMessage } from "@avalabs/subnet-evm-contracts@1.2.2/contracts/interfaces/IWarpMessenger.sol"; import { TeleporterMessageReceipt, TeleporterMessageInput, TeleporterMessage, TeleporterFeeInfo, - ITeleporterMessenger + ITeleporterMessenger, + ICMMessage } from "./ITeleporterMessenger.sol"; import {ReceiptQueue} from "./ReceiptQueue.sol"; import {SafeERC20TransferFrom} from "@utilities/SafeERC20TransferFrom.sol"; import {ITeleporterReceiver} from "./ITeleporterReceiver.sol"; import {ReentrancyGuards} from "@utilities/ReentrancyGuards.sol"; +import {IWarpExt} from "./IWarpExt.sol"; +import {IWarpMessenger} from "../../lib/subnet-evm/contracts/contracts/interfaces/IWarpMessenger.sol"; /** * @dev Implementation of the {ITeleporterMessenger} interface. @@ -45,11 +47,20 @@ contract TeleporterMessenger is ITeleporterMessenger, ReentrancyGuards { TeleporterFeeInfo feeInfo; } + /* + * @dev The address of the Warp contract this TeleportMessenger instance + * uses. This indirection is to allow initializing the `WARP_MESSENGER` value + * exactly once without using constructors. This is to allow using Nick's method + * for deploying this contract + */ + address private WARP_CONTRACT_ADDRESS; + /** - * @notice Warp precompile used for sending and receiving Warp messages. + * @notice The contract for verifying Warp messages */ - IWarpMessenger public constant WARP_MESSENGER = - IWarpMessenger(0x0200000000000000000000000000000000000005); + IWarpExt private WARP_MESSENGER; + + string public constant VERSION = "V2"; /** * @notice The blockchain ID of the chain the contract is deployed on. @@ -111,6 +122,19 @@ contract TeleporterMessenger is ITeleporterMessenger, ReentrancyGuards { => mapping(address feeTokenContract => uint256 redeemableRewardAmount) ) internal _relayerRewardAmounts; + /* + * @notice Register the address of the Warp contract to be used by + * this teleporter. This can be done only once. + * @dev This function is a delayed constructor to allow using Nick's method + * to deploy this contract + */ + function initialize(address warpContract) external { + if ( WARP_CONTRACT_ADDRESS == address (0) ) { + WARP_CONTRACT_ADDRESS = warpContract; + WARP_MESSENGER = IWarpExt(warpContract); + } + } + /** * @dev See {ITeleporterMessenger-sendCrossChainMessage} * @@ -230,15 +254,12 @@ contract TeleporterMessenger is ITeleporterMessenger, ReentrancyGuards { /** * @dev Emits a {ReceiveCrossChainMessage} event. + * Receives a Warp message via storage slots and processes it. * Re-entrancy is explicitly disallowed between receiving functions. One message is not able to receive another message. * Requirements: * - * - `relayerRewardAddress` must not be the zero address. - * - `messageIndex` must specify a valid warp message in the transaction's storage slots. - * - Valid warp message provided in storage slots, and sender address matches the address of this contract. - * - Teleporter message `destinationBlockchainID` must match the `blockchainID` of this contract. - * - Teleporter message was not previously received. - * - Transaction was sent by an allowed relayer for corresponding teleporter message. + * - Valid warp message provided in storage slots + * - sender address matches the address of this contract * * @inheritdoc ITeleporterMessenger */ @@ -251,15 +272,50 @@ contract TeleporterMessenger is ITeleporterMessenger, ReentrancyGuards { (WarpMessage memory warpMessage, bool success) = WARP_MESSENGER.getVerifiedWarpMessage(messageIndex); require(success, "TeleporterMessenger: invalid warp message"); - // Only allow for messages to be received from the same address as this teleporter contract. // The contract should be deployed using the universal deployer pattern, such that it knows messages // received from the same address on other chains were constructed using the same bytecode of this contract. // This allows for trusting the message format and uniqueness as specified by sendCrossChainMessage. + // TODO: This check may not be sufficient if this contract is receiving message from non-avalanche L1s require( warpMessage.originSenderAddress == address(this), "TeleporterMessenger: invalid origin sender address" ); + _processWarpMessage(warpMessage, relayerRewardAddress); + } + + /** + * @dev Emits a {ReceiveCrossChainMessage} event. + * Receives a Warp message as a byte payload and processes it. + * Re-entrancy is explicitly disallowed between receiving functions. One message is not able to receive another message. + * Requirements: + * + * - Valid warp message is decoded from the payload + * + * @inheritdoc ITeleporterMessenger + */ + function receiveInterChainMessage( + ICMMessage calldata icmMessage, + address relayerRewardAddress + ) external receiverNonReentrant { + WarpMessage memory warpMessage = + WARP_MESSENGER.getVerifiedICMMessage(icmMessage); + _processWarpMessage(warpMessage, relayerRewardAddress); + } + + /** + * @dev Emits a {ReceiveCrossChainMessage} event. + * + * - `relayerRewardAddress` must not be the zero address. + * - Teleporter message `destinationBlockchainID` must match the `blockchainID` of this contract. + * - Teleporter message was not previously received. + * - Transaction was sent by an allowed relayer for corresponding teleporter message. + * + */ + function _processWarpMessage( + WarpMessage memory warpMessage, + address relayerRewardAddress + ) internal { // Parse the payload of the message. TeleporterMessage memory teleporterMessage = @@ -579,6 +635,7 @@ contract TeleporterMessenger is ITeleporterMessenger, ReentrancyGuards { blockchainID = blockchainID_; emit BlockchainIDInitialized(blockchainID_); } + return blockchainID_; } @@ -590,9 +647,9 @@ contract TeleporterMessenger is ITeleporterMessenger, ReentrancyGuards { bytes32 sourceBlockchainID, bytes32 destinationBlockchainID, uint256 nonce - ) public view returns (bytes32) { + ) public pure returns (bytes32) { return - keccak256(abi.encode(address(this), sourceBlockchainID, destinationBlockchainID, nonce)); + keccak256(abi.encode(VERSION, sourceBlockchainID, destinationBlockchainID, nonce)); } /** @@ -628,16 +685,46 @@ contract TeleporterMessenger is ITeleporterMessenger, ReentrancyGuards { TeleporterMessageInput memory messageInput, TeleporterMessageReceipt[] memory receipts ) private returns (bytes32) { + + (bytes32 messageID, TeleporterMessage memory teleporterMessage, TeleporterFeeInfo memory adjustedFeeInfo) + = _prepareTeleporterMessage(messageInput, receipts); + + bytes memory teleporterMessageBytes = abi.encode(teleporterMessage); + sentMessageInfo[messageID] = SentMessageInfo({ + messageHash: keccak256(teleporterMessageBytes), + feeInfo: adjustedFeeInfo + }); + + emit SendCrossChainMessage( + messageID, messageInput.destinationBlockchainID, teleporterMessage, adjustedFeeInfo + ); + + // Submit the message to the AWM precompile. + WARP_MESSENGER.sendWarpMessage(teleporterMessageBytes); + + return messageID; + } + + + /** + * @dev Helper function that assempbles the actual telepoter message and associated + * metadata (message id, fee info) + */ + function _prepareTeleporterMessage( + TeleporterMessageInput memory messageInput, + TeleporterMessageReceipt[] memory receipts + ) private returns (bytes32 messageID, TeleporterMessage memory teleporterMessage, TeleporterFeeInfo memory ) { // If the blockchain ID has yet to be initialized, do so now. bytes32 blockchainID_ = initializeBlockchainID(); + // Get the message ID to use for this message by incrementing it. uint256 messageNonce_ = ++messageNonce; - bytes32 messageID = + messageID = calculateMessageID(blockchainID_, messageInput.destinationBlockchainID, messageNonce_); // Construct and serialize the message. - TeleporterMessage memory teleporterMessage = TeleporterMessage({ + teleporterMessage = TeleporterMessage({ messageNonce: messageNonce_, originSenderAddress: msg.sender, destinationBlockchainID: messageInput.destinationBlockchainID, @@ -647,7 +734,7 @@ contract TeleporterMessenger is ITeleporterMessenger, ReentrancyGuards { receipts: receipts, message: messageInput.message }); - bytes memory teleporterMessageBytes = abi.encode(teleporterMessage); + // If the fee amount is non-zero, transfer the asset into control of this TeleporterMessenger contract instance. // The fee is allowed to be 0 because it's possible for someone to run their own relayer and deliver their own messages, @@ -672,19 +759,8 @@ contract TeleporterMessenger is ITeleporterMessenger, ReentrancyGuards { feeTokenAddress: messageInput.feeInfo.feeTokenAddress, amount: adjustedFeeAmount }); - sentMessageInfo[messageID] = SentMessageInfo({ - messageHash: keccak256(teleporterMessageBytes), - feeInfo: adjustedFeeInfo - }); - - emit SendCrossChainMessage( - messageID, messageInput.destinationBlockchainID, teleporterMessage, adjustedFeeInfo - ); - // Submit the message to the AWM precompile. - WARP_MESSENGER.sendWarpMessage(teleporterMessageBytes); - - return messageID; + return (messageID, teleporterMessage, adjustedFeeInfo); } /** diff --git a/contracts/teleporter/registry/README.md b/avalanche/contracts/teleporter/registry/README.md similarity index 100% rename from contracts/teleporter/registry/README.md rename to avalanche/contracts/teleporter/registry/README.md diff --git a/contracts/teleporter/registry/TeleporterRegistry.sol b/avalanche/contracts/teleporter/registry/TeleporterRegistry.sol similarity index 99% rename from contracts/teleporter/registry/TeleporterRegistry.sol rename to avalanche/contracts/teleporter/registry/TeleporterRegistry.sol index df48bc5b3..61cc60170 100644 --- a/contracts/teleporter/registry/TeleporterRegistry.sol +++ b/avalanche/contracts/teleporter/registry/TeleporterRegistry.sol @@ -3,7 +3,7 @@ // SPDX-License-Identifier: LicenseRef-Ecosystem -pragma solidity 0.8.25; +pragma solidity ^0.8.25; import {ITeleporterMessenger} from "@teleporter/ITeleporterMessenger.sol"; import { diff --git a/contracts/teleporter/registry/TeleporterRegistryApp.sol b/avalanche/contracts/teleporter/registry/TeleporterRegistryApp.sol similarity index 100% rename from contracts/teleporter/registry/TeleporterRegistryApp.sol rename to avalanche/contracts/teleporter/registry/TeleporterRegistryApp.sol diff --git a/contracts/teleporter/registry/TeleporterRegistryAppUpgradeable.sol b/avalanche/contracts/teleporter/registry/TeleporterRegistryAppUpgradeable.sol similarity index 99% rename from contracts/teleporter/registry/TeleporterRegistryAppUpgradeable.sol rename to avalanche/contracts/teleporter/registry/TeleporterRegistryAppUpgradeable.sol index 580d6d05a..f5e0a04c6 100644 --- a/contracts/teleporter/registry/TeleporterRegistryAppUpgradeable.sol +++ b/avalanche/contracts/teleporter/registry/TeleporterRegistryAppUpgradeable.sol @@ -3,7 +3,7 @@ // SPDX-License-Identifier: LicenseRef-Ecosystem -pragma solidity 0.8.25; +pragma solidity ^0.8.25; import {TeleporterRegistry} from "./TeleporterRegistry.sol"; import {ITeleporterReceiver} from "@teleporter/ITeleporterReceiver.sol"; diff --git a/contracts/teleporter/registry/TeleporterRegistryOwnableApp.sol b/avalanche/contracts/teleporter/registry/TeleporterRegistryOwnableApp.sol similarity index 100% rename from contracts/teleporter/registry/TeleporterRegistryOwnableApp.sol rename to avalanche/contracts/teleporter/registry/TeleporterRegistryOwnableApp.sol diff --git a/contracts/teleporter/registry/TeleporterRegistryOwnableAppUpgradeable.sol b/avalanche/contracts/teleporter/registry/TeleporterRegistryOwnableAppUpgradeable.sol similarity index 100% rename from contracts/teleporter/registry/TeleporterRegistryOwnableAppUpgradeable.sol rename to avalanche/contracts/teleporter/registry/TeleporterRegistryOwnableAppUpgradeable.sol diff --git a/contracts/teleporter/registry/UPGRADING.md b/avalanche/contracts/teleporter/registry/UPGRADING.md similarity index 100% rename from contracts/teleporter/registry/UPGRADING.md rename to avalanche/contracts/teleporter/registry/UPGRADING.md diff --git a/contracts/teleporter/registry/tests/BaseTeleporterRegistryAppTests.t.sol b/avalanche/contracts/teleporter/registry/tests/BaseTeleporterRegistryAppTests.t.sol similarity index 98% rename from contracts/teleporter/registry/tests/BaseTeleporterRegistryAppTests.t.sol rename to avalanche/contracts/teleporter/registry/tests/BaseTeleporterRegistryAppTests.t.sol index 9c70d48e7..de53796e7 100644 --- a/contracts/teleporter/registry/tests/BaseTeleporterRegistryAppTests.t.sol +++ b/avalanche/contracts/teleporter/registry/tests/BaseTeleporterRegistryAppTests.t.sol @@ -102,6 +102,7 @@ abstract contract BaseTeleporterRegistryAppTest is TeleporterRegistryTest { TeleporterRegistryTest.setUp(); _addProtocolVersion(teleporterRegistry, teleporterAddress); _mockFeeAsset = new UnitTestMockERC20(); + TeleporterMessenger(teleporterAddress).initialize(address(0x0200000000000000000000000000000000000005)); TeleporterMessenger(teleporterAddress).initializeBlockchainID(); } @@ -123,6 +124,7 @@ abstract contract BaseTeleporterRegistryAppTest is TeleporterRegistryTest { // Now add new protocol version to registry and update the app's min version address newTeleporterAddress = address(new TeleporterMessenger()); + _addProtocolVersion(teleporterRegistry, newTeleporterAddress); _updateMinTeleporterVersionSuccess(app, teleporterRegistry.latestVersion()); diff --git a/contracts/teleporter/registry/tests/BaseTeleporterRegistryOwnableAppTest.t.sol b/avalanche/contracts/teleporter/registry/tests/BaseTeleporterRegistryOwnableAppTest.t.sol similarity index 100% rename from contracts/teleporter/registry/tests/BaseTeleporterRegistryOwnableAppTest.t.sol rename to avalanche/contracts/teleporter/registry/tests/BaseTeleporterRegistryOwnableAppTest.t.sol diff --git a/contracts/teleporter/registry/tests/GetTeleporterMessengerTests.t.sol b/avalanche/contracts/teleporter/registry/tests/GetTeleporterMessengerTests.t.sol similarity index 100% rename from contracts/teleporter/registry/tests/GetTeleporterMessengerTests.t.sol rename to avalanche/contracts/teleporter/registry/tests/GetTeleporterMessengerTests.t.sol diff --git a/contracts/teleporter/registry/tests/NonReentrantTests.t.sol b/avalanche/contracts/teleporter/registry/tests/NonReentrantTests.t.sol similarity index 98% rename from contracts/teleporter/registry/tests/NonReentrantTests.t.sol rename to avalanche/contracts/teleporter/registry/tests/NonReentrantTests.t.sol index 5bd2c354f..caee908b1 100644 --- a/contracts/teleporter/registry/tests/NonReentrantTests.t.sol +++ b/avalanche/contracts/teleporter/registry/tests/NonReentrantTests.t.sol @@ -108,6 +108,7 @@ abstract contract NonReentrantTest is BaseTeleporterRegistryAppTest { function testNonReentrantDifferentTeleporter() public { TeleporterMessenger teleporterV2 = new TeleporterMessenger(); + teleporterV2.initialize(address(0x0200000000000000000000000000000000000005)); teleporterV2.initializeBlockchainID(); _addProtocolVersion(teleporterRegistry, address(teleporterV2)); diff --git a/contracts/teleporter/registry/tests/PauseTeleporterAddressTests.t.sol b/avalanche/contracts/teleporter/registry/tests/PauseTeleporterAddressTests.t.sol similarity index 100% rename from contracts/teleporter/registry/tests/PauseTeleporterAddressTests.t.sol rename to avalanche/contracts/teleporter/registry/tests/PauseTeleporterAddressTests.t.sol diff --git a/contracts/teleporter/registry/tests/SendTeleporterMessageTests.t.sol b/avalanche/contracts/teleporter/registry/tests/SendTeleporterMessageTests.t.sol similarity index 100% rename from contracts/teleporter/registry/tests/SendTeleporterMessageTests.t.sol rename to avalanche/contracts/teleporter/registry/tests/SendTeleporterMessageTests.t.sol diff --git a/contracts/teleporter/registry/tests/TeleporterRegistryAppTests.t.sol b/avalanche/contracts/teleporter/registry/tests/TeleporterRegistryAppTests.t.sol similarity index 100% rename from contracts/teleporter/registry/tests/TeleporterRegistryAppTests.t.sol rename to avalanche/contracts/teleporter/registry/tests/TeleporterRegistryAppTests.t.sol diff --git a/contracts/teleporter/registry/tests/TeleporterRegistryOwnableAppTests.t.sol b/avalanche/contracts/teleporter/registry/tests/TeleporterRegistryOwnableAppTests.t.sol similarity index 100% rename from contracts/teleporter/registry/tests/TeleporterRegistryOwnableAppTests.t.sol rename to avalanche/contracts/teleporter/registry/tests/TeleporterRegistryOwnableAppTests.t.sol diff --git a/contracts/teleporter/registry/tests/TeleporterRegistryTests.t.sol b/avalanche/contracts/teleporter/registry/tests/TeleporterRegistryTests.t.sol similarity index 100% rename from contracts/teleporter/registry/tests/TeleporterRegistryTests.t.sol rename to avalanche/contracts/teleporter/registry/tests/TeleporterRegistryTests.t.sol diff --git a/contracts/teleporter/registry/tests/UnpauseTeleporterAddressTests.t.sol b/avalanche/contracts/teleporter/registry/tests/UnpauseTeleporterAddressTests.t.sol similarity index 99% rename from contracts/teleporter/registry/tests/UnpauseTeleporterAddressTests.t.sol rename to avalanche/contracts/teleporter/registry/tests/UnpauseTeleporterAddressTests.t.sol index 4e7a4d807..e4300b45b 100644 --- a/contracts/teleporter/registry/tests/UnpauseTeleporterAddressTests.t.sol +++ b/avalanche/contracts/teleporter/registry/tests/UnpauseTeleporterAddressTests.t.sol @@ -23,6 +23,7 @@ abstract contract UnpauseTeleporterAddressTest is BaseTeleporterRegistryAppTest app.receiveTeleporterMessage(DEFAULT_SOURCE_BLOCKCHAIN_ID, DEFAULT_ORIGIN_ADDRESS, ""); // Add a new Teleporter address to the registry and update minimum version + address newTeleporterAddress = address(new TeleporterMessenger()); _addProtocolVersion(teleporterRegistry, newTeleporterAddress); _updateMinTeleporterVersionSuccess(app, teleporterRegistry.latestVersion()); diff --git a/contracts/teleporter/registry/tests/UpdateMinTeleporterVersionTests.t.sol b/avalanche/contracts/teleporter/registry/tests/UpdateMinTeleporterVersionTests.t.sol similarity index 100% rename from contracts/teleporter/registry/tests/UpdateMinTeleporterVersionTests.t.sol rename to avalanche/contracts/teleporter/registry/tests/UpdateMinTeleporterVersionTests.t.sol diff --git a/contracts/teleporter/registry/upgrade-uml.png b/avalanche/contracts/teleporter/registry/upgrade-uml.png similarity index 100% rename from contracts/teleporter/registry/upgrade-uml.png rename to avalanche/contracts/teleporter/registry/upgrade-uml.png diff --git a/contracts/teleporter/tests/AddFeeAmountTests.t.sol b/avalanche/contracts/teleporter/tests/AddFeeAmountTests.t.sol similarity index 100% rename from contracts/teleporter/tests/AddFeeAmountTests.t.sol rename to avalanche/contracts/teleporter/tests/AddFeeAmountTests.t.sol diff --git a/contracts/teleporter/tests/CheckAllowedRelayerTests.t.sol b/avalanche/contracts/teleporter/tests/CheckAllowedRelayerTests.t.sol similarity index 96% rename from contracts/teleporter/tests/CheckAllowedRelayerTests.t.sol rename to avalanche/contracts/teleporter/tests/CheckAllowedRelayerTests.t.sol index d465e09c7..1678637f6 100644 --- a/contracts/teleporter/tests/CheckAllowedRelayerTests.t.sol +++ b/avalanche/contracts/teleporter/tests/CheckAllowedRelayerTests.t.sol @@ -8,7 +8,11 @@ pragma solidity 0.8.25; import {TeleporterMessenger} from "../TeleporterMessenger.sol"; import {Test} from "@forge-std/Test.sol"; -contract CheckIsAllowedRelayerTest is TeleporterMessenger, Test { +contract CheckIsAllowedRelayerTest is + TeleporterMessenger, + Test +{ + function testIsSpecifiedAllowedRelayer() public pure { address relayerAddress = 0x6288dAdf62B57dd9A4ddcd02F88A98d0eb6c2598; address[] memory allowedRelayers = new address[](3); diff --git a/contracts/teleporter/tests/FallbackReceiveTests.t.sol b/avalanche/contracts/teleporter/tests/FallbackReceiveTests.t.sol similarity index 100% rename from contracts/teleporter/tests/FallbackReceiveTests.t.sol rename to avalanche/contracts/teleporter/tests/FallbackReceiveTests.t.sol diff --git a/contracts/teleporter/tests/GetFeeInfoTests.t.sol b/avalanche/contracts/teleporter/tests/GetFeeInfoTests.t.sol similarity index 100% rename from contracts/teleporter/tests/GetFeeInfoTests.t.sol rename to avalanche/contracts/teleporter/tests/GetFeeInfoTests.t.sol diff --git a/contracts/teleporter/tests/GetMessageHashTests.t.sol b/avalanche/contracts/teleporter/tests/GetMessageHashTests.t.sol similarity index 100% rename from contracts/teleporter/tests/GetMessageHashTests.t.sol rename to avalanche/contracts/teleporter/tests/GetMessageHashTests.t.sol diff --git a/contracts/teleporter/tests/GetNextMessageIdTests.t.sol b/avalanche/contracts/teleporter/tests/GetNextMessageIdTests.t.sol similarity index 100% rename from contracts/teleporter/tests/GetNextMessageIdTests.t.sol rename to avalanche/contracts/teleporter/tests/GetNextMessageIdTests.t.sol diff --git a/contracts/teleporter/tests/GetOutstandingReceiptsToSendTests.t.sol b/avalanche/contracts/teleporter/tests/GetOutstandingReceiptsToSendTests.t.sol similarity index 100% rename from contracts/teleporter/tests/GetOutstandingReceiptsToSendTests.t.sol rename to avalanche/contracts/teleporter/tests/GetOutstandingReceiptsToSendTests.t.sol diff --git a/contracts/teleporter/tests/GetRelayerRewardAddressTests.t.sol b/avalanche/contracts/teleporter/tests/GetRelayerRewardAddressTests.t.sol similarity index 100% rename from contracts/teleporter/tests/GetRelayerRewardAddressTests.t.sol rename to avalanche/contracts/teleporter/tests/GetRelayerRewardAddressTests.t.sol diff --git a/contracts/teleporter/tests/HandleInitialMessageExecutionTests.t.sol b/avalanche/contracts/teleporter/tests/HandleInitialMessageExecutionTests.t.sol similarity index 100% rename from contracts/teleporter/tests/HandleInitialMessageExecutionTests.t.sol rename to avalanche/contracts/teleporter/tests/HandleInitialMessageExecutionTests.t.sol diff --git a/contracts/teleporter/tests/InitializeBlockchainIDTests.t.sol b/avalanche/contracts/teleporter/tests/InitializeBlockchainIDTests.t.sol similarity index 98% rename from contracts/teleporter/tests/InitializeBlockchainIDTests.t.sol rename to avalanche/contracts/teleporter/tests/InitializeBlockchainIDTests.t.sol index 40db2974d..965c20963 100644 --- a/contracts/teleporter/tests/InitializeBlockchainIDTests.t.sol +++ b/avalanche/contracts/teleporter/tests/InitializeBlockchainIDTests.t.sol @@ -37,6 +37,7 @@ contract InitializeBlockchainIDTest is Test { ); teleporterMessenger = new TeleporterMessenger(); + teleporterMessenger.initialize(address(0x0200000000000000000000000000000000000005)); } function testUninitialized() public { diff --git a/contracts/teleporter/tests/MarkReceiptTests.t.sol b/avalanche/contracts/teleporter/tests/MarkReceiptTests.t.sol similarity index 100% rename from contracts/teleporter/tests/MarkReceiptTests.t.sol rename to avalanche/contracts/teleporter/tests/MarkReceiptTests.t.sol diff --git a/contracts/teleporter/tests/MessageReceivedTests.t.sol b/avalanche/contracts/teleporter/tests/MessageReceivedTests.t.sol similarity index 100% rename from contracts/teleporter/tests/MessageReceivedTests.t.sol rename to avalanche/contracts/teleporter/tests/MessageReceivedTests.t.sol diff --git a/contracts/teleporter/tests/ReceiptsQueueTests.t.sol b/avalanche/contracts/teleporter/tests/ReceiptsQueueTests.t.sol similarity index 100% rename from contracts/teleporter/tests/ReceiptsQueueTests.t.sol rename to avalanche/contracts/teleporter/tests/ReceiptsQueueTests.t.sol diff --git a/contracts/teleporter/tests/ReceiveCrossChainMessageTests.t.sol b/avalanche/contracts/teleporter/tests/ReceiveCrossChainMessageTests.t.sol similarity index 100% rename from contracts/teleporter/tests/ReceiveCrossChainMessageTests.t.sol rename to avalanche/contracts/teleporter/tests/ReceiveCrossChainMessageTests.t.sol diff --git a/contracts/teleporter/tests/RedeemRelayerRewardsTests.t.sol b/avalanche/contracts/teleporter/tests/RedeemRelayerRewardsTests.t.sol similarity index 100% rename from contracts/teleporter/tests/RedeemRelayerRewardsTests.t.sol rename to avalanche/contracts/teleporter/tests/RedeemRelayerRewardsTests.t.sol diff --git a/contracts/teleporter/tests/RetryMessageExecutionTests.t.sol b/avalanche/contracts/teleporter/tests/RetryMessageExecutionTests.t.sol similarity index 100% rename from contracts/teleporter/tests/RetryMessageExecutionTests.t.sol rename to avalanche/contracts/teleporter/tests/RetryMessageExecutionTests.t.sol diff --git a/contracts/teleporter/tests/RetrySendCrossChainMessageTests.t.sol b/avalanche/contracts/teleporter/tests/RetrySendCrossChainMessageTests.t.sol similarity index 100% rename from contracts/teleporter/tests/RetrySendCrossChainMessageTests.t.sol rename to avalanche/contracts/teleporter/tests/RetrySendCrossChainMessageTests.t.sol diff --git a/contracts/teleporter/tests/SendCrossChainMessageTests.t.sol b/avalanche/contracts/teleporter/tests/SendCrossChainMessageTests.t.sol similarity index 100% rename from contracts/teleporter/tests/SendCrossChainMessageTests.t.sol rename to avalanche/contracts/teleporter/tests/SendCrossChainMessageTests.t.sol diff --git a/contracts/teleporter/tests/SendSpecifiedReceiptsTests.t.sol b/avalanche/contracts/teleporter/tests/SendSpecifiedReceiptsTests.t.sol similarity index 100% rename from contracts/teleporter/tests/SendSpecifiedReceiptsTests.t.sol rename to avalanche/contracts/teleporter/tests/SendSpecifiedReceiptsTests.t.sol diff --git a/contracts/teleporter/tests/TeleporterMessengerTest.t.sol b/avalanche/contracts/teleporter/tests/TeleporterMessengerTest.t.sol similarity index 99% rename from contracts/teleporter/tests/TeleporterMessengerTest.t.sol rename to avalanche/contracts/teleporter/tests/TeleporterMessengerTest.t.sol index baa401121..2c4425bcb 100644 --- a/contracts/teleporter/tests/TeleporterMessengerTest.t.sol +++ b/avalanche/contracts/teleporter/tests/TeleporterMessengerTest.t.sol @@ -78,6 +78,7 @@ contract TeleporterMessengerTest is Test { ); teleporterMessenger = new TeleporterMessenger(); + teleporterMessenger.initialize(address(0x0200000000000000000000000000000000000005)); // Blockchain ID should be 0 before it is initialized. assertEq(teleporterMessenger.blockchainID(), bytes32(0)); diff --git a/contracts/teleporter/tests/TestMessenger.sol b/avalanche/contracts/teleporter/tests/TestMessenger.sol similarity index 98% rename from contracts/teleporter/tests/TestMessenger.sol rename to avalanche/contracts/teleporter/tests/TestMessenger.sol index 147f8eeb8..c9198cdae 100644 --- a/contracts/teleporter/tests/TestMessenger.sol +++ b/avalanche/contracts/teleporter/tests/TestMessenger.sol @@ -34,7 +34,7 @@ contract TestMessenger is ReentrancyGuardUpgradeable, TeleporterRegistryOwnableA mapping(bytes32 sourceBlockchainID => Message message) private _messages; /** - * @dev Emitted when a message is submited to be sent. + * @dev Emitted when a message is submitted to be sent. */ event SendMessage( bytes32 indexed destinationBlockchainID, diff --git a/contracts/utilities/CallUtils.sol b/avalanche/contracts/utilities/CallUtils.sol similarity index 100% rename from contracts/utilities/CallUtils.sol rename to avalanche/contracts/utilities/CallUtils.sol diff --git a/contracts/utilities/ICMInitializable.sol b/avalanche/contracts/utilities/ICMInitializable.sol similarity index 100% rename from contracts/utilities/ICMInitializable.sol rename to avalanche/contracts/utilities/ICMInitializable.sol diff --git a/contracts/utilities/ReentrancyGuards.sol b/avalanche/contracts/utilities/ReentrancyGuards.sol similarity index 100% rename from contracts/utilities/ReentrancyGuards.sol rename to avalanche/contracts/utilities/ReentrancyGuards.sol diff --git a/contracts/utilities/SafeERC20TransferFrom.sol b/avalanche/contracts/utilities/SafeERC20TransferFrom.sol similarity index 100% rename from contracts/utilities/SafeERC20TransferFrom.sol rename to avalanche/contracts/utilities/SafeERC20TransferFrom.sol diff --git a/contracts/utilities/SafeWrappedNativeTokenDeposit.sol b/avalanche/contracts/utilities/SafeWrappedNativeTokenDeposit.sol similarity index 100% rename from contracts/utilities/SafeWrappedNativeTokenDeposit.sol rename to avalanche/contracts/utilities/SafeWrappedNativeTokenDeposit.sol diff --git a/contracts/utilities/SendReentrancyGuardUpgradeable.sol b/avalanche/contracts/utilities/SendReentrancyGuardUpgradeable.sol similarity index 100% rename from contracts/utilities/SendReentrancyGuardUpgradeable.sol rename to avalanche/contracts/utilities/SendReentrancyGuardUpgradeable.sol diff --git a/contracts/utilities/TokenScalingUtils.sol b/avalanche/contracts/utilities/TokenScalingUtils.sol similarity index 100% rename from contracts/utilities/TokenScalingUtils.sol rename to avalanche/contracts/utilities/TokenScalingUtils.sol diff --git a/contracts/utilities/tests/ReentrancyGuardsTests.t.sol b/avalanche/contracts/utilities/tests/ReentrancyGuardsTests.t.sol similarity index 100% rename from contracts/utilities/tests/ReentrancyGuardsTests.t.sol rename to avalanche/contracts/utilities/tests/ReentrancyGuardsTests.t.sol diff --git a/contracts/validator-manager/ACP99Manager.sol b/avalanche/contracts/validator-manager/ACP99Manager.sol similarity index 100% rename from contracts/validator-manager/ACP99Manager.sol rename to avalanche/contracts/validator-manager/ACP99Manager.sol diff --git a/contracts/validator-manager/ERC20TokenStakingManager.sol b/avalanche/contracts/validator-manager/ERC20TokenStakingManager.sol similarity index 100% rename from contracts/validator-manager/ERC20TokenStakingManager.sol rename to avalanche/contracts/validator-manager/ERC20TokenStakingManager.sol diff --git a/contracts/validator-manager/ExampleRewardCalculator.sol b/avalanche/contracts/validator-manager/ExampleRewardCalculator.sol similarity index 100% rename from contracts/validator-manager/ExampleRewardCalculator.sol rename to avalanche/contracts/validator-manager/ExampleRewardCalculator.sol diff --git a/contracts/validator-manager/MigratingFromV1.md b/avalanche/contracts/validator-manager/MigratingFromV1.md similarity index 100% rename from contracts/validator-manager/MigratingFromV1.md rename to avalanche/contracts/validator-manager/MigratingFromV1.md diff --git a/contracts/validator-manager/NativeTokenStakingManager.sol b/avalanche/contracts/validator-manager/NativeTokenStakingManager.sol similarity index 100% rename from contracts/validator-manager/NativeTokenStakingManager.sol rename to avalanche/contracts/validator-manager/NativeTokenStakingManager.sol diff --git a/contracts/validator-manager/PoAManager.sol b/avalanche/contracts/validator-manager/PoAManager.sol similarity index 100% rename from contracts/validator-manager/PoAManager.sol rename to avalanche/contracts/validator-manager/PoAManager.sol diff --git a/contracts/validator-manager/PoAMigration.md b/avalanche/contracts/validator-manager/PoAMigration.md similarity index 100% rename from contracts/validator-manager/PoAMigration.md rename to avalanche/contracts/validator-manager/PoAMigration.md diff --git a/contracts/validator-manager/README.md b/avalanche/contracts/validator-manager/README.md similarity index 100% rename from contracts/validator-manager/README.md rename to avalanche/contracts/validator-manager/README.md diff --git a/contracts/validator-manager/StakingManager.sol b/avalanche/contracts/validator-manager/StakingManager.sol similarity index 100% rename from contracts/validator-manager/StakingManager.sol rename to avalanche/contracts/validator-manager/StakingManager.sol diff --git a/contracts/validator-manager/StateTransition.md b/avalanche/contracts/validator-manager/StateTransition.md similarity index 100% rename from contracts/validator-manager/StateTransition.md rename to avalanche/contracts/validator-manager/StateTransition.md diff --git a/contracts/validator-manager/UptimeMessageSpec.md b/avalanche/contracts/validator-manager/UptimeMessageSpec.md similarity index 100% rename from contracts/validator-manager/UptimeMessageSpec.md rename to avalanche/contracts/validator-manager/UptimeMessageSpec.md diff --git a/contracts/validator-manager/ValidatorManager.sol b/avalanche/contracts/validator-manager/ValidatorManager.sol similarity index 100% rename from contracts/validator-manager/ValidatorManager.sol rename to avalanche/contracts/validator-manager/ValidatorManager.sol diff --git a/contracts/validator-manager/ValidatorMessages.sol b/avalanche/contracts/validator-manager/ValidatorMessages.sol similarity index 100% rename from contracts/validator-manager/ValidatorMessages.sol rename to avalanche/contracts/validator-manager/ValidatorMessages.sol diff --git a/contracts/validator-manager/interfaces/IACP99Manager.sol b/avalanche/contracts/validator-manager/interfaces/IACP99Manager.sol similarity index 100% rename from contracts/validator-manager/interfaces/IACP99Manager.sol rename to avalanche/contracts/validator-manager/interfaces/IACP99Manager.sol diff --git a/contracts/validator-manager/interfaces/IERC20Mintable.sol b/avalanche/contracts/validator-manager/interfaces/IERC20Mintable.sol similarity index 100% rename from contracts/validator-manager/interfaces/IERC20Mintable.sol rename to avalanche/contracts/validator-manager/interfaces/IERC20Mintable.sol diff --git a/contracts/validator-manager/interfaces/IERC20TokenStakingManager.sol b/avalanche/contracts/validator-manager/interfaces/IERC20TokenStakingManager.sol similarity index 100% rename from contracts/validator-manager/interfaces/IERC20TokenStakingManager.sol rename to avalanche/contracts/validator-manager/interfaces/IERC20TokenStakingManager.sol diff --git a/contracts/validator-manager/interfaces/INativeTokenStakingManager.sol b/avalanche/contracts/validator-manager/interfaces/INativeTokenStakingManager.sol similarity index 100% rename from contracts/validator-manager/interfaces/INativeTokenStakingManager.sol rename to avalanche/contracts/validator-manager/interfaces/INativeTokenStakingManager.sol diff --git a/contracts/validator-manager/interfaces/IPoAManager.sol b/avalanche/contracts/validator-manager/interfaces/IPoAManager.sol similarity index 100% rename from contracts/validator-manager/interfaces/IPoAManager.sol rename to avalanche/contracts/validator-manager/interfaces/IPoAManager.sol diff --git a/contracts/validator-manager/interfaces/IRewardCalculator.sol b/avalanche/contracts/validator-manager/interfaces/IRewardCalculator.sol similarity index 100% rename from contracts/validator-manager/interfaces/IRewardCalculator.sol rename to avalanche/contracts/validator-manager/interfaces/IRewardCalculator.sol diff --git a/contracts/validator-manager/interfaces/IStakingManager.sol b/avalanche/contracts/validator-manager/interfaces/IStakingManager.sol similarity index 100% rename from contracts/validator-manager/interfaces/IStakingManager.sol rename to avalanche/contracts/validator-manager/interfaces/IStakingManager.sol diff --git a/contracts/validator-manager/interfaces/IValidatorManager.sol b/avalanche/contracts/validator-manager/interfaces/IValidatorManager.sol similarity index 100% rename from contracts/validator-manager/interfaces/IValidatorManager.sol rename to avalanche/contracts/validator-manager/interfaces/IValidatorManager.sol diff --git a/contracts/validator-manager/interfaces/IValidatorManagerExternalOwnable.sol b/avalanche/contracts/validator-manager/interfaces/IValidatorManagerExternalOwnable.sol similarity index 100% rename from contracts/validator-manager/interfaces/IValidatorManagerExternalOwnable.sol rename to avalanche/contracts/validator-manager/interfaces/IValidatorManagerExternalOwnable.sol diff --git a/contracts/validator-manager/tests/ERC20TokenStakingManagerTests.t.sol b/avalanche/contracts/validator-manager/tests/ERC20TokenStakingManagerTests.t.sol similarity index 100% rename from contracts/validator-manager/tests/ERC20TokenStakingManagerTests.t.sol rename to avalanche/contracts/validator-manager/tests/ERC20TokenStakingManagerTests.t.sol diff --git a/contracts/validator-manager/tests/ExamplesRewardCalculatorTests.t.sol b/avalanche/contracts/validator-manager/tests/ExamplesRewardCalculatorTests.t.sol similarity index 100% rename from contracts/validator-manager/tests/ExamplesRewardCalculatorTests.t.sol rename to avalanche/contracts/validator-manager/tests/ExamplesRewardCalculatorTests.t.sol diff --git a/contracts/validator-manager/tests/NativeTokenStakingManagerTests.t.sol b/avalanche/contracts/validator-manager/tests/NativeTokenStakingManagerTests.t.sol similarity index 100% rename from contracts/validator-manager/tests/NativeTokenStakingManagerTests.t.sol rename to avalanche/contracts/validator-manager/tests/NativeTokenStakingManagerTests.t.sol diff --git a/contracts/validator-manager/tests/PoAManagerTests.t.sol b/avalanche/contracts/validator-manager/tests/PoAManagerTests.t.sol similarity index 100% rename from contracts/validator-manager/tests/PoAManagerTests.t.sol rename to avalanche/contracts/validator-manager/tests/PoAManagerTests.t.sol diff --git a/contracts/validator-manager/tests/PoAValidatorManagerTests.t.sol b/avalanche/contracts/validator-manager/tests/PoAValidatorManagerTests.t.sol similarity index 100% rename from contracts/validator-manager/tests/PoAValidatorManagerTests.t.sol rename to avalanche/contracts/validator-manager/tests/PoAValidatorManagerTests.t.sol diff --git a/contracts/validator-manager/tests/StakingManagerTests.t.sol b/avalanche/contracts/validator-manager/tests/StakingManagerTests.t.sol similarity index 100% rename from contracts/validator-manager/tests/StakingManagerTests.t.sol rename to avalanche/contracts/validator-manager/tests/StakingManagerTests.t.sol diff --git a/contracts/validator-manager/tests/ValidatorManagerTests.t.sol b/avalanche/contracts/validator-manager/tests/ValidatorManagerTests.t.sol similarity index 100% rename from contracts/validator-manager/tests/ValidatorManagerTests.t.sol rename to avalanche/contracts/validator-manager/tests/ValidatorManagerTests.t.sol diff --git a/contracts/validator-manager/tests/ValidatorMessagesTests.t.sol b/avalanche/contracts/validator-manager/tests/ValidatorMessagesTests.t.sol similarity index 100% rename from contracts/validator-manager/tests/ValidatorMessagesTests.t.sol rename to avalanche/contracts/validator-manager/tests/ValidatorMessagesTests.t.sol diff --git a/foundry.toml b/avalanche/foundry.toml similarity index 100% rename from foundry.toml rename to avalanche/foundry.toml diff --git a/lib/forge-std b/avalanche/lib/forge-std similarity index 100% rename from lib/forge-std rename to avalanche/lib/forge-std diff --git a/lib/openzeppelin-contracts-upgradeable b/avalanche/lib/openzeppelin-contracts-upgradeable similarity index 100% rename from lib/openzeppelin-contracts-upgradeable rename to avalanche/lib/openzeppelin-contracts-upgradeable diff --git a/lib/subnet-evm b/avalanche/lib/subnet-evm similarity index 100% rename from lib/subnet-evm rename to avalanche/lib/subnet-evm diff --git a/remappings.txt b/avalanche/remappings.txt similarity index 100% rename from remappings.txt rename to avalanche/remappings.txt diff --git a/ethereum/README.md b/ethereum/README.md new file mode 100644 index 000000000..08c9ad2fe --- /dev/null +++ b/ethereum/README.md @@ -0,0 +1,52 @@ +# Ethereum ICM Verification + +Smart contracts for verifying Avalanche ICM messages on Ethereum using the BLS precompiles from [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537). + +> NOTE: These contracts are proof-of-concepts and have not been audited. **Do not use them in production.** + +## How it works + +- Avalanche validator sets get registered in the `AvalancheValidatorSetRegistry` contract +- Validator set updates are authenticated by signatures from the current set +- Other contracts call `verifyICMMessage()` to validate ICM messages from Avalanche L1s + +## Contracts / Libraries +- `AvalancheValidatorSetRegistry` - manages validator sets and verifies ICM messages +- `BLSTUtils` - BLS12-381 crypto operations using Ethereum precompiles +- `ICMUtils` - ICM message parsing and signature verification +- `ValidatorSetUtils` - validator set data structures and serialization + +## Usage Example + +```solidity +// Deploy registry for Avalanche Fuji testnet (network ID 5) +AvalancheValidatorSetRegistry registry = new AvalancheValidatorSetRegistry(5); + +// Register initial validator set (must be self-signed by that set) +uint256 validatorSetID = registry.registerValidatorSet(icmMessage, validatorBytes); + +// Verify messages from that L1 +bool isValid = registry.verifyICMMessage(validatorSetID, someICMMessage); + +// Update the validator set when changes are made to it. +registry.updateValidatorSet(validatorSetID, validatorSetStateICMMessage, updatedValidatorBytes); + +``` + +## Integration + +```solidity +contract MyDApp { + AvalancheValidatorSetRegistry immutable registry; + uint256 immutable validatorSetID; + + function processAvalancheMessage(ICMMessage memory message) external { + require(registry.verifyICMMessage(validatorSetID, message), "Invalid ICM message"); + + // Process the verified message... + bytes memory data = message.unsignedMessage.payload; + } +} +``` + +Since multiple validator sets can be registered per blockchain ID, make sure you're using the correct `validatorSetID` for your intended L1. diff --git a/ethereum/contracts/AvalancheValidatorSetRegistry.sol b/ethereum/contracts/AvalancheValidatorSetRegistry.sol new file mode 100644 index 000000000..d9629706b --- /dev/null +++ b/ethereum/contracts/AvalancheValidatorSetRegistry.sol @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {IAvalancheValidatorSetRegistry} from "./interfaces/IAvalancheValidatorSetRegistry.sol"; +import { + Validator, + ValidatorSet, + ValidatorSetStatePayload, + ValidatorSets +} from "./utils/ValidatorSets.sol"; +import {ICMMessage} from "@avalabs/avalanche-contracts/teleporter/ITeleporterMessenger.sol"; +import {ICM, AddressedCall} from "./utils/ICM.sol"; +import {IVerifyICMMessage} from "./interfaces/IVerifyWarpMessage.sol"; + +/** + * @title AvalancheValidatorSetRegistry + * @notice Registry for managing Avalanche validator sets + * @dev This contract allows registration and updates of validator sets for Avalanche blockchains. + * Updates are authenticated through signed ICM messages from the current validator set. + */ +contract AvalancheValidatorSetRegistry is + IAvalancheValidatorSetRegistry, + IVerifyICMMessage +{ + uint32 public immutable avalancheNetworkID; + /** + * @notice The blockchain this registry maintains validator sets for + * @dev This should be a blockchain for which the registered validators + * represents the entire validator set. E.g., if this contract instance is + * verifying Avalanche L1 instances, this ID should be the L1 ID, not the + * P-chain ID. + */ + bytes32 public immutable avalancheBlockChainID; + uint32 public nextValidatorSetID = 0; + + // Mapping of validator set IDs to their complete validator set data. + mapping(uint256 => ValidatorSet) private _validatorSets; + + constructor( + uint32 _avalancheNetworkID, + bytes32 _avalancheBlockChainID + ) { + avalancheNetworkID = _avalancheNetworkID; + avalancheBlockChainID = _avalancheBlockChainID; + } + + /** + * @notice Get the current (latest) validator set + */ + function getCurrentValidatorSet() public view returns (ValidatorSet memory) { + require(0 < nextValidatorSetID, "No validator sets exist"); + return _validatorSets[nextValidatorSetID - 1]; + } + + /** + * @notice Get the ID of the current (latest) validator set + */ + function getCurrentValidatorSetID() public view returns (uint256) { + require(0 < nextValidatorSetID, "No validator sets exist"); + return nextValidatorSetID - 1; + } + + /** + * @notice Registers a new validator set + * @dev A validator set can be registered by anyone. The correctness should be verified + * with the actual validator set on the Avalanche P-Chain. + * @param message The ICM message containing the validator set to register. The message must be signed by validator set + * @param validatorBytes The serialized validator set to register. + * @return The ID of the registered validator set + */ + function registerValidatorSet( + ICMMessage calldata message, + bytes memory validatorBytes + ) external override returns (uint256) { + // Parse and validate the validator set data + ( + ValidatorSetStatePayload memory validatorSetStatePayload, + Validator[] memory validators, + uint64 totalWeight + ) = _parseAndValidateValidatorSetData(message, validatorBytes); + + // Construct the validator set and confirm the ICM was self-signed by it. + ValidatorSet memory validatorSet = ValidatorSet({ + avalancheBlockchainID: validatorSetStatePayload.avalancheBlockchainID, + validators: validators, + totalWeight: totalWeight, + pChainHeight: validatorSetStatePayload.pChainHeight, + pChainTimestamp: validatorSetStatePayload.pChainTimestamp + }); + require( + ICM.verifyICMMessage(message, avalancheNetworkID, avalancheBlockChainID,validatorSet), "Invalid ICM message" + ); + + // Store the validator set. + uint256 validatorSetID = nextValidatorSetID++; + _validatorSets[validatorSetID] = validatorSet; + + emit ValidatorSetRegistered(validatorSetID, validatorSet.avalancheBlockchainID); + return validatorSetID; + } + + /** + * @notice Updates a validator set + * @dev Updates are authenticated by a signed ICM message from the current validator set + * @param validatorSetID The ID of the validator set to update + * @param message The ICM message containing the update + */ + function updateValidatorSet( + uint256 validatorSetID, + ICMMessage calldata message, + bytes memory validatorBytes + ) external override { + require(validatorSetID < nextValidatorSetID, "Validator set does not exist"); + + ValidatorSet storage currentValidatorSet = _validatorSets[validatorSetID]; + + // Verify the ICM message using the current validator set + bool isValid = ICM.verifyICMMessage(message, avalancheNetworkID, avalancheBlockChainID,currentValidatorSet); + require(isValid, "Invalid ICM message"); + + // Parse and validate the validator set data + ( + ValidatorSetStatePayload memory validatorSetStatePayload, + Validator[] memory validators, + uint64 totalWeight + ) = _parseAndValidateValidatorSetData(message, validatorBytes); + + // Check that blockchain ID matches the current validator set. + require( + validatorSetStatePayload.avalancheBlockchainID + == currentValidatorSet.avalancheBlockchainID, + "Blockchain ID mismatch" + ); + + // Check that the pChain height is greater than the current validator set. + require( + validatorSetStatePayload.pChainHeight > currentValidatorSet.pChainHeight, + "P-Chain height must be greater than the current validator set" + ); + + // Check that the pChain timestamp is greater than the current validator set. + require( + validatorSetStatePayload.pChainTimestamp > currentValidatorSet.pChainTimestamp, + "P-Chain timestamp must be greater than the current validator set" + ); + + // Update the validator set + _validatorSets[validatorSetID] = ValidatorSet({ + avalancheBlockchainID: validatorSetStatePayload.avalancheBlockchainID, + validators: validators, + totalWeight: totalWeight, + pChainHeight: validatorSetStatePayload.pChainHeight, + pChainTimestamp: validatorSetStatePayload.pChainTimestamp + }); + + emit ValidatorSetUpdated(validatorSetID, validatorSetStatePayload.avalancheBlockchainID); + } + + /** + * @notice Gets a validator set by its ID + * @param validatorSetID The ID of the validator set to get + * @return The validator set + */ + function getValidatorSet( + uint256 validatorSetID + ) external view override returns (ValidatorSet memory) { + return _getValidatorSet(validatorSetID); + } + + /** + * @notice Gets the Avalanche network ID + * @return The Avalanche network ID + */ + function getAvalancheNetworkID() external view returns (uint32) { + return avalancheNetworkID; + } + + /** + * @notice Verifies an ICM message against a validator set + * @dev This function validates that the message is properly signed by a sufficient quorum of validators + * from the validator set identified by validatorSetID. The verification includes checking the network ID, + * blockchain ID, and cryptographic signature verification. + * @param validatorSetID The ID of the validator set to verify the message against + * @param message The ICM message to verify + * @return True if the message is valid, false otherwise + */ + function verifyICMMessageWithID( + uint256 validatorSetID, + ICMMessage calldata message + ) external view returns (bool) { + ValidatorSet memory validatorSet = _getValidatorSet(validatorSetID); + return ICM.verifyICMMessage(message, avalancheNetworkID, avalancheBlockChainID, validatorSet); + } + + /** + * @notice Verify the signatures of an ICM message against the latest validator set. + * @param message The ICM message to be verified + * @return True if the message is valid, false otherwise. + */ + function verifyICMMessage( + ICMMessage calldata message + ) external view returns (bool) { + ValidatorSet memory validatorSet = getCurrentValidatorSet(); + bool valid = ICM.verifyICMMessage(message, avalancheNetworkID, avalancheBlockChainID, validatorSet); + return valid; + } + + function _getValidatorSet( + uint256 validatorSetID + ) private view returns (ValidatorSet memory) { + require(validatorSetID < nextValidatorSetID, "Validator set does not exist"); + return _validatorSets[validatorSetID]; + } + + /** + * @notice Parses and validates validator set data from an ICM message + * @dev This is a helper function that consolidates common validation logic + * @param message The ICM message containing the validator set data + * @param validatorBytes The serialized validator set + * @return validatorSetStatePayload The parsed validator set state payload + * @return validators The parsed validators array + * @return totalWeight The total weight of all validators + */ + function _parseAndValidateValidatorSetData( + ICMMessage calldata message, + bytes memory validatorBytes + ) + private + pure + returns ( + ValidatorSetStatePayload memory validatorSetStatePayload, + Validator[] memory validators, + uint64 totalWeight + ) + { + // Parse the addressed call and validate that the source address is empty. + AddressedCall memory addressedCall = ICM.parseAddressedCall(message.unsignedMessage.payload); + require(addressedCall.sourceAddress.length == 0, "Source address must be empty"); + + // Parse the validator set state payload. + validatorSetStatePayload = + ValidatorSets.parseValidatorSetStatePayload(addressedCall.payload); + + // Check that the validator set hash matches the hash of the serialized validator set. + require( + validatorSetStatePayload.validatorSetHash == sha256(validatorBytes), + "Validator set hash mismatch" + ); + + // Parse the validators. + (validators, totalWeight) = ValidatorSets.parseValidators(validatorBytes); + require(validators.length > 0, "Validator set cannot be empty"); + require(totalWeight > 0, "Total weight must be greater than 0"); + } +} diff --git a/ethereum/contracts/EthWarp.sol b/ethereum/contracts/EthWarp.sol new file mode 100644 index 000000000..71248cd4f --- /dev/null +++ b/ethereum/contracts/EthWarp.sol @@ -0,0 +1,96 @@ +// (c) 2025, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +// SPDX-License-Identifier: LicenseRef-Ecosystem + +pragma solidity ^0.8.25; + +import { + WarpMessage, + WarpBlockHash +} from "@avalabs/subnet-evm-contracts@1.2.2/contracts/interfaces/IWarpMessenger.sol"; +import {IWarpExt} from "@avalabs/avalanche-contracts/teleporter/IWarpExt.sol"; +import {ICMMessage} from "@avalabs/avalanche-contracts/teleporter/ITeleporterMessenger.sol"; +import {ICM} from "./utils/ICM.sol"; +import {IVerifyICMMessage} from "./interfaces/IVerifyWarpMessage.sol"; + + +contract EthWarp is IWarpExt { + + /** + * @notice The chain ID of the Ethereum network the contract is deployed on. + * @dev The chain ID for Ethereum is a uint which we reinterpret as bytes32 + * to remain consistent with the existing interface + */ + bytes32 public blockchainID; + + /** + * @notice The chain ID of that the Warp message originated from. Used + * to ensure that message IDs are computed computed consistently on source and + * target teleporter contracts. + */ + bytes32 public warpSourceChainID; + + /** + * @notice A mapping of avalanche chain IDs to contract addresses that know how + * to validate received Warp message. + */ + mapping(bytes32 avaBlockchainId => address verifyWarpMessage) internal _registeredChains; + + constructor (uint256 blockChainId, bytes32 _warpSourceChainID) { + blockchainID = bytes32(uint256(blockChainId)); + warpSourceChainID = _warpSourceChainID; + } + + function getVerifiedICMMessage( + ICMMessage calldata icmMessage + ) external view returns (WarpMessage memory warpMessage) { + require( + isChainRegistered(icmMessage.unsignedMessage.avalancheSourceBlockchainID), + "Cannot receive a Warp message from a chain whose validator set is unknown" + ); + bool isValid = IVerifyICMMessage(_registeredChains[icmMessage.unsignedMessage.avalancheSourceBlockchainID]) + .verifyICMMessage(icmMessage); + require(isValid, "Received an invalid ICM message"); + warpMessage = ICM.handleMessage(icmMessage.unsignedMessage, warpSourceChainID); + return warpMessage; + } + + function sendWarpMessage(bytes calldata payload) external returns (bytes32) { + revert("Sending Warp messages from Ethereum is not currently supported"); + } + + function getVerifiedWarpMessage(uint32 index) external pure returns (WarpMessage calldata, bool) { + revert("This method can't be called on Ethereum, use `getVerifiedICMMessage` instead"); + } + + function getVerifiedWarpBlockHash( + uint32 index + ) external pure returns (WarpBlockHash calldata, bool) { + revert("This method cannot be called on Ethereum"); + } + + function getBlockchainID() external view returns (bytes32) { + return blockchainID; + } + + /** + * @notice Check if a source chain is registered with this Warp contract. If it is not, + * this contract will be unable to verify a quorum of signatures is present on the + * received message. + * @return registered A boolean indicating presence of the given key + */ + function isChainRegistered(bytes32 avaBlockchainId) public view returns (bool) { + return _registeredChains[avaBlockchainId] != address(0); + } + + /** + * @notice Register a contract implementing `IVerifyWarpMessage` here to validate messages + * originating from `avaBlockchainId`. + */ + function registerChain(bytes32 avaBlockchainId, address verifyWarpMessage) external { + require(!isChainRegistered(avaBlockchainId), "This chain is already registered"); + require(verifyWarpMessage != address(0), "Provided address does not exist"); + _registeredChains[avaBlockchainId] = verifyWarpMessage; + } +} \ No newline at end of file diff --git a/ethereum/contracts/interfaces/IAvalancheValidatorSetRegistry.sol b/ethereum/contracts/interfaces/IAvalancheValidatorSetRegistry.sol new file mode 100644 index 000000000..c675bef63 --- /dev/null +++ b/ethereum/contracts/interfaces/IAvalancheValidatorSetRegistry.sol @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {ValidatorSet} from "../utils/ValidatorSets.sol"; +import {ICMMessage} from "@avalabs/avalanche-contracts/teleporter/ITeleporterMessenger.sol"; + +/** + * @title IAvalancheValidatorSetRegistry + * @notice Interface for an Avalanche Validator Registry contract + * @dev This interface defines the events and functions for managing Avalanche validators and validating signed message + * from a given validator set. + */ +interface IAvalancheValidatorSetRegistry { + event ValidatorSetRegistered( + uint256 indexed validatorSetID, bytes32 indexed avalancheBlockchainID + ); + event ValidatorSetUpdated( + uint256 indexed validatorSetID, bytes32 indexed avalancheBlockchainID + ); + + /** + * @notice Registers a new validator set + * @dev A validator set can be registered by anyone, and its correctness should be verified with the actual validator set. + * registered on the Avalanche P-Chain. Updates to any validator set after registration are always authenticated by a + * signed ICM message from the current validator set, giving the party that registered the validator set no elevated + * permission after registration. Because any given validator set cannot be confirmed to be correct at time of registration + * on chain, a validator set for a given blockchain ID is allowed to be be registered multiple times, and they are + * identified by a unique ID assigned by the registry, rather than the blockchain ID they claim to be + * representing. + * @param message The ICM message containing the validator set to register. The message must be signed by validator set + * that it claims to be representing. + * @return The ID of the registered validator set + */ + function registerValidatorSet( + ICMMessage calldata message, + bytes memory validatorBytes + ) external returns (uint256); + + /** + * @notice Updates a validator set + * @dev Updates to any validator set after registration are always authenticated by a signed ICM message + * from the current validator set, giving the party that registered the validator set no elevated + * permission after registration. + * @param validatorSetID The ID of the validator set to update + * @param message The ICM message containing the update + */ + function updateValidatorSet( + uint256 validatorSetID, + ICMMessage calldata message, + bytes memory validatorBytes + ) external; + + /** + * @notice Gets a validator set by its ID + * @param validatorSetID The ID of the validator set to get + * @return The validator set + */ + function getValidatorSet( + uint256 validatorSetID + ) external view returns (ValidatorSet memory); + + /** + * @notice Gets the Avalanche network ID + * @return The Avalanche network ID + */ + function getAvalancheNetworkID() external view returns (uint32); + + /** + * @notice Verifies an ICM message against a validator set + * @dev This function validates that the message is properly signed by a sufficient quorum of validators + * from the validator set identified by validatorSetID. The verification includes checking the network ID, + * blockchain ID, and cryptographic signature verification. + * @param validatorSetID The ID of the validator set to verify the message against + * @param message The ICM message to verify + * @return True if the message is valid, false otherwise + */ + function verifyICMMessageWithID( + uint256 validatorSetID, + ICMMessage calldata message + ) external view returns (bool); +} diff --git a/ethereum/contracts/interfaces/IVerifyWarpMessage.sol b/ethereum/contracts/interfaces/IVerifyWarpMessage.sol new file mode 100644 index 000000000..a292cb609 --- /dev/null +++ b/ethereum/contracts/interfaces/IVerifyWarpMessage.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {ICMMessage} from "@avalabs/avalanche-contracts/teleporter/ITeleporterMessenger.sol"; + +/** + * @notice Allows a contract to specify how a Warp message should be verified. + */ +interface IVerifyICMMessage { + /* + * @notice Verify an ICM message + * @return True if the message is valid, false otherwise. + */ + function verifyICMMessage( + ICMMessage calldata message + ) external view returns (bool); +} \ No newline at end of file diff --git a/ethereum/contracts/tests/AvalancheValidatorSetRegistry.t.sol b/ethereum/contracts/tests/AvalancheValidatorSetRegistry.t.sol new file mode 100644 index 000000000..04c8b5f78 --- /dev/null +++ b/ethereum/contracts/tests/AvalancheValidatorSetRegistry.t.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import "forge-std/Test.sol"; +import "../AvalancheValidatorSetRegistry.sol"; +import "../utils/ValidatorSets.sol"; +import "../utils/ICM.sol"; +import "../utils/BLST.sol"; + +contract AvalancheValidatorSetRegistryTest is Test { + AvalancheValidatorSetRegistry registry; + + uint32 constant NETWORK_ID = 1; + + function setUp() public { + registry = new AvalancheValidatorSetRegistry(NETWORK_ID, bytes32(hex"3d0ad12b8ee8928edf248ca91ca55600fb383f07c32bff1d6dec472b25cf59a7")); + } + + function testGetAvalancheNetworkID() public view { + assertEq(registry.getAvalancheNetworkID(), NETWORK_ID); + } + + function testRegisterValidatorSet() public { + bytes memory validatorBytes = + hex"000000000004055b1e5892c401dc04a72699da740f768f25f16fbac3debaed3caa7f502242b9b8b5890c6795d30bd6011451aef8b547133e7251b1d022c842645433528f94d9e118d2b3a7bd2ec8e8feb971e7d2fe7f5ba81f056147a61f4b4e5e747529ac1d0000000000000064064bb2e2313f21f36907e4c010a7bfee0216a3f0000bf2b1c83adf6aa6675bada4b68dd023f4f4c9285be2c75ff745ac0b790412ba453f7d1a0c49c9c7e1fd7a791110499ea762a96d57b69e67d2e25fb5756a37e26f4c4a69b27939799b92f9000000000000006413d331edb3c1f4113b5148e25bf32658f962d43dea4115fe40fb0c38ac3acd58537cc147218e34e86fd5366ed1ef0d00173010db4bbb9e64cb676d39f4bae156b7b8bc76102d6e41e7bc46c6b6a369d21726f9e7be4b929ce4dcf84fa1a1a56600000000000000641831d57287d398005355881a59ee05384c9467c7974650cb6a38fd1346d3ec58484ab0ad97678bf21521c6e6824e08180d16fb7a9257aac66442415c3f51f35b691f5ce4389ce22c0701b2a1ac6d05f2907e040eb7a03b5aef68bbd90cfbea770000000000000064"; + + bytes memory signedValidtorSetStateMessage = + hex"0000000000013d0ad12b8ee8928edf248ca91ca55600fb383f07c32bff1d6dec472b25cf59a70000006400000000000100000000000000560000000000043d0ad12b8ee8928edf248ca91ca55600fb383f07c32bff1d6dec472b25cf59a700000000000000640000000068712555234da730fe88131b61174151e4a00b7f47b024818550869e9d11a75e2cf4fa4900000000000000010b0525ddc62d270271ab07307867f19b7b70b83a11231b463980fc359d2622a99e2c160f29461422e0455d5279480d77fc08f8d71020f434478e25aa2a1a7c1e468add5a0e113c9544d846335965215f404f59b6e198f6c02659747803fe9502f40bb6e436071f743d6453ecfc97e30d840119bb1003fc3e71df8fa5e822687a9cf7021e40fa75c7756bfe5079c2e8896e1454653389759028106f34e2c1810e08caa6e2c88edbb9bdecb8914c2201c9ae4c82c3c06236d0df0a886068fcfa3f81"; + bytes32 expectedBlockchainID = + bytes32(hex"3d0ad12b8ee8928edf248ca91ca55600fb383f07c32bff1d6dec472b25cf59a7"); + uint32 expectedPChainHeight = 100; + uint32 expectedPChainTimestamp = 1752245589; + bytes[] memory expectedPublicKeys = new bytes[](4); + expectedPublicKeys[0] = + hex"055b1e5892c401dc04a72699da740f768f25f16fbac3debaed3caa7f502242b9b8b5890c6795d30bd6011451aef8b547133e7251b1d022c842645433528f94d9e118d2b3a7bd2ec8e8feb971e7d2fe7f5ba81f056147a61f4b4e5e747529ac1d"; + expectedPublicKeys[1] = + hex"064bb2e2313f21f36907e4c010a7bfee0216a3f0000bf2b1c83adf6aa6675bada4b68dd023f4f4c9285be2c75ff745ac0b790412ba453f7d1a0c49c9c7e1fd7a791110499ea762a96d57b69e67d2e25fb5756a37e26f4c4a69b27939799b92f9"; + expectedPublicKeys[2] = + hex"13d331edb3c1f4113b5148e25bf32658f962d43dea4115fe40fb0c38ac3acd58537cc147218e34e86fd5366ed1ef0d00173010db4bbb9e64cb676d39f4bae156b7b8bc76102d6e41e7bc46c6b6a369d21726f9e7be4b929ce4dcf84fa1a1a566"; + expectedPublicKeys[3] = + hex"1831d57287d398005355881a59ee05384c9467c7974650cb6a38fd1346d3ec58484ab0ad97678bf21521c6e6824e08180d16fb7a9257aac66442415c3f51f35b691f5ce4389ce22c0701b2a1ac6d05f2907e040eb7a03b5aef68bbd90cfbea77"; + uint64 expectedWeight = 100; + uint64 expectedTotalWeight = 400; + + // Parse the ICM message. + ICMMessage memory message = ICM.parseICMMessage(signedValidtorSetStateMessage); + + // Get the current validator set ID. + uint256 expectedValidatorSetID = registry.nextValidatorSetID(); + + // Register the validator set. + uint256 validatorSetID = registry.registerValidatorSet(message, validatorBytes); + + // Check that the validator set ID is correct. + assertEq(validatorSetID, expectedValidatorSetID); + + // Check that the validator set is correct. + ValidatorSet memory validatorSet = registry.getValidatorSet(validatorSetID); + assertEq(validatorSet.avalancheBlockchainID, expectedBlockchainID); + assertEq(validatorSet.pChainHeight, expectedPChainHeight); + assertEq(validatorSet.pChainTimestamp, expectedPChainTimestamp); + assertEq(validatorSet.validators.length, 4); + for (uint256 i = 0; i < 4; i++) { + assertEq( + validatorSet.validators[i].blsPublicKey, + BLST.formatUncompressedBLSPublicKey(expectedPublicKeys[i]) + ); + assertEq(validatorSet.validators[i].weight, expectedWeight); + } + assertEq(validatorSet.totalWeight, expectedTotalWeight); + } + + function testIncorrectNetworkId() public { + // create a new registry with a network id different than the one the message is intended for + registry = new AvalancheValidatorSetRegistry(NETWORK_ID + 1, bytes32(hex"3d0ad12b8ee8928edf248ca91ca55600fb383f07c32bff1d6dec472b25cf59a7")); + bytes memory validatorBytes = + hex"000000000004055b1e5892c401dc04a72699da740f768f25f16fbac3debaed3caa7f502242b9b8b5890c6795d30bd6011451aef8b547133e7251b1d022c842645433528f94d9e118d2b3a7bd2ec8e8feb971e7d2fe7f5ba81f056147a61f4b4e5e747529ac1d0000000000000064064bb2e2313f21f36907e4c010a7bfee0216a3f0000bf2b1c83adf6aa6675bada4b68dd023f4f4c9285be2c75ff745ac0b790412ba453f7d1a0c49c9c7e1fd7a791110499ea762a96d57b69e67d2e25fb5756a37e26f4c4a69b27939799b92f9000000000000006413d331edb3c1f4113b5148e25bf32658f962d43dea4115fe40fb0c38ac3acd58537cc147218e34e86fd5366ed1ef0d00173010db4bbb9e64cb676d39f4bae156b7b8bc76102d6e41e7bc46c6b6a369d21726f9e7be4b929ce4dcf84fa1a1a56600000000000000641831d57287d398005355881a59ee05384c9467c7974650cb6a38fd1346d3ec58484ab0ad97678bf21521c6e6824e08180d16fb7a9257aac66442415c3f51f35b691f5ce4389ce22c0701b2a1ac6d05f2907e040eb7a03b5aef68bbd90cfbea770000000000000064"; + bytes memory signedValidtorSetStateMessage = + hex"0000000000013d0ad12b8ee8928edf248ca91ca55600fb383f07c32bff1d6dec472b25cf59a70000006400000000000100000000000000560000000000043d0ad12b8ee8928edf248ca91ca55600fb383f07c32bff1d6dec472b25cf59a700000000000000640000000068712555234da730fe88131b61174151e4a00b7f47b024818550869e9d11a75e2cf4fa4900000000000000010b0525ddc62d270271ab07307867f19b7b70b83a11231b463980fc359d2622a99e2c160f29461422e0455d5279480d77fc08f8d71020f434478e25aa2a1a7c1e468add5a0e113c9544d846335965215f404f59b6e198f6c02659747803fe9502f40bb6e436071f743d6453ecfc97e30d840119bb1003fc3e71df8fa5e822687a9cf7021e40fa75c7756bfe5079c2e8896e1454653389759028106f34e2c1810e08caa6e2c88edbb9bdecb8914c2201c9ae4c82c3c06236d0df0a886068fcfa3f81"; + // Parse the ICM message. + ICMMessage memory message = ICM.parseICMMessage(signedValidtorSetStateMessage); + vm.expectRevert(); + registry.registerValidatorSet(message, validatorBytes); + } +} diff --git a/ethereum/contracts/tests/BLSTUtils.t.sol b/ethereum/contracts/tests/BLSTUtils.t.sol new file mode 100644 index 000000000..5a4c44b98 --- /dev/null +++ b/ethereum/contracts/tests/BLSTUtils.t.sol @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "forge-std/Test.sol"; +import "../utils/BLST.sol"; + +contract BLSTUtilsTest is Test { + function testFormatUncompressedBLSPublicKey() public pure { + bytes memory unformatted = + hex"074a926af04042ab5876a9ba4297a806a34732d7df7a33b2d34d8e77313c34c49f365eba61e923acfbdfa160c3e51d2710b93b3ff2351cc019178b142ecb2eed17b0c99c2b6e9c30bedae8cfc26f8f7cdf75b9f0dbb2ea31e11117a04dbe962f"; + bytes memory formatted = + hex"00000000000000000000000000000000074a926af04042ab5876a9ba4297a806a34732d7df7a33b2d34d8e77313c34c49f365eba61e923acfbdfa160c3e51d270000000000000000000000000000000010b93b3ff2351cc019178b142ecb2eed17b0c99c2b6e9c30bedae8cfc26f8f7cdf75b9f0dbb2ea31e11117a04dbe962f"; + + assertEq(formatted, BLST.formatUncompressedBLSPublicKey(unformatted)); + } + + function testNoAggregatePublicKeysSuccess() public view { + // Test data from bls_formatter.go output + bytes memory pk1 = + hex"00000000000000000000000000000000105fdda3f4e22ea318d3831af1de2ef487f4b0506dfe61dca9cbd5c042484b3ecad5565855a557c237081456979433ea0000000000000000000000000000000013711c822adbbcb4f5811d48576f14c5ab78a9e5313636bf5a3722ad60ecdb96629f7e7d76873291960f6d08ab312869"; + + bytes[] memory publicKeys = new bytes[](1); + publicKeys[0] = pk1; + bytes memory aggregated = BLST.aggregatePublicKeys(publicKeys); + assertEq(aggregated, pk1); + } + + function testAggregatePublicKeysSuccess() public view { + // Test data from bls_formatter.go output + bytes memory pk1 = + hex"00000000000000000000000000000000105fdda3f4e22ea318d3831af1de2ef487f4b0506dfe61dca9cbd5c042484b3ecad5565855a557c237081456979433ea0000000000000000000000000000000013711c822adbbcb4f5811d48576f14c5ab78a9e5313636bf5a3722ad60ecdb96629f7e7d76873291960f6d08ab312869"; + bytes memory pk2 = + hex"000000000000000000000000000000000f872fdc2f552676f3297330d13d888f9921038cce6cc087f1087d315363c79847e43f85d836a796cf6ddf101d13e2d9000000000000000000000000000000000b1737099061d418482275164132e3cea936ebb202661cac3df9c2dfba028fd164a947b0f62b38cae6dba6784ba475d8"; + bytes memory expectedAggregated = + hex"00000000000000000000000000000000086401cb5b1276627747ca377b2de206fd0b6427bac06fdbd21e4cf5c71b57676367e5cc198c54c8ab0e4d0e5fa05663000000000000000000000000000000001436d02c536eb6e244867b806bc9453b367e923edcf1ada35d743122c5d2503d4114d8c776b64e67d22f3c5c6e4583e7"; + + bytes[] memory publicKeys = new bytes[](2); + publicKeys[0] = pk1; + publicKeys[1] = pk2; + + bytes memory aggregated = BLST.aggregatePublicKeys(publicKeys); + assertEq(aggregated, expectedAggregated); + } + + function testAddG1Success() public view { + bytes memory pk1 = + hex"0984b5daad5db34822a5b73103587ea28209087d3ad92fba376f669692e07771f9945661a2d6fc9114ea098015ef44a0107993eb8136dfbb698c9b36736b093000e7c6d704c131c9534e45bb11069a6ce296ce15878e8cbd39800c52773c8841"; + bytes memory pk2 = + hex"10ffae60e1c05689695b551f442351306be88aa4f98faa7521a120e12b5ba597bfa310c4ef9c59e31622bf678241ea9a0cebd5284f2326f38f0515652d16471bc699b9654870e49219b091f2717caf07b170e40bb23aad749a99dfd9cc072982"; + bytes memory pk3 = + hex"0252a35315cec61341b676c42ac45c058f23e76f49194349f8c80d5e1414e6043560ebe4d129f23bff1f3692f4052396175832741f48604400a1b43f76e43f738f196472058158573c1e9d14de62b9137d2e4548507fd48b8f28a5ad9baa1063"; + bytes memory expectedAggregate = + hex"11a1c66b14aa6d316416583e6490b081cf09dcd59ddd5001c4c9acf236b2c4ecab638ae32003ddce690de7ace0ed32c017363c0c67531f30c01618ab4df0dfe6c13c21ed5efe7943b7110c80e77ee085984d19df331de1514981c559b2659200"; + + bytes memory res1 = BLST.addG1( + BLST.formatUncompressedBLSPublicKey(pk1), BLST.formatUncompressedBLSPublicKey(pk2) + ); + bytes memory res2 = BLST.addG1(res1, BLST.formatUncompressedBLSPublicKey(pk3)); + assertEq(res2, BLST.formatUncompressedBLSPublicKey(expectedAggregate)); + } + + function testVerifyBLSSignatureSuccess() public view { + bytes memory message = "Hello Ethereum, it's Avalanche."; + bytes memory pk = + hex"000000000000000000000000000000000d89fe5ee3754167f889ff991c81e1717b665690955ad302a50e285dbe68aac93d03177fba54622bf5c4926ce90d0ac60000000000000000000000000000000015874901c0288afcdf442b402199d6a2ed38c5ac28d055637e7bafb44dc4a46a56db1c74caf0e339f6ed665dbc0c0c60"; + bytes memory sig = + hex"1572ad7226ef5d2a52c89d824179e1723a523c7a30c8ff2643aee0b19aca4e3670a28d8749991075d72dd9d64aba703a0ed0d39f4a935cfc5b96c5fbc8985596a9556dec84286c0f945c93ebf33c96bc58ce5cf54a70c3b5221da81d01b6640e058b6a69058a96395acf26fb8013e93dcacbe83f93ed0697e6fd080132062c8e3fc4b63488e00ec5dd60dd2dcda6264112ce2d0e1e024de26bc4d75fb1a7b0fa823b44770570e1539cf500aa5fa2c5abd8e806246d0009d260e224e1f435cc97"; + + bool valid = BLST.verifySignature(pk, sig, message); + assertTrue(valid); + } + + function testVerifyBLSAggregateSignatureSuccess() public view { + bytes memory message = "Hello Ethereum, it's Avalanche."; + bytes[] memory pks = new bytes[](2); + pks[0] = + hex"000000000000000000000000000000000d89fe5ee3754167f889ff991c81e1717b665690955ad302a50e285dbe68aac93d03177fba54622bf5c4926ce90d0ac60000000000000000000000000000000015874901c0288afcdf442b402199d6a2ed38c5ac28d055637e7bafb44dc4a46a56db1c74caf0e339f6ed665dbc0c0c60"; + pks[1] = + hex"00000000000000000000000000000000001f2946023547012bf42ca45962136ebca74aeea4291a25e9bf46bf37c5fdd37ecad6d5a389bcecf3f3d1f4f73c44db000000000000000000000000000000000385c2753673a29e199f0a0dc02772b5e2dec7a3aa70e012b313195906a27ac95d0a4963d96340df6f4d13cf40f7c78f"; + bytes memory sig = + hex"0ace4f38b5e22e8cfd27951b8327d5260def6e6370e334c3f74fb9b5ccd209d0d80d1a34bb804f6ac40dd991141d87b5147a0a08008b085fd27341456bb43654fed88ebca4407d0b5ae66a67df8141edc58fced0468b5e34cec33dc2d58f023d1770616fe829ef9af2350c7c9d7b72ee1c05edefc7cd831ac13114e8ae7e1466c7ef2990a8e6387f9def145be2c9be8b0cbc8f7e6ebcb1b099a1785ea2001d70887faaaf86c937a292049134d02c7bc9aeaed7a3354673985a88a6e3aff66ccd"; + bool valid = BLST.verifyAggregateSignature(pks, sig, message); + assertTrue(valid); + } + + function testCreateAndVerifySignature() public { + bytes memory message = "Hello Ethereum, it's Avalanche."; + uint256 secretKey = 273952; + bytes memory pk = BLST.getPublicKeyFromSecret(secretKey); + bytes memory sig = BLST.createSignature(secretKey, message); + bool valid = BLST.verifySignature(pk, sig, message); + assertTrue(valid); + // check that everything works the same when making an aggregate signature with a single secret key + uint256[] memory secretKeys = new uint256[](1); + secretKeys[0] = secretKey; + bytes memory sig_aggregate = BLST.createAggregateSignature(secretKeys, message); + assertEq(sig, sig_aggregate); + bool valid_aggregate = BLST.verifySignature(pk, sig_aggregate, message); + assertTrue(valid); + } + + function testCreateAndVerifyAggregateSignature() public { + bytes memory message = "Hello Ethereum, it's Avalanche."; + uint256[] memory secretKeys = new uint256[](2); + secretKeys[0] = 273952; + secretKeys[1] = 93293485; + bytes[] memory pks = new bytes[](2); + pks[0] = BLST.getPublicKeyFromSecret(secretKeys[0]); + pks[1] = BLST.getPublicKeyFromSecret(secretKeys[1]); + bytes memory sig = BLST.createAggregateSignature(secretKeys, message); + bool valid = BLST.verifyAggregateSignature(pks, sig, message); + assertTrue(valid); + } +} diff --git a/ethereum/contracts/tests/EthWarp.t.sol b/ethereum/contracts/tests/EthWarp.t.sol new file mode 100644 index 000000000..08cead65f --- /dev/null +++ b/ethereum/contracts/tests/EthWarp.t.sol @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import "forge-std/Test.sol"; +import { + ICMMessage, + ICMUnsignedMessage, + ICMSignature +} from "@avalabs/avalanche-contracts/teleporter/ITeleporterMessenger.sol"; +import "../AvalancheValidatorSetRegistry.sol"; +import "../EthWarp.sol"; +import "../utils/ValidatorSets.sol"; +import "../utils/BLST.sol"; + +contract EthWarpTest is Test { + AvalancheValidatorSetRegistry registry; + EthWarp warp; + + uint32 constant NETWORK_ID = 1; + bytes32 constant AvalancheBlockchainId = bytes32(hex"3d0ad12b8ee8928edf248ca91ca55600fb383f07c32bff1d6dec472b25cf59a7"); + + function setUp() public { + registry = new AvalancheValidatorSetRegistry(NETWORK_ID, AvalancheBlockchainId); + warp = new EthWarp(1, AvalancheBlockchainId); + } + + /** + * @dev The `getVerifiedWarpBlockHash` method is part of the IWarpExt interface, but it + * is specifically not implemented for the Ethereum Warp messenger + */ + function testWarpBlochHashReverts() public { + vm.expectRevert("This method cannot be called on Ethereum"); + warp.getVerifiedWarpBlockHash(0); + } + + /** + * @dev The `getVerifiedWarpMessage` method is part of the IWarpExt interface, but it + * is specifically not implemented for the Ethereum Warp messenger + */ + function testGetVerifiedWarpMessageReverts() public { + vm.expectRevert("This method can't be called on Ethereum, use `getVerifiedICMMessage` instead"); + warp.getVerifiedWarpMessage(0); + } + + /** + * @dev An Ethereum warp contract must be able to look up an `AvalancheValidatorSetRegistry` + * contract from the respective blockchain id in order to validate a message. + * + * Here we test that if this look up fails, the function reverts + */ + function testUnregisteredBlockchain() public { + // the blockchain is not registered with this contract + assertFalse(warp.isChainRegistered(AvalancheBlockchainId)); + ICMMessage memory message = icmMessageFixture(); + vm.expectRevert( "Cannot receive a Warp message from a chain whose validator set is unknown"); + warp.getVerifiedICMMessage(message); + } + + /** + * @dev The ICM message given to the warp contract will reach out to an `AvalancheValidatorSetRegistry` + * with no validators registered. This should cause message verification to fail. + */ + function testWrongValidatorSet() public { + // register the `AvalancheValidatorSetRegistry` contract + warp.registerChain(AvalancheBlockchainId, address(registry)); + assertTrue(warp.isChainRegistered(AvalancheBlockchainId)); + + ICMMessage memory message = icmMessageFixture(); + + // The call should fail when attempting to find the current validator set + vm.expectRevert(); + warp.getVerifiedICMMessage(message); + } + + /** + * @dev Test happy flow that warp can receive a message signed by a quorum of validators + */ + function testGetVerifiedMessageFromPayload() public { + // add a validator set to the registry with all equal weights + registerValidatorSet([uint64(100), uint64(100), uint64(100), uint64(100)]); + + // register this registry with the warp contract + warp.registerChain(AvalancheBlockchainId, address(registry)); + // verify that we can receive and validate this message + warp.getVerifiedICMMessage(icmMessageFixture()); + } + + function secretKeysFixture() private pure returns (uint256[4] memory) { + return [uint256(1337), uint256(1338), uint256(1339), uint256(1340)]; + } + + /** + * @dev An ICM message used for testing. It is signed by all validators except the second + */ + function icmMessageFixture() private view returns (ICMMessage memory) { + AddressedCall memory addressedCall = AddressedCall({ + sourceAddress: hex"deadbeef", + payload: hex"48656c6c6f2c20576f726c6421" + }); + ICMUnsignedMessage memory unsignedMessage = ICMUnsignedMessage ({ + avalancheNetworkID: 1, + avalancheSourceBlockchainID: AvalancheBlockchainId, + payload: ICM.serializeAddressedCall(addressedCall) + }); + bytes memory unsignedMessageBytes = ICM.serializeICMUnsignedMessage(unsignedMessage); + uint256[4] memory secretKeys = secretKeysFixture(); + uint256[] memory sks = new uint256[] (3); + sks[0] = secretKeys[0]; + sks[1] = secretKeys[2]; + sks[2] = secretKeys[3]; + bytes memory sig = BLST.createAggregateSignature(sks, unsignedMessageBytes); + return ICMMessage({ + unsignedMessage: unsignedMessage, + unsignedMessageBytes: unsignedMessageBytes, + signature: ICMSignature({ + signers: hex"0d", + signature: sig + }) + }); + } + + /** + * @dev A factory function to register a set of four validators to the registry + * The weights are passed in as parameter + */ + function registerValidatorSet(uint64[4] memory weights) private { + // construct public keys + bytes[] memory publicKeys = new bytes[](4); + uint256[4] memory secretKeys = secretKeysFixture(); + publicKeys[0] = BLST.getPublicKeyFromSecret(secretKeys[0]); + publicKeys[1] = BLST.getPublicKeyFromSecret(secretKeys[1]); + publicKeys[2] = BLST.getPublicKeyFromSecret(secretKeys[2]); + publicKeys[3] = BLST.getPublicKeyFromSecret(secretKeys[3]); + + // construct the validator set + Validator[] memory validators = new Validator[](4); + for (uint256 i = 0; i < 4; ++i) { + validators[i] = Validator({ + blsPublicKey: publicKeys[i], + weight: weights[i] + }); + } + + bytes memory validatorBytes = ValidatorSets.serializeValidators(validators); + + // construct the validator set state payload + ValidatorSetStatePayload memory validatorSetState = ValidatorSetStatePayload({ + avalancheBlockchainID: AvalancheBlockchainId, + pChainHeight: 1, + pChainTimestamp: 1, + validatorSetHash: sha256(validatorBytes) + }); + + // construct the addressed call for registering validators + AddressedCall memory addressedCall = AddressedCall({ + sourceAddress: new bytes(0), + payload: ValidatorSets.serializeValidatorSetStatePayload(validatorSetState) + }); + + // construct the unsigned ICM message + ICMUnsignedMessage memory unsignedMessage = ICMUnsignedMessage ({ + avalancheNetworkID: 1, + avalancheSourceBlockchainID: AvalancheBlockchainId, + payload: ICM.serializeAddressedCall(addressedCall) + }); + + bytes memory unsignedMessageBytes = ICM.serializeICMUnsignedMessage(unsignedMessage); + + // sign the ICM message + uint256[] memory sks = new uint256[] (4); + sks[0] = secretKeys[0]; + sks[1] = secretKeys[1]; + sks[2] = secretKeys[2]; + sks[3] = secretKeys[3]; + bytes memory sig = BLST.createAggregateSignature(sks, unsignedMessageBytes); + + // construct the final ICM message + ICMMessage memory icmMessage = ICMMessage({ + unsignedMessage: unsignedMessage, + unsignedMessageBytes: unsignedMessageBytes, + signature: ICMSignature({ + signers: hex"0f", + signature: sig + }) + }); + uint256 expected_id = registry.nextValidatorSetID(); + uint256 id = registry.registerValidatorSet(icmMessage, validatorBytes); + assertEq(id, expected_id); + } +} diff --git a/ethereum/contracts/tests/ICMUtils.t.sol b/ethereum/contracts/tests/ICMUtils.t.sol new file mode 100644 index 000000000..435fdc28a --- /dev/null +++ b/ethereum/contracts/tests/ICMUtils.t.sol @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import "../utils/ICM.sol"; +import "../utils/ICM.sol"; +import {BLST} from "../utils/BLST.sol"; +import {AddressedCall, ICMMessage, ICMUnsignedMessage, ICMSignature, ICM} from "../utils/ICM.sol"; +import {Test} from "forge-std/Test.sol"; +import {Validator, ValidatorSet} from "../utils/ValidatorSets.sol"; + +contract ICMUtilsTest is Test { + function testParseICMMessage() public pure { + bytes memory messageBytes = + hex"0000000000013d0ad12b8ee8928edf248ca91ca55600fb383f07c32bff1d6dec472b25cf59a70000000d48656c6c6f2c20576f726c64210000000000000001010cb7f52fa291c273810bcf0dd1d3dc41e0449e6da4ff2b90243ce33b6ff4733cbd3f8446878109e369db1ae9a67622430d3d6ec6a9b1abb9e6cd86df330080a546d2b8599950618eb76efbdfe13ef74fc14e4fa9919bd440dd2bd02bf84421af089653aef1a209f9bbf2837562b02adc6e766753e0247417225a4de4ad095ad50d619b719e234702df7f87e8cd54873310c55d7516d586441d7dd978e199f08383013aa6e3b2f9a48ac3366e9a5df7a003786b93b937d9ccf463a6f10b342306"; + ICMMessage memory message = ICM.parseICMMessage(messageBytes); + assertEq(message.unsignedMessage.avalancheNetworkID, 1); + assertEq( + message.unsignedMessage.avalancheSourceBlockchainID, + bytes32(hex"3d0ad12b8ee8928edf248ca91ca55600fb383f07c32bff1d6dec472b25cf59a7") + ); + assertEq(message.unsignedMessage.payload, hex"48656c6c6f2c20576f726c6421"); + assertEq( + message.unsignedMessageBytes, + hex"0000000000013d0ad12b8ee8928edf248ca91ca55600fb383f07c32bff1d6dec472b25cf59a70000000d48656c6c6f2c20576f726c6421" + ); + assertEq(message.signature.signers, hex"01"); + assertEq( + message.signature.signature, + hex"0cb7f52fa291c273810bcf0dd1d3dc41e0449e6da4ff2b90243ce33b6ff4733cbd3f8446878109e369db1ae9a67622430d3d6ec6a9b1abb9e6cd86df330080a546d2b8599950618eb76efbdfe13ef74fc14e4fa9919bd440dd2bd02bf84421af089653aef1a209f9bbf2837562b02adc6e766753e0247417225a4de4ad095ad50d619b719e234702df7f87e8cd54873310c55d7516d586441d7dd978e199f08383013aa6e3b2f9a48ac3366e9a5df7a003786b93b937d9ccf463a6f10b342306" + ); + } + + function testICMMessageRoundTrip() public pure { + ICMMessage memory expected = ICMMessage({ + unsignedMessage: ICMUnsignedMessage ({ + avalancheNetworkID: 1, + avalancheSourceBlockchainID: bytes32(hex"3d0ad12b8ee8928edf248ca91ca55600fb383f07c32bff1d6dec472b25cf59a7"), + payload: hex"48656c6c6f2c20576f726c6421" + }), + unsignedMessageBytes: hex"0000000000013d0ad12b8ee8928edf248ca91ca55600fb383f07c32bff1d6dec472b25cf59a70000000d48656c6c6f2c20576f726c6421", + signature: ICMSignature({ + signers:hex"01", + signature: hex"0cb7f52fa291c273810bcf0dd1d3dc41e0449e6da4ff2b90243ce33b6ff4733cbd3f8446878109e369db1ae9a67622430d3d6ec6a9b1abb9e6cd86df330080a546d2b8599950618eb76efbdfe13ef74fc14e4fa9919bd440dd2bd02bf84421af089653aef1a209f9bbf2837562b02adc6e766753e0247417225a4de4ad095ad50d619b719e234702df7f87e8cd54873310c55d7516d586441d7dd978e199f08383013aa6e3b2f9a48ac3366e9a5df7a003786b93b937d9ccf463a6f10b342306" + }) + }); + bytes memory serialized = ICM.serializeICMMessage(expected); + assertEq( + serialized, + hex"0000000000013d0ad12b8ee8928edf248ca91ca55600fb383f07c32bff1d6dec472b25cf59a70000000d48656c6c6f2c20576f726c64210000000000000001010cb7f52fa291c273810bcf0dd1d3dc41e0449e6da4ff2b90243ce33b6ff4733cbd3f8446878109e369db1ae9a67622430d3d6ec6a9b1abb9e6cd86df330080a546d2b8599950618eb76efbdfe13ef74fc14e4fa9919bd440dd2bd02bf84421af089653aef1a209f9bbf2837562b02adc6e766753e0247417225a4de4ad095ad50d619b719e234702df7f87e8cd54873310c55d7516d586441d7dd978e199f08383013aa6e3b2f9a48ac3366e9a5df7a003786b93b937d9ccf463a6f10b342306" + ); + } + + function testICMUnsignedMessageRoundtrip() public pure { + ICMUnsignedMessage memory unsignedMessage = ICMUnsignedMessage ({ + avalancheNetworkID: 1, + avalancheSourceBlockchainID: bytes32(hex"3d0ad12b8ee8928edf248ca91ca55600fb383f07c32bff1d6dec472b25cf59a7"), + payload: hex"48656c6c6f2c20576f726c6421" + }); + bytes memory serialized = ICM.serializeICMUnsignedMessage(unsignedMessage); + assertEq(serialized, hex"0000000000013d0ad12b8ee8928edf248ca91ca55600fb383f07c32bff1d6dec472b25cf59a70000000d48656c6c6f2c20576f726c6421"); + ICMUnsignedMessage memory message = ICM.parseICMUnsignedMessage(serialized); + assertEq(message.avalancheNetworkID, unsignedMessage.avalancheNetworkID); + assertEq(message.avalancheSourceBlockchainID, unsignedMessage.avalancheSourceBlockchainID); + assertEq(message.payload, unsignedMessage.payload); + } + + function testAddressedCallRoundtrip() public pure { + AddressedCall memory expected = AddressedCall({ + sourceAddress: hex"deadbeef", + payload: hex"48656c6c6f2c20576f726c6421" + }); + + bytes memory serialized = ICM.serializeAddressedCall(expected); + AddressedCall memory addressedCall = ICM.parseAddressedCall(serialized); + assertEq(expected.sourceAddress, addressedCall.sourceAddress); + assertEq(expected.payload, addressedCall.payload); + } + + function testBytesToBoolArray() public pure { + bytes memory data = hex"01"; + bool[] memory result = ICM.bytesToBoolArray(data); + assertEq(result.length, 1); + assertEq(result[0], true); + + data = hex"80"; + result = ICM.bytesToBoolArray(data); + assertEq(result.length, 8); + assertEq(result[0], true); + assertEq(result[1], false); + assertEq(result[2], false); + assertEq(result[3], false); + assertEq(result[4], false); + assertEq(result[5], false); + assertEq(result[6], false); + assertEq(result[7], false); + } + + function testVerifyWeight() public pure { + assertEq(ICM.verifyWeight(100, 100), true); + assertEq(ICM.verifyWeight(68, 100), true); + assertEq(ICM.verifyWeight(67, 100), true); + assertEq(ICM.verifyWeight(3936137349139582, 5874831864387435), true); + assertEq(ICM.verifyWeight(3936137349139581, 5874831864387435), false); + assertEq(ICM.verifyWeight(67, 100), true); + assertEq(ICM.verifyWeight(67000000000, 100000000000), true); + assertEq(ICM.verifyWeight(66666666669, 100000000000), false); + assertEq(ICM.verifyWeight(66, 100), false); + assertEq(ICM.verifyWeight(0, 100), false); + } + + function testVerifyICMMessageSingleSignerSuccess() public view { + bytes memory unformattedPublicKey = + hex"074a926af04042ab5876a9ba4297a806a34732d7df7a33b2d34d8e77313c34c49f365eba61e923acfbdfa160c3e51d2710b93b3ff2351cc019178b142ecb2eed17b0c99c2b6e9c30bedae8cfc26f8f7cdf75b9f0dbb2ea31e11117a04dbe962f"; + bytes memory formattedPublicKey = BLST.formatUncompressedBLSPublicKey(unformattedPublicKey); + + Validator[] memory validators = new Validator[](1); + validators[0] = Validator({blsPublicKey: formattedPublicKey, weight: 100}); + + ValidatorSet memory validatorSet = ValidatorSet({ + avalancheBlockchainID: bytes32( + hex"3d0ad12b8ee8928edf248ca91ca55600fb383f07c32bff1d6dec472b25cf59a7" + ), + validators: validators, + totalWeight: 100, + pChainHeight: 1, + pChainTimestamp: 1 + }); + ICMMessage memory message = ICM.parseICMMessage( + hex"0000000000013d0ad12b8ee8928edf248ca91ca55600fb383f07c32bff1d6dec472b25cf59a70000000d48656c6c6f2c20576f726c64210000000000000001010cb7f52fa291c273810bcf0dd1d3dc41e0449e6da4ff2b90243ce33b6ff4733cbd3f8446878109e369db1ae9a67622430d3d6ec6a9b1abb9e6cd86df330080a546d2b8599950618eb76efbdfe13ef74fc14e4fa9919bd440dd2bd02bf84421af089653aef1a209f9bbf2837562b02adc6e766753e0247417225a4de4ad095ad50d619b719e234702df7f87e8cd54873310c55d7516d586441d7dd978e199f08383013aa6e3b2f9a48ac3366e9a5df7a003786b93b937d9ccf463a6f10b342306" + ); + assertEq(ICM.verifyICMMessage( + message, 1, + bytes32(hex"3d0ad12b8ee8928edf248ca91ca55600fb383f07c32bff1d6dec472b25cf59a7"), + validatorSet + ), true); + } + + function testVerifyICMMessageMultiSignerSuccess() public view { + bytes[] memory unformattedPublicKeys = new bytes[](4); + unformattedPublicKeys[0] = + hex"0984b5daad5db34822a5b73103587ea28209087d3ad92fba376f669692e07771f9945661a2d6fc9114ea098015ef44a0107993eb8136dfbb698c9b36736b093000e7c6d704c131c9534e45bb11069a6ce296ce15878e8cbd39800c52773c8841"; + unformattedPublicKeys[1] = + hex"10ffae60e1c05689695b551f442351306be88aa4f98faa7521a120e12b5ba597bfa310c4ef9c59e31622bf678241ea9a0cebd5284f2326f38f0515652d16471bc699b9654870e49219b091f2717caf07b170e40bb23aad749a99dfd9cc072982"; + unformattedPublicKeys[2] = + hex"0a8c197bfda5978a8fb1ee76b36b544029594a32191916f46568a18b31594e53aebea9cb0a0c218d9f2a7ddf63d7cc68196c71b6c4c816e3d3adc8189e9e89d677160272eebc84070185da00ac4b97ed3a0b3b18aab35381239882c8a3250072"; + unformattedPublicKeys[3] = + hex"0252a35315cec61341b676c42ac45c058f23e76f49194349f8c80d5e1414e6043560ebe4d129f23bff1f3692f4052396175832741f48604400a1b43f76e43f738f196472058158573c1e9d14de62b9137d2e4548507fd48b8f28a5ad9baa1063"; + + Validator[] memory validators = new Validator[](4); + for (uint256 i = 0; i < 4; ++i) { + validators[i] = Validator({ + blsPublicKey: BLST.formatUncompressedBLSPublicKey(unformattedPublicKeys[i]), + weight: 100 + }); + } + + ValidatorSet memory validatorSet = ValidatorSet({ + avalancheBlockchainID: bytes32( + hex"3d0ad12b8ee8928edf248ca91ca55600fb383f07c32bff1d6dec472b25cf59a7" + ), + validators: validators, + totalWeight: 400, + pChainHeight: 1, + pChainTimestamp: 1 + }); + + ICMMessage memory message = ICM.parseICMMessage( + hex"0000000000013d0ad12b8ee8928edf248ca91ca55600fb383f07c32bff1d6dec472b25cf59a70000000d48656c6c6f2c20576f726c642100000000000000010b0a09516a15348d6d981453e57d7cfc8c9f4d965b96773cefa8edf77c763d549507a2ba420e4a717011b3d9c1f4f1eb3f158970399057617f161b6e9dcfd82682291c21bbe1d7600334c1fe70efa58b03f2eeacea089bd9ec940d64f98d6b177e086ba348a850a39b4ee758645b0c273857133d448f310be2d3d7ad16c2c377d4d9156a6f18e47437e405ed7f042cec7605c18a3fac0ae6569fa482a3210d6a50b913d9e607494f239f178d11ea9904bd3598c87970a8b69d955dc6fe0178e8b7" + ); + assertEq(ICM.verifyICMMessage( + message, + 1, + bytes32(hex"3d0ad12b8ee8928edf248ca91ca55600fb383f07c32bff1d6dec472b25cf59a7"), + validatorSet + ), true); + } +} diff --git a/ethereum/contracts/tests/ValidatorSets.t.sol b/ethereum/contracts/tests/ValidatorSets.t.sol new file mode 100644 index 000000000..efc24e641 --- /dev/null +++ b/ethereum/contracts/tests/ValidatorSets.t.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import "forge-std/Test.sol"; +import "../utils/ValidatorSets.sol"; +import "../utils/ICM.sol"; +import "../utils/BLST.sol"; + +contract ValidatorSetTest is Test { + function testParseValidatorsRoundtrip() public view { + Validator[] memory validators = new Validator[](3); + validators[0] = Validator({ + blsPublicKey: BLST.getPublicKeyFromSecret(1), + weight: 1 + }); + validators[1] = Validator({ + blsPublicKey: BLST.getPublicKeyFromSecret(2), + weight: 2 + }); + validators[2] = Validator({ + blsPublicKey: BLST.getPublicKeyFromSecret(3), + weight: 3 + }); + bytes memory serialized = ValidatorSets.serializeValidators(validators); + (Validator[] memory deserialized, uint64 totalWeight) = ValidatorSets.parseValidators(serialized); + for (uint256 i = 0; i < 3; i++) { + assertEq(validators[i].blsPublicKey, deserialized[i].blsPublicKey); + assertEq(validators[i].weight, deserialized[i].weight); + } + assertEq(deserialized.length, 3); + assertEq(totalWeight, 6); + } + + function testPayloadRoundtrip() public pure { + ValidatorSetStatePayload memory payload = ValidatorSetStatePayload({ + avalancheBlockchainID: hex"3d0ad12b8ee8928edf248ca91ca55600fb383f07c32bff1d6dec472b25cf59a7", + pChainHeight: 22, + pChainTimestamp: 32, + validatorSetHash: hex"3d0ad12b8ee8928edf248ca91ca55600fb383f07c32bff1d6dec472b25cf59a7" + }); + bytes memory serialized = ValidatorSets.serializeValidatorSetStatePayload(payload); + ValidatorSetStatePayload memory deserialized = ValidatorSets.parseValidatorSetStatePayload(serialized); + assertEq(payload.avalancheBlockchainID, deserialized.avalancheBlockchainID); + assertEq(payload.pChainHeight, deserialized.pChainHeight); + assertEq(payload.pChainTimestamp, deserialized.pChainTimestamp); + assertEq(payload.validatorSetHash, deserialized.validatorSetHash); + } +} \ No newline at end of file diff --git a/ethereum/contracts/utils/BLST.sol b/ethereum/contracts/utils/BLST.sol new file mode 100644 index 000000000..3fcc4f0f3 --- /dev/null +++ b/ethereum/contracts/utils/BLST.sol @@ -0,0 +1,550 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +struct FieldPoint2 { + bytes32[2] u; + bytes32[2] u_I; +} + +/** + * @title BLST + * @notice Utility library for BLS12-381 operations. + */ +library BLST { + uint256 constant BLS_UNCOMPRESSED_PUBLIC_KEY_INPUT_LENGTH = 96; + + address constant BLS12381_G1_ADD_PRECOMPILE = + address(0x000000000000000000000000000000000000000b); + address constant BLS12381_G1_MSM_PRECOMPILE = + address(0x000000000000000000000000000000000000000C); + address constant BLS12381_G2_ADD_PRECOMPILE = + address(0x000000000000000000000000000000000000000d); + address constant BLS12381_G2_MSM_PRECOMPILE = + address(0x000000000000000000000000000000000000000E); + address constant BLS12381_PAIRING_CHECK_PRECOMPILE = + address(0x000000000000000000000000000000000000000F); + address constant BLS12381_MAP_FP2_G2_PRECOMPILE = + address(0x0000000000000000000000000000000000000011); + + bytes constant BLS_G1_GENERATOR = + hex"0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1"; + bytes constant BLS_G1_NEG_GENERATOR = + hex"0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb00000000000000000000000000000000114d1d6855d545a8aa7d76c8cf2e21f267816aef1db507c96655b9d5caac42364e6f38ba0ecb751bad54dcd6b939c2ca"; + bytes constant BLS_G2_GENERATOR = + hex"00000000000000000000000000000000024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80000000000000000000000000000000013e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e000000000000000000000000000000000ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801000000000000000000000000000000000606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be"; + bytes constant BLS12381G2_SIG_DST = "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"; + bytes constant BLS12381G2_POP_DST = "BLS_POP_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"; + + /** + * @notice Formats a 96-byte uncompressed BLS public key into the 128-byte format expected by the + * BLS12381_G1_ADD_PRECOMPILE. + * @param publicKey The 96-byte uncompressed BLS public key, as produced by the BLST library's + * P1Affine.Serialize() function. + * @return The 128-byte serialized public key. Its X and Y coordinates are left-padded to be 64 bytes each, for a + * total of 128 bytes. + */ + function formatUncompressedBLSPublicKey( + bytes memory publicKey + ) internal pure returns (bytes memory) { + require(publicKey.length == 96, "Invalid input public key length"); + bytes memory res = new bytes(128); + + // Copy the X coordinate. + for (uint256 i = 0; i < 48; ++i) { + res[16 + i] = publicKey[i]; + } + + // Copy the Y coordinate. + for (uint256 i = 0; i < 48; ++i) { + res[80 + i] = publicKey[i + 48]; + } + + return res; + } + + /** + * @notice Turns the 128-byte format expected by the BLS12381_G1_ADD_PRECOMPILE into + * a 96-byte uncompressed BLS public key + * @param publicKey The the 128-byte padded format. + * @return The 96-byte uncompressed BLS public key. + */ + function getUncompressedBlsPublicKey( + bytes memory publicKey + ) internal pure returns (bytes memory) { + require(publicKey.length == 128, "Invalid input public key length"); + bytes memory res = new bytes(96); + + // Copy the X coordinate. + for (uint256 i = 0; i < 48; ++i) { + res[i] = publicKey[16 + i]; + } + + // Copy the Y coordinate. + for (uint256 i = 0; i < 48; ++i) { + res[48 + i] = publicKey[i + 80]; + } + + return res; + } + + /** + * @notice Given a secret key, get the public counterpart + * @dev According to the EIP-2537 spec, this method can fail as it may not land on the curve or + * is not in the correct subgroup + * @param secretKey is a 256 bit scalar. + * @return The 128-byte serialized public key. Its X and Y coordinates are left-padded to be 64 bytes each, + * for a total of 128 bytes. + */ + function getPublicKeyFromSecret( + uint256 secretKey + ) internal view returns (bytes memory) { + bytes memory input = new bytes(160); + for (uint256 i = 0; i < 128; i++) { + input[i] = BLS_G1_GENERATOR[i]; + } + bytes32 sk = bytes32(secretKey); + for (uint256 j = 0; j < 32; j++) { + input[128 + j] = sk[j]; + } + + (bool success, bytes memory result) = + BLS12381_G1_MSM_PRECOMPILE.staticcall(abi.encodePacked(input)); + require(success, "Failed to perform scalar multiplication over G1"); + return result; + } + + /** + * @notice Formats a 192-byte uncompressed BLS signature into the 256-byte format expected by the + * BLS12381_PAIRING_CHECK_PRECOMPILE. + * @param signature The 192-byte uncompressed BLS signature. Must have the format [x.c1, x.c0, y.c1, y.c0]. + * @return The 256-byte formatted signature. Has the format + * [16 pad + x.c0, 16 pad + x.c1, 16 pad + y.c0, 16 pad + y.c1]. + */ + function formatUncompressedBLSTSignature( + bytes memory signature + ) internal pure returns (bytes memory) { + require(signature.length == 192, "Invalid input signature length"); + bytes memory res = new bytes(256); + + // Copy X0 + for (uint256 i = 0; i < 48; ++i) { + res[16 + i] = signature[i + 48]; + } + + // Copy X1 + for (uint256 i = 0; i < 48; ++i) { + res[80 + i] = signature[i]; + } + + // Copy Y0 + for (uint256 i = 0; i < 48; ++i) { + res[144 + i] = signature[i + 144]; + } + + // Copy Y1 + for (uint256 i = 0; i < 48; ++i) { + res[208 + i] = signature[i + 96]; + } + + return res; + } + + /** + * @notice Formats the the 256-byte format expected by the BLS12381_PAIRING_CHECK_PRECOMPILE into the + * 192-byte uncompressed BLS signature. + * @param signature The 256-byte BLS signature. Must have the format + * [16 pad + x.c0, 16 pad + x.c1, 16 pad + y.c0, 16 pad + y.c1]. + * @return The 192-byte uncompressed signature. Has the format [x.c1, x.c0, y.c1, y.c0] + */ + function getUncompressedBLSTSignature( + bytes memory signature + ) internal pure returns (bytes memory) { + require(signature.length == 256, "Invalid input signature length"); + bytes memory res = new bytes(192); + + // COPY X0 + for (uint256 i = 0; i < 48; i++) { + res[i + 48] = signature[16 + i]; + } + + // COPY X1 + for (uint256 i = 0; i < 48; i++) { + res[i] = signature[80 + i]; + } + + // COPY Y0 + for (uint256 i = 0; i < 48; i++) { + res[i + 144] = signature[144 + i]; + } + + // COPY Y1 + for (uint256 i = 0; i < 48; i++) { + res[i + 96] = signature[208 + i]; + } + + return res; + } + + /** + * @notice Aggregates a list of public keys. + * @param publicKeys The public keys to aggregate. Each public key must be in uncompressed, and its X and Y coordinates must be + * left-padded to be 64 bytes each, for a total of 128 bytes. + * @return The aggregated public key. + */ + function aggregatePublicKeys( + bytes[] memory publicKeys + ) internal view returns (bytes memory) { + // Use the BLS public key aggregation precompile to aggregate the public keys. + require(publicKeys.length > 0, "Missing public keys"); + bytes memory aggregatedPublicKey = publicKeys[0]; + for (uint256 i = 1; i < publicKeys.length; i++) { + aggregatedPublicKey = addG1(aggregatedPublicKey, publicKeys[i]); + } + return aggregatedPublicKey; + } + + /** + * @notice Create a signature over a message with a secret key. + * @dev According to the EIP-2537 spec, G2 MSM method can fail as it may not land on the curve or + * is not in the correct subgroup + * @param secretKey is a 256 bit scalar. + * @param message the message to be signed. + * @return The 192-byte uncompressed BLS signature + */ + function createSignature( + uint256 secretKey, + bytes memory message + ) internal view returns (bytes memory) { + return getUncompressedBLSTSignature(_createSignatureRaw(secretKey, message)); + } + + /** + * @notice Create an aggregate signature over a message with a list of secret keys. + * @dev According to the EIP-2537 spec, this method can fail as it may not land on the curve or + * is not in the correct subgroup + * @param secretKeys a vector 256 bit scalars. + * @param message the message to be signed. + * @return The 192-byte uncompressed aggregated BLS signature + */ + function createAggregateSignature( + uint256[] memory secretKeys, + bytes memory message + ) internal view returns (bytes memory) { + bytes memory sig = new bytes(256); + for (uint256 i = 0; i < secretKeys.length; i++) { + sig = addG2(sig, _createSignatureRaw(secretKeys[i], message)); + } + return getUncompressedBLSTSignature(sig); + } + + function _createSignatureRaw( + uint256 secretKey, + bytes memory message + ) private view returns (bytes memory) { + bytes memory messageG2 = hashToG2(message, BLS12381G2_SIG_DST); + bytes memory input = new bytes(288); + for (uint256 i = 0; i < 256; i++) { + input[i] = messageG2[i]; + } + bytes32 sk = bytes32(secretKey); + for (uint256 j = 0; j < 32; j++) { + input[256 + j] = sk[j]; + } + + (bool success, bytes memory result) = + BLS12381_G2_MSM_PRECOMPILE.staticcall(abi.encodePacked(input)); + require(success, "Failed to perform scalar multiplication over G2"); + return result; + } + + /** + * @notice Verifies a BLS12-381 signature of the given message using the given public key. + * @param publicKey The public key to verify the signature against. Must be in uncompressed, and its X and Y coordinates must be + * left-padded to be 64 bytes each, for a total of 128 bytes. + * @param signature The signature to verify. Must be in uncompressed form, 192 bytes long, and have the format [x.c1, x.c0, y.c1, y.c0]. + * This is the format used by the BLST library for the P2Affine.Serialize() function. + * @param message The message to verify the signature against. + * @return True if the signature is valid, false otherwise. + */ + function verifySignature( + bytes memory publicKey, + bytes memory signature, + bytes memory message + ) internal view returns (bool) { + return _verifySignature(publicKey, signature, message, BLS12381G2_SIG_DST); + } + + /** + * @notice Verifies a BLS12-381 aggregate signature of the given message using the given public keys. + * @param publicKeys The public keys to verify the signature against. Each public key must be in uncompressed, and its X and Y coordinates must be + * left-padded to be 64 bytes each, for a total of 128 bytes. + * @param signature The signature to verify. Must be in uncompressed form, 192 bytes long, and have the format [x.c1, x.c0, y.c1, y.c0]. + * This is the format used by the BLST library for the P2Affine.Serialize() function. + * @param message The message to verify the signature against. + * @return True if the signature is valid for the public key resulting from aggregating the given public keys, false otherwise. + */ + function verifyAggregateSignature( + bytes[] memory publicKeys, + bytes memory signature, + bytes memory message + ) internal view returns (bool) { + bytes memory aggregatePublicKey = aggregatePublicKeys(publicKeys); + return verifySignature(aggregatePublicKey, signature, message); + } + + /** + * @notice Verifies a BLS12-381 proof of possession of the given public key. + * @param publicKey The public key to verify the proof of possession against. Must be in uncompressed, and its X and Y coordinates must be + * left-padded to be 64 bytes each, for a total of 128 bytes. + * @param signature The signature to verify. Must be in uncompressed form, 192 bytes long, and have the format [x.c1, x.c0, y.c1, y.c0]. + * This is the format used by the BLST library for the P2Affine.Serialize() function. + * @param message The message to verify the proof of possession against. + * @return True if the proof of possession is valid, false otherwise. + */ + function verifyProofOfPossession( + bytes memory publicKey, + bytes memory signature, + bytes memory message + ) internal view returns (bool) { + return _verifySignature(publicKey, signature, message, BLS12381G2_POP_DST); + } + + /** + * @notice Hashes a message to the G2 curve + * @dev Original source: https://github.com/ethyla/bls12-381-hash-to-curve/blob/main/src/HashToCurve.sol + */ + function hashToG2( + bytes memory message, + bytes memory dst + ) internal view returns (bytes memory) { + FieldPoint2[2] memory u = hashToFieldFp2(message, dst); + bytes memory q0 = _mapFpToG2(u[0]); + bytes memory q1 = _mapFpToG2(u[1]); + return addG2(q0, q1); + } + + /** + * @notice Computes a field point from a message + * @dev Follows https://datatracker.ietf.org/doc/html/rfc9380#section-5.2 + * @param message Arbitrarylength byte string to be hashed + * @param dst The domain separation tag + * @return Two field points + */ + function hashToFieldFp2( + bytes memory message, + bytes memory dst + ) internal view returns (FieldPoint2[2] memory) { + // 1. len_in_bytes = count * m * L + // so always 2 * 2 * 64 = 256 + uint16 lenInBytes = 256; + // 2. uniform_bytes = expand_message(msg, DST, len_in_bytes) + bytes32[] memory pseudoRandomBytes = _expandMsgXmd(message, dst, lenInBytes); + FieldPoint2[2] memory u; + // No loop here saves 800 gas hardcoding offset an additional 300 + // 3. for i in (0, ..., count - 1): + // 4. for j in (0, ..., m - 1): + // 5. elm_offset = L * (j + i * m) + // 6. tv = substr(uniform_bytes, elm_offset, HTF_L) + // uint8 HTF_L = 64; + // bytes memory tv = new bytes(64); + // 7. e_j = OS2IP(tv) mod p + // 8. u_i = (e_0, ..., e_(m - 1)) + // tv = bytes.concat(pseudo_random_bytes[0], pseudo_random_bytes[1]); + u[0].u = _modfield(pseudoRandomBytes[0], pseudoRandomBytes[1]); + u[0].u_I = _modfield(pseudoRandomBytes[2], pseudoRandomBytes[3]); + u[1].u = _modfield(pseudoRandomBytes[4], pseudoRandomBytes[5]); + u[1].u_I = _modfield(pseudoRandomBytes[6], pseudoRandomBytes[7]); + // 9. return (u_0, ..., u_(count - 1)) + return u; + } + + /** + * @notice Adds two G1 points + * @param p0 The first G1 point + * @param p1 The second G1 point + * @return The sum of the two G1 points + */ + function addG1(bytes memory p0, bytes memory p1) internal view returns (bytes memory) { + require(p0.length == 128 && p1.length == 128, "Invalid G1 point length"); + (bool success, bytes memory result) = + BLS12381_G1_ADD_PRECOMPILE.staticcall(abi.encodePacked(p0, p1)); + require(success, "Failed to add G1 points"); + return result; + } + + /** + * @notice Adds two G2 points + * @param q0 The first G2 point + * @param q1 The second G2 point + * @return The sum of the two G2 points + */ + function addG2(bytes memory q0, bytes memory q1) internal view returns (bytes memory) { + require(q0.length == 256 && q1.length == 256, "Invalid G2 point length"); + bytes memory addG2input = abi.encodePacked(q0, q1); + (bool success, bytes memory output) = BLS12381_G2_ADD_PRECOMPILE.staticcall(addG2input); + require(success, "Failed to add G2 points"); + return output; + } + + function _verifySignature( + bytes memory publicKey, + bytes memory signature, + bytes memory message, + bytes memory dst + ) private view returns (bool) { + // Check the input lengths + require(publicKey.length == 128, "Invalid public key length"); + require(signature.length == 192, "Invalid signature length"); + + // Hash the message to the G2 curve + bytes memory messageG2 = hashToG2(message, dst); + + bytes memory pairingCheckInput = abi.encodePacked( + publicKey, messageG2, BLS_G1_NEG_GENERATOR, formatUncompressedBLSTSignature(signature) + ); + (bool success, bytes memory output) = + BLS12381_PAIRING_CHECK_PRECOMPILE.staticcall(pairingCheckInput); + require(success, "Failed to perform pairing check"); + require(output.length == 32, "Invalid pairing check output length"); + return uint256(bytes32(output)) == 1; + } + + /** + * @dev Maps a field point to a G2 point + * @param fp2 The field point to map + * @return The G2 point + */ + function _mapFpToG2( + FieldPoint2 memory fp2 + ) private view returns (bytes memory) { + bytes memory mapFp2ToG2input = abi.encodePacked(fp2.u[0], fp2.u[1], fp2.u_I[0], fp2.u_I[1]); + (bool success, bytes memory output) = + BLS12381_MAP_FP2_G2_PRECOMPILE.staticcall(mapFp2ToG2input); + require(success, "Failed to map Fp2 to G2"); + return output; + } + + /** + * @notice Computes a field point from a message + * @dev Follows https://datatracker.ietf.org/doc/html/rfc9380#section-5.3 + * @dev bytes32[] because len_in_bytes is always a multiple of 32 in our case even 128 + * @param message Arbitrarylength byte string to be hashed + * @param dst The domain separation tag of at most 255 bytes + * @param lenInBytes The length of the requested output in bytes + * @return A field point + */ + function _expandMsgXmd( + bytes memory message, + bytes memory dst, + uint16 lenInBytes + ) private pure returns (bytes32[] memory) { + // 1. ell = ceil(len_in_bytes / b_in_bytes) + // b_in_bytes seems to be 32 for sha256 + // ceil the division + uint256 ell = (lenInBytes - 1) / 32 + 1; + + // 2. ABORT if ell > 255 or len_in_bytes > 65535 or len(DST) > 255 + require(ell <= 255, "len_in_bytes too large for sha256"); + // Not really needed because of parameter type + // require(lenInBytes <= 65535, "len_in_bytes too large"); + // no length normalizing via hashing + require(dst.length <= 255, "dst too long"); + + bytes memory dstPrime = bytes.concat(dst, bytes1(uint8(dst.length))); + + // 4. Z_pad = I2OSP(0, s_in_bytes) + // this should be sha256 blocksize so 64 bytes + // bytes + // memory zPad = hex"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + // spliting like below saves 250 gas + bytes32 zPad1 = hex"0000000000000000000000000000000000000000000000000000000000000000"; + bytes32 zPad2 = hex"0000000000000000000000000000000000000000000000000000000000000000"; + + // 5. l_i_b_str = I2OSP(len_in_bytes, 2) + // length in bytes string + bytes2 libStr = bytes2(lenInBytes); + + // 6. msg_prime = Z_pad || msg || l_i_b_str || I2OSP(0, 1) || DST_prime + bytes memory msgPrime = bytes.concat(zPad1, zPad2, message, libStr, hex"00", dstPrime); + + bytes32 b_0; + bytes32[] memory b = new bytes32[](ell); + + // 7. b_0 = H(msg_prime) + b_0 = sha256(msgPrime); + + // 8. b_1 = H(b_0 || I2OSP(1, 1) || DST_prime) + b[0] = sha256(bytes.concat(b_0, hex"01", dstPrime)); + + // 9. for i in (2, ..., ell): + for (uint8 i = 2; i <= ell; i++) { + // 10. b_i = H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime) + bytes memory tmp = abi.encodePacked(b_0 ^ b[i - 2], i, dstPrime); + b[i - 1] = sha256(tmp); + } + // 11. uniform_bytes = b_1 || ... || b_ell + // 12. return substr(uniform_bytes, 0, len_in_bytes) + // Here we don't need the uniform_bytes because b is already properly formed + return b; + } + + /** + * @dev Computes the mod against the bls12-381 field modulus + */ + function _modfield(bytes32 _b1, bytes32 _b2) private view returns (bytes32[2] memory r) { + assembly { + let bl := 0x40 + let ml := 0x40 + + let freemem := mload(0x40) // Free memory pointer is always stored at 0x40 + + // arg[0] = base.length @ +0 + mstore(freemem, bl) + // arg[1] = exp.length @ +0x20 + mstore(add(freemem, 0x20), 0x20) + // arg[2] = mod.length @ +0x40 + mstore(add(freemem, 0x40), ml) + + // arg[3] = base.bits @ + 0x60 + // places the first 32 bytes of _b1 and the last 32 bytes of _b2 + mstore(add(freemem, 0x60), _b1) + mstore(add(freemem, 0x80), _b2) + + // arg[4] = exp.bits @ +0x60+base.length + // exponent always 1 + mstore(add(freemem, 0xa0), 1) + + // arg[5] = mod.bits @ +96+base.length+exp.length + // this field_modulus as hex 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787 + // we add the 0 prefix so that the result will be exactly 64 bytes + // saves 300 gas per call instead of sending it along every time + // places the first 32 bytes and the last 32 bytes of the field modulus + mstore( + add(freemem, 0xc0), + 0x000000000000000000000000000000001a0111ea397fe69a4b1ba7b6434bacd7 + ) + mstore( + add(freemem, 0xe0), + 0x64774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab + ) + + // Invoke contract 0x5, put return value right after mod.length, @ 0x60 + let success := + staticcall( + sub(gas(), 1350), // gas + 0x5, // mpdexp precompile + freemem, //input offset + 0x100, // input size = 0x60+base.length+exp.length+mod.length + freemem, // output offset + ml // output size + ) + switch success + case 0 { invalid() } //fail where we haven't enough gas to make the call + + // point to mod length, result was placed immediately after + r := freemem + //adjust freemem pointer + mstore(0x40, add(freemem, ml)) + } + } +} diff --git a/ethereum/contracts/utils/ByteComparator.sol b/ethereum/contracts/utils/ByteComparator.sol new file mode 100644 index 000000000..519722220 --- /dev/null +++ b/ethereum/contracts/utils/ByteComparator.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +/** + * @title ByteComparator + * @notice Library for comparing byte arrays lexicographically + */ +library ByteComparator { + /** + * @notice Compares two bytes arrays lexicographically + * @param a First byte array to compare + * @param b Second byte array to compare + * @return Returns 0 if a == b, -1 if a < b, and +1 if a > b + */ + function compare(bytes memory a, bytes memory b) internal pure returns (int256) { + if (a.length == 0 && b.length == 0) { + return 0; + } + if (a.length == 0) { + return 1; + } + if (b.length == 0) { + return 1; + } + + uint256 minLength = a.length < b.length ? a.length : b.length; + + for (uint256 i = 0; i < minLength; i++) { + if (a[i] < b[i]) { + return -1; + } + if (a[i] > b[i]) { + return 1; + } + } + + if (a.length < b.length) { + return -1; + } + if (a.length > b.length) { + return 1; + } + + return 0; + } +} diff --git a/ethereum/contracts/utils/ByteSlicer.sol b/ethereum/contracts/utils/ByteSlicer.sol new file mode 100644 index 000000000..dea82a867 --- /dev/null +++ b/ethereum/contracts/utils/ByteSlicer.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +/** + * @title ByteSlicer + * @notice Utility library for slicing bytes arrays + * @dev This library provides helper functions for working with bytes arrays + */ +library ByteSlicer { + /** + * @notice Slices a bytes array from a given start index for a given length. + * @param data The bytes array to slice. + * @param start The starting index (inclusive). + * @param length The number of bytes to slice. + * @return result The sliced bytes array. + */ + function slice(bytes memory data, uint256 start, uint256 length) internal pure returns (bytes memory result) { + require(data.length >= start + length, "ByteSlicer: out of bounds"); + result = new bytes(length); + for (uint256 i = 0; i < length; i++) { + result[i] = data[start + i]; + } + } + + + /** + * @notice Add the source bytes to the target bytes at the indicated position + * @param target the array be extended + * @param source the array be copied to target + * @param cursor the position in target to start copying source to. Typically the end + * @return the new ending position of target + */ + function extendFromSlice( + bytes memory target, + bytes memory source, + uint256 cursor + ) public pure returns (bytes memory, uint256){ + uint256 length = source.length; + for (uint256 i = 0; i < length; i++) { + target[cursor + i] = source[i]; + } + return (target, cursor + length); + } +} diff --git a/ethereum/contracts/utils/ICM.sol b/ethereum/contracts/utils/ICM.sol new file mode 100644 index 000000000..9ff192698 --- /dev/null +++ b/ethereum/contracts/utils/ICM.sol @@ -0,0 +1,376 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {WarpMessage} from "@avalabs/subnet-evm-contracts@1.2.2/contracts/interfaces/IWarpMessenger.sol"; +import { + ICMMessage, + ICMUnsignedMessage, + ICMSignature +} from "@avalabs/avalanche-contracts/teleporter/ITeleporterMessenger.sol"; +import {Validator, ValidatorSet} from "../utils/ValidatorSets.sol"; +import {BLST} from "./BLST.sol"; +import {ByteSlicer} from "./ByteSlicer.sol"; + +struct AddressedCall { + bytes sourceAddress; + bytes payload; +} + +/** + * @title ICM + * @notice Utility library for Interchain Messaging (ICM) operations + * @dev This library provides helper functions for working with ICM signatures and validation + */ +library ICM { + uint256 constant QUORUM_NUM = 67; + uint256 constant QUORUM_DEN = 100; + + /** + * @dev Converts a bytes array to a bool[] array + * @param data The bytes array to convert + * @return A bool[] array where each element is true if the corresponding bit is 1, false otherwise + */ + function bytesToBoolArray( + bytes memory data + ) internal pure returns (bool[] memory) { + require(data.length > 0 && data[0] != 0x00, "Invalid bit set"); + + // Find the position of the most significant bit in the first byte + // This determines how many leading zeros we have + uint8 firstByte = uint8(data[0]); + uint256 leadingZeros = 0; + uint8 mask = 0x80; // Start with 10000000 + + while ((firstByte & mask) == 0) { + leadingZeros++; + mask >>= 1; + } + + // Calculate the final result size (total bits minus leading zeros) + uint256 totalBits = data.length * 8; + uint256 resultSize = totalBits - leadingZeros; + + // Create result array with the exact size needed + bool[] memory result = new bool[](resultSize); + + // Fill the result array directly, starting from the first significant bit + uint256 resultIndex = 0; + + // Process all bytes, skipping leading zeros in the first byte + for (uint256 i = 0; i < data.length; ++i) { + uint256 startJ = (i == 0) ? leadingZeros : 0; + for (uint256 j = startJ; j < 8; ++j) { + result[resultIndex] = (uint8(data[i]) & (1 << (7 - j))) != 0; + resultIndex++; + } + } + + return result; + } + + function parseICMMessage( + bytes memory data + ) internal pure returns (ICMMessage memory) { + ICMUnsignedMessage memory unsignedMessage = parseICMUnsignedMessage(data); + uint32 payloadLength = uint32(unsignedMessage.payload.length); + // Parse the unsigned message bytes + bytes memory unsignedMessageBytes = ByteSlicer.slice(data, 0, 42 + payloadLength); + + // Check that the signature type ID is 0 + uint32 signatureType = uint32(bytes4(ByteSlicer.slice(data, 42 + payloadLength, 4))); + require(signatureType == 0, "Invalid signature type ID"); + + // Parse the bit set length + uint32 bitSetLength = uint32(bytes4(ByteSlicer.slice(data, 46 + payloadLength, 4))); + + // Parse the bit set + bytes memory bitSet = ByteSlicer.slice(data, 50 + payloadLength, bitSetLength); + + // Check that there are exactly 96 bytes remaining, and parse them as the signature + require(data.length == 50 + payloadLength + bitSetLength + 192, "Invalid signature length"); + bytes memory signature = ByteSlicer.slice(data, 50 + payloadLength + bitSetLength, 192); + + return ICMMessage({ + unsignedMessage: unsignedMessage, + unsignedMessageBytes: unsignedMessageBytes, + signature: ICMSignature({signers: bitSet, signature: signature}) + }); + } + + function parseICMUnsignedMessage( + bytes memory data + ) internal pure returns (ICMUnsignedMessage memory) { + // Validate the codec ID is 0 + require(data[0] == 0 && data[1] == 0, "Invalid codec ID"); + + // Parse the avalancheNetworkID + uint32 avalancheNetworkID = uint32(bytes4(ByteSlicer.slice(data, 2, 4))); + + // Parse the avalancheSourceBlockchainID + bytes32 avalancheSourceBlockchainID = abi.decode(ByteSlicer.slice(data, 6, 32), (bytes32)); + + // Parse the payload + uint32 payloadLength = uint32(bytes4(ByteSlicer.slice(data, 38, 4))); + bytes memory payload = ByteSlicer.slice(data, 42, payloadLength); + return ICMUnsignedMessage({ + avalancheNetworkID: avalancheNetworkID, + avalancheSourceBlockchainID: avalancheSourceBlockchainID, + payload: payload + }); + } + + /** + * @notice Serialize an ICM unsigned message to bytes. + */ + function serializeICMUnsignedMessage( + ICMUnsignedMessage memory message + ) internal pure returns (bytes memory) { + bytes memory serialized = new bytes( + // the codec + 2 + // the avalancheNetworkID + + 4 + // the avalancheSourceBlockchainID + + 32 + // the payload length + + 4 + // the message payload + + message.payload.length + ); + // the codec + serialized[0] = 0x00; + serialized[1] = 0x00; + // encode the avalancheNetworkID + bytes4 avalancheNetworkID = bytes4(message.avalancheNetworkID); + for (uint256 i = 0; i < 4; i++) { + serialized[2 + i] = avalancheNetworkID[i]; + } + // encode the avalancheSourceBlockchainID + for (uint256 i = 0; i < 32; i++) { + serialized[6 + i] = message.avalancheSourceBlockchainID[i]; + } + // encode the payload length + bytes4 payloadLength = bytes4(uint32(message.payload.length)); + for (uint256 i = 0; i < 4; i++) { + serialized[38 + i] = payloadLength[i]; + } + // encode the payload + for (uint256 i = 0; i < message.payload.length; i++) { + serialized[42 + i] = message.payload[i]; + } + + return serialized; + } + + /** + * @notice Serialize an ICM message to bytes + */ + function serializeICMMessage( + ICMMessage memory message + ) internal pure returns (bytes memory) { + + bytes memory data = new bytes( + // unsigned message length + message.unsignedMessageBytes.length + + 4 + // to encode the length of the serialize bitset + + 4 + // the length of the serialized bitset + + message.signature.signers.length + // the signature + + message.signature.signature.length + ); + uint256 cursor = 0; + // add the unsigned message bytes + (data, cursor) = ByteSlicer.extendFromSlice(data, message.unsignedMessageBytes, cursor); + + (data, cursor) = ByteSlicer.extendFromSlice(data, new bytes(4), cursor); + + // add the length of the signers (as a bitset) + bytes4 bitsetLength = bytes4(uint32(message.signature.signers.length)); + for (uint256 i = 0; i < 4; i++) { + data[cursor + i] = bitsetLength[i]; + } + cursor += 4; + + // add the signers bitset + (data, cursor) = ByteSlicer.extendFromSlice(data, message.signature.signers, cursor); + // add the signature bytes + (data, cursor) = ByteSlicer.extendFromSlice(data, message.signature.signature, cursor); + + return data; + } + + function parseAddressedCall( + bytes memory data + ) internal pure returns (AddressedCall memory) { + // Validate the codec ID is 0. + require(data[0] == 0 && data[1] == 0, "Invalid codec ID"); + + // Parse the payload type ID, and confirm it is 1 for AddressedCall + uint32 payloadTypeID = uint32(bytes4(ByteSlicer.slice(data, 2, 4))); + require(payloadTypeID == 1, "Invalid payload type ID"); + // Parse the source address length + uint32 sourceAddressLength = uint32(bytes4(ByteSlicer.slice(data, 6, 4))); + // Parse the source address + bytes memory sourceAddress = ByteSlicer.slice(data, 10, sourceAddressLength); + + // Parse the payload length + uint32 payloadLength = uint32(bytes4(ByteSlicer.slice(data, 10 + sourceAddressLength, 4))); + + // Parse the payload + bytes memory payload = ByteSlicer.slice(data, 14 + sourceAddressLength, payloadLength); + + return AddressedCall({sourceAddress: sourceAddress, payload: payload}); + } + + function serializeAddressedCall( + AddressedCall memory addressedCall + ) internal pure returns (bytes memory) { + bytes memory serialized = new bytes( + // codec bytes + 2 + // payload type ID + + 4 + // length of the source address + + 4 + // the source address + + addressedCall.sourceAddress.length + // length of the payload + + 4 + // the payload + + addressedCall.payload.length + ); + // encode the codec + serialized[0] = 0x00; + serialized[1] = 0x00; + // encode the payload type ID + serialized[2] = 0x00; + serialized[3] = 0x00; + serialized[4] = 0x00; + serialized[5] = 0x01; + // encode the source address length + bytes4 sourceAddrLength = bytes4(uint32(addressedCall.sourceAddress.length)); + for (uint256 i = 0; i < 4; i++) { + serialized[6 + i] = sourceAddrLength[i]; + } + // encode the the source address + for (uint256 i = 0; i < addressedCall.sourceAddress.length; i++) { + serialized[10 + i] = addressedCall.sourceAddress[i]; + } + // encode the payload length + bytes4 payloadLength = bytes4(uint32(addressedCall.payload.length)); + for (uint256 i = 0; i < 4; i++) { + serialized[10 + addressedCall.sourceAddress.length + i] = payloadLength[i]; + } + // encode the payload + for (uint256 i = 0; i < addressedCall.payload.length; i++) { + serialized[14 + addressedCall.sourceAddress.length + i] = addressedCall.payload[i]; + } + + return serialized; + } + + function filterValidators( + bool[] memory signers, + Validator[] memory validators + ) internal view returns (bytes memory, uint64) { + require( + signers.length <= validators.length, + "Signers length must be less than or equal to validators length" + ); + bytes memory aggregatePublicKey; + uint64 aggregateWeight = 0; + for (uint256 i = 0; i < validators.length; ++i) { + if (i < signers.length && signers[signers.length - i - 1]) { + // Cache the validator to avoid repeated array access + Validator memory validator = validators[i]; + + if (aggregateWeight > 0) { + aggregatePublicKey = BLST.addG1(aggregatePublicKey, validator.blsPublicKey); + aggregateWeight += validator.weight; + } else { + aggregatePublicKey = validator.blsPublicKey; + aggregateWeight = validator.weight; + } + } + } + return (aggregatePublicKey, aggregateWeight); + } + + // Verifies that quorumNum * totalWeight <= quorumDen * signatureWeight + function verifyWeight( + uint64 signatureWeight, + uint64 totalWeight + ) internal pure returns (bool) { + uint256 scaledTotalWeight = QUORUM_NUM * uint256(totalWeight); + uint256 scaledSignatureWeight = QUORUM_DEN * uint256(signatureWeight); + return scaledTotalWeight <= scaledSignatureWeight; + } + + function verifyICMMessage( + ICMMessage memory message, + uint32 avalancheNetworkID, + bytes32 avalancheBlockChainID, + ValidatorSet memory validatorSet + ) internal view returns (bool) { + if (message.unsignedMessage.avalancheNetworkID != avalancheNetworkID) { + revert("Invalid avalanche network ID"); + } + + // TODO: Do we need to check the avalanche source blockchain ID? + // It's expected to be different in cases where the message is from the primary network. + // if ( + // message.unsignedMessage.avalancheSourceBlockchainID + // != validatorSet.avalancheBlockchainID + // ) { + // revert("Invalid avalanche source blockchain ID"); + // } + + + if ( + avalancheBlockChainID != validatorSet.avalancheBlockchainID + ) { + revert("Invalid avalanche source blockchain ID"); + } + + bool[] memory signers = bytesToBoolArray(message.signature.signers); + (bytes memory aggregatePublicKey, uint64 aggregateWeight) = + filterValidators(signers, validatorSet.validators); + + if (!verifyWeight(aggregateWeight, validatorSet.totalWeight)) { + revert("Invalid weight"); + } + + bool result = BLST.verifySignature( + aggregatePublicKey, message.signature.signature, message.unsignedMessageBytes + ); + if (!result) { + revert("Invalid signature"); + } + return result; + } + + /** + * @notice Convert the unsigned part of an ICM message to Warp message. This should + * be called after an ICM message has been verified. + * @dev This function should only be called when communicating with an external + * chain. If used during internal interop, the teleport contracts will reject the + * `originSenderAddress`. + * + * This function loosely reproduces the logic of the handleMessage method used in the + * Warp precompile. + * @param message The unsigned part of an ICM message + * @return A Warp message + */ + function handleMessage(ICMUnsignedMessage memory message, bytes32 sourceChainID ) internal pure returns (WarpMessage memory) { + AddressedCall memory addressedCall = parseAddressedCall(message.payload); + return WarpMessage({ + sourceChainID: sourceChainID, + // N.B. This prevents this function from being used for internal interop calls + // to teleporter + originSenderAddress: address(0), + payload: addressedCall.payload + }); + } +} diff --git a/ethereum/contracts/utils/ValidatorSets.sol b/ethereum/contracts/utils/ValidatorSets.sol new file mode 100644 index 000000000..d5c95663a --- /dev/null +++ b/ethereum/contracts/utils/ValidatorSets.sol @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.30; + +import {ByteSlicer} from "./ByteSlicer.sol"; +import {BLST} from "./BLST.sol"; +import {ByteComparator} from "./ByteComparator.sol"; + +struct Validator { + bytes blsPublicKey; + uint64 weight; +} + +struct ValidatorSet { + bytes32 avalancheBlockchainID; + Validator[] validators; + uint64 totalWeight; + uint64 pChainHeight; + uint64 pChainTimestamp; +} + +struct ValidatorSetStatePayload { + bytes32 avalancheBlockchainID; + uint64 pChainHeight; + uint64 pChainTimestamp; + bytes32 validatorSetHash; +} + +library ValidatorSets { + /** + * @notice Parses the validators from a serialized validator set + * @param data The serialized validator set. The serialized format is: + * - 2 bytes: codec ID (0x0000) + * - 4 bytes: number of validators + * - 96 bytes per validator: unformatted BLS public key + * - 8 bytes per validator: weight + * @return validators The parsed validators + * @return totalWeight The total weight of all validators + */ + function parseValidators( + bytes memory data + ) internal pure returns (Validator[] memory, uint64) { + // Check the codec ID is 0 + require(data[0] == 0 && data[1] == 0, "Invalid codec ID"); + + // Parse the number of validators + uint32 numValidators = uint32(bytes4(ByteSlicer.slice(data, 2, 4))); + + // Parse the validators + Validator[] memory validators = new Validator[](numValidators); + uint64 totalWeight = 0; + uint256 offset = 6; + bytes memory previousPublicKey = new bytes(BLST.BLS_UNCOMPRESSED_PUBLIC_KEY_INPUT_LENGTH); + for (uint32 i = 0; i < numValidators; i++) { + bytes memory unformattedPublicKey = ByteSlicer.slice(data, offset, 96); + require( + ByteComparator.compare(unformattedPublicKey, previousPublicKey) > 0, + "BLS public key must be greater than the latest public key" + ); + uint64 weight = uint64(bytes8(ByteSlicer.slice(data, offset + 96, 8))); + require(weight > 0, "Validator weight must be greater than 0"); + validators[i] = Validator({ + blsPublicKey: BLST.formatUncompressedBLSPublicKey(unformattedPublicKey), + weight: weight + }); + totalWeight += weight; + offset += 104; + } + return (validators, totalWeight); + } + + function serializeValidators( + Validator[] memory validators + ) public pure returns (bytes memory) { + bytes memory serialized = new bytes( + 2 + 4 + validators.length * (96 + 8) + ); + // the codec + serialized[0] = 0x00; + serialized[1] = 0x00; + //encode the number of validators + bytes4 numValidators = bytes4(uint32(validators.length)); + for (uint256 i = 0; i < 4; i++) { + serialized[2 + i] = numValidators[i]; + } + // encode the validators + uint256 offset = 6; + for (uint256 i = 0; i < validators.length; i++) { + // encode the 96-bytes uncompressed BLS public key + bytes memory uncompressedBlsPublicKey = BLST.getUncompressedBlsPublicKey(validators[i].blsPublicKey); + for(uint256 j = 0; j < 96; j++ ) { + serialized[j + offset] = uncompressedBlsPublicKey[j]; + } + offset += 96; + // encode the validator weight + bytes8 weight = bytes8(validators[i].weight); + for(uint256 j = 0; j < 8; j++ ) { + serialized[j + offset] = weight[j]; + } + offset += 8; + } + return serialized; + } + + function parseValidatorSetStatePayload( + bytes memory data + ) internal pure returns (ValidatorSetStatePayload memory) { + // Check the codec ID is 0 + require(data[0] == 0 && data[1] == 0, "Invalid codec ID"); + + // Parse the payload type ID, and confirm it is 4 for ValidatorSetState + uint32 payloadTypeID = uint32(bytes4(ByteSlicer.slice(data, 2, 4))); + require(payloadTypeID == 4, "Invalid ValidatorSetState payload type ID"); + + // Parse the avalancheBlockchainID + bytes32 avalancheBlockchainID = abi.decode(ByteSlicer.slice(data, 6, 32), (bytes32)); + + // Parse the pChainHeight + uint64 pChainHeight = uint64(bytes8(ByteSlicer.slice(data, 38, 8))); + + // Parse the pChainTimestamp + uint64 pChainTimestamp = uint64(bytes8(ByteSlicer.slice(data, 46, 8))); + + // Parse the validatorSetHash + bytes32 validatorSetHash = abi.decode(ByteSlicer.slice(data, 54, 32), (bytes32)); + + return ValidatorSetStatePayload({ + avalancheBlockchainID: avalancheBlockchainID, + pChainHeight: pChainHeight, + pChainTimestamp: pChainTimestamp, + validatorSetHash: validatorSetHash + }); + } + + function serializeValidatorSetStatePayload( + ValidatorSetStatePayload memory payload + ) public pure returns (bytes memory) { + bytes memory serialized = new bytes( + // codec + 2 + // payload type ID + + 4 + // Avalanche block chain ID + + 32 + // the P-chain height + + 8 + // the P-chain timestamp + + 8 + // hash of validator set + + 32 + ); + // encode the codec + serialized[0] = 0x00; + serialized[1] = 0x00; + // the payload type ID + serialized[2] = 0x00; + serialized[3] = 0x00; + serialized[4] = 0x00; + serialized[5] = 0x04; + // encode avalancheBlockchainID + for (uint256 i = 0; i < 32; i++) { + serialized[6 + i] = payload.avalancheBlockchainID[i]; + } + // encode the P-chain block height + bytes8 pChainHeight = bytes8(payload.pChainHeight); + for (uint256 i = 0; i < 8; i++) { + serialized[38 + i] = pChainHeight[i]; + } + // encode the P-chain timestamp + bytes8 pChainTimestamp = bytes8(payload.pChainTimestamp); + for (uint256 i = 0; i < 8; i++) { + serialized[46 + i] = pChainTimestamp[i]; + } + // encode the validator set hash + for (uint256 i = 0; i < 32; i++) { + serialized[54 + i] = payload.validatorSetHash[i]; + } + return serialized; + } +} diff --git a/ethereum/docker/Dockerfile.geth b/ethereum/docker/Dockerfile.geth new file mode 100644 index 000000000..3bb223212 --- /dev/null +++ b/ethereum/docker/Dockerfile.geth @@ -0,0 +1,30 @@ +FROM ubuntu:24.04 + +# Install dependencies +RUN apt-get update && \ + apt-get install -y wget ca-certificates psmisc && \ + rm -rf /var/lib/apt/lists/* + +# Set Geth version with commit hash +# The "12b4131f" is the commit hash for the official v1.16.1 release of geth. +# See: https://geth.ethereum.org/downloads/ and https://github.com/ethereum/go-ethereum/releases/tag/v1.16.1 +ARG GETH_VERSION=v1.16.1-12b4131f + +# Download and install geth +RUN wget https://gethstore.blob.core.windows.net/builds/geth-linux-amd64-${GETH_VERSION#v}.tar.gz && \ + tar -xzf geth-linux-amd64-${GETH_VERSION#v}.tar.gz && \ + cp geth-linux-amd64-${GETH_VERSION#v}/geth /usr/local/bin/ && \ + rm -rf geth-linux-amd64-${GETH_VERSION#v}* + +# Set working directory +WORKDIR /ethereum + +# Copy configuration files and scripts +COPY docker/genesis.json /ethereum/genesis.json +COPY docker/run_ethereum_network.sh /ethereum/run_ethereum_network.sh + +# Make the script executable +RUN chmod +x /ethereum/run_ethereum_network.sh + +# Verify installation +RUN geth version diff --git a/ethereum/docker/genesis.json b/ethereum/docker/genesis.json new file mode 100644 index 000000000..dcf8bd7a6 --- /dev/null +++ b/ethereum/docker/genesis.json @@ -0,0 +1,49 @@ +{ + "config": { + "chainId": 1337, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "arrowGlacierBlock": 0, + "grayGlacierBlock": 0, + "mergeNetsplitBlock": 0, + "shanghaiTime": 0, + "cancunTime": 0, + "pragueTime": 0, + "terminalTotalDifficulty": 0, + "terminalTotalDifficultyPassed": true, + "blobSchedule": { + "cancun": { + "target": 3, + "max": 6, + "baseFeeUpdateFraction": 3338477 + }, + "prague": { + "target": 3, + "max": 6, + "baseFeeUpdateFraction": 3338477 + } + } + }, + "coinbase": "0x0000000000000000000000000000000000000000", + "difficulty": "0x0", + "extraData": "", + "gasLimit": "0x2fefd8", + "nonce": "0x0000001234000042", + "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "timestamp": "0x00", + "alloc": { + "6288dadf62b57dd9a4ddcd02f88a98d0eb6c2598": { + "balance": "13000000000000000000000000" + } + } +} diff --git a/ethereum/docker/run_ethereum_network.sh b/ethereum/docker/run_ethereum_network.sh new file mode 100755 index 000000000..f556b86f7 --- /dev/null +++ b/ethereum/docker/run_ethereum_network.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +# Exit on any errors +set -e + +original_dir=$(pwd) +data_dir=~/.local_geth_network + +function delete_old_files() { + rm -rf $data_dir +} + +_term() { # Cleanup when Docker Compose sends a SIGTERM + echo "Cleaning up..." + killall geth + delete_old_files + exit 0 +} + +trap _term INT # Cleanup child processes and write log on Ctrl+C +trap _term SIGTERM # Cleanup when Docker Compose kills the container + +# Delete old nodes +delete_old_files + +# Initialize new node +mkdir -p $data_dir +echo "Creating genesis..." +geth init --datadir $data_dir genesis.json + +# Start the node +echo "Starting Geth node..." +geth --dev --http --http.addr "0.0.0.0" --http.port "5050" --http.vhosts "geth,localhost" --http.corsdomain "0.0.0.0" --datadir $data_dir --http.api "eth,net,web3" --dev.period 1 & +node_pid=$! + +# Wait for the node to start +until [ -e "$data_dir/geth.ipc" ] +do + echo 'Waiting on geth.ipc socket to be present...' + sleep 1 +done + +echo "Successfully started network." + +wait $node_pid + diff --git a/ethereum/foundry.toml b/ethereum/foundry.toml new file mode 100644 index 000000000..35ceb9aed --- /dev/null +++ b/ethereum/foundry.toml @@ -0,0 +1,33 @@ +[profile.default] +src = "contracts" +out = "out" +libs = ["lib"] +solc_version = '0.8.30' +evm_version = 'prague' +via_ir = true +test = 'tests' +bytecode_hash = "none" +optimizer = true +optimizer_runs = 200 + +[fmt] +line_length = 100 +tab_width = 4 +bracket_spacing = false +int_types = 'preserve' +multiline_func_header = 'params_first' +quote_style = 'double' +number_underscores = 'thousands' +override_spacing = true +wrap_comments = false + +# Add the following to your VSCode settings to enable automatic formatting. +# { +# "editor.formatOnSave": true, +# "[solidity]": { +# "editor.defaultFormatter": "JuanBlanco.solidity" +# }, +# "solidity.formatter": "forge", +# } + +# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options diff --git a/ethereum/lib/forge-std b/ethereum/lib/forge-std new file mode 160000 index 000000000..77041d2ce --- /dev/null +++ b/ethereum/lib/forge-std @@ -0,0 +1 @@ +Subproject commit 77041d2ce690e692d6e03cc812b57d1ddaa4d505 diff --git a/ethereum/remappings.txt b/ethereum/remappings.txt new file mode 100644 index 000000000..cd382034e --- /dev/null +++ b/ethereum/remappings.txt @@ -0,0 +1,2 @@ +@avalabs/subnet-evm-contracts@1.2.2=../avalanche/lib/subnet-evm/contracts +@avalabs/avalanche-contracts=../avalanche/contracts \ No newline at end of file diff --git a/go.mod b/go.mod index 7d664b487..0f56a89d0 100644 --- a/go.mod +++ b/go.mod @@ -3,13 +3,13 @@ module github.com/ava-labs/icm-contracts go 1.23.11 require ( - github.com/ava-labs/avalanchego v1.13.2 + github.com/ava-labs/avalanchego v1.13.4-0.20250724134817-e387b32bd5eb github.com/supranational/blst v0.3.14 // indirect ) require ( github.com/ava-labs/libevm v1.13.14-0.3.0.rc.1 - github.com/ava-labs/subnet-evm v0.7.5 + github.com/ava-labs/subnet-evm v0.7.7-rc.0 github.com/onsi/ginkgo/v2 v2.23.4 github.com/onsi/gomega v1.37.0 github.com/pkg/errors v0.9.1 @@ -23,9 +23,10 @@ require ( require ( github.com/DataDog/zstd v1.5.2 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect - github.com/StephenButtolph/canoto v0.15.0 // indirect + github.com/StephenButtolph/canoto v0.17.1 // indirect github.com/VictoriaMetrics/fastcache v1.12.1 // indirect - github.com/ava-labs/coreth v0.15.2-rc.0.0.20250620163936-0058a7ec6d9d // indirect + github.com/ava-labs/coreth v0.15.3-rc.1 // indirect + github.com/ava-labs/firewood-go-ethhash/ffi v0.0.8 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.10.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect @@ -53,7 +54,7 @@ require ( github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 // indirect github.com/getsentry/sentry-go v0.18.0 // indirect - github.com/go-cmd/cmd v1.4.1 // indirect + github.com/go-cmd/cmd v1.4.3 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect @@ -148,7 +149,7 @@ require ( golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e // indirect golang.org/x/mod v0.26.0 // indirect golang.org/x/net v0.42.0 // indirect - golang.org/x/oauth2 v0.23.0 // indirect + golang.org/x/oauth2 v0.27.0 // indirect golang.org/x/sync v0.16.0 // indirect golang.org/x/sys v0.34.0 // indirect golang.org/x/term v0.33.0 // indirect diff --git a/go.sum b/go.sum index 0da451d41..597106d8c 100644 --- a/go.sum +++ b/go.sum @@ -49,8 +49,8 @@ github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKz github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= -github.com/StephenButtolph/canoto v0.15.0 h1:3iGdyTSQZ7/y09WaJCe0O/HIi53ZyTrnmVzfCqt64mM= -github.com/StephenButtolph/canoto v0.15.0/go.mod h1:IcnAHC6nJUfQFVR9y60ko2ecUqqHHSB6UwI9NnBFZnE= +github.com/StephenButtolph/canoto v0.17.1 h1:WnN5czIHHALq7pwc+Z2F1sCsKJCDhxlq0zL0YK1etHc= +github.com/StephenButtolph/canoto v0.17.1/go.mod h1:IcnAHC6nJUfQFVR9y60ko2ecUqqHHSB6UwI9NnBFZnE= github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= @@ -60,14 +60,16 @@ github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/ava-labs/avalanchego v1.13.2 h1:Kx/T2a8vqLlgHde3DWT5zMF5yBIh1rqEd6nJQMMzV/Y= -github.com/ava-labs/avalanchego v1.13.2/go.mod h1:s7W/kim5L6hiD2PB1v/Ozy1ZZyoLQ4H6mxVO0aMnxng= -github.com/ava-labs/coreth v0.15.2-rc.0.0.20250620163936-0058a7ec6d9d h1:nZA7nEhlf2uWM1doZz4WFiMkZVZ0iH+c3IebokIO1sk= -github.com/ava-labs/coreth v0.15.2-rc.0.0.20250620163936-0058a7ec6d9d/go.mod h1:Mk5g2ZI9lEbxA67qikOtUrq71Yr389B34S+Ddsa51K4= +github.com/ava-labs/avalanchego v1.13.4-0.20250724134817-e387b32bd5eb h1:CeIjP8MIxo6p5q+sfvcpdY11q+jaZHOT2oNjUmKz83g= +github.com/ava-labs/avalanchego v1.13.4-0.20250724134817-e387b32bd5eb/go.mod h1:w4sWmDbm1ngkRjh89kUqirZUpSbBCmxd7yA+J4SMZNA= +github.com/ava-labs/coreth v0.15.3-rc.1 h1:v7CMNT3tVi1cFp/6I9Xlln372+e6ztwAaCzW6vSDSVY= +github.com/ava-labs/coreth v0.15.3-rc.1/go.mod h1:80rG3mFUUPEfx9vj5QCAgKcrd1SH2UbbTAHKqYJfUpI= +github.com/ava-labs/firewood-go-ethhash/ffi v0.0.8 h1:f0ZbAiRE1srMiv/0DuXvPQZwgYbLC9OgAWbQUCMebTE= +github.com/ava-labs/firewood-go-ethhash/ffi v0.0.8/go.mod h1:j6spQFNSBAfcXKt9g0xbObW/8tMlGP4bFjPIsJmDg/o= github.com/ava-labs/libevm v1.13.14-0.3.0.rc.1 h1:vBMYo+Iazw0rGTr+cwjkBdh5eadLPlv4ywI4lKye3CA= github.com/ava-labs/libevm v1.13.14-0.3.0.rc.1/go.mod h1:+Iol+sVQ1KyoBsHf3veyrBmHCXr3xXRWq6ZXkgVfNLU= -github.com/ava-labs/subnet-evm v0.7.5 h1:2lEGhTLR4nirTD5031dIJUJVC1FfCSF6ihz22TbJDug= -github.com/ava-labs/subnet-evm v0.7.5/go.mod h1:fR6+mKlylACo0O47kY4VptfEeLYVcshWgVtiiR/0kOE= +github.com/ava-labs/subnet-evm v0.7.7-rc.0 h1:+6AeoylDr1Ym9ivvj/9h9T/Dfe0oNVBfXRedkKmdVf0= +github.com/ava-labs/subnet-evm v0.7.7-rc.0/go.mod h1:j4QYtOm4t9+LtZtO2dmyDM5x+/HfMaCdcHqQDDhfpCA= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -201,8 +203,8 @@ github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnR github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= -github.com/go-cmd/cmd v1.4.1 h1:JUcEIE84v8DSy02XTZpUDeGKExk2oW3DA10hTjbQwmc= -github.com/go-cmd/cmd v1.4.1/go.mod h1:tbBenttXtZU4c5djS1o7PWL5pd2xAr5sIqH1kGdNiRc= +github.com/go-cmd/cmd v1.4.3 h1:6y3G+3UqPerXvPcXvj+5QNPHT02BUw7p6PsqRxLNA7Y= +github.com/go-cmd/cmd v1.4.3/go.mod h1:u3hxg/ry+D5kwh8WvUkHLAMe2zQCaXd00t35WfQaOFk= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= @@ -230,8 +232,8 @@ github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5Nq github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M= -github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= @@ -772,8 +774,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= -golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= +golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/scripts/abi_bindings.sh b/scripts/abi_bindings.sh index 76f0b9c1d..c0bee5151 100755 --- a/scripts/abi_bindings.sh +++ b/scripts/abi_bindings.sh @@ -12,13 +12,24 @@ ICM_CONTRACTS_PATH=$( source $ICM_CONTRACTS_PATH/scripts/constants.sh source $ICM_CONTRACTS_PATH/scripts/versions.sh +echo "Ethereum EVM Version: $ETHEREUM_EVM_VERSION" +echo "Ethereum Solidity Version: $ETHEREUM_SOLIDITY_VERSION" +echo "Avalanche EVM Version: $AVALANCHE_EVM_VERSION" +echo "Avalanche Solidity Version: $AVALANCHE_SOLIDITY_VERSION" + +AVALANCHE_ICM_PATH=${ICM_CONTRACTS_PATH}/avalanche +ETHEREUM_ICM_PATH=${ICM_CONTRACTS_PATH}/ethereum + export ARCH=$(uname -m) [ $ARCH = x86_64 ] && ARCH=amd64 echo "ARCH set to $ARCH" -DEFAULT_CONTRACT_LIST="TeleporterMessenger TeleporterRegistry ExampleERC20 ExampleRewardCalculator TestMessenger ValidatorSetSig NativeTokenStakingManager ERC20TokenStakingManager +DEFAULT_AVALANCHE_CONTRACT_LIST="TeleporterMessenger TeleporterRegistry ExampleERC20 ExampleRewardCalculator TestMessenger ValidatorSetSig NativeTokenStakingManager ERC20TokenStakingManager TokenHome TokenRemote ERC20TokenHome ERC20TokenHomeUpgradeable ERC20TokenRemote ERC20TokenRemoteUpgradeable NativeTokenHome NativeTokenHomeUpgradeable NativeTokenRemote NativeTokenRemoteUpgradeable -WrappedNativeToken MockERC20SendAndCallReceiver MockNativeSendAndCallReceiver ExampleERC20Decimals IStakingManager ACP99Manager ValidatorManager PoAManager" +WrappedNativeToken MockERC20SendAndCallReceiver MockNativeSendAndCallReceiver ExampleERC20Decimals IStakingManager ACP99Manager ValidatorManager PoAManager NativeWarp" + +DEFAULT_ETHEREUM_CONTRACT_LIST="AvalancheValidatorSetRegistry EthWarp" + PROXY_LIST="TransparentUpgradeableProxy ProxyAdmin" ACCESS_LIST="OwnableUpgradeable" @@ -26,12 +37,14 @@ SUBNET_EVM_LIST="INativeMinter" EXTERNAL_LIBS="ValidatorMessages" -CONTRACT_LIST= +AVALANCHE_CONTRACT_LIST= +ETHEREUM_CONTRACT_LIST= HELP= while [ $# -gt 0 ]; do case "$1" in - -c | --contract) CONTRACT_LIST=$2 ;; - -h | --help) HELP=true ;; + -ac | --avalanche-contracts) AVALANCHE_CONTRACT_LIST=$2 ;; + -ec | --ethereum-contracts) ETHEREUM_CONTRACT_LIST=$2 ;; + -h | --help) HELP=true ;; esac shift done @@ -41,9 +54,9 @@ if [ "$HELP" = true ]; then echo "Build contracts and generate Go bindings" echo "" echo "Options:" - echo " -c, --contract Generate Go bindings for the contract. If empty, generate Go bindings for a default list of contracts" - echo " -c, --contract "contract1 contract2" Generate Go bindings for multiple contracts" - echo " -h, --help Print this help message" + echo " -ac, --avalanche-contracts contract1 contract2 Generate Go bindings for the contract. If empty, generate Go bindings for a default list of Avalanche contracts" + echo " -ec, --ethereum-contracts contract1 contract Generate Go bindings for the contract. If empty, generate Go bindings for a default list of Ethereum contracts" + echo " -h, --help Print this help message" exit 0 fi @@ -51,19 +64,8 @@ if ! command -v forge &> /dev/null; then echo "forge not found. You can install by calling $ICM_CONTRACTS_PATH/scripts/install_foundry.sh" && exit 1 fi -if ! command -v solc &> /dev/null; then - echo "solc not found. See https://docs.soliditylang.org/en/latest/installing-solidity.html for installation instructions" && exit 1 -fi - -# Get the version from solc output -solc_version_output=$(solc --version 2>&1) - -# Extract the semver version from the output -extracted_version=$(solc --version 2>&1 | awk '/Version:/ {print $2}' | awk -F'+' '{print $1}') - -# Check if the extracted version matches the expected version -if ! [[ "$extracted_version" == "$SOLIDITY_VERSION" ]]; then - echo "Expected solc version $SOLIDITY_VERSION, but found $extracted_version. Please install the correct version." && exit 1 +if ! command -v svm &> /dev/null; then + echo "svm not found. Please install svm-rs to manage Solidity versions. See: https://github.com/roynalnaruto/svm-rs" && exit 1 fi # Install abigen @@ -71,20 +73,33 @@ echo "Building subnet-evm abigen" go install github.com/ava-labs/subnet-evm/cmd/abigen@${SUBNET_EVM_VERSION} # Solc does not recursively expand remappings, so we must construct them manually -remappings=$(cat $ICM_CONTRACTS_PATH/remappings.txt) - -# Recursively search for all remappings.txt files in the lib directory. -# For each file, prepend the remapping with the relative path to the file. -while read -r filepath; do - relative_path="${filepath#$ICM_CONTRACTS_PATH/}" - dir_path=$(dirname "$relative_path") - echo $dir_path - - # Use sed to transform each line with the relative path if it matches the @token=remapping pattern, - # so that each remapping is of the form @token=lib/path/to/remapping - transformed_lines=$(sed -n "s|^\(@[^=]*=\)\(.*\)|\1$dir_path/\2|p" "$filepath") - remappings+=" $transformed_lines " -done < <(find "$ICM_CONTRACTS_PATH/lib" -type f -name "remappings.txt" ) +avalanche_remappings=$(cat $AVALANCHE_ICM_PATH/remappings.txt) +ethereum_remappings=$(cat $ETHEREUM_ICM_PATH/remappings.txt) + +# Helper function to expand remappings for a given base path and variable name +expand_remappings() { + local base_path="$1" + local remappings_var="$2" + local remappings_value + + while read -r filepath; do + relative_path="${filepath#$base_path/}" + dir_path=$(dirname "$relative_path") + echo $dir_path + + # Use sed to transform each line with the relative path if it matches the @token=remapping pattern, + # so that each remapping is of the form @token=lib/path/to/remapping + transformed_lines=$(sed -n "s|^\(@[^=]*=\)\(.*\)|\1$dir_path/\2|p" "$filepath") + remappings_value+=" $transformed_lines " + done < <(find "$base_path/lib" -type f -name "remappings.txt" ) + + # Use indirect reference to set the variable by name + eval "$remappings_var=\"\${$remappings_var}\$remappings_value\"" +} + +# Expand remappings for Avalanche and Ethereum +expand_remappings "$AVALANCHE_ICM_PATH" "avalanche_remappings" +expand_remappings "$ETHEREUM_ICM_PATH" "ethereum_remappings" function convertToLower() { if [ "$ARCH" = 'arm64' ]; then @@ -118,7 +133,24 @@ remove_matching_string() { } function generate_bindings() { + local project_base_path="$1" + local evm_version="$2" + local solc_version="$3" + local remappings="$4" + local additional_flags="$5" + shift 5 local contract_names=("$@") + + # Use svm to switch to the required Solidity version + echo "Switching to Solidity version $solc_version..." + svm install $solc_version --non-interactive + svm use $solc_version + + echo "Project: $project_base_path" + echo "EVM Version: $evm_version" + echo "Solidity Version: $solc_version" + echo "Additional flags: $additional_flags" + for contract_name in "${contract_names[@]}" do path=$(find . -name $contract_name.sol) @@ -126,13 +158,13 @@ function generate_bindings() { dir="${dir#./}" echo "Building $contract_name..." - mkdir -p $ICM_CONTRACTS_PATH/out/$contract_name.sol + mkdir -p $project_base_path/out/$contract_name.sol - combined_json=$ICM_CONTRACTS_PATH/out/$contract_name.sol/combined-output.json + combined_json=$project_base_path/out/$contract_name.sol/combined-output.json cwd=$(pwd) - cd $ICM_CONTRACTS_PATH - solc --optimize --evm-version $EVM_VERSION --combined-json abi,bin,metadata,ast,devdoc,userdoc --pretty-json $cwd/$dir/$contract_name.sol $remappings > $combined_json + cd $project_base_path + solc --optimize --evm-version $evm_version $additional_flags --combined-json abi,bin,metadata,ast,devdoc,userdoc --pretty-json $cwd/$dir/$contract_name.sol $remappings > $combined_json cd $cwd # construct the exclude list @@ -170,24 +202,34 @@ function generate_bindings() { contract_names=($CONTRACT_LIST) -# If CONTRACT_LIST is empty, use DEFAULT_CONTRACT_LIST -if [[ -z "${CONTRACT_LIST}" ]]; then - contract_names=($DEFAULT_CONTRACT_LIST) +# If AVALANCHE_CONTRACT_LIST is empty, use DEFAULT_AVALANCHE_CONTRACT_LIST +if [[ -z "${AVALANCHE_CONTRACT_LIST}" ]]; then + AVALANCHE_CONTRACT_LIST=($DEFAULT_AVALANCHE_CONTRACT_LIST) +fi + +# If ETHEREUM_CONTRACT_LIST is empty, use DEFAULT_ETHEREUM_CONTRACT_LIST +if [[ -z "${ETHEREUM_CONTRACT_LIST}" ]]; then + ETHEREUM_CONTRACT_LIST=($DEFAULT_ETHEREUM_CONTRACT_LIST) fi -cd $ICM_CONTRACTS_PATH/contracts -generate_bindings "${contract_names[@]}" +contract_names=($AVALANCHE_CONTRACT_LIST) +cd $AVALANCHE_ICM_PATH/contracts +generate_bindings "$AVALANCHE_ICM_PATH" "$AVALANCHE_EVM_VERSION" "$AVALANCHE_SOLIDITY_VERSION" "$avalanche_remappings" "" "${contract_names[@]}" contract_names=($PROXY_LIST) -cd $ICM_CONTRACTS_PATH/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/proxy/transparent -generate_bindings "${contract_names[@]}" +cd $AVALANCHE_ICM_PATH/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/proxy/transparent +generate_bindings "$AVALANCHE_ICM_PATH" "$AVALANCHE_EVM_VERSION" "$AVALANCHE_SOLIDITY_VERSION" "$avalanche_remappings" "" "${contract_names[@]}" contract_names=($SUBNET_EVM_LIST) -cd $ICM_CONTRACTS_PATH/lib/subnet-evm/contracts/contracts/interfaces -generate_bindings "${contract_names[@]}" +cd $AVALANCHE_ICM_PATH/lib/subnet-evm/contracts/contracts/interfaces +generate_bindings "$AVALANCHE_ICM_PATH" "$AVALANCHE_EVM_VERSION" "$AVALANCHE_SOLIDITY_VERSION" "$avalanche_remappings" "" "${contract_names[@]}" contract_names=($ACCESS_LIST) -cd $ICM_CONTRACTS_PATH/lib/openzeppelin-contracts-upgradeable/contracts/access -generate_bindings "${contract_names[@]}" +cd $AVALANCHE_ICM_PATH/lib/openzeppelin-contracts-upgradeable/contracts/access +generate_bindings "$AVALANCHE_ICM_PATH" "$AVALANCHE_EVM_VERSION" "$AVALANCHE_SOLIDITY_VERSION" "$avalanche_remappings" "" "${contract_names[@]}" + +contract_names=($ETHEREUM_CONTRACT_LIST) +cd $ETHEREUM_ICM_PATH/contracts +generate_bindings "$ETHEREUM_ICM_PATH" "$ETHEREUM_EVM_VERSION" "$ETHEREUM_SOLIDITY_VERSION" "$ethereum_remappings" "--via-ir" "${contract_names[@]}" exit 0 diff --git a/scripts/e2e_test.sh b/scripts/e2e_test.sh index 984f96ac0..8fa71f966 100755 --- a/scripts/e2e_test.sh +++ b/scripts/e2e_test.sh @@ -61,7 +61,7 @@ done source "$ICM_CONTRACTS_PATH"/scripts/constants.sh source "$ICM_CONTRACTS_PATH"/scripts/versions.sh -BASEDIR=${BASEDIR:-"$HOME/.teleporter-deps"} +BASEDIR=${BASEDIR:-"$HOME/.icm-contracts-e2e-deps"} cwd=$(pwd) # Install the avalanchego and subnet-evm binaries diff --git a/scripts/versions.sh b/scripts/versions.sh index a14c67378..1d11d27d1 100755 --- a/scripts/versions.sh +++ b/scripts/versions.sh @@ -41,6 +41,12 @@ SUBNET_EVM_VERSION=${SUBNET_EVM_VERSION:-$(extract_commit "$(getDepVersion githu # Set golangci-lint version GOLANGCI_LINT_VERSION=${GOLANGCI_LINT_VERSION:-'v1.64.5'} -# Extract the Solidity version from foundry.toml -SOLIDITY_VERSION=$(awk -F"'" '/^solc_version/ {print $2}' $ICM_CONTRACTS_PATH/foundry.toml) -EVM_VERSION=$(awk -F"'" '/^evm_version/ {print $2}' $ICM_CONTRACTS_PATH/foundry.toml) +# Extract the Solidity version from the Avalanche foundry.toml file +AVALANCHE_ICM_PATH=${ICM_CONTRACTS_PATH}/avalanche +AVALANCHE_SOLIDITY_VERSION=$(awk -F"'" '/^solc_version/ {print $2}' $AVALANCHE_ICM_PATH/foundry.toml) +AVALANCHE_EVM_VERSION=$(awk -F"'" '/^evm_version/ {print $2}' $AVALANCHE_ICM_PATH/foundry.toml) + +# Extract the Solidity version from the Ethereum foundry.toml file +ETHEREUM_ICM_PATH=${ICM_CONTRACTS_PATH}/ethereum +ETHEREUM_SOLIDITY_VERSION=$(awk -F"'" '/^solc_version/ {print $2}' $ETHEREUM_ICM_PATH/foundry.toml) +ETHEREUM_EVM_VERSION=$(awk -F"'" '/^evm_version/ {print $2}' $ETHEREUM_ICM_PATH/foundry.toml) diff --git a/tests/flows/ethereum-icm-verification/README.md b/tests/flows/ethereum-icm-verification/README.md new file mode 100644 index 000000000..bc63b8e04 --- /dev/null +++ b/tests/flows/ethereum-icm-verification/README.md @@ -0,0 +1,11 @@ +# Ethereum External ICM Verification E2E Tests + +1. Creates an Avalanche L1 on the Fuji testnet with 3 local validators, running a custom version of AvalancheGo. +1. Deploys an `AvalancheValidatorSetRegistry` contract on the Sepolia testnet. +1. Registers the Avalanche L1's validator set in the registry via an ICM message from the P-Chain, self-signed by the validator set of the L1. +1. Sends a transaction on the L1 to send an ICM message to Sepolia. +1. Gets an aggregate signature of the ICM message using the ICM signature aggregator. +1. Broadcasts the signed ICM message to Sepolia, and confirms successful inclusion and verification. +1. Adds a new validator to the L1, representing 40% of the new total weight. +1. Updates the validator set reigstered on the Sepolia registry via a validator set update message signed by sufficient weight of the previous validator set. +1. Sends and verifies another ICM message from the L1 to Sepolia. diff --git a/tests/flows/ethereum-icm-verification/ethereum_icm_verification.go b/tests/flows/ethereum-icm-verification/ethereum_icm_verification.go new file mode 100644 index 000000000..83148274b --- /dev/null +++ b/tests/flows/ethereum-icm-verification/ethereum_icm_verification.go @@ -0,0 +1,138 @@ +package ethereum_icm_verification + +import ( + "context" + + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/vms/platformvm" + "github.com/ava-labs/icm-contracts/tests/network" + "github.com/ava-labs/icm-contracts/tests/utils" + "github.com/ava-labs/libevm/log" + . "github.com/onsi/gomega" +) + +func EthereumICMVerification( + avalancheNetwork *network.LocalAvalancheNetwork, + ethereumNetwork *network.LocalEthereumNetwork, + teleporter utils.TeleporterTestInfo, +) { + // 1. Deploy an AvalancheValidatorSetRegistry contract on the Ethereum network + // 2. Register the Avalanche L1 network's validator set in the registry via an ICM message from the P-Chain, self-signed by the validator set of the Avalanche network + // 3. Deploy an adapted Warp contract to Ethereum that can verify ICM messages against validator set signatures + // 4. Deploy a Teleporter contract to Ethereum using the adapted Warp contract + // 5. Send a transaction on the Avalanche L1 network to send an ICM message to the Ethereum network + // 6. Get an aggregate signature of the ICM message using the ICM signature aggregator + // 7. Broadcast the signed ICM message to the Ethereum network, and confirm successful inclusion and verification + // 8. Add a new validator to the Avalanche L1 network, representing 40% of the new total weight + // 9. Update the validator set registered on the Ethereum registry via a validator set update message signed by sufficient weight of the previous validator set + // 10. Send and verify another ICM message from the Avalanche L1 network to the Ethereum network + ctx := context.Background() + _, ethereumFundedKey := ethereumNetwork.GetFundedAccountInfo() + + // Start a signature aggregator for the Avalanche network to be able to generate signed ICM messages. + primaryNetworkInfo := avalancheNetwork.GetPrimaryNetworkInfo() + Expect(len(primaryNetworkInfo.NodeURIs)).Should(BeNumerically(">", 0), "No NodeURIs found in primaryNetworkInfo") + pChainInfo := utils.GetPChainInfo(primaryNetworkInfo) + l1Infos := avalancheNetwork.GetL1Infos() + l1Info := l1Infos[0] + Expect(len(l1Infos)).Should(BeNumerically(">", 0), "No L1s found in Avalanche network") + + // Deploy an AvalancheValidatorSetRegistry contract on the Ethereum network + validatorSetRegistryContractAddress, validatorSetRegistry := utils.DeployAvalancheValidatorSetRegistry( + ctx, + ethereumFundedKey, + ethereumNetwork.ChainID, + ethereumNetwork.Client, + avalancheNetwork.GetNetworkID(), + l1Info.BlockchainID, + ) + log.Info("Deployed AvalancheValidatorSetRegistry contract on the Ethereum network", "address", validatorSetRegistryContractAddress) + + // Deploy a test cross chain messenger to the Avalanche subnet + fundedAvaAddress, fundedAvaKey := avalancheNetwork.GetFundedAccountInfo() + _, testMessengerL1 := utils.DeployTestMessenger( + ctx, + fundedAvaKey, + fundedAvaAddress, + teleporter.TeleporterRegistryAddress(l1Info), + l1Info, + ) + + signatureAggregator := utils.NewSignatureAggregator( + primaryNetworkInfo.NodeURIs[0], + []ids.ID{ + l1Info.SubnetID, + }, + ) + defer signatureAggregator.Shutdown() + + // Register the Avalanche L1 network's validator set in the registry via an ICM message from the P-Chain, self-signed by the validator set of the Avalanche network + pChainClient := platformvm.NewClient(primaryNetworkInfo.NodeURIs[0]) + utils.RegisterAvalancheValidatorSet( + ctx, + ethereumFundedKey, + ethereumNetwork.ChainID, + ethereumNetwork.Client, + validatorSetRegistry, + avalancheNetwork.GetNetworkID(), + pChainInfo.BlockchainID, + l1Info.SubnetID, + l1Info.BlockchainID, + pChainClient, + signatureAggregator, + ) + + // Register the EthWarp contract and register the above ValidatorSetRegistry with it + ethWarpAddress, ethWarpContract := utils.DeployEthWarp( + ctx, + ethereumFundedKey, + ethereumNetwork.ChainID, + ethereumNetwork.Client, + l1Info.BlockchainID, + ) + log.Info("Deployed EthWarp contract on the Ethereum network", "address", ethWarpAddress) + + utils.RegisterValSetRegistryWithEthWarp( + ctx, + ethereumFundedKey, + ethereumNetwork.ChainID, + ethereumNetwork.Client, + ethWarpContract, + l1Info.BlockchainID, + validatorSetRegistryContractAddress, + ) + + // Deploy Teleporter contract to Ethereum using the adapted Warp contract + ethTeleporterAddress, ethTeleporter := utils.DeployTeleporterMessengerToEthereum( + ctx, + ethereumFundedKey, + ethereumNetwork.ChainID, + ethereumNetwork.Client, + ethWarpAddress, + ) + log.Info("Deployed Teleporter to Ethereum network", "address", ethTeleporterAddress) + + // Send and verify an ICM message from the Avalanche L1 network to the Ethereum network. + teleporter.SendExampleInterChainMessageAndVerify( + ctx, + ethereumNetwork.ChainID, + ethereumNetwork.Client, + avalancheNetwork.GetNetworkID(), + pChainInfo.BlockchainID, + l1Info, + testMessengerL1, + ethTeleporterAddress, + ethTeleporter, + fundedAvaKey, + ethereumFundedKey, + "Hello Ethereum", + signatureAggregator, + false, + ) + + log.Info("Message successfully sent to Ethereum") + + // TODO: + // 1. Add a new validator to the L1, and update the validator set on the Ethereum network. + // 2. Send and verify another message, using the updated validator set. +} diff --git a/tests/flows/governance/validator_set_sig.go b/tests/flows/governance/validator_set_sig.go index ab506f855..ff5bc6ca0 100644 --- a/tests/flows/governance/validator_set_sig.go +++ b/tests/flows/governance/validator_set_sig.go @@ -12,7 +12,7 @@ import ( . "github.com/onsi/gomega" ) -func ValidatorSetSig(network *localnetwork.LocalNetwork) { +func ValidatorSetSig(network *localnetwork.LocalAvalancheNetwork) { // ************************************************************************************************ // Setup // ************************************************************************************************ diff --git a/tests/flows/ictt/erc20_home_erc20_remote.go b/tests/flows/ictt/erc20_home_erc20_remote.go index fd67fe363..f857229eb 100644 --- a/tests/flows/ictt/erc20_home_erc20_remote.go +++ b/tests/flows/ictt/erc20_home_erc20_remote.go @@ -19,7 +19,7 @@ import ( * Transfers C-Chain example ERC20 tokens to L1 A * Transfer tokens from L1 A to C-Chain */ -func ERC20TokenHomeERC20TokenRemote(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func ERC20TokenHomeERC20TokenRemote(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { cChainInfo := network.GetPrimaryNetworkInfo() l1AInfo, _ := network.GetTwoL1s() fundedAddress, fundedKey := network.GetFundedAccountInfo() diff --git a/tests/flows/ictt/erc20_home_erc20_remote_multihop.go b/tests/flows/ictt/erc20_home_erc20_remote_multihop.go index 4408d334b..5cb8be1d6 100644 --- a/tests/flows/ictt/erc20_home_erc20_remote_multihop.go +++ b/tests/flows/ictt/erc20_home_erc20_remote_multihop.go @@ -19,7 +19,7 @@ import ( * Transfer tokens from L1 A to L1 B through multi-hop * Transfer back tokens from L1 B to L1 A through multi-hop */ -func ERC20TokenHomeERC20TokenRemoteMultiHop(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func ERC20TokenHomeERC20TokenRemoteMultiHop(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { cChainInfo := network.GetPrimaryNetworkInfo() l1AInfo, l1BInfo := network.GetTwoL1s() fundedAddress, fundedKey := network.GetFundedAccountInfo() diff --git a/tests/flows/ictt/erc20_home_erc20_remote_send_and_call.go b/tests/flows/ictt/erc20_home_erc20_remote_send_and_call.go index 7d87fbc15..5b90e42b0 100644 --- a/tests/flows/ictt/erc20_home_erc20_remote_send_and_call.go +++ b/tests/flows/ictt/erc20_home_erc20_remote_send_and_call.go @@ -21,7 +21,7 @@ import ( * C-Chain and calls contract on the C-Chain using sendAndCall */ func ERC20TokenHomeERC20TokenRemoteSendAndCall( - network *localnetwork.LocalNetwork, + network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo, ) { cChainInfo := network.GetPrimaryNetworkInfo() diff --git a/tests/flows/ictt/erc20_home_native_remote.go b/tests/flows/ictt/erc20_home_native_remote.go index 1ca7b34e9..1b5f4e405 100644 --- a/tests/flows/ictt/erc20_home_native_remote.go +++ b/tests/flows/ictt/erc20_home_native_remote.go @@ -31,7 +31,7 @@ var ( * Transfers C-Chain example ERC20 tokens to L1 A as L1 A's native token * Transfer back tokens from L1 A to C-Chain */ -func ERC20TokenHomeNativeTokenRemote(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func ERC20TokenHomeNativeTokenRemote(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { cChainInfo := network.GetPrimaryNetworkInfo() l1AInfo, _ := network.GetTwoL1s() fundedAddress, fundedKey := network.GetFundedAccountInfo() diff --git a/tests/flows/ictt/erc20_home_native_remote_multihop.go b/tests/flows/ictt/erc20_home_native_remote_multihop.go index c1ba08a70..93a2a4677 100644 --- a/tests/flows/ictt/erc20_home_native_remote_multihop.go +++ b/tests/flows/ictt/erc20_home_native_remote_multihop.go @@ -22,7 +22,7 @@ import ( - Transfer tokens from L1 A to L1 B through multi-hop - Transfer back tokens from L1 B to L1 A through multi-hop */ -func ERC20TokenHomeNativeTokenRemoteMultiHop(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func ERC20TokenHomeNativeTokenRemoteMultiHop(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { cChainInfo := network.GetPrimaryNetworkInfo() l1AInfo, l1BInfo := network.GetTwoL1s() fundedAddress, fundedKey := network.GetFundedAccountInfo() diff --git a/tests/flows/ictt/native_home_erc20_remote.go b/tests/flows/ictt/native_home_erc20_remote.go index c7b71c48b..225c810d5 100644 --- a/tests/flows/ictt/native_home_erc20_remote.go +++ b/tests/flows/ictt/native_home_erc20_remote.go @@ -19,7 +19,7 @@ import ( * Transfers C-Chain native tokens to L1 A * Transfer back tokens from L1 A to C-Chain */ -func NativeTokenHomeERC20TokenRemote(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func NativeTokenHomeERC20TokenRemote(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { cChainInfo := network.GetPrimaryNetworkInfo() l1AInfo, _ := network.GetTwoL1s() fundedAddress, fundedKey := network.GetFundedAccountInfo() diff --git a/tests/flows/ictt/native_home_erc20_remote_multihop.go b/tests/flows/ictt/native_home_erc20_remote_multihop.go index 72a034f09..91588fe8b 100644 --- a/tests/flows/ictt/native_home_erc20_remote_multihop.go +++ b/tests/flows/ictt/native_home_erc20_remote_multihop.go @@ -20,7 +20,7 @@ import ( * Transfer tokens from L1 A to L1 B through multi-hop * Brige back tokens from L1 B to L1 A through multi-hop */ -func NativeTokenHomeERC20TokenRemoteMultiHop(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func NativeTokenHomeERC20TokenRemoteMultiHop(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { cChainInfo := network.GetPrimaryNetworkInfo() l1AInfo, l1BInfo := network.GetTwoL1s() fundedAddress, fundedKey := network.GetFundedAccountInfo() diff --git a/tests/flows/ictt/native_home_native_remote.go b/tests/flows/ictt/native_home_native_remote.go index 32f0070a0..45d414461 100644 --- a/tests/flows/ictt/native_home_native_remote.go +++ b/tests/flows/ictt/native_home_native_remote.go @@ -18,7 +18,7 @@ import ( * Transfers C-Chain native tokens to L1 A * Transfer back tokens from L1 A to C-Chain */ -func NativeTokenHomeNativeDestination(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func NativeTokenHomeNativeDestination(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { cChainInfo := network.GetPrimaryNetworkInfo() l1AInfo, _ := network.GetTwoL1s() fundedAddress, fundedKey := network.GetFundedAccountInfo() diff --git a/tests/flows/ictt/native_home_native_remote_multihop.go b/tests/flows/ictt/native_home_native_remote_multihop.go index 44bced622..de5382b9b 100644 --- a/tests/flows/ictt/native_home_native_remote_multihop.go +++ b/tests/flows/ictt/native_home_native_remote_multihop.go @@ -21,7 +21,7 @@ import ( - Transfer tokens from L1 A to L1 B through multi-hop - Transfer back tokens from L1 B to L1 A through multi-hop */ -func NativeTokenHomeNativeTokenRemoteMultiHop(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func NativeTokenHomeNativeTokenRemoteMultiHop(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { cChainInfo := network.GetPrimaryNetworkInfo() l1AInfo, l1BInfo := network.GetTwoL1s() fundedAddress, fundedKey := network.GetFundedAccountInfo() diff --git a/tests/flows/ictt/registration_and_collateral_check.go b/tests/flows/ictt/registration_and_collateral_check.go index 97d87e5d6..67abf152f 100644 --- a/tests/flows/ictt/registration_and_collateral_check.go +++ b/tests/flows/ictt/registration_and_collateral_check.go @@ -21,7 +21,7 @@ import ( * Collateralize the remote * Check sending to collateralized remote succeeds and withdraws with correct scale. */ -func RegistrationAndCollateralCheck(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func RegistrationAndCollateralCheck(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { cChainInfo := network.GetPrimaryNetworkInfo() l1AInfo, _ := network.GetTwoL1s() fundedAddress, fundedKey := network.GetFundedAccountInfo() diff --git a/tests/flows/ictt/transparent_proxy_upgradeability.go b/tests/flows/ictt/transparent_proxy_upgradeability.go index 531af1b66..899b8f356 100644 --- a/tests/flows/ictt/transparent_proxy_upgradeability.go +++ b/tests/flows/ictt/transparent_proxy_upgradeability.go @@ -26,7 +26,7 @@ import ( * Check that the transfer was successful, and expected balances are correct */ -func TransparentUpgradeableProxy(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func TransparentUpgradeableProxy(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { cChainInfo := network.GetPrimaryNetworkInfo() l1AInfo, _ := network.GetTwoL1s() fundedAddress, fundedKey := network.GetFundedAccountInfo() diff --git a/tests/flows/teleporter/add_fee_amount.go b/tests/flows/teleporter/add_fee_amount.go index d7cb2736c..cdecfde0b 100644 --- a/tests/flows/teleporter/add_fee_amount.go +++ b/tests/flows/teleporter/add_fee_amount.go @@ -12,7 +12,7 @@ import ( . "github.com/onsi/gomega" ) -func AddFeeAmount(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func AddFeeAmount(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { l1AInfo := network.GetPrimaryNetworkInfo() l1BInfo, _ := network.GetTwoL1s() teleporterContractAddress := teleporter.TeleporterMessengerAddress(l1AInfo) diff --git a/tests/flows/teleporter/basic_send_receive.go b/tests/flows/teleporter/basic_send_receive.go index e801ef24d..f1a4d9679 100644 --- a/tests/flows/teleporter/basic_send_receive.go +++ b/tests/flows/teleporter/basic_send_receive.go @@ -13,7 +13,7 @@ import ( ) // Tests basic one-way send from L1 A to L1 B and vice versa -func BasicSendReceive(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func BasicSendReceive(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { l1AInfo := network.GetPrimaryNetworkInfo() l1BInfo, _ := network.GetTwoL1s() teleporterContractAddress := teleporter.TeleporterMessengerAddress(l1AInfo) diff --git a/tests/flows/teleporter/deliver_to_nonexistent_contract.go b/tests/flows/teleporter/deliver_to_nonexistent_contract.go index 15cfc94a7..e277a56fe 100644 --- a/tests/flows/teleporter/deliver_to_nonexistent_contract.go +++ b/tests/flows/teleporter/deliver_to_nonexistent_contract.go @@ -14,7 +14,7 @@ import ( . "github.com/onsi/gomega" ) -func DeliverToNonExistentContract(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func DeliverToNonExistentContract(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { l1AInfo := network.GetPrimaryNetworkInfo() l1BInfo, _ := network.GetTwoL1s() fundedAddress, fundedKey := network.GetFundedAccountInfo() diff --git a/tests/flows/teleporter/deliver_to_wrong_chain.go b/tests/flows/teleporter/deliver_to_wrong_chain.go index d4d0c7349..d693f2447 100644 --- a/tests/flows/teleporter/deliver_to_wrong_chain.go +++ b/tests/flows/teleporter/deliver_to_wrong_chain.go @@ -13,7 +13,7 @@ import ( . "github.com/onsi/gomega" ) -func DeliverToWrongChain(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func DeliverToWrongChain(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { l1AInfo := network.GetPrimaryNetworkInfo() l1BInfo, L1CInfo := network.GetTwoL1s() fundedAddress, fundedKey := network.GetFundedAccountInfo() diff --git a/tests/flows/teleporter/insufficient_gas.go b/tests/flows/teleporter/insufficient_gas.go index a229bc141..f04f993ef 100644 --- a/tests/flows/teleporter/insufficient_gas.go +++ b/tests/flows/teleporter/insufficient_gas.go @@ -10,7 +10,7 @@ import ( . "github.com/onsi/gomega" ) -func InsufficientGas(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func InsufficientGas(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { l1AInfo := network.GetPrimaryNetworkInfo() l1BInfo, _ := network.GetTwoL1s() fundedAddress, fundedKey := network.GetFundedAccountInfo() diff --git a/tests/flows/teleporter/registry/check_upgrade_access.go b/tests/flows/teleporter/registry/check_upgrade_access.go index 8a3d013d1..d726a02d8 100644 --- a/tests/flows/teleporter/registry/check_upgrade_access.go +++ b/tests/flows/teleporter/registry/check_upgrade_access.go @@ -13,7 +13,7 @@ import ( . "github.com/onsi/gomega" ) -func CheckUpgradeAccess(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func CheckUpgradeAccess(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { l1Info := network.GetPrimaryNetworkInfo() fundedAddress, fundedKey := network.GetFundedAccountInfo() diff --git a/tests/flows/teleporter/registry/pause_teleporter.go b/tests/flows/teleporter/registry/pause_teleporter.go index b1bef12ac..22a2778d5 100644 --- a/tests/flows/teleporter/registry/pause_teleporter.go +++ b/tests/flows/teleporter/registry/pause_teleporter.go @@ -9,7 +9,7 @@ import ( . "github.com/onsi/gomega" ) -func PauseTeleporter(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func PauseTeleporter(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { l1AInfo := network.GetPrimaryNetworkInfo() l1BInfo, _ := network.GetTwoL1s() fundedAddress, fundedKey := network.GetFundedAccountInfo() diff --git a/tests/flows/teleporter/registry/teleporter_registry.go b/tests/flows/teleporter/registry/teleporter_registry.go index b74426cd2..bf73b864b 100644 --- a/tests/flows/teleporter/registry/teleporter_registry.go +++ b/tests/flows/teleporter/registry/teleporter_registry.go @@ -11,10 +11,10 @@ import ( ) const ( - teleporterByteCodeFile = "./out/TeleporterMessenger.sol/TeleporterMessenger.json" + teleporterByteCodeFile = "./avalanche/out/TeleporterMessenger.sol/TeleporterMessenger.json" ) -func TeleporterRegistry(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func TeleporterRegistry(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { // Deploy dApp on both chains that use Teleporter Registry // Deploy version 2 of Teleporter to both chains // Construct AddProtocolVersion txs for both chains @@ -155,6 +155,7 @@ func TeleporterRegistry(network *localnetwork.LocalNetwork, teleporter utils.Tel // Update teleporter with the new TeleporterMessengers for _, l1 := range network.GetAllL1Infos() { teleporter.SetTeleporter(newTeleporterAddress, l1) + teleporter.Initialize(l1, fundedKey, common.HexToAddress("0x0200000000000000000000000000000000000005")) teleporter.InitializeBlockchainID(l1, fundedKey) } diff --git a/tests/flows/teleporter/relay_message_twice.go b/tests/flows/teleporter/relay_message_twice.go index bbc6c4b01..6ee54af34 100644 --- a/tests/flows/teleporter/relay_message_twice.go +++ b/tests/flows/teleporter/relay_message_twice.go @@ -14,7 +14,7 @@ import ( . "github.com/onsi/gomega" ) -func RelayMessageTwice(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func RelayMessageTwice(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { l1AInfo := network.GetPrimaryNetworkInfo() l1BInfo, _ := network.GetTwoL1s() fundedAddress, fundedKey := network.GetFundedAccountInfo() diff --git a/tests/flows/teleporter/relayer_modifies_message.go b/tests/flows/teleporter/relayer_modifies_message.go index 15940ab74..96fda5ce0 100644 --- a/tests/flows/teleporter/relayer_modifies_message.go +++ b/tests/flows/teleporter/relayer_modifies_message.go @@ -23,7 +23,7 @@ import ( ) // Disallow this test from being run on anything but a local network, since it requires special behavior by the relayer -func RelayerModifiesMessage(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func RelayerModifiesMessage(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { l1AInfo := network.GetPrimaryNetworkInfo() l1BInfo, _ := network.GetTwoL1s() fundedAddress, fundedKey := network.GetFundedAccountInfo() @@ -69,7 +69,7 @@ func relayAlteredMessage( sourceReceipt *types.Receipt, source interfaces.L1TestInfo, destination interfaces.L1TestInfo, - network *localnetwork.LocalNetwork, + network *localnetwork.LocalAvalancheNetwork, ) { // Fetch the Teleporter message from the logs sendEvent, err := utils.GetEventFromLogs( diff --git a/tests/flows/teleporter/resubmit_altered_message.go b/tests/flows/teleporter/resubmit_altered_message.go index 80db93e23..4cd2222c2 100644 --- a/tests/flows/teleporter/resubmit_altered_message.go +++ b/tests/flows/teleporter/resubmit_altered_message.go @@ -13,7 +13,7 @@ import ( . "github.com/onsi/gomega" ) -func ResubmitAlteredMessage(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func ResubmitAlteredMessage(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { l1AInfo := network.GetPrimaryNetworkInfo() l1BInfo, _ := network.GetTwoL1s() fundedAddress, fundedKey := network.GetFundedAccountInfo() diff --git a/tests/flows/teleporter/retry_successful_execution.go b/tests/flows/teleporter/retry_successful_execution.go index 7584b8dfa..5aa9d4105 100644 --- a/tests/flows/teleporter/retry_successful_execution.go +++ b/tests/flows/teleporter/retry_successful_execution.go @@ -11,7 +11,7 @@ import ( . "github.com/onsi/gomega" ) -func RetrySuccessfulExecution(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func RetrySuccessfulExecution(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { l1AInfo := network.GetPrimaryNetworkInfo() l1BInfo, _ := network.GetTwoL1s() fundedAddress, fundedKey := network.GetFundedAccountInfo() diff --git a/tests/flows/teleporter/send_specific_receipts.go b/tests/flows/teleporter/send_specific_receipts.go index 8d662ee6b..f1b681b7f 100644 --- a/tests/flows/teleporter/send_specific_receipts.go +++ b/tests/flows/teleporter/send_specific_receipts.go @@ -18,7 +18,7 @@ import ( . "github.com/onsi/gomega" ) -func SendSpecificReceipts(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func SendSpecificReceipts(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { l1AInfo := network.GetPrimaryNetworkInfo() l1BInfo, _ := network.GetTwoL1s() l1ATeleporterMessenger := teleporter.TeleporterMessenger(l1AInfo) @@ -254,7 +254,6 @@ func receiptIncluded( ) bool { for _, receipt := range receipts { messageID, err := teleporterutils.CalculateMessageID( - teleporterMessengerAddress, sourceL1.BlockchainID, destinationL1.BlockchainID, receipt.ReceivedMessageNonce, diff --git a/tests/flows/teleporter/teleporter_message_ids.go b/tests/flows/teleporter/teleporter_message_ids.go index b25e554e6..57ebb82d5 100644 --- a/tests/flows/teleporter/teleporter_message_ids.go +++ b/tests/flows/teleporter/teleporter_message_ids.go @@ -16,9 +16,8 @@ import ( ) // Tests Teleporter message ID calculation -func CalculateMessageID(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func CalculateMessageID(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { l1Info := network.GetPrimaryNetworkInfo() - teleporterContractAddress := teleporter.TeleporterMessengerAddress(l1Info) sourceBlockchainID := common.HexToHash("0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd") destinationBlockchainID := common.HexToHash("0x1234567812345678123456781234567812345678123456781234567812345678") @@ -33,7 +32,6 @@ func CalculateMessageID(network *localnetwork.LocalNetwork, teleporter utils.Tel Expect(err).Should(BeNil()) calculatedMessageID, err := teleporterutils.CalculateMessageID( - teleporterContractAddress, ids.ID(sourceBlockchainID), ids.ID(destinationBlockchainID), nonce, diff --git a/tests/flows/teleporter/unallowed_relayer.go b/tests/flows/teleporter/unallowed_relayer.go index 38eedafbb..8e2158b35 100644 --- a/tests/flows/teleporter/unallowed_relayer.go +++ b/tests/flows/teleporter/unallowed_relayer.go @@ -13,7 +13,7 @@ import ( . "github.com/onsi/gomega" ) -func UnallowedRelayer(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func UnallowedRelayer(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { l1AInfo := network.GetPrimaryNetworkInfo() l1BInfo, _ := network.GetTwoL1s() fundedAddress, fundedKey := network.GetFundedAccountInfo() diff --git a/tests/flows/teleporter/validator_churn.go b/tests/flows/teleporter/validator_churn.go index cb3aa65ae..22f5e6d44 100644 --- a/tests/flows/teleporter/validator_churn.go +++ b/tests/flows/teleporter/validator_churn.go @@ -21,7 +21,7 @@ const ( sleepPeriodSeconds = 5 ) -func ValidatorChurn(network *localnetwork.LocalNetwork, teleporter utils.TeleporterTestInfo) { +func ValidatorChurn(network *localnetwork.LocalAvalancheNetwork, teleporter utils.TeleporterTestInfo) { l1AInfo, l1BInfo := network.GetTwoL1s() teleporterContractAddress := teleporter.TeleporterMessengerAddress(l1AInfo) fundedAddress, fundedKey := network.GetFundedAccountInfo() diff --git a/tests/flows/validator-manager/delegator_inactive_validator.go b/tests/flows/validator-manager/delegator_inactive_validator.go index 5c881734a..eaaf36eed 100644 --- a/tests/flows/validator-manager/delegator_inactive_validator.go +++ b/tests/flows/validator-manager/delegator_inactive_validator.go @@ -25,7 +25,7 @@ import ( * - Disable the validator by issuing a DisableL1ValidatorTx on the P-Chain * - Initiate and complete validator removal */ -func RemoveDelegatorInactiveValidator(network *localnetwork.LocalNetwork) { +func RemoveDelegatorInactiveValidator(network *localnetwork.LocalAvalancheNetwork) { // Get the L1s info cChainInfo := network.GetPrimaryNetworkInfo() l1AInfo, _ := network.GetTwoL1s() diff --git a/tests/flows/validator-manager/erc20_token_staking.go b/tests/flows/validator-manager/erc20_token_staking.go index 6f982bcd4..a6ab8db19 100644 --- a/tests/flows/validator-manager/erc20_token_staking.go +++ b/tests/flows/validator-manager/erc20_token_staking.go @@ -33,7 +33,7 @@ import ( * - Deliver the Warp message to the L1 * - Verify that the validator is delisted from the staking contract */ -func ERC20TokenStakingManager(network *localnetwork.LocalNetwork) { +func ERC20TokenStakingManager(network *localnetwork.LocalAvalancheNetwork) { // Get the L1s info cChainInfo := network.GetPrimaryNetworkInfo() l1AInfo, _ := network.GetTwoL1s() diff --git a/tests/flows/validator-manager/native_token_staking.go b/tests/flows/validator-manager/native_token_staking.go index 4e48696ce..7265239be 100644 --- a/tests/flows/validator-manager/native_token_staking.go +++ b/tests/flows/validator-manager/native_token_staking.go @@ -32,7 +32,7 @@ import ( * - Deliver the Warp message to the L1 * - Verify that the validator is delisted from the staking contract */ -func NativeTokenStakingManager(network *localnetwork.LocalNetwork) { +func NativeTokenStakingManager(network *localnetwork.LocalAvalancheNetwork) { // Get the L1s info cChainInfo := network.GetPrimaryNetworkInfo() l1AInfo, _ := network.GetTwoL1s() diff --git a/tests/flows/validator-manager/poa_to_pos.go b/tests/flows/validator-manager/poa_to_pos.go index 7796fc1b8..4e934a5d7 100644 --- a/tests/flows/validator-manager/poa_to_pos.go +++ b/tests/flows/validator-manager/poa_to_pos.go @@ -38,7 +38,7 @@ import ( * - Delist the previous PoA validator properly * - Delist the PoS validator */ -func PoAMigrationToPoS(network *localnetwork.LocalNetwork) { +func PoAMigrationToPoS(network *localnetwork.LocalAvalancheNetwork) { cChainInfo := network.GetPrimaryNetworkInfo() l1AInfo, _ := network.GetTwoL1s() _, fundedKey := network.GetFundedAccountInfo() diff --git a/tests/network/network.go b/tests/network/local_avalanche_network.go similarity index 91% rename from tests/network/network.go rename to tests/network/local_avalanche_network.go index f6b898ebf..6ee403bc0 100644 --- a/tests/network/network.go +++ b/tests/network/local_avalanche_network.go @@ -40,13 +40,15 @@ import ( . "github.com/onsi/gomega" ) +var _ LocalNetwork = &LocalAvalancheNetwork{} + type ProxyAddress struct { common.Address *proxyadmin.ProxyAdmin } // Implements Network, pointing to the network setup in local_network_setup.go -type LocalNetwork struct { +type LocalAvalancheNetwork struct { *tmpnet.Network extraNodes []*tmpnet.Node // to add as more L1 validators in the tests @@ -75,7 +77,7 @@ type L1Spec struct { RequirePrimaryNetworkSigners bool } -func NewLocalNetwork( +func NewLocalAvalancheNetwork( ctx context.Context, name string, warpGenesisTemplateFile string, @@ -83,7 +85,7 @@ func NewLocalNetwork( numPrimaryNetworkValidators int, extraNodeCount int, // for use by tests, eg to add new L1 validators flagVars *e2e.FlagVars, -) *LocalNetwork { +) *LocalAvalancheNetwork { // There must be at least one primary network validator per L1 Expect(numPrimaryNetworkValidators).Should(BeNumerically(">=", len(l1Specs))) @@ -170,7 +172,7 @@ func NewLocalNetwork( var primaryNetworkValidators []*tmpnet.Node primaryNetworkValidators = append(primaryNetworkValidators, network.Nodes...) - localNetwork := &LocalNetwork{ + localNetwork := &LocalAvalancheNetwork{ Network: network, extraNodes: extraNodes, globalFundedKey: globalFundedKey, @@ -184,7 +186,7 @@ func NewLocalNetwork( return localNetwork } -func (n *LocalNetwork) ConvertSubnet( +func (n *LocalAvalancheNetwork) ConvertSubnet( ctx context.Context, l1 interfaces.L1TestInfo, managerType utils.ValidatorManagerConcreteType, @@ -328,7 +330,7 @@ func (n *LocalNetwork) ConvertSubnet( return nodes, validationIDs } -func (n *LocalNetwork) AddSubnetValidators( +func (n *LocalAvalancheNetwork) AddSubnetValidators( nodes []*tmpnet.Node, l1 interfaces.L1TestInfo, partialSync bool, @@ -366,11 +368,11 @@ func (n *LocalNetwork) AddSubnetValidators( return n.GetL1Info(l1.SubnetID) } -func (n *LocalNetwork) GetValidatorManager(subnetID ids.ID) (ProxyAddress, ProxyAddress) { +func (n *LocalAvalancheNetwork) GetValidatorManager(subnetID ids.ID) (ProxyAddress, ProxyAddress) { return n.validatorManagers[subnetID], n.validatorManagerSpecializations[subnetID] } -func (n *LocalNetwork) GetSignatureAggregator() *utils.SignatureAggregator { +func (n *LocalAvalancheNetwork) GetSignatureAggregator() *utils.SignatureAggregator { var subnetIDs []ids.ID for _, l1 := range n.GetL1Infos() { subnetIDs = append(subnetIDs, l1.SubnetID) @@ -381,7 +383,7 @@ func (n *LocalNetwork) GetSignatureAggregator() *utils.SignatureAggregator { ) } -func (n *LocalNetwork) GetExtraNodes(count int) []*tmpnet.Node { +func (n *LocalAvalancheNetwork) GetExtraNodes(count int) []*tmpnet.Node { Expect(len(n.extraNodes) >= count).Should( BeTrue(), "not enough extra nodes to use", @@ -391,11 +393,11 @@ func (n *LocalNetwork) GetExtraNodes(count int) []*tmpnet.Node { return nodes } -func (n *LocalNetwork) GetPrimaryNetworkValidators() []*tmpnet.Node { +func (n *LocalAvalancheNetwork) GetPrimaryNetworkValidators() []*tmpnet.Node { return n.primaryNetworkValidators } -func (n *LocalNetwork) GetPrimaryNetworkInfo() interfaces.L1TestInfo { +func (n *LocalAvalancheNetwork) GetPrimaryNetworkInfo() interfaces.L1TestInfo { var nodeURIs []string for _, node := range n.primaryNetworkValidators { nodeURIs = append(nodeURIs, node.URI) @@ -423,18 +425,14 @@ func (n *LocalNetwork) GetPrimaryNetworkInfo() interfaces.L1TestInfo { } } -func (n *LocalNetwork) GetL1Info(subnetID ids.ID) interfaces.L1TestInfo { +func (n *LocalAvalancheNetwork) GetL1Info(subnetID ids.ID) interfaces.L1TestInfo { for _, l1 := range n.Network.Subnets { if l1.SubnetID == subnetID { var nodeURIs []string for _, nodeID := range l1.ValidatorIDs { node, err := n.Network.GetNode(nodeID) Expect(err).Should(BeNil()) - - uri, _, err := node.GetLocalURI(context.Background()) - Expect(err).Should(BeNil()) - - nodeURIs = append(nodeURIs, uri) + nodeURIs = append(nodeURIs, node.GetAccessibleURI()) } blockchainID := l1.Chains[0].ChainID wsClient, err := ethclient.Dial(utils.HttpToWebsocketURI(nodeURIs[0], blockchainID.String())) @@ -461,18 +459,14 @@ func (n *LocalNetwork) GetL1Info(subnetID ids.ID) interfaces.L1TestInfo { } // Returns all l1 info sorted in lexicographic order of L1Name. -func (n *LocalNetwork) GetL1Infos() []interfaces.L1TestInfo { +func (n *LocalAvalancheNetwork) GetL1Infos() []interfaces.L1TestInfo { l1s := make([]interfaces.L1TestInfo, len(n.Network.Subnets)) for i, l1 := range n.Network.Subnets { var nodeURIs []string for _, nodeID := range l1.ValidatorIDs { node, err := n.Network.GetNode(nodeID) Expect(err).Should(BeNil()) - - uri, _, err := node.GetLocalURI(context.Background()) - Expect(err).Should(BeNil()) - - nodeURIs = append(nodeURIs, uri) + nodeURIs = append(nodeURIs, node.GetAccessibleURI()) } blockchainID := l1.Chains[0].ChainID wsClient, err := ethclient.Dial(utils.HttpToWebsocketURI(nodeURIs[0], blockchainID.String())) @@ -498,25 +492,25 @@ func (n *LocalNetwork) GetL1Infos() []interfaces.L1TestInfo { } // Returns L1 info for all L1s, including the primary network -func (n *LocalNetwork) GetAllL1Infos() []interfaces.L1TestInfo { +func (n *LocalAvalancheNetwork) GetAllL1Infos() []interfaces.L1TestInfo { l1s := n.GetL1Infos() return append(l1s, n.GetPrimaryNetworkInfo()) } -func (n *LocalNetwork) GetFundedAccountInfo() (common.Address, *ecdsa.PrivateKey) { +func (n *LocalAvalancheNetwork) GetFundedAccountInfo() (common.Address, *ecdsa.PrivateKey) { ecdsaKey := n.globalFundedKey.ToECDSA() fundedAddress := crypto.PubkeyToAddress(ecdsaKey.PublicKey) return fundedAddress, ecdsaKey } -func (n *LocalNetwork) TearDownNetwork() { - log.Info("Tearing down network") +func (n *LocalAvalancheNetwork) TearDownNetwork() { + log.Info("Tearing down local Avalanche network") Expect(n).ShouldNot(BeNil()) Expect(n.Network).ShouldNot(BeNil()) Expect(n.Network.Stop(context.Background())).Should(BeNil()) } -func (n *LocalNetwork) SetChainConfigs(chainConfigs map[string]string) { +func (n *LocalAvalancheNetwork) SetChainConfigs(chainConfigs map[string]string) { for chainIDStr, chainConfig := range chainConfigs { var cfg tmpnet.ConfigMap err := json.Unmarshal([]byte(chainConfig), &cfg) @@ -560,15 +554,15 @@ func (n *LocalNetwork) SetChainConfigs(chainConfigs map[string]string) { Expect(err).Should(BeNil()) } -func (n *LocalNetwork) GetNetworkID() uint32 { +func (n *LocalAvalancheNetwork) GetNetworkID() uint32 { return n.Network.Genesis.NetworkID } -func (n *LocalNetwork) Dir() string { +func (n *LocalAvalancheNetwork) Dir() string { return n.Network.Dir } -func (n *LocalNetwork) GetPChainWallet(validationIDs ...ids.ID) pwallet.Wallet { +func (n *LocalAvalancheNetwork) GetPChainWallet(validationIDs ...ids.ID) pwallet.Wallet { // Create the P-Chain wallet to issue transactions kc := secp256k1fx.NewKeychain(n.globalFundedKey) var subnetIDs []ids.ID @@ -588,7 +582,7 @@ func (n *LocalNetwork) GetPChainWallet(validationIDs ...ids.ID) pwallet.Wallet { return wallet.P() } -func (n *LocalNetwork) GetTwoL1s() ( +func (n *LocalAvalancheNetwork) GetTwoL1s() ( interfaces.L1TestInfo, interfaces.L1TestInfo, ) { diff --git a/tests/network/local_ethereum_network.go b/tests/network/local_ethereum_network.go new file mode 100644 index 000000000..a1c9cbdc1 --- /dev/null +++ b/tests/network/local_ethereum_network.go @@ -0,0 +1,64 @@ +package network + +import ( + "context" + "crypto/ecdsa" + "encoding/hex" + "math/big" + + "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/subnet-evm/ethclient" + . "github.com/onsi/gomega" +) + +var _ LocalNetwork = &LocalEthereumNetwork{} + +type LocalEthereumNetwork struct { + BaseURL string + Client ethclient.Client + ChainID *big.Int + globalFundedKey *secp256k1.PrivateKey +} + +const ( + localEthereumNetworkBaseURL = "http://127.0.0.1:5050" + localEthereumNetworkFundedKey = "764A4A322753120B4667A20B6309CB5EC754A22BDBCBD62398BE8F803B255337" +) + +func NewLocalEthereumNetwork(ctx context.Context) *LocalEthereumNetwork { + // The local Ethereum network must already be running and accessible at a known endpoint. + // We test that it is accessible here. + client, err := ethclient.Dial(localEthereumNetworkBaseURL) + Expect(err).Should(BeNil()) + + // Get the chain ID of the local Ethereum network + chainID, err := client.ChainID(ctx) + Expect(err).Should(BeNil()) + + fundedKeyBytes, err := hex.DecodeString(localEthereumNetworkFundedKey) + Expect(err).Should(BeNil()) + globalFundedKey, err := secp256k1.ToPrivateKey(fundedKeyBytes) + Expect(err).Should(BeNil()) + + return &LocalEthereumNetwork{ + BaseURL: localEthereumNetworkBaseURL, + Client: client, + ChainID: chainID, + globalFundedKey: globalFundedKey, + } +} + +func (n *LocalEthereumNetwork) GetFundedAccountInfo() (common.Address, *ecdsa.PrivateKey) { + ecdsaKey := n.globalFundedKey.ToECDSA() + fundedAddress := crypto.PubkeyToAddress(ecdsaKey.PublicKey) + return fundedAddress, ecdsaKey +} + +func (n *LocalEthereumNetwork) TearDownNetwork() { + log.Info("Tearing down local Ethereum network") + Expect(n).ShouldNot(BeNil()) + Expect(n.Client).ShouldNot(BeNil()) +} diff --git a/tests/network/local_network.go b/tests/network/local_network.go new file mode 100644 index 000000000..842925cd5 --- /dev/null +++ b/tests/network/local_network.go @@ -0,0 +1,12 @@ +package network + +import ( + "crypto/ecdsa" + + "github.com/ava-labs/libevm/common" +) + +type LocalNetwork interface { + GetFundedAccountInfo() (common.Address, *ecdsa.PrivateKey) + TearDownNetwork() +} diff --git a/tests/suites/ethereum-icm-verification/ethereum_icm_verification_suite_test.go b/tests/suites/ethereum-icm-verification/ethereum_icm_verification_suite_test.go new file mode 100644 index 000000000..74579cae4 --- /dev/null +++ b/tests/suites/ethereum-icm-verification/ethereum_icm_verification_suite_test.go @@ -0,0 +1,121 @@ +package ethereum_icm_verification_test + +import ( + "context" + "os" + "testing" + "time" + + "github.com/ava-labs/avalanchego/tests/fixture/e2e" + ethereumICMVerification "github.com/ava-labs/icm-contracts/tests/flows/ethereum-icm-verification" + "github.com/ava-labs/icm-contracts/tests/network" + "github.com/ava-labs/icm-contracts/tests/utils" + deploymentUtils "github.com/ava-labs/icm-contracts/utils/deployment-utils" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/log" + "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +const ( + teleporterByteCodeFile = "./avalanche/out/TeleporterMessenger.sol/TeleporterMessenger.json" + warpGenesisTemplateFile = "./tests/utils/warp-genesis-template.json" + ethereumICMVerificationLabel = "ethereum-icm-verification" +) + +var ( + LocalAvalancheNetworkInstance *network.LocalAvalancheNetwork + LocalEthereumNetworkInstance *network.LocalEthereumNetwork + TeleporterInfo utils.TeleporterTestInfo + e2eFlags *e2e.FlagVars +) + +func TestEthereumICMVerification(t *testing.T) { + if os.Getenv("RUN_E2E") == "" { + t.Skip("Environment variable RUN_E2E not set; skipping E2E tests") + } + + e2eFlags = e2e.RegisterFlags() + RegisterFailHandler(ginkgo.Fail) + ginkgo.RunSpecs(t, "Ethereum ICM Verification e2e test") +} + +var _ = ginkgo.BeforeSuite(func() { + // Configure logging for tests + utils.ConfigureDefaultLoggingForTests() + + // Generate the Teleporter deployment values + teleporterDeployerTransaction, + teleporterDeployedBytecode, + teleporterDeployerAddress, + teleporterContractAddress, + err := deploymentUtils.ConstructKeylessTransaction( + teleporterByteCodeFile, + false, + deploymentUtils.GetDefaultContractCreationGasPrice(), + ) + Expect(err).Should(BeNil()) + + // Create the local network instances + ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second) + defer cancel() + + LocalAvalancheNetworkInstance = network.NewLocalAvalancheNetwork( + ctx, + "ethereum-icm-verification-test-local-network", + warpGenesisTemplateFile, + []network.L1Spec{ + { + Name: "L1", + EVMChainID: 12345, + TeleporterContractAddress: teleporterContractAddress, + TeleporterDeployedBytecode: teleporterDeployedBytecode, + TeleporterDeployerAddress: teleporterDeployerAddress, + NodeCount: 2, + }, + }, + 2, + 2, + e2eFlags, + ) + TeleporterInfo = utils.NewTeleporterTestInfo(LocalAvalancheNetworkInstance.GetAllL1Infos()) + log.Info("Started local Avalanche network", "networkID", LocalAvalancheNetworkInstance.NetworkID) + + // Only need to deploy Teleporter on the C-Chain since it is included in the genesis of the L1 chains. + _, fundedKey := LocalAvalancheNetworkInstance.GetFundedAccountInfo() + TeleporterInfo.DeployTeleporterMessenger( + ctx, + LocalAvalancheNetworkInstance.GetPrimaryNetworkInfo(), + teleporterDeployerTransaction, + teleporterDeployerAddress, + teleporterContractAddress, + fundedKey, + ) + for _, l1 := range LocalAvalancheNetworkInstance.GetAllL1Infos() { + TeleporterInfo.SetTeleporter(teleporterContractAddress, l1) + TeleporterInfo.Initialize(l1, fundedKey, common.HexToAddress("0x0200000000000000000000000000000000000005")) + TeleporterInfo.InitializeBlockchainID(l1, fundedKey) + TeleporterInfo.DeployTeleporterRegistry(l1, fundedKey) + } + + LocalEthereumNetworkInstance = network.NewLocalEthereumNetwork(ctx) + log.Info("Started local Ethereum network", "chainID", LocalEthereumNetworkInstance.ChainID) + + log.Info("Set up ginkgo before suite") +}) + +var _ = ginkgo.AfterSuite(func() { + LocalAvalancheNetworkInstance.TearDownNetwork() + LocalAvalancheNetworkInstance = nil + LocalEthereumNetworkInstance.TearDownNetwork() + LocalEthereumNetworkInstance = nil +}) + +var _ = ginkgo.Describe("[Ethereum ICM verification integration tests]", func() { + // Ethereum ICM verification tests + ginkgo.It("Deploy and test Ethereum ICM verification", + ginkgo.Label(ethereumICMVerificationLabel), + func() { + ethereumICMVerification.EthereumICMVerification(LocalAvalancheNetworkInstance, LocalEthereumNetworkInstance, TeleporterInfo) + }) +}) diff --git a/tests/suites/governance/governance_suite_test.go b/tests/suites/governance/governance_suite_test.go index fd196cc0b..b99f956c0 100644 --- a/tests/suites/governance/governance_suite_test.go +++ b/tests/suites/governance/governance_suite_test.go @@ -9,6 +9,7 @@ import ( "github.com/ava-labs/avalanchego/tests/fixture/e2e" governanceFlows "github.com/ava-labs/icm-contracts/tests/flows/governance" localnetwork "github.com/ava-labs/icm-contracts/tests/network" + "github.com/ava-labs/icm-contracts/tests/utils" "github.com/ava-labs/libevm/log" "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -20,7 +21,7 @@ const ( ) var ( - LocalNetworkInstance *localnetwork.LocalNetwork + LocalNetworkInstance *localnetwork.LocalAvalancheNetwork e2eFlags *e2e.FlagVars ) @@ -36,10 +37,13 @@ func TestGovernance(t *testing.T) { // Define the before and after suite functions. var _ = ginkgo.BeforeSuite(func() { + // Configure logging for tests + utils.ConfigureDefaultLoggingForTests() + // Create the local network instance ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second) defer cancel() - LocalNetworkInstance = localnetwork.NewLocalNetwork( + LocalNetworkInstance = localnetwork.NewLocalAvalancheNetwork( ctx, "governance-test-local-network", warpGenesisTemplateFile, diff --git a/tests/suites/ictt/ictt_suite_test.go b/tests/suites/ictt/ictt_suite_test.go index 3edab6175..9c381420c 100644 --- a/tests/suites/ictt/ictt_suite_test.go +++ b/tests/suites/ictt/ictt_suite_test.go @@ -11,13 +11,14 @@ import ( localnetwork "github.com/ava-labs/icm-contracts/tests/network" "github.com/ava-labs/icm-contracts/tests/utils" deploymentUtils "github.com/ava-labs/icm-contracts/utils/deployment-utils" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/log" "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) const ( - teleporterByteCodeFile = "./out/TeleporterMessenger.sol/TeleporterMessenger.json" + teleporterByteCodeFile = "./avalanche/out/TeleporterMessenger.sol/TeleporterMessenger.json" warpGenesisTemplateFile = "./tests/utils/warp-genesis-template.json" icttLabel = "ICTT" @@ -32,7 +33,7 @@ const ( ) var ( - LocalNetworkInstance *localnetwork.LocalNetwork + LocalNetworkInstance *localnetwork.LocalAvalancheNetwork TeleporterInfo utils.TeleporterTestInfo e2eFlags *e2e.FlagVars ) @@ -49,6 +50,9 @@ func TestValidatorManager(t *testing.T) { // Define the Teleporter before and after suite functions. var _ = ginkgo.BeforeSuite(func() { + // Configure logging for tests + utils.ConfigureDefaultLoggingForTests() + // Generate the Teleporter deployment values teleporterDeployerTransaction, teleporterDeployedBytecode, @@ -64,7 +68,7 @@ var _ = ginkgo.BeforeSuite(func() { // Create the local network instance ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second) defer cancel() - LocalNetworkInstance = localnetwork.NewLocalNetwork( + LocalNetworkInstance = localnetwork.NewLocalAvalancheNetwork( ctx, "teleporter-test-local-network", warpGenesisTemplateFile, @@ -105,6 +109,7 @@ var _ = ginkgo.BeforeSuite(func() { ) for _, l1 := range LocalNetworkInstance.GetAllL1Infos() { TeleporterInfo.SetTeleporter(teleporterContractAddress, l1) + TeleporterInfo.Initialize(l1, fundedKey, common.HexToAddress("0x0200000000000000000000000000000000000005")) TeleporterInfo.InitializeBlockchainID(l1, fundedKey) TeleporterInfo.DeployTeleporterRegistry(l1, fundedKey) } diff --git a/tests/suites/teleporter/teleporter_suite_test.go b/tests/suites/teleporter/teleporter_suite_test.go index cdbdadf60..4b4cf230e 100644 --- a/tests/suites/teleporter/teleporter_suite_test.go +++ b/tests/suites/teleporter/teleporter_suite_test.go @@ -16,13 +16,14 @@ import ( "github.com/ava-labs/icm-contracts/tests/network" "github.com/ava-labs/icm-contracts/tests/utils" deploymentUtils "github.com/ava-labs/icm-contracts/utils/deployment-utils" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/log" "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) const ( - teleporterByteCodeFile = "./out/TeleporterMessenger.sol/TeleporterMessenger.json" + teleporterByteCodeFile = "./avalanche/out/TeleporterMessenger.sol/TeleporterMessenger.json" warpGenesisTemplateFile = "./tests/utils/warp-genesis-template.json" teleporterMessengerLabel = "TeleporterMessenger" @@ -31,7 +32,7 @@ const ( ) var ( - LocalNetworkInstance *network.LocalNetwork + LocalNetworkInstance *network.LocalAvalancheNetwork TeleporterInfo utils.TeleporterTestInfo e2eFlags *e2e.FlagVars ) @@ -48,6 +49,9 @@ func TestTeleporter(t *testing.T) { // Define the Teleporter before and after suite functions. var _ = ginkgo.BeforeSuite(func() { + // Configure logging for tests + utils.ConfigureDefaultLoggingForTests() + // Generate the Teleporter deployment values teleporterDeployerTransaction, teleporterDeployedBytecode, @@ -64,7 +68,7 @@ var _ = ginkgo.BeforeSuite(func() { ctx, cancel := context.WithTimeout(context.Background(), 240*2*time.Second) defer cancel() - LocalNetworkInstance = network.NewLocalNetwork( + LocalNetworkInstance = network.NewLocalAvalancheNetwork( ctx, "teleporter-test-local-network", warpGenesisTemplateFile, @@ -108,6 +112,7 @@ var _ = ginkgo.BeforeSuite(func() { for _, l1 := range LocalNetworkInstance.GetAllL1Infos() { TeleporterInfo.SetTeleporter(teleporterContractAddress, l1) + TeleporterInfo.Initialize(l1, fundedKey, common.HexToAddress("0x0200000000000000000000000000000000000005")) TeleporterInfo.InitializeBlockchainID(l1, fundedKey) TeleporterInfo.DeployTeleporterRegistry(l1, fundedKey) } diff --git a/tests/suites/validator-manager/validator_manager_suite_test.go b/tests/suites/validator-manager/validator_manager_suite_test.go index 4f2691ae3..b8999cb9b 100644 --- a/tests/suites/validator-manager/validator_manager_suite_test.go +++ b/tests/suites/validator-manager/validator_manager_suite_test.go @@ -9,6 +9,7 @@ import ( "github.com/ava-labs/avalanchego/tests/fixture/e2e" validatorManagerFlows "github.com/ava-labs/icm-contracts/tests/flows/validator-manager" localnetwork "github.com/ava-labs/icm-contracts/tests/network" + "github.com/ava-labs/icm-contracts/tests/utils" "github.com/ava-labs/libevm/log" "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -20,7 +21,7 @@ const ( ) var ( - LocalNetworkInstance *localnetwork.LocalNetwork + LocalNetworkInstance *localnetwork.LocalAvalancheNetwork e2eFlags *e2e.FlagVars ) @@ -36,10 +37,13 @@ func TestValidatorManager(t *testing.T) { // Define the before and after suite functions. var _ = ginkgo.BeforeEach(func() { + // Configure logging for tests + utils.ConfigureDefaultLoggingForTests() + // Create the local network instance ctx, cancel := context.WithTimeout(context.Background(), 240*time.Second) defer cancel() - LocalNetworkInstance = localnetwork.NewLocalNetwork( + LocalNetworkInstance = localnetwork.NewLocalAvalancheNetwork( ctx, "validator-manager-test-local-network", warpGenesisTemplateFile, diff --git a/tests/utils/avalanche_validator_registry.go b/tests/utils/avalanche_validator_registry.go new file mode 100644 index 000000000..d18cef091 --- /dev/null +++ b/tests/utils/avalanche_validator_registry.go @@ -0,0 +1,230 @@ +package utils + +import ( + "bytes" + "context" + "crypto/ecdsa" + "crypto/sha256" + "encoding/hex" + "math/big" + "strings" + + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/vms/platformvm" + "github.com/ava-labs/avalanchego/vms/platformvm/api" + "github.com/ava-labs/avalanchego/vms/platformvm/block" + "github.com/ava-labs/avalanchego/vms/platformvm/warp" + "github.com/ava-labs/avalanchego/vms/platformvm/warp/message" + "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" + avalanchevalidatorsetregistry "github.com/ava-labs/icm-contracts/abi-bindings/go/AvalancheValidatorSetRegistry" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/subnet-evm/accounts/abi" + "github.com/ava-labs/subnet-evm/accounts/abi/bind" + "github.com/ava-labs/subnet-evm/ethclient" + . "github.com/onsi/gomega" +) + +func DeployAvalancheValidatorSetRegistry( + ctx context.Context, + fundedKey *ecdsa.PrivateKey, + chainID *big.Int, + client ethclient.Client, + avalancheNetworkID uint32, + avalancheBlockChainID ids.ID, +) (common.Address, *avalanchevalidatorsetregistry.AvalancheValidatorSetRegistry) { + opts, err := bind.NewKeyedTransactorWithChainID(fundedKey, chainID) + Expect(err).Should(BeNil()) + + address, tx, validatorSetRegistry, err := avalanchevalidatorsetregistry.DeployAvalancheValidatorSetRegistry(opts, client, avalancheNetworkID, avalancheBlockChainID) + Expect(err).Should(BeNil()) + + WaitForTransactionSuccessWithClient(ctx, client, tx.Hash()) + + return address, validatorSetRegistry +} + +func RegisterAvalancheValidatorSet( + ctx context.Context, + fundedKey *ecdsa.PrivateKey, + chainID *big.Int, + client ethclient.Client, + validatorSetRegistry *avalanchevalidatorsetregistry.AvalancheValidatorSetRegistry, + avalancheNetworkID uint32, + avalanchePChainBlockchainID ids.ID, + avalancheSubnetID ids.ID, + avalancheL1BlockchainID ids.ID, + pChainClient *platformvm.Client, + signatureAggregator *SignatureAggregator, +) *big.Int { + opts, err := bind.NewKeyedTransactorWithChainID(fundedKey, chainID) + Expect(err).Should(BeNil()) + + // Get the validator set information to create the serialized pre-image. + pChainHeight, err := pChainClient.GetHeight(ctx) + Expect(err).Should(BeNil()) + pChainBlockBytes, err := pChainClient.GetBlockByHeight(ctx, pChainHeight) + Expect(err).Should(BeNil()) + + // Parse the block + pChainBlock, err := block.Parse(block.Codec, pChainBlockBytes) + Expect(err).Should(BeNil()) + + // Confirm that the block is a Banff block + banffBlock, ok := pChainBlock.(block.BanffBlock) + Expect(ok).Should(BeTrue()) + + // Get the validators from the block height + rawValidators, err := pChainClient.GetValidatorsAt(ctx, avalancheSubnetID, api.Height(pChainHeight)) + Expect(err).Should(BeNil()) + + canonicalValidatorSet, err := warp.FlattenValidatorSet(rawValidators) + Expect(err).Should(BeNil()) + + log.Info("Canonical validator set", "numValidators", len(canonicalValidatorSet.Validators), "totalWeight", canonicalValidatorSet.TotalWeight) + + // Create the unsigned message including the validator set hash in the payload. + validators := make([]*message.Validator, len(canonicalValidatorSet.Validators)) + for i, validator := range canonicalValidatorSet.Validators { + validators[i] = &message.Validator{ + UncompressedPublicKeyBytes: [96]byte(validator.PublicKey.Serialize()), + Weight: validator.Weight, + } + } + validatorsBytes, err := message.Codec.Marshal(message.CodecVersion, validators) + Expect(err).Should(BeNil()) + + validatorSetHash := sha256.Sum256(validatorsBytes) + validaterSetStatePayload, err := message.NewValidatorSetState( + avalancheL1BlockchainID, + pChainHeight, + uint64(banffBlock.Timestamp().Unix()), + validatorSetHash, + ) + Expect(err).Should(BeNil()) + + addressCallPayload, err := payload.NewAddressedCall([]byte{}, validaterSetStatePayload.Bytes()) + Expect(err).Should(BeNil()) + + // Create the unsigned message + unsignedMessage, err := warp.NewUnsignedMessage(avalancheNetworkID, avalanchePChainBlockchainID, addressCallPayload.Bytes()) + Expect(err).Should(BeNil()) + + // create the ICM message suitable for Ethereum + icmMessage := PrepareICMMessageForEthereum( + avalancheNetworkID, + avalanchePChainBlockchainID, + avalancheSubnetID, + avalanchePChainBlockchainID, + signatureAggregator, + unsignedMessage, + ) + log.Info("DEBUG: Validator Set Details:", + "validatorsBytesLength", len(validatorsBytes), + "validatorsBytes", hex.EncodeToString(validatorsBytes), + ) + // Try to encode the transaction data to see what would be sent + registryABI, abiErr := abi.JSON(strings.NewReader(avalanchevalidatorsetregistry.AvalancheValidatorSetRegistryABI)) + if abiErr == nil { + txData, encodeErr := registryABI.Pack("registerValidatorSet", icmMessage, validatorsBytes) + if encodeErr == nil { + log.Info("DEBUG: Raw transaction calldata", + "data", hex.EncodeToString(txData), + "dataLength", len(txData), + ) + } else { + log.Error("Failed to encode transaction data", "error", encodeErr) + } + } else { + log.Error("Failed to parse contract ABI", "error", abiErr) + } + + // Test the verification before sending the transaction + registryNetworkID, err := validatorSetRegistry.GetAvalancheNetworkID(nil) + if err != nil { + log.Error("Failed to get registry network ID", "error", err) + } else { + log.Info("DEBUG: Registry network ID", "registryNetworkID", registryNetworkID, "expectedNetworkID", avalancheNetworkID) + if registryNetworkID != avalancheNetworkID { + log.Error("Network ID mismatch", "registryNetworkID", registryNetworkID, "expectedNetworkID", avalancheNetworkID) + } + } + + // Parse the addressed call payload to debug its contents + log.Info("DEBUG: AddressedCall payload details", + "payloadBytes", hex.EncodeToString(addressCallPayload.Bytes()), + "sourceAddressLength", len([]byte{}), + "validatorSetStatePayloadBytes", hex.EncodeToString(validaterSetStatePayload.Bytes()), + ) + + // Additional debug: check the validator set hash that was computed vs what's expected + computedHash := sha256.Sum256(validatorsBytes) + log.Info("DEBUG: Validator set hash validation", + "expectedHash", hex.EncodeToString(validatorSetHash[:]), + "computedHash", hex.EncodeToString(computedHash[:]), + "hashMatch", bytes.Equal(validatorSetHash[:], computedHash[:]), + ) + + // Debug the unsigned message structure + log.Info("DEBUG: Unsigned message structure breakdown", + "networkID", avalancheNetworkID, + "sourceBlockchainID", hex.EncodeToString(avalanchePChainBlockchainID[:]), + "targetBlockchainID", hex.EncodeToString(avalancheL1BlockchainID[:]), + "isSameChain", bytes.Equal(avalanchePChainBlockchainID[:], avalancheL1BlockchainID[:]), + "payloadSize", len(addressCallPayload.Bytes()), + ) + + // Comprehensive ICM message debugging + DebugICMMessage(icmMessage, validatorsBytes, avalancheNetworkID) + CompareICMMessageFields(icmMessage, avalancheNetworkID, avalanchePChainBlockchainID) + + // Try a static call first to simulate the transaction and see detailed error + log.Info("DEBUG: Attempting static call simulation...") + callOpts := &bind.CallOpts{ + From: opts.From, + Context: ctx, + } + + // We can't directly simulate registerValidatorSet because it's not a view function + // But we can at least validate the network ID and other accessible info + currentValidatorSetID, err := validatorSetRegistry.NextValidatorSetID(callOpts) + if err != nil { + log.Error("Failed to get next validator set ID", "error", err) + } else { + log.Info("DEBUG: Next validator set ID", "nextID", currentValidatorSetID) + } + + // Register the validator set in the registry. + tx, err := validatorSetRegistry.RegisterValidatorSet(opts, into(icmMessage), validatorsBytes) + if err != nil { + log.Error("Failed to register validator set", "error", err) + log.Info("Register validator set transaction failed", "error", err) + + // Additional debugging: examine the specific error message + errorStr := err.Error() + log.Info("DEBUG: Detailed error analysis", "errorString", errorStr) + if strings.Contains(errorStr, "Invalid ICM message") { + log.Error("DIAGNOSIS: ICM message validation failed - check networkID, sourceBlockchainID, signature verification, or weight quorum") + } + if strings.Contains(errorStr, "execution reverted") { + log.Error("DIAGNOSIS: Transaction reverted - likely a require() statement failed in the contract") + } + } else if tx != nil { + log.Info("Register validator set transaction", "tx", tx.Hash(), "txData", hex.EncodeToString(tx.Data())) + } else { + log.Error("Transaction is nil but no error returned") + } + Expect(err).Should(BeNil()) + + // Wait for the transaction to be mined and get the receipt. + txReceipt := WaitForTransactionSuccessWithClient(ctx, client, tx.Hash()) + log.Info("DEBUG: Transaction receipt", "txReceipt", txReceipt, "gasUsed", txReceipt.GasUsed) + + // Get the event from the logs, and confirm the validator set was registered. + validatorSetRegisteredEvent, err := GetEventFromLogs(txReceipt.Logs, validatorSetRegistry.ParseValidatorSetRegistered) + Expect(err).Should(BeNil()) + Expect(validatorSetRegisteredEvent.AvalancheBlockchainID).Should(BeEquivalentTo(avalancheL1BlockchainID)) + + // Return the validator set ID. + return validatorSetRegisteredEvent.ValidatorSetID +} diff --git a/tests/utils/chain.go b/tests/utils/chain.go index 04fb7e492..15bea5ea0 100644 --- a/tests/utils/chain.go +++ b/tests/utils/chain.go @@ -152,14 +152,14 @@ func SendNativeTransfer( // Asserts Receipt.status equals success. func sendAndWaitForTransaction( ctx context.Context, - l1Info interfaces.L1TestInfo, + client ethclient.Client, tx *types.Transaction, success bool, ) *types.Receipt { - err := l1Info.RPCClient.SendTransaction(ctx, tx) + err := client.SendTransaction(ctx, tx) Expect(err).Should(BeNil()) - return waitForTransaction(ctx, l1Info, tx.Hash(), success) + return waitForTransaction(ctx, client, tx.Hash(), success) } // Sends a tx, and waits for it to be mined. @@ -169,7 +169,7 @@ func SendTransactionAndWaitForFailure( l1Info interfaces.L1TestInfo, tx *types.Transaction, ) *types.Receipt { - return sendAndWaitForTransaction(ctx, l1Info, tx, false) + return sendAndWaitForTransaction(ctx, l1Info.RPCClient, tx, false) } // Sends a tx, and waits for it to be mined. @@ -179,7 +179,7 @@ func SendTransactionAndWaitForSuccess( l1Info interfaces.L1TestInfo, tx *types.Transaction, ) *types.Receipt { - return sendAndWaitForTransaction(ctx, l1Info, tx, true) + return sendAndWaitForTransaction(ctx, l1Info.RPCClient, tx, true) } // Waits for a transaction to be mined. @@ -189,7 +189,15 @@ func WaitForTransactionSuccess( l1Info interfaces.L1TestInfo, txHash common.Hash, ) *types.Receipt { - return waitForTransaction(ctx, l1Info, txHash, true) + return waitForTransaction(ctx, l1Info.RPCClient, txHash, true) +} + +func WaitForTransactionSuccessWithClient( + ctx context.Context, + client ethclient.Client, + txHash common.Hash, +) *types.Receipt { + return waitForTransaction(ctx, client, txHash, true) } // Waits for a transaction to be mined. @@ -199,26 +207,26 @@ func WaitForTransactionFailure( l1Info interfaces.L1TestInfo, txHash common.Hash, ) *types.Receipt { - return waitForTransaction(ctx, l1Info, txHash, false) + return waitForTransaction(ctx, l1Info.RPCClient, txHash, false) } // Waits for a transaction to be mined. // Asserts Receipt.status equals success. func waitForTransaction( ctx context.Context, - l1Info interfaces.L1TestInfo, + client ethclient.Client, txHash common.Hash, success bool, ) *types.Receipt { cctx, cancel := context.WithTimeout(ctx, 20*time.Second) defer cancel() - receipt, err := WaitMined(cctx, l1Info.RPCClient, txHash) + receipt, err := WaitMined(cctx, client, txHash) Expect(err).Should(BeNil()) if success { if receipt.Status == types.ReceiptStatusFailed { - TraceTransactionAndExit(ctx, l1Info.RPCClient, receipt.TxHash) + TraceTransactionAndExit(ctx, client, receipt.TxHash) } } else { Expect(receipt.Status).Should(Equal(types.ReceiptStatusFailed)) @@ -654,8 +662,7 @@ func SetupProposerVM(ctx context.Context, fundedKey *ecdsa.PrivateKey, network * node, err := network.GetNode(l1Details.ValidatorIDs[0]) Expect(err).Should(BeNil()) - nodeURI, _, err := node.GetLocalURI(context.Background()) - Expect(err).Should(BeNil()) + nodeURI := node.GetAccessibleURI() uri := HttpToWebsocketURI(nodeURI, chainID.String()) client, err := ethclient.Dial(uri) diff --git a/tests/utils/eth_warp.go b/tests/utils/eth_warp.go new file mode 100644 index 000000000..44a251241 --- /dev/null +++ b/tests/utils/eth_warp.go @@ -0,0 +1,62 @@ +package utils + +import ( + "context" + "crypto/ecdsa" + "encoding/hex" + "math/big" + + "github.com/ava-labs/avalanchego/ids" + ethwarp "github.com/ava-labs/icm-contracts/abi-bindings/go/EthWarp" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/subnet-evm/accounts/abi/bind" + "github.com/ava-labs/subnet-evm/ethclient" + . "github.com/onsi/gomega" +) + +func DeployEthWarp( + ctx context.Context, + fundedKey *ecdsa.PrivateKey, + chainID *big.Int, + client ethclient.Client, + warpChainID ids.ID, +) (common.Address, *ethwarp.EthWarp) { + opts, err := bind.NewKeyedTransactorWithChainID(fundedKey, chainID) + Expect(err).Should(BeNil()) + log.Info("Deploying WARP with dest chain", "id", warpChainID.Hex()) + address, tx, ethWarp, err := ethwarp.DeployEthWarp(opts, client, chainID, warpChainID) + Expect(err).Should(BeNil()) + + WaitForTransactionSuccessWithClient(ctx, client, tx.Hash()) + + return address, ethWarp +} + +func RegisterValSetRegistryWithEthWarp( + ctx context.Context, + fundedKey *ecdsa.PrivateKey, + chainID *big.Int, + client ethclient.Client, + ethWarp *ethwarp.EthWarp, + avalancheL1BlockchainID ids.ID, + validatorSetRegistryAddress common.Address, +) { + opts, err := bind.NewKeyedTransactorWithChainID(fundedKey, chainID) + Expect(err).Should(BeNil()) + tx, err := ethWarp.RegisterChain(opts, avalancheL1BlockchainID, validatorSetRegistryAddress) + if err != nil { + log.Error("Failed to register ValidatorSetRegistry to EthWarp contract", "error", err) + log.Info("Registering a ValidatorSetRegistry to an EthWarp contract failed", "error", err) + } else if tx != nil { + log.Info("EthWarp contract registered validator set", "Blockchain ID", avalancheL1BlockchainID, "contract", validatorSetRegistryAddress) + log.Info("Register chain to EthWarp transaction", "tx", tx.Hash(), "txData", hex.EncodeToString(tx.Data())) + } else { + log.Error("Transaction is nil but no error returned") + } + Expect(err).Should(BeNil()) + + // Wait for the transaction to be mined and get the receipt. + txReceipt := WaitForTransactionSuccessWithClient(ctx, client, tx.Hash()) + log.Info("DEBUG: Transaction receipt", "txReceipt", txReceipt, "gasUsed", txReceipt.GasUsed) +} diff --git a/tests/utils/icm_debug_helper.go b/tests/utils/icm_debug_helper.go new file mode 100644 index 000000000..dfdf32984 --- /dev/null +++ b/tests/utils/icm_debug_helper.go @@ -0,0 +1,111 @@ +package utils + +import ( + "crypto/sha256" + "encoding/hex" + + "github.com/ava-labs/avalanchego/vms/platformvm/warp" + "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" + teleportermessenger "github.com/ava-labs/icm-contracts/abi-bindings/go/teleporter/TeleporterMessenger" + "github.com/ava-labs/libevm/log" +) + +// DebugICMMessage provides detailed analysis of an ICM message for debugging validation issues +func DebugICMMessage( + icmMessage teleportermessenger.ICMMessage, + validatorsBytes []byte, + expectedNetworkID uint32, +) { + log.Info("=== ICM MESSAGE DEBUG ANALYSIS ===") + + // 1. Basic message structure + log.Info("1. Message Structure", + "networkID", icmMessage.UnsignedMessage.AvalancheNetworkID, + "sourceBlockchainID", hex.EncodeToString(icmMessage.UnsignedMessage.AvalancheSourceBlockchainID[:]), + "payloadLength", len(icmMessage.UnsignedMessage.Payload), + ) + + // 2. Network ID validation + networkIDValid := icmMessage.UnsignedMessage.AvalancheNetworkID == expectedNetworkID + log.Info("2. Network ID Validation", + "expected", expectedNetworkID, + "actual", icmMessage.UnsignedMessage.AvalancheNetworkID, + "valid", networkIDValid, + ) + + // 3. Try to parse the payload as AddressedCall + addressedCall, err := payload.ParseAddressedCall(icmMessage.UnsignedMessage.Payload) + if err != nil { + log.Error("3. AddressedCall Parsing FAILED", "error", err) + return + } + + sourceAddressValid := len(addressedCall.SourceAddress) == 0 + log.Info("3. AddressedCall Structure", + "sourceAddressLength", len(addressedCall.SourceAddress), + "sourceAddressValid", sourceAddressValid, + "innerPayloadLength", len(addressedCall.Payload), + ) + + // 4. Validator set hash verification + computedHash := sha256.Sum256(validatorsBytes) + log.Info("4. Validator Set Hash", + "validatorBytesLength", len(validatorsBytes), + "computedHash", hex.EncodeToString(computedHash[:]), + ) + + // 5. Signature analysis + log.Info("5. Signature Analysis", + "signersLength", len(icmMessage.Signature.Signers), + "signers", hex.EncodeToString(icmMessage.Signature.Signers), + "signatureLength", len(icmMessage.Signature.Signature), + "signature", hex.EncodeToString(icmMessage.Signature.Signature), + ) + + // 6. Try to parse the full signed message + unsignedMessage, err := warp.ParseUnsignedMessage(icmMessage.UnsignedMessageBytes) + if err != nil { + log.Error("6. Signed Message Parsing FAILED", "error", err) + } else { + log.Info("6. Signed Message Structure", + "messageID", unsignedMessage.ID().String(), + "networkID", unsignedMessage.NetworkID, + "sourceChainID", unsignedMessage.SourceChainID.String(), + ) + } + + log.Info("=== END ICM MESSAGE DEBUG ANALYSIS ===") +} + +// CompareICMMessageFields helps identify specific field mismatches +func CompareICMMessageFields( + icmMessage teleportermessenger.ICMMessage, + expectedNetworkID uint32, + expectedSourceBlockchainID [32]byte, +) { + log.Info("=== ICM MESSAGE FIELD COMPARISON ===") + + // Network ID comparison + if icmMessage.UnsignedMessage.AvalancheNetworkID != expectedNetworkID { + log.Error("❌ Network ID Mismatch", + "expected", expectedNetworkID, + "actual", icmMessage.UnsignedMessage.AvalancheNetworkID, + ) + } else { + log.Info("✅ Network ID Match", "networkID", expectedNetworkID) + } + + // Blockchain ID comparison + if icmMessage.UnsignedMessage.AvalancheSourceBlockchainID != expectedSourceBlockchainID { + log.Error("❌ Source Blockchain ID Mismatch", + "expected", hex.EncodeToString(expectedSourceBlockchainID[:]), + "actual", hex.EncodeToString(icmMessage.UnsignedMessage.AvalancheSourceBlockchainID[:]), + ) + } else { + log.Info("✅ Source Blockchain ID Match", + "blockchainID", hex.EncodeToString(expectedSourceBlockchainID[:]), + ) + } + + log.Info("=== END FIELD COMPARISON ===") +} diff --git a/tests/utils/icm_messages.go b/tests/utils/icm_messages.go new file mode 100644 index 000000000..a8f1aea3b --- /dev/null +++ b/tests/utils/icm_messages.go @@ -0,0 +1,81 @@ +package utils + +import ( + "encoding/hex" + + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/utils/crypto/bls" + "github.com/ava-labs/avalanchego/vms/platformvm/warp" + avalanchevalidatorsetregistry "github.com/ava-labs/icm-contracts/abi-bindings/go/AvalancheValidatorSetRegistry" + teleportermessenger "github.com/ava-labs/icm-contracts/abi-bindings/go/teleporter/TeleporterMessenger" + "github.com/ava-labs/libevm/log" + . "github.com/onsi/gomega" +) + +func PrepareICMMessageForEthereum( + avalancheNetworkID uint32, + avalanchePChainBlockchainID ids.ID, + avalancheSubnetID ids.ID, + avalancheL1BlockchainID ids.ID, + signatureAggregator *SignatureAggregator, + unsignedMessage *warp.UnsignedMessage, +) teleportermessenger.ICMMessage { + + // Generate the signature of the unsigned message using the signature aggregator. + log.Info("Generating signature of unsigned message", "networkID", avalancheNetworkID, "pChainBlockchainID", avalanchePChainBlockchainID, "subnetID", avalancheSubnetID, "weightThreshold", 70) + signedMessage, err := signatureAggregator.CreateSignedMessage(unsignedMessage, nil, avalancheSubnetID, 70) + Expect(err).Should(BeNil()) + bitSetSignature, ok := signedMessage.Signature.(*warp.BitSetSignature) + Expect(ok).Should(BeTrue()) + + // Parse the BLS signature + blsSignature, err := bls.SignatureFromBytes(bitSetSignature.Signature[:]) + Expect(err).Should(BeNil()) + + // Serialize the BLS signature + blsSignatureBytes := blsSignature.Serialize() + + // Create the ICM message struct + icmMessage := teleportermessenger.ICMMessage{ + UnsignedMessage: teleportermessenger.ICMUnsignedMessage{ + AvalancheNetworkID: avalancheNetworkID, + AvalancheSourceBlockchainID: avalancheL1BlockchainID, + Payload: unsignedMessage.Payload, + }, + UnsignedMessageBytes: unsignedMessage.Bytes(), + Signature: teleportermessenger.ICMSignature{ + Signers: bitSetSignature.Signers, + Signature: blsSignatureBytes, + }, + } + + // Debug logging before sending transaction + log.Info("DEBUG: ICM Message Details", + "avalancheNetworkID", avalancheNetworkID, + "avalancheSourceBlockchainID", hex.EncodeToString(avalanchePChainBlockchainID[:]), + "avalancheL1BlockchainID", hex.EncodeToString(avalancheL1BlockchainID[:]), + "payloadLength", len(unsignedMessage.Payload), + "payload", hex.EncodeToString(unsignedMessage.Payload), + "unsignedMessageLength", len(unsignedMessage.Bytes()), + "signersLength", len(bitSetSignature.Signers), + "signers", hex.EncodeToString(bitSetSignature.Signers), + "signatureLength", len(bitSetSignature.Signature[:]), + "signature", hex.EncodeToString(bitSetSignature.Signature[:]), + ) + return icmMessage +} + +func into(msg teleportermessenger.ICMMessage) avalanchevalidatorsetregistry.ICMMessage { + return avalanchevalidatorsetregistry.ICMMessage{ + UnsignedMessage: avalanchevalidatorsetregistry.ICMUnsignedMessage{ + AvalancheNetworkID: msg.UnsignedMessage.AvalancheNetworkID, + AvalancheSourceBlockchainID: msg.UnsignedMessage.AvalancheSourceBlockchainID, + Payload: msg.UnsignedMessage.Payload, + }, + UnsignedMessageBytes: msg.UnsignedMessageBytes, + Signature: avalanchevalidatorsetregistry.ICMSignature{ + Signers: msg.Signature.Signers, + Signature: msg.Signature.Signature, + }, + } +} diff --git a/tests/utils/signature_aggregator.go b/tests/utils/signature_aggregator.go index ec37ec1b1..3d5f87f39 100644 --- a/tests/utils/signature_aggregator.go +++ b/tests/utils/signature_aggregator.go @@ -36,7 +36,7 @@ type SignatureAggregatorConfig struct { PChainAPI ApiConfig `json:"p-chain-api"` InfoAPI ApiConfig `json:"info-api"` SubnetIDs []string `json:"tracked-subnet-ids"` - ApiPort int `json:"api-port"` + APIPort int `json:"api-port"` AllowPrivateIPs bool `json:"allow-private-ips"` } @@ -62,7 +62,7 @@ func (s *SignatureAggregator) Shutdown() { } // Aggregator utils -func NewSignatureAggregator(apiUri string, subnetIDs []ids.ID) *SignatureAggregator { +func NewSignatureAggregator(baseURL string, subnetIDs []ids.ID) *SignatureAggregator { sigAggPath := os.Getenv("SIG_AGG_PATH") Expect(sigAggPath).ShouldNot(BeEmpty()) subnetIDStrings := make([]string, 0, len(subnetIDs)) @@ -71,13 +71,13 @@ func NewSignatureAggregator(apiUri string, subnetIDs []ids.ID) *SignatureAggrega } cfg := SignatureAggregatorConfig{ PChainAPI: ApiConfig{ - BaseURL: apiUri, + BaseURL: baseURL, }, InfoAPI: ApiConfig{ - BaseURL: apiUri, + BaseURL: baseURL, }, SubnetIDs: subnetIDStrings, - ApiPort: DEFAULT_API_PORT, + APIPort: DEFAULT_API_PORT, AllowPrivateIPs: true, } // write config to a JSON file in /tmp directory diff --git a/tests/utils/teleporter.go b/tests/utils/teleporter.go index 48bde37ec..11df31ec3 100644 --- a/tests/utils/teleporter.go +++ b/tests/utils/teleporter.go @@ -23,6 +23,7 @@ import ( "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/accounts/abi/bind" + "github.com/ava-labs/subnet-evm/ethclient" "github.com/ava-labs/subnet-evm/precompile/contracts/warp" predicateutils "github.com/ava-labs/subnet-evm/predicate" "github.com/ava-labs/subnet-evm/rpc" @@ -82,6 +83,14 @@ func (t TeleporterTestInfo) SetTeleporter(address common.Address, l1 interfaces. info.TeleporterMessenger = teleporterMessenger } +func (t TeleporterTestInfo) Initialize(l1 interfaces.L1TestInfo, fundedKey *ecdsa.PrivateKey, warpContractAddress common.Address) { + opts, err := bind.NewKeyedTransactorWithChainID(fundedKey, l1.EVMChainID) + Expect(err).Should(BeNil()) + tx, err := t.TeleporterMessenger(l1).Initialize(opts, warpContractAddress) + Expect(err).Should(BeNil()) + WaitForTransactionSuccess(context.Background(), l1, tx.Hash()) +} + func (t TeleporterTestInfo) InitializeBlockchainID(l1 interfaces.L1TestInfo, fundedKey *ecdsa.PrivateKey) { opts, err := bind.NewKeyedTransactorWithChainID(fundedKey, l1.EVMChainID) Expect(err).Should(BeNil()) @@ -112,6 +121,30 @@ func (t TeleporterTestInfo) DeployTeleporterRegistry(l1 interfaces.L1TestInfo, d info.TeleporterRegistry = teleporterRegistry } +func DeployTeleporterMessengerToEthereum( + ctx context.Context, + fundedKey *ecdsa.PrivateKey, + chainID *big.Int, + client ethclient.Client, + warpContract common.Address, +) (common.Address, *teleportermessenger.TeleporterMessenger) { + opts, err := bind.NewKeyedTransactorWithChainID(fundedKey, chainID) + Expect(err).Should(BeNil()) + address, tx, teleporterMessenger, err := teleportermessenger.DeployTeleporterMessenger(opts, client) + Expect(err).Should(BeNil()) + + WaitForTransactionSuccessWithClient(ctx, client, tx.Hash()) + + // initialize the Warp contracts + tx, err = teleporterMessenger.Initialize(opts, warpContract) + Expect(err).Should(BeNil()) + + WaitForTransactionSuccessWithClient(ctx, client, tx.Hash()) + + return address, teleporterMessenger + +} + func (t TeleporterTestInfo) DeployTeleporterMessenger( ctx context.Context, l1 interfaces.L1TestInfo, @@ -197,6 +230,55 @@ func (t TeleporterTestInfo) RelayTeleporterMessage( return receipt } +func (t TeleporterTestInfo) RelayInterchainTeleporterMessage( + ctx context.Context, + ethereumChainID *big.Int, + ethClient ethclient.Client, + avalancheNetworkID uint32, + avalanchePChainBlockchainID ids.ID, + sourceReceipt *types.Receipt, + source interfaces.L1TestInfo, + destination *teleportermessenger.TeleporterMessenger, + ethFundedKey *ecdsa.PrivateKey, + signatureAggregator *SignatureAggregator, +) *types.Receipt { + log.Info("Relaying transaction to destination chain") + // Fetch the Teleporter message from the logs + unsignedMsg := ExtractWarpMessageFromLog(ctx, sourceReceipt, source) + + // Loop over each client on source chain to ensure they all have time to accept the block. + // Note: if we did not confirm this here, the next stage could be racy since it assumes every node + // has accepted the block. + WaitForAllValidatorsToAcceptBlock(ctx, source.NodeURIs, source.BlockchainID, sourceReceipt.BlockNumber.Uint64()) + + icmMessage := PrepareICMMessageForEthereum( + avalancheNetworkID, + avalanchePChainBlockchainID, + source.SubnetID, + source.BlockchainID, + signatureAggregator, + unsignedMsg, + ) + + opts, err := bind.NewKeyedTransactorWithChainID(ethFundedKey, ethereumChainID) + Expect(err).Should(BeNil()) + + tx, err := destination.ReceiveInterChainMessage(opts, icmMessage, PrivateKeyToAddress(ethFundedKey)) + Expect(err).Should(BeNil()) + + log.Info("Sending transaction to destination chain") + receipt := WaitForTransactionSuccessWithClient(ctx, ethClient, tx.Hash()) + + // Check the transaction logs for the ReceiveCrossChainMessage event emitted by the Teleporter contract + receiveEvent, err := GetEventFromLogs( + receipt.Logs, + destination.ParseReceiveCrossChainMessage, + ) + Expect(err).Should(BeNil()) + Expect(receiveEvent.SourceBlockchainID[:]).Should(Equal(source.BlockchainID[:])) + return receipt +} + func (t TeleporterTestInfo) SendExampleCrossChainMessageAndVerify( ctx context.Context, source interfaces.L1TestInfo, @@ -209,7 +291,7 @@ func (t TeleporterTestInfo) SendExampleCrossChainMessageAndVerify( signatureAggregator *SignatureAggregator, expectSuccess bool, ) { - // Call the example messenger contract on L1 A + // Call the example messenger contract on L1 AF optsA, err := bind.NewKeyedTransactorWithChainID(senderKey, source.EVMChainID) Expect(err).Should(BeNil()) tx, err := sourceExampleMessenger.SendMessage( @@ -279,6 +361,107 @@ func (t TeleporterTestInfo) SendExampleCrossChainMessageAndVerify( } } +func (t TeleporterTestInfo) SendExampleInterChainMessageAndVerify( + ctx context.Context, + ethereumChainID *big.Int, + ethClient ethclient.Client, + avalancheNetworkID uint32, + avalanchePChainBlockchainID ids.ID, + source interfaces.L1TestInfo, + sourceExampleMessenger *testmessenger.TestMessenger, + destExampleMessengerAddress common.Address, + destinationMessenger *teleportermessenger.TeleporterMessenger, + senderKey *ecdsa.PrivateKey, + ethFundedKey *ecdsa.PrivateKey, + message string, + signatureAggregator *SignatureAggregator, + expectSuccess bool, +) { + // Call the example messenger contract on L1 AF + optsA, err := bind.NewKeyedTransactorWithChainID(senderKey, source.EVMChainID) + Expect(err).Should(BeNil()) + destinationChainID := [32]byte{} + ethereumChainID.FillBytes(destinationChainID[:]) + log.Info("Sending message to chain", "id", ethereumChainID) + tx, err := sourceExampleMessenger.SendMessage( + optsA, + destinationChainID, + destExampleMessengerAddress, + common.BigToAddress(common.Big0), + big.NewInt(0), + testmessenger.SendMessageRequiredGas, + message, + ) + Expect(err).Should(BeNil()) + + // Wait for the transaction to be mined + receipt := WaitForTransactionSuccess(ctx, source, tx.Hash()) + + sourceTeleporterMessenger := t.TeleporterMessenger(source) + + event, err := GetEventFromLogs(receipt.Logs, sourceTeleporterMessenger.ParseSendCrossChainMessage) + Expect(err).Should(BeNil()) + Expect(event.DestinationBlockchainID[:]).Should(Equal(destinationChainID[:])) + + teleporterMessageID := event.MessageID + + // + // Relay the message to the destination + // + receipt = t.RelayInterchainTeleporterMessage( + ctx, + ethereumChainID, + ethClient, + avalancheNetworkID, + avalanchePChainBlockchainID, + receipt, + source, + destinationMessenger, + ethFundedKey, + signatureAggregator, + ) + + // + // Check Teleporter message received on the destination + // and that we received the expected string + // + delivered, err := destinationMessenger.MessageReceived( + &bind.CallOpts{}, teleporterMessageID, + ) + Expect(err).Should(BeNil()) + Expect(delivered).Should(BeTrue()) + + if expectSuccess { + // Check that message execution was successful + messageExecutedEvent, err := GetEventFromLogs( + receipt.Logs, + destinationMessenger.ParseMessageExecuted, + ) + Expect(err).Should(BeNil()) + Expect(messageExecutedEvent.MessageID[:]).Should(Equal(teleporterMessageID[:])) + messageReceivedMessageEvent, err := GetEventFromLogs( + receipt.Logs, + destinationMessenger.ParseReceiveCrossChainMessage, + ) + Expect(err).Should(BeNil()) + Expect(messageReceivedMessageEvent.MessageID[:]).Should(Equal(teleporterMessageID[:])) + } else { + // Check that message execution failed + messageExecutionFailedEvent, err := GetEventFromLogs( + receipt.Logs, + destinationMessenger.ParseMessageExecutionFailed, + ) + Expect(err).Should(BeNil()) + Expect(messageExecutionFailedEvent.MessageID[:]).Should(Equal(teleporterMessageID[:])) + messageReceivedMessageEvent, err := GetEventFromLogs( + receipt.Logs, + destinationMessenger.ParseReceiveCrossChainMessage, + ) + Expect(err).Should(BeNil()) + Expect(messageReceivedMessageEvent.MessageID[:]).Should(Equal(teleporterMessageID[:])) + } +} + func (t TeleporterTestInfo) AddProtocolVersionAndWaitForAcceptance( ctx context.Context, l1 interfaces.L1TestInfo, diff --git a/tests/utils/test_utils.go b/tests/utils/test_utils.go new file mode 100644 index 000000000..1a0037ca3 --- /dev/null +++ b/tests/utils/test_utils.go @@ -0,0 +1,14 @@ +package utils + +import ( + "os" + + "github.com/ava-labs/libevm/log" +) + +// ConfigureDefaultLoggingForTests sets up the default logger to show INFO level and above. +// This should be called once at the beginning of test suites to ensure log.Info() statements are visible. +func ConfigureDefaultLoggingForTests() { + // Configure log level to ensure Info logs are visible in tests + log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true))) +} diff --git a/utils/teleporter-utils/teleporter_utils.go b/utils/teleporter-utils/teleporter_utils.go index b4692ac12..3545f6ee9 100644 --- a/utils/teleporter-utils/teleporter_utils.go +++ b/utils/teleporter-utils/teleporter_utils.go @@ -7,7 +7,6 @@ import ( "math/big" "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/subnet-evm/accounts/abi" ) @@ -16,29 +15,30 @@ var ( uint256Ty abi.Type bytes32Ty abi.Type addressTy abi.Type + stringTy abi.Type ) func init() { uint256Ty, _ = abi.NewType("uint256", "uint256", nil) bytes32Ty, _ = abi.NewType("bytes32", "bytes32", nil) addressTy, _ = abi.NewType("address", "address", nil) + stringTy, _ = abi.NewType("string", "string", nil) } func CalculateMessageID( - teleporterMessengerAddress common.Address, sourceBlockchainID ids.ID, destinationBlockchainID ids.ID, nonce *big.Int, ) (ids.ID, error) { arguments := abi.Arguments{ - {Type: addressTy}, + {Type: stringTy}, {Type: bytes32Ty}, {Type: bytes32Ty}, {Type: uint256Ty}, } bytes, err := arguments.Pack( - teleporterMessengerAddress, + "V2", sourceBlockchainID, destinationBlockchainID, nonce,