diff --git a/packages/evm/contracts/adapters/DendrETH/DendrETHAdapter.sol b/packages/evm/contracts/adapters/DendrETH/DendrETHAdapter.sol index 87e29bb2..24e9a2fb 100644 --- a/packages/evm/contracts/adapters/DendrETH/DendrETHAdapter.sol +++ b/packages/evm/contracts/adapters/DendrETH/DendrETHAdapter.sol @@ -8,6 +8,7 @@ import { BlockHashOracleAdapter } from "../BlockHashOracleAdapter.sol"; contract DendrETHAdapter is BlockHashOracleAdapter { error InvalidUpdate(); error BlockHeaderNotAvailable(uint256 slot); + error InvalidSlot(); error InvalidBlockNumberProof(); error InvalidBlockHashProof(); @@ -22,6 +23,8 @@ contract DendrETHAdapter is BlockHashOracleAdapter { function storeBlockHeader( uint32 _chainId, uint64 _slot, + bytes32[] calldata _slotProof, + bytes32 _finalizedBlockHeader, uint256 _blockNumber, bytes32[] calldata _blockNumberProof, bytes32 _blockHash, @@ -34,7 +37,7 @@ contract DendrETHAdapter is BlockHashOracleAdapter { bool found = false; do { - if (_slot == lightClient.optimisticSlots(i)) { + if (_finalizedBlockHeader == lightClient.finalizedHeaders(i)) { found = true; break; } @@ -48,13 +51,15 @@ contract DendrETHAdapter is BlockHashOracleAdapter { revert BlockHeaderNotAvailable(_slot); } - bytes32 blockHeaderRoot = lightClient.optimisticHeaders(i); + if (!SSZ.verifySlot(_slot, _slotProof, _finalizedBlockHeader)) { + revert InvalidSlot(); + } - if (!SSZ.verifyBlockNumber(_blockNumber, _blockNumberProof, blockHeaderRoot)) { + if (!SSZ.verifyBlockNumber(_blockNumber, _blockNumberProof, _finalizedBlockHeader)) { revert InvalidBlockNumberProof(); } - if (!SSZ.verifyBlockHash(_blockHash, _blockHashProof, blockHeaderRoot)) { + if (!SSZ.verifyBlockHash(_blockHash, _blockHashProof, _finalizedBlockHeader)) { revert InvalidBlockHashProof(); } @@ -66,6 +71,7 @@ contract DendrETHAdapter is BlockHashOracleAdapter { function storeBlockHeader( uint32 _chainId, uint64 _slot, + bytes32[] calldata _slotProof, uint256 _blockNumber, bytes32[] calldata _blockNumberProof, bytes32 _blockHash, @@ -76,17 +82,17 @@ contract DendrETHAdapter is BlockHashOracleAdapter { lightClient.light_client_update(update); - if (lightClient.optimisticHeaderSlot() != _slot) { + bytes32 finalizedHeaderRoot = lightClient.finalizedHeaderRoot(); + + if (!SSZ.verifySlot(_slot, _slotProof, finalizedHeaderRoot)) { revert InvalidUpdate(); } - bytes32 blockHeaderRoot = lightClient.optimisticHeaderRoot(); - - if (!SSZ.verifyBlockNumber(_blockNumber, _blockNumberProof, blockHeaderRoot)) { + if (!SSZ.verifyBlockNumber(_blockNumber, _blockNumberProof, finalizedHeaderRoot)) { revert InvalidBlockNumberProof(); } - if (!SSZ.verifyBlockHash(_blockHash, _blockHashProof, blockHeaderRoot)) { + if (!SSZ.verifyBlockHash(_blockHash, _blockHashProof, finalizedHeaderRoot)) { revert InvalidBlockHashProof(); } diff --git a/packages/evm/contracts/adapters/DendrETH/interfaces/IDendrETH.sol b/packages/evm/contracts/adapters/DendrETH/interfaces/IDendrETH.sol index a4e98267..c198d362 100644 --- a/packages/evm/contracts/adapters/DendrETH/interfaces/IDendrETH.sol +++ b/packages/evm/contracts/adapters/DendrETH/interfaces/IDendrETH.sol @@ -14,13 +14,9 @@ struct LightClientUpdate { interface ILightClient { function currentIndex() external view returns (uint256); - function optimisticHeaders(uint256 index) external view returns (bytes32); + function finalizedHeaders(uint256 index) external view returns (bytes32); - function optimisticHeaderRoot() external view returns (bytes32); - - function optimisticSlots(uint256 index) external view returns (uint256); - - function optimisticHeaderSlot() external view returns (uint256); + function finalizedHeaderRoot() external view returns (bytes32); function light_client_update(LightClientUpdate calldata update) external; } diff --git a/packages/evm/contracts/adapters/Telepathy/libraries/SimpleSerialize.sol b/packages/evm/contracts/adapters/Telepathy/libraries/SimpleSerialize.sol index 3ba3f9d3..a4fc6f64 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); + } }