From 605b234121a69139f06a8193e112be906a3e10e0 Mon Sep 17 00:00:00 2001 From: Dimo99 Date: Mon, 10 Jul 2023 14:06:10 +0300 Subject: [PATCH 1/4] feat(evm): Make dendreth adapter work with finalized header --- .../adapters/DendrETH/DendrETHAdapter.sol | 56 +++++++++++-------- .../DendrETH/interfaces/IDendrETH.sol | 20 +++++-- .../Telepathy/libraries/SimpleSerialize.sol | 7 +++ 3 files changed, 53 insertions(+), 30 deletions(-) diff --git a/packages/evm/contracts/adapters/DendrETH/DendrETHAdapter.sol b/packages/evm/contracts/adapters/DendrETH/DendrETHAdapter.sol index a480cafb..6fc6c408 100644 --- a/packages/evm/contracts/adapters/DendrETH/DendrETHAdapter.sol +++ b/packages/evm/contracts/adapters/DendrETH/DendrETHAdapter.sol @@ -15,8 +15,8 @@ contract DendrETHAdapter is BlockHashAdapter { address public immutable SOURCE_YAHO; uint256 public immutable SOURCE_CHAIN_ID; - error InvalidUpdate(); - error BlockHeaderNotAvailable(uint256 slot); + error FinalizedBlockHeaderNotAvailable(bytes32 finalizedHeader); + error InvalidSlot(); error InvalidBlockNumberProof(); error InvalidBlockHashProof(); error InvalidReceiptsRoot(); @@ -24,6 +24,11 @@ contract DendrETHAdapter is BlockHashAdapter { error InvalidEventSignature(); error InvalidEventSource(); + modifier onlyFinalizedHeaderIsInLightClient(bytes32 finalizedBlockHeader) { + _checkFinalizedHeaderIsInLightClient(finalizedBlockHeader); + _; + } + constructor(address dendrETHAddress, uint256 sourceChainId, address sourceYaho) { DENDRETH_ADDRESS = dendrETHAddress; SOURCE_CHAIN_ID = sourceChainId; @@ -33,18 +38,17 @@ contract DendrETHAdapter is BlockHashAdapter { /// @notice Stores the block header for a given block only if it exists // in the DendrETH Light Client for the SOURCE_CHAIN_ID. function storeBlockHeader( - uint64 slot, + bytes32 finalizedBlockHeader, uint256 blockNumber, bytes32[] calldata blockNumberProof, bytes32 blockHash, bytes32[] calldata blockHashProof - ) external { - ILightClient lightClient = ILightClient(DENDRETH_ADDRESS); - bytes32 blockHeaderRoot = lightClient.optimisticHeaders(_getIndex(slot, lightClient)); - if (!SSZ.verifyBlockNumber(blockNumber, blockNumberProof, blockHeaderRoot)) { + ) external onlyFinalizedHeaderIsInLightClient(finalizedBlockHeader) { + if (!SSZ.verifyBlockNumber(blockNumber, blockNumberProof, finalizedBlockHeader)) { revert InvalidBlockNumberProof(); } - if (!SSZ.verifyBlockHash(blockHash, blockHashProof, blockHeaderRoot)) { + + if (!SSZ.verifyBlockHash(blockHash, blockHashProof, finalizedBlockHeader)) { revert InvalidBlockHashProof(); } @@ -54,7 +58,6 @@ contract DendrETHAdapter is BlockHashAdapter { /// @notice Updates DendrETH Light client and stores the given block // for the update function storeBlockHeader( - uint64 slot, uint256 blockNumber, bytes32[] calldata blockNumberProof, bytes32 blockHash, @@ -62,16 +65,16 @@ contract DendrETHAdapter is BlockHashAdapter { LightClientUpdate calldata update ) external { ILightClient lightClient = ILightClient(DENDRETH_ADDRESS); - lightClient.light_client_update(update); - if (lightClient.optimisticHeaderSlot() != slot) { - revert InvalidUpdate(); - } - bytes32 blockHeaderRoot = lightClient.optimisticHeaderRoot(); - if (!SSZ.verifyBlockNumber(blockNumber, blockNumberProof, blockHeaderRoot)) { + lightClient.lightClientUpdate(update); + + bytes32 finalizedHeaderRoot = lightClient.finalizedHeaderRoot(); + + if (!SSZ.verifyBlockNumber(blockNumber, blockNumberProof, finalizedHeaderRoot)) { revert InvalidBlockNumberProof(); } - if (!SSZ.verifyBlockHash(blockHash, blockHashProof, blockHeaderRoot)) { + + if (!SSZ.verifyBlockHash(blockHash, blockHashProof, finalizedHeaderRoot)) { revert InvalidBlockHashProof(); } @@ -79,24 +82,28 @@ contract DendrETHAdapter is BlockHashAdapter { } function verifyAndStoreDispatchedMessage( + bytes32 srcFinalizedHeader, uint64 srcSlot, + bytes32[] calldata slotProof, uint64 txSlot, bytes32[] memory receiptsRootProof, bytes32 receiptsRoot, bytes[] memory receiptProof, bytes memory txIndexRLPEncoded, uint256 logIndex - ) external { - ILightClient lightClient = ILightClient(DENDRETH_ADDRESS); - bytes32 blockHeaderRoot = lightClient.optimisticHeaders(_getIndex(srcSlot, lightClient)); + ) external onlyFinalizedHeaderIsInLightClient(srcFinalizedHeader) { + if (!SSZ.verifySlot(srcSlot, slotProof, srcFinalizedHeader)) { + revert InvalidSlot(); + } bool isValidReceiptsRoot = Merkle.verifyReceiptsRoot( receiptsRootProof, receiptsRoot, srcSlot, txSlot, - blockHeaderRoot + srcFinalizedHeader ); + if (!isValidReceiptsRoot) revert InvalidReceiptsRoot(); Receipt.ParsedReceipt memory parsedReceipt = Receipt.parseReceipt( @@ -116,13 +123,15 @@ contract DendrETHAdapter is BlockHashAdapter { _storeHash(SOURCE_CHAIN_ID, messageId, messageHash); } - function _getIndex(uint64 slot, ILightClient lightClient) internal view returns (uint256) { + function _checkFinalizedHeaderIsInLightClient(bytes32 finalizedBlockHeader) internal view { + ILightClient lightClient = ILightClient(DENDRETH_ADDRESS); + uint256 currentIndex = lightClient.currentIndex(); uint256 i = currentIndex; bool found = false; do { - if (slot == lightClient.optimisticSlots(i)) { + if (finalizedBlockHeader == lightClient.finalizedHeaders(i)) { found = true; break; } @@ -133,8 +142,7 @@ contract DendrETHAdapter is BlockHashAdapter { } while (i != currentIndex); if (!found) { - revert BlockHeaderNotAvailable(slot); + revert FinalizedBlockHeaderNotAvailable(finalizedBlockHeader); } - return i; } } diff --git a/packages/evm/contracts/adapters/DendrETH/interfaces/IDendrETH.sol b/packages/evm/contracts/adapters/DendrETH/interfaces/IDendrETH.sol index f86d1839..01e6f879 100644 --- a/packages/evm/contracts/adapters/DendrETH/interfaces/IDendrETH.sol +++ b/packages/evm/contracts/adapters/DendrETH/interfaces/IDendrETH.sol @@ -1,5 +1,5 @@ -// SPDX-License-Identifier: LGPL-3.0-only -pragma solidity 0.8.20; +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; struct LightClientUpdate { bytes32 attestedHeaderRoot; @@ -14,13 +14,21 @@ struct LightClientUpdate { interface ILightClient { function currentIndex() external view returns (uint256); - function optimisticHeaders(uint256 index) external view returns (bytes32); - function optimisticHeaderRoot() external view returns (bytes32); + function optimisticHeaderSlot() external view returns (uint256); + + function finalizedHeaderRoot() external view returns (bytes32); + + function executionStateRoot() external view returns (bytes32); + + function optimisticHeaders(uint256 index) external view returns (bytes32); + function optimisticSlots(uint256 index) external view returns (uint256); - function optimisticHeaderSlot() external view returns (uint256); + function finalizedHeaders(uint256 index) external view returns (bytes32); + + function executionStateRoots(uint256 index) external view returns (bytes32); - function light_client_update(LightClientUpdate calldata update) external; + function lightClientUpdate(LightClientUpdate calldata update) external payable; } diff --git a/packages/evm/contracts/adapters/Telepathy/libraries/SimpleSerialize.sol b/packages/evm/contracts/adapters/Telepathy/libraries/SimpleSerialize.sol index 8f43e34c..055b96af 100644 --- a/packages/evm/contracts/adapters/Telepathy/libraries/SimpleSerialize.sol +++ b/packages/evm/contracts/adapters/Telepathy/libraries/SimpleSerialize.sol @@ -6,6 +6,9 @@ library SSZ { uint256 internal constant EXECUTION_PAYLOAD_BLOCK_NUMBER_INDEX = 3222; uint256 internal constant EXECUTION_PAYLOAD_BLOCK_HASH_INDEX = 3228; + // G-index for the BeaconBlockHeader -> slot + uint256 internal constant SLOT_INDEX = 8; + function toLittleEndian(uint256 _v) internal pure returns (bytes32) { _v = ((_v & 0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00) >> 8) | @@ -74,4 +77,8 @@ library SSZ { ) internal pure returns (bool) { return isValidMerkleBranch(_blockHash, EXECUTION_PAYLOAD_BLOCK_HASH_INDEX, _blockHashProof, _headerRoot); } + + function verifySlot(uint256 _slot, bytes32[] memory _slotProof, bytes32 _headerRoot) internal pure returns (bool) { + return isValidMerkleBranch(toLittleEndian(_slot), SLOT_INDEX, _slotProof, _headerRoot); + } } From 8d7bfb3e74c85e05457b237beeb98b117cc9e546 Mon Sep 17 00:00:00 2001 From: Dimo99 Date: Tue, 20 Aug 2024 17:28:14 +0300 Subject: [PATCH 2/4] fix(evm): SSZ library to work for deneb fork --- .../adapters/Telepathy/libraries/SimpleSerialize.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/evm/contracts/adapters/Telepathy/libraries/SimpleSerialize.sol b/packages/evm/contracts/adapters/Telepathy/libraries/SimpleSerialize.sol index 055b96af..17ec7541 100644 --- a/packages/evm/contracts/adapters/Telepathy/libraries/SimpleSerialize.sol +++ b/packages/evm/contracts/adapters/Telepathy/libraries/SimpleSerialize.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.20; library SSZ { // G-indicies for the BeaconBlockHeader -> bodyRoot -> executionPayload -> {blockNumber, blockHash} - uint256 internal constant EXECUTION_PAYLOAD_BLOCK_NUMBER_INDEX = 3222; - uint256 internal constant EXECUTION_PAYLOAD_BLOCK_HASH_INDEX = 3228; + uint256 internal constant EXECUTION_PAYLOAD_BLOCK_NUMBER_INDEX = 6438; + uint256 internal constant EXECUTION_PAYLOAD_BLOCK_HASH_INDEX = 6444; // G-index for the BeaconBlockHeader -> slot uint256 internal constant SLOT_INDEX = 8; From b3f74277dfd703cde33a024e9d6550844d16bde5 Mon Sep 17 00:00:00 2001 From: Dimo99 Date: Thu, 5 Sep 2024 16:54:56 +0300 Subject: [PATCH 3/4] feat: Add MerklePatricia library for lukso and sepolia --- packages/evm/tasks/deploy/adapters/dendreth.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/evm/tasks/deploy/adapters/dendreth.ts b/packages/evm/tasks/deploy/adapters/dendreth.ts index cb8d5855..b08e7871 100644 --- a/packages/evm/tasks/deploy/adapters/dendreth.ts +++ b/packages/evm/tasks/deploy/adapters/dendreth.ts @@ -8,6 +8,8 @@ import { verify } from "../index" const MerklePatriciaAddresses = { 10200: "0x777662E6A65411e0A425E59C496A7D1C0635A935", + 11155111: "0x1b19Dfd5e1986A0d524644F081AcB14d51159818", + 4201: "0xC82e50cc90C84DC492B4Beb6792DEeB496d52424", } task("deploy:adapter:DendrETHAdapter") From 1af09d61dd3c968a16b0c4fb2d3f3823b419c755 Mon Sep 17 00:00:00 2001 From: Kristin Kirkov Date: Mon, 9 Sep 2024 14:39:21 +0300 Subject: [PATCH 4/4] feat(evm): Add lukso-testnet to supported networks --- packages/evm/hardhat.config.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/evm/hardhat.config.ts b/packages/evm/hardhat.config.ts index 2397917f..f875ef45 100644 --- a/packages/evm/hardhat.config.ts +++ b/packages/evm/hardhat.config.ts @@ -36,6 +36,7 @@ const chainIds = { "polygon-mainnet": 137, "polygon-mumbai": 80001, sepolia: 11155111, + "lukso-testnet": 4201, } function getChainConfig(chain: keyof typeof chainIds): NetworkUserConfig { @@ -57,6 +58,9 @@ function getChainConfig(chain: keyof typeof chainIds): NetworkUserConfig { case "chiado": jsonRpcUrl = "https://rpc.chiadochain.net/" break + case "lukso-testnet": + jsonRpcUrl = "https://rpc.testnet.lukso.network" + break default: jsonRpcUrl = `https://${chain}.infura.io/v3/${infuraApiKey}` } @@ -109,6 +113,7 @@ const config: HardhatUserConfig = { bsc: getChainConfig("bsc"), gnosis: getChainConfig("gnosis"), chiado: getChainConfig("chiado"), + "lukso-testnet": getChainConfig("lukso-testnet"), mainnet: getChainConfig("mainnet"), optimism: getChainConfig("optimism-mainnet"), "polygon-mainnet": getChainConfig("polygon-mainnet"),