diff --git a/.gitmodules b/.gitmodules index f94071e53..d89963a2c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -15,3 +15,6 @@ [submodule "lib/@matterlabs/zksync-contracts"] path = lib/@matterlabs/zksync-contracts url = https://github.com/matter-labs/v2-testnet-contracts +[submodule "da-contracts/lib/eigenda"] + path = da-contracts/lib/eigenda + url = https://github.com/Layr-Labs/eigenda diff --git a/da-contracts/contracts/da-layers/eigenda/DummyEigenDABridge.sol b/da-contracts/contracts/da-layers/eigenda/DummyEigenDABridge.sol index dd893253b..115226c8c 100644 --- a/da-contracts/contracts/da-layers/eigenda/DummyEigenDABridge.sol +++ b/da-contracts/contracts/da-layers/eigenda/DummyEigenDABridge.sol @@ -5,12 +5,15 @@ pragma solidity 0.8.24; import {IEigenDABridge} from "./IEigenDABridge.sol"; import {IImplementation} from "./IImplementation.sol"; import {DummyImplementation} from "./DummyImplementation.sol"; +import {IBlobVerifier} from "./IBlobVerifier.sol"; contract DummyEigenDABridge is IEigenDABridge { IImplementation public implementationContract; + IBlobVerifier public eigenBlobVerifier; - constructor() { + constructor(address _eigenBlobVerifier) { implementationContract = new DummyImplementation(); + eigenBlobVerifier = IBlobVerifier(_eigenBlobVerifier); } function implementation() external view returns (IImplementation) { @@ -18,33 +21,7 @@ contract DummyEigenDABridge is IEigenDABridge { } function verifyBlobLeaf(MerkleProofInput calldata merkleProof) external view returns (bool) { - // Inspired by eigenlayer contracts Merkle.verifyInclusionKeccak - // https://github.com/Layr-Labs/eigenlayer-contracts/blob/3f3f83bd194b3bdc77d06d8fe6b101fafc3bcfd5/src/contracts/libraries/Merkle.sol - uint256 index = merkleProof.index; - bytes memory inclusionProof = merkleProof.inclusionProof; - require(inclusionProof.length % 32 == 0, "proof length not multiple of 32"); - bytes32 computedHash = merkleProof.leaf; - uint256 length = inclusionProof.length; - for (uint256 i = 32; i <= length; i += 32) { - if (index % 2 == 0) { - // if ith bit of index is 0, then computedHash is a left sibling - assembly { - mstore(0x00, computedHash) - mstore(0x20, mload(add(inclusionProof, i))) - computedHash := keccak256(0x00, 0x40) - index := div(index, 2) - } - } else { - // if ith bit of index is 1, then computedHash is a right sibling - assembly { - mstore(0x00, mload(add(inclusionProof, i))) - mstore(0x20, computedHash) - computedHash := keccak256(0x00, 0x40) - index := div(index, 2) - } - } - } - require(computedHash == merkleProof.batchRoot, "invalid proof"); + eigenBlobVerifier.verifyBlobV1(merkleProof.blobHeader, merkleProof.blobVerificationProof); return true; } } diff --git a/da-contracts/contracts/da-layers/eigenda/IBlobVerifier.sol b/da-contracts/contracts/da-layers/eigenda/IBlobVerifier.sol new file mode 100644 index 000000000..7fecf12a7 --- /dev/null +++ b/da-contracts/contracts/da-layers/eigenda/IBlobVerifier.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.24; + +import {IEigenDABridge} from "./IEigenDABridge.sol"; + +interface IBlobVerifier { + function verifyBlobV1( + IEigenDABridge.BlobHeader calldata blobHeader, + IEigenDABridge.BlobVerificationProof calldata blobVerificationProof + ) external view; +} diff --git a/da-contracts/contracts/da-layers/eigenda/IEigenDABridge.sol b/da-contracts/contracts/da-layers/eigenda/IEigenDABridge.sol index 11947e045..39deb43be 100644 --- a/da-contracts/contracts/da-layers/eigenda/IEigenDABridge.sol +++ b/da-contracts/contracts/da-layers/eigenda/IEigenDABridge.sol @@ -6,11 +6,48 @@ import {IImplementation} from "./IImplementation.sol"; interface IEigenDABridge { // solhint-disable-next-line gas-struct-packing - struct MerkleProofInput { - bytes32 batchRoot; - bytes32 leaf; - uint256 index; + struct BatchHeader { + bytes32 blobHeadersRoot; + bytes quorumNumbers; + bytes signedStakeForQuorums; + uint32 referenceBlockNumber; + } + + struct BatchMetadata { + BatchHeader batchHeader; + bytes32 signatoryRecordHash; + uint32 confirmationBlockNumber; + } + + struct BlobVerificationProof { + uint32 batchId; + uint32 blobIndex; + BatchMetadata batchMetadata; bytes inclusionProof; + bytes quorumIndices; + } + + struct QuorumBlobParam { + uint8 quorumNumber; + uint8 adversaryThresholdPercentage; + uint8 confirmationThresholdPercentage; + uint32 chunkLength; + } + + struct G1Point { + uint256 X; + uint256 Y; + } + + struct BlobHeader { + G1Point commitment; + uint32 dataLength; + QuorumBlobParam[] quorumBlobParams; + } + + struct MerkleProofInput { + BlobHeader blobHeader; + BlobVerificationProof blobVerificationProof; } function implementation() external view returns (IImplementation implementation); diff --git a/da-contracts/foundry.toml b/da-contracts/foundry.toml index 6f29a31cc..f4c9638e0 100644 --- a/da-contracts/foundry.toml +++ b/da-contracts/foundry.toml @@ -5,7 +5,11 @@ libs = ['node_modules', 'lib'] remappings = [ "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", - "l2-contracts/=../l2-contracts/contracts/" + "l2-contracts/=../l2-contracts/contracts/", + "@eigenda/eigenda-utils/libraries/=lib/eigenda/contracts/src/libraries/", + "@eigenda/eigenda-utils/interfaces/=lib/eigenda/contracts/src/interfaces/", + "eigenlayer-middleware/=lib/eigenda/contracts/lib/eigenlayer-middleware/src/", + "eigenlayer-core/=lib/eigenda/contracts/lib/eigenlayer-middleware/lib/eigenlayer-contracts/src/" ] allow_paths = ["../l2-contracts/contracts"] fs_permissions = [ diff --git a/da-contracts/lib/eigenda b/da-contracts/lib/eigenda new file mode 160000 index 000000000..82af794f0 --- /dev/null +++ b/da-contracts/lib/eigenda @@ -0,0 +1 @@ +Subproject commit 82af794f09b4c3739aee020c23100739b922107d diff --git a/l1-contracts/deploy-scripts/DeployL1.s.sol b/l1-contracts/deploy-scripts/DeployL1.s.sol index 0d8378ed1..2c3474524 100644 --- a/l1-contracts/deploy-scripts/DeployL1.s.sol +++ b/l1-contracts/deploy-scripts/DeployL1.s.sol @@ -212,7 +212,7 @@ contract DeployL1Script is Script, DeployUtils { } if (config.contracts.eigenDAL1Validator == address(0)) { - address eigendaBridge = deployViaCreate2(Utils.readDummyEigenDABridgeBytecode(), ""); + address eigendaBridge = deployViaCreate2(Utils.readDummyEigenDABridgeBytecode(), abi.encode(config.contracts.eigenDABlobVerifier)); addresses.daAddresses.eigenDAL1Validator = deployViaCreate2( Utils.readEigenDAL1ValidatorBytecode(), abi.encode(eigendaBridge) diff --git a/l1-contracts/deploy-scripts/DeployUtils.s.sol b/l1-contracts/deploy-scripts/DeployUtils.s.sol index e79516904..68f4333d1 100644 --- a/l1-contracts/deploy-scripts/DeployUtils.s.sol +++ b/l1-contracts/deploy-scripts/DeployUtils.s.sol @@ -167,6 +167,7 @@ struct ContractsConfig { bytes32 defaultAAHash; address availL1DAValidator; address eigenDAL1Validator; + address eigenDABlobVerifier; } struct TokensConfig { @@ -246,6 +247,10 @@ contract DeployUtils is Script { config.contracts.eigenDAL1Validator = toml.readAddress("$.contracts.eigenda_l1_validator"); } + if (vm.keyExistsToml(toml, "$.contracts.eigenda_blob_verifier_addr")) { + config.contracts.eigenDABlobVerifier = toml.readAddress("$.contracts.eigenda_blob_verifier_addr"); + } + config.tokens.tokenWethAddress = toml.readAddress("$.tokens.token_weth_address"); }