From d577c94597d0faa20d1989486450fd38e6f5841a Mon Sep 17 00:00:00 2001 From: ajimeno04 <143208098+ajimeno04@users.noreply.github.com> Date: Fri, 28 Jun 2024 11:59:36 +0200 Subject: [PATCH] [feat] Layer Zero Relayer support (#36) * Chore: Add ABIs for Layer Zero Collector * Chore: Add store and utils functions which collector is dependent on * Chore: Add the script that initialises the worker and the worker script itself that functions as a layer-zero collector. * Fix: remove useless comments and improve readability of decodeHeader * Fix: Requested changes related to logging * Fix: Improve queryLogs function in order to have consistency on the relayer * Fix: remove debugging code * fix: Error logging * chore: Remove unused import * feat: Add layer-zero example configuration --------- Co-authored-by: Jorge Sanmiguel <8038323+jsanmigimeno@users.noreply.github.com> --- abis/LayerZeroEnpointV2.json | 1392 +++++++++++++++++ abis/ReceiveULN302.json | 526 +++++++ config.example.yaml | 44 + src/collector/layer-zero/layer-zero.ts | 240 +++ src/collector/layer-zero/layer-zero.worker.ts | 611 ++++++++ src/common/utils.ts | 7 +- src/store/store.lib.ts | 11 + 7 files changed, 2830 insertions(+), 1 deletion(-) create mode 100644 abis/LayerZeroEnpointV2.json create mode 100644 abis/ReceiveULN302.json create mode 100644 src/collector/layer-zero/layer-zero.ts create mode 100644 src/collector/layer-zero/layer-zero.worker.ts diff --git a/abis/LayerZeroEnpointV2.json b/abis/LayerZeroEnpointV2.json new file mode 100644 index 0000000..e38c1d8 --- /dev/null +++ b/abis/LayerZeroEnpointV2.json @@ -0,0 +1,1392 @@ +[ + { + "inputs": [ + { "internalType": "uint32", "name": "_eid", "type": "uint32" }, + { "internalType": "address", "name": "_owner", "type": "address" } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { "inputs": [], "name": "LZ_AlreadyRegistered", "type": "error" }, + { "inputs": [], "name": "LZ_ComposeExists", "type": "error" }, + { + "inputs": [ + { "internalType": "bytes32", "name": "expected", "type": "bytes32" }, + { "internalType": "bytes32", "name": "actual", "type": "bytes32" } + ], + "name": "LZ_ComposeNotFound", + "type": "error" + }, + { "inputs": [], "name": "LZ_DefaultReceiveLibUnavailable", "type": "error" }, + { "inputs": [], "name": "LZ_DefaultSendLibUnavailable", "type": "error" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "requiredNative", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "suppliedNative", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "requiredLzToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "suppliedLzToken", + "type": "uint256" + } + ], + "name": "LZ_InsufficientFee", + "type": "error" + }, + { "inputs": [], "name": "LZ_InvalidExpiry", "type": "error" }, + { + "inputs": [{ "internalType": "uint64", "name": "nonce", "type": "uint64" }], + "name": "LZ_InvalidNonce", + "type": "error" + }, + { "inputs": [], "name": "LZ_InvalidPayloadHash", "type": "error" }, + { "inputs": [], "name": "LZ_InvalidReceiveLibrary", "type": "error" }, + { "inputs": [], "name": "LZ_LzTokenUnavailable", "type": "error" }, + { "inputs": [], "name": "LZ_OnlyNonDefaultLib", "type": "error" }, + { "inputs": [], "name": "LZ_OnlyReceiveLib", "type": "error" }, + { "inputs": [], "name": "LZ_OnlyRegisteredLib", "type": "error" }, + { "inputs": [], "name": "LZ_OnlyRegisteredOrDefaultLib", "type": "error" }, + { "inputs": [], "name": "LZ_OnlySendLib", "type": "error" }, + { "inputs": [], "name": "LZ_PathNotInitializable", "type": "error" }, + { "inputs": [], "name": "LZ_PathNotVerifiable", "type": "error" }, + { + "inputs": [ + { "internalType": "bytes32", "name": "expected", "type": "bytes32" }, + { "internalType": "bytes32", "name": "actual", "type": "bytes32" } + ], + "name": "LZ_PayloadHashNotFound", + "type": "error" + }, + { "inputs": [], "name": "LZ_SameValue", "type": "error" }, + { "inputs": [], "name": "LZ_SendReentrancy", "type": "error" }, + { "inputs": [], "name": "LZ_Unauthorized", "type": "error" }, + { "inputs": [], "name": "LZ_UnsupportedEid", "type": "error" }, + { "inputs": [], "name": "LZ_UnsupportedInterface", "type": "error" }, + { "inputs": [], "name": "LZ_ZeroLzTokenFee", "type": "error" }, + { + "inputs": [ + { "internalType": "address", "name": "_to", "type": "address" }, + { "internalType": "uint256", "name": "_value", "type": "uint256" } + ], + "name": "Transfer_NativeFailed", + "type": "error" + }, + { "inputs": [], "name": "Transfer_ToAddressIsZero", "type": "error" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "guid", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "index", + "type": "uint16" + } + ], + "name": "ComposeDelivered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "guid", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "index", + "type": "uint16" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "message", + "type": "bytes" + } + ], + "name": "ComposeSent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint32", + "name": "eid", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "address", + "name": "newLib", + "type": "address" + } + ], + "name": "DefaultReceiveLibrarySet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint32", + "name": "eid", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "address", + "name": "oldLib", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "expiry", + "type": "uint256" + } + ], + "name": "DefaultReceiveLibraryTimeoutSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint32", + "name": "eid", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "address", + "name": "newLib", + "type": "address" + } + ], + "name": "DefaultSendLibrarySet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "delegate", + "type": "address" + } + ], + "name": "DelegateSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint32", + "name": "srcEid", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "sender", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "nonce", + "type": "uint64" + } + ], + "name": "InboundNonceSkipped", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newLib", + "type": "address" + } + ], + "name": "LibraryRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "executor", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "guid", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "index", + "type": "uint16" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "gas", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "message", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "extraData", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "reason", + "type": "bytes" + } + ], + "name": "LzComposeAlert", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "executor", + "type": "address" + }, + { + "components": [ + { "internalType": "uint32", "name": "srcEid", "type": "uint32" }, + { "internalType": "bytes32", "name": "sender", "type": "bytes32" }, + { "internalType": "uint64", "name": "nonce", "type": "uint64" } + ], + "indexed": false, + "internalType": "struct Origin", + "name": "origin", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "guid", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "gas", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "message", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "extraData", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "reason", + "type": "bytes" + } + ], + "name": "LzReceiveAlert", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "LzTokenSet", + "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": false, + "internalType": "uint32", + "name": "srcEid", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "sender", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "nonce", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "payloadHash", + "type": "bytes32" + } + ], + "name": "PacketBurnt", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { "internalType": "uint32", "name": "srcEid", "type": "uint32" }, + { "internalType": "bytes32", "name": "sender", "type": "bytes32" }, + { "internalType": "uint64", "name": "nonce", "type": "uint64" } + ], + "indexed": false, + "internalType": "struct Origin", + "name": "origin", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "PacketDelivered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint32", + "name": "srcEid", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "sender", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "nonce", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "payloadHash", + "type": "bytes32" + } + ], + "name": "PacketNilified", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes", + "name": "encodedPayload", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "options", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "sendLibrary", + "type": "address" + } + ], + "name": "PacketSent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { "internalType": "uint32", "name": "srcEid", "type": "uint32" }, + { "internalType": "bytes32", "name": "sender", "type": "bytes32" }, + { "internalType": "uint64", "name": "nonce", "type": "uint64" } + ], + "indexed": false, + "internalType": "struct Origin", + "name": "origin", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "payloadHash", + "type": "bytes32" + } + ], + "name": "PacketVerified", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "eid", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "address", + "name": "newLib", + "type": "address" + } + ], + "name": "ReceiveLibrarySet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "eid", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "address", + "name": "oldLib", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timeout", + "type": "uint256" + } + ], + "name": "ReceiveLibraryTimeoutSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "eid", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "address", + "name": "newLib", + "type": "address" + } + ], + "name": "SendLibrarySet", + "type": "event" + }, + { + "inputs": [], + "name": "EMPTY_PAYLOAD_HASH", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "NIL_PAYLOAD_HASH", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "blockedLibrary", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_oapp", "type": "address" }, + { "internalType": "uint32", "name": "_srcEid", "type": "uint32" }, + { "internalType": "bytes32", "name": "_sender", "type": "bytes32" }, + { "internalType": "uint64", "name": "_nonce", "type": "uint64" }, + { "internalType": "bytes32", "name": "_payloadHash", "type": "bytes32" } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_oapp", "type": "address" }, + { + "components": [ + { "internalType": "uint32", "name": "srcEid", "type": "uint32" }, + { "internalType": "bytes32", "name": "sender", "type": "bytes32" }, + { "internalType": "uint64", "name": "nonce", "type": "uint64" } + ], + "internalType": "struct Origin", + "name": "_origin", + "type": "tuple" + }, + { "internalType": "bytes32", "name": "_guid", "type": "bytes32" }, + { "internalType": "bytes", "name": "_message", "type": "bytes" } + ], + "name": "clear", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "from", "type": "address" }, + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "bytes32", "name": "guid", "type": "bytes32" }, + { "internalType": "uint16", "name": "index", "type": "uint16" } + ], + "name": "composeQueue", + "outputs": [ + { "internalType": "bytes32", "name": "messageHash", "type": "bytes32" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint32", "name": "srcEid", "type": "uint32" } + ], + "name": "defaultReceiveLibrary", + "outputs": [ + { "internalType": "address", "name": "lib", "type": "address" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint32", "name": "srcEid", "type": "uint32" } + ], + "name": "defaultReceiveLibraryTimeout", + "outputs": [ + { "internalType": "address", "name": "lib", "type": "address" }, + { "internalType": "uint256", "name": "expiry", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint32", "name": "dstEid", "type": "uint32" } + ], + "name": "defaultSendLibrary", + "outputs": [ + { "internalType": "address", "name": "lib", "type": "address" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "oapp", "type": "address" } + ], + "name": "delegates", + "outputs": [ + { "internalType": "address", "name": "delegate", "type": "address" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "eid", + "outputs": [{ "internalType": "uint32", "name": "", "type": "uint32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_oapp", "type": "address" }, + { "internalType": "address", "name": "_lib", "type": "address" }, + { "internalType": "uint32", "name": "_eid", "type": "uint32" }, + { "internalType": "uint32", "name": "_configType", "type": "uint32" } + ], + "name": "getConfig", + "outputs": [{ "internalType": "bytes", "name": "config", "type": "bytes" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_receiver", "type": "address" }, + { "internalType": "uint32", "name": "_srcEid", "type": "uint32" } + ], + "name": "getReceiveLibrary", + "outputs": [ + { "internalType": "address", "name": "lib", "type": "address" }, + { "internalType": "bool", "name": "isDefault", "type": "bool" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRegisteredLibraries", + "outputs": [ + { "internalType": "address[]", "name": "", "type": "address[]" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getSendContext", + "outputs": [ + { "internalType": "uint32", "name": "", "type": "uint32" }, + { "internalType": "address", "name": "", "type": "address" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_sender", "type": "address" }, + { "internalType": "uint32", "name": "_dstEid", "type": "uint32" } + ], + "name": "getSendLibrary", + "outputs": [ + { "internalType": "address", "name": "lib", "type": "address" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_receiver", "type": "address" }, + { "internalType": "uint32", "name": "_srcEid", "type": "uint32" }, + { "internalType": "bytes32", "name": "_sender", "type": "bytes32" } + ], + "name": "inboundNonce", + "outputs": [{ "internalType": "uint64", "name": "", "type": "uint64" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "receiver", "type": "address" }, + { "internalType": "uint32", "name": "srcEid", "type": "uint32" }, + { "internalType": "bytes32", "name": "sender", "type": "bytes32" }, + { "internalType": "uint64", "name": "inboundNonce", "type": "uint64" } + ], + "name": "inboundPayloadHash", + "outputs": [ + { "internalType": "bytes32", "name": "payloadHash", "type": "bytes32" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "uint32", "name": "srcEid", "type": "uint32" }, + { "internalType": "bytes32", "name": "sender", "type": "bytes32" }, + { "internalType": "uint64", "name": "nonce", "type": "uint64" } + ], + "internalType": "struct Origin", + "name": "_origin", + "type": "tuple" + }, + { "internalType": "address", "name": "_receiver", "type": "address" } + ], + "name": "initializable", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_sender", "type": "address" }, + { "internalType": "uint32", "name": "_dstEid", "type": "uint32" } + ], + "name": "isDefaultSendLibrary", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "lib", "type": "address" }], + "name": "isRegisteredLibrary", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isSendingMessage", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint32", "name": "_eid", "type": "uint32" }], + "name": "isSupportedEid", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_receiver", "type": "address" }, + { "internalType": "uint32", "name": "_srcEid", "type": "uint32" }, + { + "internalType": "address", + "name": "_actualReceiveLib", + "type": "address" + } + ], + "name": "isValidReceiveLibrary", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "receiver", "type": "address" }, + { "internalType": "uint32", "name": "srcEid", "type": "uint32" }, + { "internalType": "bytes32", "name": "sender", "type": "bytes32" } + ], + "name": "lazyInboundNonce", + "outputs": [ + { "internalType": "uint64", "name": "nonce", "type": "uint64" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_from", "type": "address" }, + { "internalType": "address", "name": "_to", "type": "address" }, + { "internalType": "bytes32", "name": "_guid", "type": "bytes32" }, + { "internalType": "uint16", "name": "_index", "type": "uint16" }, + { "internalType": "bytes", "name": "_message", "type": "bytes" }, + { "internalType": "bytes", "name": "_extraData", "type": "bytes" } + ], + "name": "lzCompose", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_from", "type": "address" }, + { "internalType": "address", "name": "_to", "type": "address" }, + { "internalType": "bytes32", "name": "_guid", "type": "bytes32" }, + { "internalType": "uint16", "name": "_index", "type": "uint16" }, + { "internalType": "uint256", "name": "_gas", "type": "uint256" }, + { "internalType": "uint256", "name": "_value", "type": "uint256" }, + { "internalType": "bytes", "name": "_message", "type": "bytes" }, + { "internalType": "bytes", "name": "_extraData", "type": "bytes" }, + { "internalType": "bytes", "name": "_reason", "type": "bytes" } + ], + "name": "lzComposeAlert", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "uint32", "name": "srcEid", "type": "uint32" }, + { "internalType": "bytes32", "name": "sender", "type": "bytes32" }, + { "internalType": "uint64", "name": "nonce", "type": "uint64" } + ], + "internalType": "struct Origin", + "name": "_origin", + "type": "tuple" + }, + { "internalType": "address", "name": "_receiver", "type": "address" }, + { "internalType": "bytes32", "name": "_guid", "type": "bytes32" }, + { "internalType": "bytes", "name": "_message", "type": "bytes" }, + { "internalType": "bytes", "name": "_extraData", "type": "bytes" } + ], + "name": "lzReceive", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "uint32", "name": "srcEid", "type": "uint32" }, + { "internalType": "bytes32", "name": "sender", "type": "bytes32" }, + { "internalType": "uint64", "name": "nonce", "type": "uint64" } + ], + "internalType": "struct Origin", + "name": "_origin", + "type": "tuple" + }, + { "internalType": "address", "name": "_receiver", "type": "address" }, + { "internalType": "bytes32", "name": "_guid", "type": "bytes32" }, + { "internalType": "uint256", "name": "_gas", "type": "uint256" }, + { "internalType": "uint256", "name": "_value", "type": "uint256" }, + { "internalType": "bytes", "name": "_message", "type": "bytes" }, + { "internalType": "bytes", "name": "_extraData", "type": "bytes" }, + { "internalType": "bytes", "name": "_reason", "type": "bytes" } + ], + "name": "lzReceiveAlert", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "lzToken", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "nativeToken", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_sender", "type": "address" }, + { "internalType": "uint32", "name": "_dstEid", "type": "uint32" }, + { "internalType": "bytes32", "name": "_receiver", "type": "bytes32" } + ], + "name": "nextGuid", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_oapp", "type": "address" }, + { "internalType": "uint32", "name": "_srcEid", "type": "uint32" }, + { "internalType": "bytes32", "name": "_sender", "type": "bytes32" }, + { "internalType": "uint64", "name": "_nonce", "type": "uint64" }, + { "internalType": "bytes32", "name": "_payloadHash", "type": "bytes32" } + ], + "name": "nilify", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "sender", "type": "address" }, + { "internalType": "uint32", "name": "dstEid", "type": "uint32" }, + { "internalType": "bytes32", "name": "receiver", "type": "bytes32" } + ], + "name": "outboundNonce", + "outputs": [ + { "internalType": "uint64", "name": "nonce", "type": "uint64" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "uint32", "name": "dstEid", "type": "uint32" }, + { "internalType": "bytes32", "name": "receiver", "type": "bytes32" }, + { "internalType": "bytes", "name": "message", "type": "bytes" }, + { "internalType": "bytes", "name": "options", "type": "bytes" }, + { "internalType": "bool", "name": "payInLzToken", "type": "bool" } + ], + "internalType": "struct MessagingParams", + "name": "_params", + "type": "tuple" + }, + { "internalType": "address", "name": "_sender", "type": "address" } + ], + "name": "quote", + "outputs": [ + { + "components": [ + { "internalType": "uint256", "name": "nativeFee", "type": "uint256" }, + { "internalType": "uint256", "name": "lzTokenFee", "type": "uint256" } + ], + "internalType": "struct MessagingFee", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "receiver", "type": "address" }, + { "internalType": "uint32", "name": "srcEid", "type": "uint32" } + ], + "name": "receiveLibraryTimeout", + "outputs": [ + { "internalType": "address", "name": "lib", "type": "address" }, + { "internalType": "uint256", "name": "expiry", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_token", "type": "address" }, + { "internalType": "address", "name": "_to", "type": "address" }, + { "internalType": "uint256", "name": "_amount", "type": "uint256" } + ], + "name": "recoverToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_lib", "type": "address" } + ], + "name": "registerLibrary", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "uint32", "name": "dstEid", "type": "uint32" }, + { "internalType": "bytes32", "name": "receiver", "type": "bytes32" }, + { "internalType": "bytes", "name": "message", "type": "bytes" }, + { "internalType": "bytes", "name": "options", "type": "bytes" }, + { "internalType": "bool", "name": "payInLzToken", "type": "bool" } + ], + "internalType": "struct MessagingParams", + "name": "_params", + "type": "tuple" + }, + { "internalType": "address", "name": "_refundAddress", "type": "address" } + ], + "name": "send", + "outputs": [ + { + "components": [ + { "internalType": "bytes32", "name": "guid", "type": "bytes32" }, + { "internalType": "uint64", "name": "nonce", "type": "uint64" }, + { + "components": [ + { + "internalType": "uint256", + "name": "nativeFee", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "lzTokenFee", + "type": "uint256" + } + ], + "internalType": "struct MessagingFee", + "name": "fee", + "type": "tuple" + } + ], + "internalType": "struct MessagingReceipt", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_to", "type": "address" }, + { "internalType": "bytes32", "name": "_guid", "type": "bytes32" }, + { "internalType": "uint16", "name": "_index", "type": "uint16" }, + { "internalType": "bytes", "name": "_message", "type": "bytes" } + ], + "name": "sendCompose", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_oapp", "type": "address" }, + { "internalType": "address", "name": "_lib", "type": "address" }, + { + "components": [ + { "internalType": "uint32", "name": "eid", "type": "uint32" }, + { "internalType": "uint32", "name": "configType", "type": "uint32" }, + { "internalType": "bytes", "name": "config", "type": "bytes" } + ], + "internalType": "struct SetConfigParam[]", + "name": "_params", + "type": "tuple[]" + } + ], + "name": "setConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint32", "name": "_eid", "type": "uint32" }, + { "internalType": "address", "name": "_newLib", "type": "address" }, + { "internalType": "uint256", "name": "_gracePeriod", "type": "uint256" } + ], + "name": "setDefaultReceiveLibrary", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint32", "name": "_eid", "type": "uint32" }, + { "internalType": "address", "name": "_lib", "type": "address" }, + { "internalType": "uint256", "name": "_expiry", "type": "uint256" } + ], + "name": "setDefaultReceiveLibraryTimeout", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint32", "name": "_eid", "type": "uint32" }, + { "internalType": "address", "name": "_newLib", "type": "address" } + ], + "name": "setDefaultSendLibrary", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_delegate", "type": "address" } + ], + "name": "setDelegate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_lzToken", "type": "address" } + ], + "name": "setLzToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_oapp", "type": "address" }, + { "internalType": "uint32", "name": "_eid", "type": "uint32" }, + { "internalType": "address", "name": "_newLib", "type": "address" }, + { "internalType": "uint256", "name": "_gracePeriod", "type": "uint256" } + ], + "name": "setReceiveLibrary", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_oapp", "type": "address" }, + { "internalType": "uint32", "name": "_eid", "type": "uint32" }, + { "internalType": "address", "name": "_lib", "type": "address" }, + { "internalType": "uint256", "name": "_expiry", "type": "uint256" } + ], + "name": "setReceiveLibraryTimeout", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_oapp", "type": "address" }, + { "internalType": "uint32", "name": "_eid", "type": "uint32" }, + { "internalType": "address", "name": "_newLib", "type": "address" } + ], + "name": "setSendLibrary", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_oapp", "type": "address" }, + { "internalType": "uint32", "name": "_srcEid", "type": "uint32" }, + { "internalType": "bytes32", "name": "_sender", "type": "bytes32" }, + { "internalType": "uint64", "name": "_nonce", "type": "uint64" } + ], + "name": "skip", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "newOwner", "type": "address" } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "uint32", "name": "srcEid", "type": "uint32" }, + { "internalType": "bytes32", "name": "sender", "type": "bytes32" }, + { "internalType": "uint64", "name": "nonce", "type": "uint64" } + ], + "internalType": "struct Origin", + "name": "_origin", + "type": "tuple" + }, + { "internalType": "address", "name": "_receiver", "type": "address" } + ], + "name": "verifiable", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "uint32", "name": "srcEid", "type": "uint32" }, + { "internalType": "bytes32", "name": "sender", "type": "bytes32" }, + { "internalType": "uint64", "name": "nonce", "type": "uint64" } + ], + "internalType": "struct Origin", + "name": "_origin", + "type": "tuple" + }, + { "internalType": "address", "name": "_receiver", "type": "address" }, + { "internalType": "bytes32", "name": "_payloadHash", "type": "bytes32" } + ], + "name": "verify", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] \ No newline at end of file diff --git a/abis/ReceiveULN302.json b/abis/ReceiveULN302.json new file mode 100644 index 0000000..853dbaa --- /dev/null +++ b/abis/ReceiveULN302.json @@ -0,0 +1,526 @@ +[ + { + "inputs": [ + { "internalType": "address", "name": "_endpoint", "type": "address" } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { "inputs": [], "name": "LZ_MessageLib_OnlyEndpoint", "type": "error" }, + { "inputs": [], "name": "LZ_ULN_AtLeastOneDVN", "type": "error" }, + { + "inputs": [ + { "internalType": "uint32", "name": "configType", "type": "uint32" } + ], + "name": "LZ_ULN_InvalidConfigType", + "type": "error" + }, + { "inputs": [], "name": "LZ_ULN_InvalidConfirmations", "type": "error" }, + { "inputs": [], "name": "LZ_ULN_InvalidEid", "type": "error" }, + { "inputs": [], "name": "LZ_ULN_InvalidOptionalDVNCount", "type": "error" }, + { + "inputs": [], + "name": "LZ_ULN_InvalidOptionalDVNThreshold", + "type": "error" + }, + { "inputs": [], "name": "LZ_ULN_InvalidPacketHeader", "type": "error" }, + { "inputs": [], "name": "LZ_ULN_InvalidPacketVersion", "type": "error" }, + { "inputs": [], "name": "LZ_ULN_InvalidRequiredDVNCount", "type": "error" }, + { "inputs": [], "name": "LZ_ULN_Unsorted", "type": "error" }, + { + "inputs": [{ "internalType": "uint32", "name": "eid", "type": "uint32" }], + "name": "LZ_ULN_UnsupportedEid", + "type": "error" + }, + { "inputs": [], "name": "LZ_ULN_Verifying", "type": "error" }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { "internalType": "uint32", "name": "eid", "type": "uint32" }, + { + "components": [ + { + "internalType": "uint64", + "name": "confirmations", + "type": "uint64" + }, + { + "internalType": "uint8", + "name": "requiredDVNCount", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "optionalDVNCount", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "optionalDVNThreshold", + "type": "uint8" + }, + { + "internalType": "address[]", + "name": "requiredDVNs", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "optionalDVNs", + "type": "address[]" + } + ], + "internalType": "struct UlnConfig", + "name": "config", + "type": "tuple" + } + ], + "indexed": false, + "internalType": "struct SetDefaultUlnConfigParam[]", + "name": "params", + "type": "tuple[]" + } + ], + "name": "DefaultUlnConfigsSet", + "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": false, + "internalType": "address", + "name": "dvn", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "header", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "confirmations", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "proofHash", + "type": "bytes32" + } + ], + "name": "PayloadVerified", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oapp", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "eid", + "type": "uint32" + }, + { + "components": [ + { + "internalType": "uint64", + "name": "confirmations", + "type": "uint64" + }, + { + "internalType": "uint8", + "name": "requiredDVNCount", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "optionalDVNCount", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "optionalDVNThreshold", + "type": "uint8" + }, + { + "internalType": "address[]", + "name": "requiredDVNs", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "optionalDVNs", + "type": "address[]" + } + ], + "indexed": false, + "internalType": "struct UlnConfig", + "name": "config", + "type": "tuple" + } + ], + "name": "UlnConfigSet", + "type": "event" + }, + { + "inputs": [ + { "internalType": "bytes", "name": "_packetHeader", "type": "bytes" }, + { "internalType": "uint32", "name": "_localEid", "type": "uint32" } + ], + "name": "assertHeader", + "outputs": [], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes", "name": "_packetHeader", "type": "bytes" }, + { "internalType": "bytes32", "name": "_payloadHash", "type": "bytes32" } + ], + "name": "commitVerification", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_oapp", "type": "address" }, + { "internalType": "uint32", "name": "_remoteEid", "type": "uint32" } + ], + "name": "getAppUlnConfig", + "outputs": [ + { + "components": [ + { + "internalType": "uint64", + "name": "confirmations", + "type": "uint64" + }, + { + "internalType": "uint8", + "name": "requiredDVNCount", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "optionalDVNCount", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "optionalDVNThreshold", + "type": "uint8" + }, + { + "internalType": "address[]", + "name": "requiredDVNs", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "optionalDVNs", + "type": "address[]" + } + ], + "internalType": "struct UlnConfig", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint32", "name": "_eid", "type": "uint32" }, + { "internalType": "address", "name": "_oapp", "type": "address" }, + { "internalType": "uint32", "name": "_configType", "type": "uint32" } + ], + "name": "getConfig", + "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_oapp", "type": "address" }, + { "internalType": "uint32", "name": "_remoteEid", "type": "uint32" } + ], + "name": "getUlnConfig", + "outputs": [ + { + "components": [ + { + "internalType": "uint64", + "name": "confirmations", + "type": "uint64" + }, + { + "internalType": "uint8", + "name": "requiredDVNCount", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "optionalDVNCount", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "optionalDVNThreshold", + "type": "uint8" + }, + { + "internalType": "address[]", + "name": "requiredDVNs", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "optionalDVNs", + "type": "address[]" + } + ], + "internalType": "struct UlnConfig", + "name": "rtnConfig", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32", "name": "headerHash", "type": "bytes32" }, + { "internalType": "bytes32", "name": "payloadHash", "type": "bytes32" }, + { "internalType": "address", "name": "dvn", "type": "address" } + ], + "name": "hashLookup", + "outputs": [ + { "internalType": "bool", "name": "submitted", "type": "bool" }, + { "internalType": "uint64", "name": "confirmations", "type": "uint64" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint32", "name": "_eid", "type": "uint32" }], + "name": "isSupportedEid", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "messageLibType", + "outputs": [ + { "internalType": "enum MessageLibType", "name": "", "type": "uint8" } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_oapp", "type": "address" }, + { + "components": [ + { "internalType": "uint32", "name": "eid", "type": "uint32" }, + { "internalType": "uint32", "name": "configType", "type": "uint32" }, + { "internalType": "bytes", "name": "config", "type": "bytes" } + ], + "internalType": "struct SetConfigParam[]", + "name": "_params", + "type": "tuple[]" + } + ], + "name": "setConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "uint32", "name": "eid", "type": "uint32" }, + { + "components": [ + { + "internalType": "uint64", + "name": "confirmations", + "type": "uint64" + }, + { + "internalType": "uint8", + "name": "requiredDVNCount", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "optionalDVNCount", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "optionalDVNThreshold", + "type": "uint8" + }, + { + "internalType": "address[]", + "name": "requiredDVNs", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "optionalDVNs", + "type": "address[]" + } + ], + "internalType": "struct UlnConfig", + "name": "config", + "type": "tuple" + } + ], + "internalType": "struct SetDefaultUlnConfigParam[]", + "name": "_params", + "type": "tuple[]" + } + ], + "name": "setDefaultUlnConfigs", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes4", "name": "_interfaceId", "type": "bytes4" } + ], + "name": "supportsInterface", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "newOwner", "type": "address" } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint64", + "name": "confirmations", + "type": "uint64" + }, + { + "internalType": "uint8", + "name": "requiredDVNCount", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "optionalDVNCount", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "optionalDVNThreshold", + "type": "uint8" + }, + { + "internalType": "address[]", + "name": "requiredDVNs", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "optionalDVNs", + "type": "address[]" + } + ], + "internalType": "struct UlnConfig", + "name": "_config", + "type": "tuple" + }, + { "internalType": "bytes32", "name": "_headerHash", "type": "bytes32" }, + { "internalType": "bytes32", "name": "_payloadHash", "type": "bytes32" } + ], + "name": "verifiable", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes", "name": "_packetHeader", "type": "bytes" }, + { "internalType": "bytes32", "name": "_payloadHash", "type": "bytes32" }, + { "internalType": "uint64", "name": "_confirmations", "type": "uint64" } + ], + "name": "verify", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { "internalType": "uint64", "name": "major", "type": "uint64" }, + { "internalType": "uint8", "name": "minor", "type": "uint8" }, + { "internalType": "uint8", "name": "endpointVersion", "type": "uint8" } + ], + "stateMutability": "pure", + "type": "function" + } + ] \ No newline at end of file diff --git a/config.example.yaml b/config.example.yaml index 068d17c..bfb8205 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -86,6 +86,9 @@ ambs: - name: wormhole isTestnet: true + - name: layer-zero + packetCost: '6000000000000' + # Chain configuration chains: - chainId: 11155111 @@ -118,6 +121,11 @@ chains: wormholeChainId: 10005 incentivesAddress: '0x198cDD55d90277726f3222D5A8111AdB8b0af9ee' bridgeAddress: '0x31377888146f3253211EFEf5c676D41ECe7D58Fe' + layer-zero: + layerZeroChainId: 40232 + incentivesAddress: '0xd41ace766aed57fefdca3a7d27d20b837284b872' + bridgeAddress: '0x6edce65403992e310a62460808c4b910d972f10f' + receiverAddress: '0x9284fd59B95b9143AF0b9795CAC16eb3C723C9Ca' - chainId: 84532 name: 'Base Sepolia' @@ -138,3 +146,39 @@ chains: wormholeChainId: 36 incentivesAddress: '0x9524ACA1fF46fAd177160F0a803189Cb552A3780' bridgeAddress: '0x473e002D7add6fB67a4964F13bFd61280Ca46886' + + - chainId: 421614 + name: "Arbitrum Sepolia" + rpc: "https://arbitrum-sepolia-rpc.publicnode.com" + pricing: + coinId: 'ethereum' # coin-gecko pricing provider specific configuration + resolver: 'arbitrum' + monitor: + blockDelay: 5 + interval: 2000 + getter: + maxBlocks: 5000 + wormhole: + wormholeChainId: 10003 + incentivesAddress: "0x59aa9e2339dd0c019f188f1ed9b27b9a10ae664d" + bridgeAddress: "0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35" + layer-zero: + layerZeroChainId: 40231 + incentivesAddress: '0xd41ace766aed57fefdca3a7d27d20b837284b872' + bridgeAddress: '0x6EDCE65403992e310A62460808c4b910D972f10f' + receiverAddress: '0x75Db67CDab2824970131D5aa9CECfC9F69c69636' + + - chainId: 713715 + name: 'Sei Devnet' + rpc: 'https://evm-rpc-arctic-1.sei-apis.com' + pricing: + coinId: 'sei-network' # coin-gecko pricing provider specific configuration + monitor: + interval: 2000 + blockDelay: 10 + layer-zero: + layerZeroChainId: 40258 + incentivesAddress: '0xd41ace766aed57fefdca3a7d27d20b837284b872' + bridgeAddress: '0x6EDCE65403992e310A62460808c4b910D972f10f' + receiverAddress: '0xcF1B0F4106B0324F96fEfcC31bA9498caa80701C' + packetCost: '100000000000000000' diff --git a/src/collector/layer-zero/layer-zero.ts b/src/collector/layer-zero/layer-zero.ts new file mode 100644 index 0000000..084c1a2 --- /dev/null +++ b/src/collector/layer-zero/layer-zero.ts @@ -0,0 +1,240 @@ +/** + * This file initializes and manages Layer Zero workers. + * + * Inputs: + * - ConfigService: Service to fetch configuration settings. + * - MonitorService: Service to monitor and manage workers. + * - LoggerService: Service to log information and errors. + * - ChainConfig: Configuration settings for different chains. + * - CollectorModuleInterface: Interface for the collector module. + * + * Outputs: + * - Initializes and manages Layer Zero worker threads. + * - Logs status and errors related to the worker threads. + */ + +import { join } from 'path'; +import { Worker, MessagePort } from 'worker_threads'; +import { CollectorModuleInterface } from '../collector.controller'; +import { + DEFAULT_GETTER_RETRY_INTERVAL, + DEFAULT_GETTER_PROCESSING_INTERVAL, + DEFAULT_GETTER_MAX_BLOCKS, +} from '../../getter/getter.service'; +import { + LoggerService, + STATUS_LOG_INTERVAL, +} from '../../logger/logger.service'; +import { ConfigService } from '../../config/config.service'; +import { ChainConfig } from '../../config/config.types'; +import { LoggerOptions } from 'pino'; +import { MonitorService } from '../../monitor/monitor.service'; + +interface GlobalLayerZeroConfig { + retryInterval: number; + processingInterval: number; + maxBlocks: number | null; + layerZeroChainIdMap: Record; + incentivesAddresses: Record; +} + +export interface LayerZeroWorkerData { + chainId: string; + rpc: string; + resolver: string | null; + startingBlock?: number; + stoppingBlock?: number; + retryInterval: number; + processingInterval: number; + maxBlocks: number | null; + layerZeroChainId: string; + bridgeAddress: string; + incentivesAddress: string; + receiverAddress: string; + monitorPort: MessagePort; + loggerOptions: LoggerOptions; + incentivesAddresses: Record; + layerZeroChainIdMap: Record; +} + +/** + * Loads global configuration settings specific to Layer Zero. + * + * @param configService - Service to fetch configuration settings. + * @returns Global configuration settings for Layer Zero. + */ +function loadGlobalLayerZeroConfig(configService: ConfigService): GlobalLayerZeroConfig { + + const getterConfig = configService.globalConfig.getter; + const retryInterval = getterConfig.retryInterval ?? DEFAULT_GETTER_RETRY_INTERVAL; + const processingInterval = getterConfig.processingInterval ?? DEFAULT_GETTER_PROCESSING_INTERVAL; + const maxBlocks = getterConfig.maxBlocks ?? DEFAULT_GETTER_MAX_BLOCKS; + + const layerZeroChainIdMap: Record = {}; + const incentivesAddresses: Record = {}; + + for (const [chainId] of configService.chainsConfig) { + const layerZeroChainId: string | undefined = configService.getAMBConfig( + 'layer-zero', + 'layerZeroChainId', + chainId.toString(), + ); + const incentivesAddress: string | undefined = configService.getAMBConfig( + 'layer-zero', + 'incentivesAddress', + chainId.toString(), + ); + + if (layerZeroChainId !== undefined) { + layerZeroChainIdMap[layerZeroChainId] = chainId; + if (incentivesAddress !== undefined) { + incentivesAddresses[chainId] = incentivesAddress.toLowerCase(); + } + } + } + + return { + retryInterval, + processingInterval, + maxBlocks, + layerZeroChainIdMap, + incentivesAddresses, + }; +} + +/** + * Loads worker data for a specific chain configuration. + * + * @param configService - Service to fetch configuration settings. + * @param monitorService - Service to monitor and manage workers. + * @param loggerService - Service to log information and errors. + * @param chainConfig - Configuration settings for a specific chain. + * @param globalConfig - Global configuration settings for Layer Zero. + * @returns Worker data for the specific chain or null if configuration is incomplete. + */ +async function loadWorkerData( + configService: ConfigService, + monitorService: MonitorService, + loggerService: LoggerService, + chainConfig: ChainConfig, + globalConfig: GlobalLayerZeroConfig, +): Promise { + const chainId = chainConfig.chainId.toString(); + const rpc = chainConfig.rpc; + + try { + const layerZeroChainId = configService.getAMBConfig('layer-zero', 'layerZeroChainId', chainId); + const bridgeAddress = configService.getAMBConfig('layer-zero', 'bridgeAddress', chainId); + const incentivesAddress = configService.getAMBConfig('layer-zero', 'incentivesAddress', chainId); + const receiverAddress = configService.getAMBConfig('layer-zero', 'receiverAddress', chainId); + + if (layerZeroChainId == null || bridgeAddress == null || incentivesAddress == null || receiverAddress == null) { + return null; + } + + const port = await monitorService.attachToMonitor(chainId); + + return { + chainId, + rpc, + resolver: chainConfig.resolver, + startingBlock: chainConfig.startingBlock, + stoppingBlock: chainConfig.stoppingBlock, + retryInterval: chainConfig.getter.retryInterval ?? globalConfig.retryInterval, + processingInterval: chainConfig.getter.processingInterval ?? globalConfig.processingInterval, + maxBlocks: chainConfig.getter.maxBlocks ?? globalConfig.maxBlocks, + layerZeroChainId, + bridgeAddress: bridgeAddress.toLowerCase(), + incentivesAddress: incentivesAddress.toLowerCase(), + receiverAddress: receiverAddress.toLowerCase(), + monitorPort: port, + loggerOptions: loggerService.loggerOptions, + incentivesAddresses: globalConfig.incentivesAddresses, + layerZeroChainIdMap: globalConfig.layerZeroChainIdMap, + }; + } catch (error) { + loggerService.error(error, 'Failed to load Layer Zero module: missing configuration.'); + throw error; + } +} + +/** + * Main function for initializing Layer Zero workers. + * + * @param moduleInterface - Interface for the collector module. + */ +export default async (moduleInterface: CollectorModuleInterface) => { + const { configService, monitorService, loggerService } = moduleInterface; + const globalLayerZeroConfig = loadGlobalLayerZeroConfig(configService); + + const workers: Record = {}; + const workersData: LayerZeroWorkerData[] = []; + + for (const [, chainConfig] of configService.chainsConfig) { + const workerData = await loadWorkerData(configService, monitorService, loggerService, chainConfig, globalLayerZeroConfig); + if (workerData) { + workersData.push(workerData); + } + } + + if (workersData.length === 0) { + loggerService.warn('Skipping Layer Zero worker initialization: no valid Layer Zero chain configs found'); + return; + } + + initializeWorkers(workersData, workers, loggerService); + + setInterval(() => logStatus(workers, loggerService), STATUS_LOG_INTERVAL); +}; + +/** + * Initializes workers with the given data and logs errors and exit statuses. + * + * @param workersData - Array of worker data to initialize. + * @param workers - Record to keep track of active workers. + * @param loggerService - Service to log information and errors. + */ +function initializeWorkers( + workersData: LayerZeroWorkerData[], + workers: Record, + loggerService: LoggerService, +) { + for (const workerData of workersData) { + const worker = new Worker(join(__dirname, 'layer-zero.worker.js'), { + workerData: workerData, + transferList: [workerData.monitorPort], + }); + workers[workerData.chainId] = worker; + + worker.on('error', (error) => loggerService.fatal(error, 'Error on Layer Zero Worker.')); + worker.on('exit', (exitCode) => { + workers[workerData.chainId] = null; + loggerService.info({ exitCode, chainId: workerData.chainId }, `Layer Zero Worker exited.`); + }); + } +} + +/** + * Logs the status of active and inactive workers. + * + * @param workers - Record of active and inactive workers. + * @param loggerService - Service to log information. + */ +function logStatus(workers: Record, loggerService: LoggerService) { + const activeWorkers = []; + const inactiveWorkers = []; + + for (const chainId of Object.keys(workers)) { + if (workers[chainId]) { + activeWorkers.push(chainId); + } else { + inactiveWorkers.push(chainId); + } + } + + const status = { + activeWorkers, + inactiveWorkers, + }; + loggerService.info(status, 'Layer Zero collector workers status.'); +} \ No newline at end of file diff --git a/src/collector/layer-zero/layer-zero.worker.ts b/src/collector/layer-zero/layer-zero.worker.ts new file mode 100644 index 0000000..f92259c --- /dev/null +++ b/src/collector/layer-zero/layer-zero.worker.ts @@ -0,0 +1,611 @@ +/** + * This file initializes and manages Layer Zero workers. + * + * Inputs: + * - Worker data from worker_threads. + * - Configuration settings for Layer Zero. + * - Logger service for logging information and errors. + * + * Outputs: + * - Initializes and manages Layer Zero worker threads. + * - Logs status and errors related to the worker threads. + */ + +import pino from 'pino'; +import { workerData, MessagePort } from 'worker_threads'; +import { + JsonRpcProvider, + Log, + LogDescription, + BytesLike, + BigNumberish, + keccak256, + ethers, +} from 'ethers6'; +import { Store } from '../../store/store.lib'; +import { LayerZeroWorkerData } from './layer-zero'; +import { + MonitorInterface, + MonitorStatus, +} from '../../monitor/monitor.interface'; +import { ReceiveULN302__factory } from 'src/contracts/factories/ReceiveULN302__factory'; +import { wait, tryErrorToString, paddedTo0xAddress } from 'src/common/utils'; +import { + ReceiveULN302, + ReceiveULN302Interface, + UlnConfigStruct, + UlnConfigStructOutput, +} from 'src/contracts/ReceiveULN302'; +import { AmbPayload } from 'src/store/types/store.types'; +import { LayerZeroEnpointV2__factory } from 'src/contracts'; +import { Resolver, loadResolver } from 'src/resolvers/resolver'; +import { ParsePayload } from 'src/payload/decode.payload'; +import { LayerZeroEnpointV2Interface, PacketSentEvent } from 'src/contracts/LayerZeroEnpointV2'; + +interface LayerZeroWorkerDataWithMapping extends LayerZeroWorkerData { + layerZeroChainIdMap: Record; +} + +class LayerZeroWorker { + private readonly config: LayerZeroWorkerDataWithMapping; + private readonly chainId: string; + private readonly store: Store; + private readonly provider: JsonRpcProvider; + private readonly logger: pino.Logger; + private readonly bridgeAddress: string; + private readonly layerZeroEnpointV2Interface: LayerZeroEnpointV2Interface; + private readonly receiveULN302: ReceiveULN302; + private readonly receiveULN302Interface: ReceiveULN302Interface; + private readonly receiverAddress: string; + private readonly resolver: Resolver; + private readonly filterTopics: string[][]; + private readonly layerZeroChainIdMap: Record; + private readonly incentivesAddresses: Record; + private currentStatus: MonitorStatus | null = null; + private monitor: MonitorInterface; + + constructor() { + this.config = workerData as LayerZeroWorkerDataWithMapping; + this.chainId = this.config.chainId; + this.layerZeroChainIdMap = this.config.layerZeroChainIdMap; + this.incentivesAddresses = this.config.incentivesAddresses; + this.store = new Store(this.chainId); + this.provider = this.initializeProvider(this.config.rpc); + this.logger = this.initializeLogger(this.chainId); + this.receiveULN302 = ReceiveULN302__factory.connect( + this.config.receiverAddress, + this.provider, + ); + this.receiveULN302Interface = ReceiveULN302__factory.createInterface(); + this.bridgeAddress = this.config.bridgeAddress; + this.receiverAddress = this.config.receiverAddress; + this.layerZeroEnpointV2Interface = + LayerZeroEnpointV2__factory.createInterface(); + this.resolver = this.loadResolver( + this.config.resolver, + this.provider, + this.logger, + ); + this.filterTopics = [ + [this.layerZeroEnpointV2Interface.getEvent('PacketSent').topicHash, + this.receiveULN302Interface.getEvent('PayloadVerified').topicHash,] + ]; + this.monitor = this.startListeningToMonitor(this.config.monitorPort); + } + + // Initialization helpers + // ******************************************************************************************** + + /** + * Initializes the logger with a specific chain ID. + * + * @param chainId - The chain ID for which to initialize the logger. + * @returns A pino logger instance. + */ + private initializeLogger(chainId: string): pino.Logger { + return pino(this.config.loggerOptions).child({ + worker: 'collector-layerzero', + chain: chainId, + }); + } + + /** + * Initializes the provider with a specific RPC URL. + * + * @param rpc - The RPC URL to use for the provider. + * @returns A JsonRpcProvider instance. + */ + private initializeProvider(rpc: string): JsonRpcProvider { + return new JsonRpcProvider(rpc, undefined, { staticNetwork: true }); + } + + /** + * Loads the resolver with a specific configuration. + * + * @param resolver - The resolver configuration. + * @param provider - The provider to use for the resolver. + * @param logger - The logger to use for the resolver. + * @returns A Resolver instance. + */ + private loadResolver( + resolver: string | null, + provider: JsonRpcProvider, + logger: pino.Logger, + ): Resolver { + return loadResolver(resolver, provider, logger); + } + + /** + * Starts listening to the monitor. + * + * @param port - The message port for the monitor. + * @returns A MonitorInterface instance. + */ + private startListeningToMonitor(port: MessagePort): MonitorInterface { + const monitor = new MonitorInterface(port); + monitor.addListener((status: MonitorStatus) => { + this.currentStatus = status; + }); + return monitor; + } + + // Main handler + // ******************************************************************************************** + + /** + * Main function to run the Layer Zero worker. + */ + async run(): Promise { + this.logger.info( + { + bridgeAddress: this.config.bridgeAddress, + receiverAddress: this.config.receiverAddress, + }, + `LayerZero collector worker started.`, + ); + let fromBlock = null; + while (fromBlock == null) { + if (this.currentStatus != null) { + if (this.config.startingBlock != null) { + if (this.config.startingBlock < 0) { + fromBlock = this.currentStatus.blockNumber + this.config.startingBlock; + if (fromBlock < 0) { + throw new Error(`Invalid 'startingBlock': negative offset is larger than the current block number.`) + } + } else { + fromBlock = this.config.startingBlock; + } + } else { + fromBlock = this.currentStatus.blockNumber; + } + } + await wait(this.config.processingInterval); + } + const stopBlock = this.config.stoppingBlock ?? Infinity; + while (true) { + try { + let toBlock = this.currentStatus?.blockNumber; + if (!toBlock || fromBlock > toBlock) { + await wait(this.config.processingInterval); + continue; + } + if (toBlock > stopBlock) { + toBlock = stopBlock; + } + const blocksToProcess = toBlock - fromBlock; + if ( + this.config.maxBlocks != null && + blocksToProcess > this.config.maxBlocks + ) { + toBlock = fromBlock + this.config.maxBlocks; + } + await this.queryAndProcessEvents(fromBlock, toBlock); + this.logger.info( + { fromBlock, toBlock }, + `Scanning LayerZero events.`, + ); + if (toBlock >= stopBlock) { + this.logger.info( + { stopBlock: toBlock }, + `Finished processing blocks: stopBlock reached.`, + ); + break; + } + fromBlock = toBlock + 1; + } catch (error) { + this.logger.error(error, `Error on Layer Zero worker: processing blocks.`); + await wait(this.config.retryInterval); + } + await wait(this.config.processingInterval); + } + this.monitor.close(); + await this.store.quit(); + } + + /** + * Queries and processes events between two blocks. + * + * @param fromBlock - The starting block number. + * @param toBlock - The ending block number. + */ + private async queryAndProcessEvents( + fromBlock: number, + toBlock: number, + ): Promise { + const logs = await this.queryLogs(fromBlock, toBlock); + for (const log of logs) { + try { + await this.handleEvent(log); + } catch (error) { + this.logger.error( + { log, error: tryErrorToString(error) }, + `Failed to process event on layer-zero collector worker.`, + ); + } + } + } + + /** + * Queries logs between two blocks. + * + * @param fromBlock - The starting block number. + * @param toBlock - The ending block number. + * @returns A list of logs. + */ + private async queryLogs(fromBlock: number, toBlock: number): Promise { + + const filter = { + address: [this.bridgeAddress, this.receiverAddress], + fromBlock, + toBlock, + topics: this.filterTopics, + }; + + let logs: Log[] | undefined; + let i = 0; + while (logs == undefined) { + try { + logs = await this.provider.getLogs(filter); + } catch (error) { + i++; + this.logger.warn( + { ...filter, error: tryErrorToString(error), try: i }, + `Failed to 'getLogs' on layer-zero worker. Worker blocked until successful query.` + ); + await wait(this.config.retryInterval); + } + } + + return logs; + } + + // Event handlers + // ******************************************************************************************** + + /** + * Handles events from logs. + * + * @param log - The log data. + */ + private async handleEvent(log: Log): Promise { + let parsedLog: LogDescription | null = null; + if (log.address.toLowerCase() === this.bridgeAddress) { + parsedLog = this.layerZeroEnpointV2Interface.parseLog(log); + } else if (log.address.toLowerCase() === this.receiverAddress) { + parsedLog = this.receiveULN302Interface.parseLog(log); + } + if (parsedLog == null) { + this.logger.error( + { topics: log.topics, data: log.data }, + `Failed to parse LayerZero event.`, + ); + return; + } + + switch (parsedLog.name) { + case 'PacketSent': + await this.handlePacketSentEvent(log, parsedLog); + break; + + case 'PayloadVerified': + await this.handlePayloadVerifiedEvent(log, parsedLog); + break; + + default: + this.logger.warn( + { name: parsedLog.name, topic: parsedLog.topic }, + `Event with unknown name/topic received.`, + ); + } + } + + /** + * Handles PacketSent events. + * + * @param log - The log data. + * @param parsedLog - The parsed log description. + */ + private async handlePacketSentEvent( + log: Log, + parsedLog: LogDescription, + ): Promise { + try { + const { + encodedPayload, + options, + sendLibrary + } = parsedLog.args as unknown as PacketSentEvent.OutputObject; + const packet = this.decodePacket(encodedPayload); + const srcEidMapped = this.layerZeroChainIdMap[packet.srcEid]; + const dstEidMapped = this.layerZeroChainIdMap[packet.dstEid]; + + this.logger.debug( + { transactionHash: log.transactionHash, packet, options, sendLibrary }, + 'PacketSent event found.', + ); + + if (srcEidMapped === undefined || dstEidMapped === undefined) { + this.logger.debug( + { + transactionHash: log.transactionHash, + packet, + options, + sendLibrary, + }, + 'Skipping packet: unsupported srcEid/dstEid.', + ); + return; + } + + const decodedMessage = ParsePayload(packet.message); + if (decodedMessage === undefined) { + throw new Error('Failed to decode message payload.'); + } + if ( + paddedTo0xAddress(packet.sender).toLowerCase() === + this.incentivesAddresses[srcEidMapped] + ) { + this.logger.info( + { sender: packet.sender, message: packet.message }, + 'Processing packet from specific sender: sender and message details.', + ); + const transactionBlockNumber = + await this.resolver.getTransactionBlockNumber(log.blockNumber); + await this.store.setAmb( + { + messageIdentifier: decodedMessage.messageIdentifier, + amb: 'layer-zero', + sourceChain: srcEidMapped.toString(), + destinationChain: dstEidMapped.toString(), + sourceEscrow: packet.sender, + payload: decodedMessage.message, + recoveryContext: '0x', + blockNumber: log.blockNumber, + transactionBlockNumber, + blockHash: log.blockHash, + transactionHash: log.transactionHash, + }, + log.transactionHash, + ); + + const payloadHash = this.calculatePayloadHash( + packet.guid, + packet.message, + ); + + await this.store.setPayload('layer-zero', 'ambMessage', payloadHash, { + messageIdentifier: decodedMessage.messageIdentifier, + destinationChain: dstEidMapped, + payload: encodedPayload, + }); + + this.logger.info( + { + messageIdentifier: decodedMessage.messageIdentifier, + transactionHash: log.transactionHash, + payloadHash + }, + 'Collected message.', + ); + } else { + this.logger.debug( + { sender: packet.sender }, + 'Skipping packet: sender is not a GARP contract.', + ); + } + } catch (error) { + this.logger.error({ error: tryErrorToString(error), log }, 'Failed to handle PacketSent event.'); + } + } + + /** + * Handles PayloadVerified events. + * + * @param _log - The log data. + * @param parsedLog - The parsed log description. + */ + private async handlePayloadVerifiedEvent( + _log: Log, + parsedLog: LogDescription, + ): Promise { + const { dvn, header, confirmations, proofHash } = parsedLog.args as any; + const decodedHeader = this.decodeHeader(header); + const srcEidMapped = this.layerZeroChainIdMap[decodedHeader.srcEid]; + const dstEidMapped = this.layerZeroChainIdMap[decodedHeader.dstEid]; + if (srcEidMapped === undefined || dstEidMapped === undefined) { + this.logger.error( + { + srcEid: decodedHeader.srcEid, + dstEid: decodedHeader.dstEid + }, + 'Failed to map srcEidMapped or dstEidMapped.', + ); + return; + } + if ( + decodedHeader.sender.toLowerCase() === + this.incentivesAddresses[srcEidMapped] + ) { + this.logger.info( + { dvn, decodedHeader, confirmations, proofHash }, + 'PayloadVerified event decoded.', + ); + const payloadData = await this.store.getPayload('layer-zero', 'ambMessage', proofHash); + if (!payloadData) { + this.logger.error( + { proofHash }, + 'No data found in database for the given payloadHash: proofHash details.', + ); + return; + } + try { + const config = await getConfigData( + this.receiveULN302, + dvn, + decodedHeader.dstEid, + ); + const isVerifiable = await checkIfVerifiable( + this.receiveULN302, + config, + keccak256(header), + proofHash, + ); + if (isVerifiable) { + const ambPayload: AmbPayload = { + messageIdentifier: '0x' + payloadData.messageIdentifier, + amb: 'layer-zero', + destinationChainId: dstEidMapped.toString(), + message: payloadData.payload, + messageCtx: '0x', + }; + this.logger.info({ proofHash }, `LayerZero proof found.`); + await this.store.submitProof( + this.layerZeroChainIdMap[decodedHeader.dstEid]!, + ambPayload, + ); + } else { + this.logger.debug('Payload could not be verified'); + } + } catch (error) { + this.logger.error( + { error: tryErrorToString(error) }, + 'Error during payload verification.', + ); + } + } + } + + // Helper function to decode the packet data + private decodePacket(encodedPacket: string): any { + return { + nonce: encodedPacket.slice(2 + 2, 2 + 2 + 16), + srcEid: Number('0x' + encodedPacket.slice(20, 28)), + sender: encodedPacket.slice(2 + 26, 2 + 26 + 64), + dstEid: Number('0x' + encodedPacket.slice(2 + 90, 2 + 98)), + receiver: encodedPacket.slice(2 + 98, 2 + 98 + 64), + guid: encodedPacket.slice(2 + 162, 2 + 162 + 64), + message: encodedPacket.slice(2 + 226), + }; + } + + /** + * Decodes the header of a payload. + * This function extracts specific fields from the encoded header string, converting + * hexadecimal values to appropriate formats, and returns an object containing these values. + * The function ensures proper handling and formatting of Ethereum addresses and numeric IDs. + * The first 2 bytes of the encoded header are skipped as they represent the version, later + * instead of using a counter to skip bytes, the slice function is used to extract the required. + * + * @param encodedHeader - The encoded header string to be decoded. + * @returns An object containing the decoded header fields. + */ + private decodeHeader(encodedHeader: string): any { + const version = encodedHeader.slice(2, 2 + 2); + const nonce = encodedHeader.slice(2 + 2, 2 + 2 + 16); + const srcEid = Number('0x' + encodedHeader.slice(2 + 18, 2 + 18 + 8)); + const sender = '0x' + encodedHeader.slice(2 + 26, 2 + 26 + 64).slice(24); + const dstEid = Number('0x' + encodedHeader.slice(2 + 90, 2 + 90 + 8)); + const receiver = '0x' + encodedHeader.slice(2 + 98, 2 + 98 + 64).slice(24); + + return { + version, + nonce: Number('0x' + nonce), + srcEid, + sender, + dstEid, + receiver, + }; + } + + + private calculatePayloadHash(guid: string, message: string): string { + const payload = `0x${guid}${message}`; + return ethers.keccak256(payload); + } +} + +/** + * Checks if the configuration is verifiable. + * + * @param receiveULN302 - The ULN302 contract instance. + * @param config - The ULN configuration. + * @param headerHash - The header hash. + * @param payloadHash - The payload hash. + * @returns A boolean indicating if the configuration is verifiable. + */ +async function checkIfVerifiable( + receiveULN302: ReceiveULN302, + config: UlnConfigStruct, + headerHash: BytesLike, + payloadHash: BytesLike, +): Promise { + try { + const requiredDVNs = config.requiredDVNs.map(dvn => dvn.toString()); + const optionalDVNs = config.optionalDVNs.map(dvn => dvn.toString()); + const formatConfig: UlnConfigStruct = { + confirmations: '0x' + config.confirmations.toString(16).padStart(16, '0'), + requiredDVNCount: + '0x' + config.requiredDVNCount.toString(16).padStart(2, '0'), + optionalDVNCount: + '0x' + config.optionalDVNCount.toString(16).padStart(2, '0'), + optionalDVNThreshold: + '0x' + config.optionalDVNThreshold.toString(16).padStart(2, '0'), + requiredDVNs: requiredDVNs, + optionalDVNs: optionalDVNs, + }; + const isVerifiable = await receiveULN302.verifiable( + formatConfig, + headerHash, + payloadHash, + ); + return isVerifiable; + } catch (error) { + throw new Error('Error verifying the payload.'); + } +} + +/** + * Retrieves the ULN configuration data. + * + * @param receiveULN302 - The ULN302 contract instance. + * @param dvn - The DVN. + * @param remoteEid - The remote EID. + * @returns The ULN configuration data. + */ +async function getConfigData( + receiveULN302: ReceiveULN302, + dvn: string, + remoteEid: BigNumberish, +): Promise { + try { + const config = await receiveULN302.getUlnConfig( + dvn, + '0x' + remoteEid.toString(16).padStart(8, '0'), + ); + return config; + } catch (error) { + throw new Error('Error fetching configuration data: error details.'); + } +} + +void new LayerZeroWorker().run(); \ No newline at end of file diff --git a/src/common/utils.ts b/src/common/utils.ts index f5a138d..29b5ebe 100644 --- a/src/common/utils.ts +++ b/src/common/utils.ts @@ -1,3 +1,4 @@ +import { ethers } from "ethers6"; export const wait = (ms: number) => new Promise((res) => setTimeout(res, ms)); @@ -22,4 +23,8 @@ export const tryErrorToString = (error: any): string | undefined => { } catch { return 'Unable to stringify error.'; } -} \ No newline at end of file +} +export function paddedTo0xAddress(paddedAddress: string): string { + const normalAddress = '0x' + paddedAddress.slice(-40); + return ethers.getAddress(normalAddress); +}; \ No newline at end of file diff --git a/src/store/store.lib.ts b/src/store/store.lib.ts index 25c6f95..a285bdc 100644 --- a/src/store/store.lib.ts +++ b/src/store/store.lib.ts @@ -643,4 +643,15 @@ export class Store { await this.postMessage(emitToChannel, ambPayload); } + async setPayload(prefix: string, suffix: string, payloadHash: string, dataToStore: any): Promise { + const key = `${prefix}:${suffix}:${payloadHash.toLowerCase()}`; + const data = JSON.stringify(dataToStore); + await this.redis.set(key, data); + } + + async getPayload(prefix: string, suffix: string, payloadHash: string): Promise { + const key = `${prefix}:${suffix}:${payloadHash.toLowerCase()}`; + const result = await this.redis.get(key); + return result ? JSON.parse(result) : null; + } }