From 04f1d374fd9d482e47509b373ae2f98d46a134ac Mon Sep 17 00:00:00 2001 From: juanbono Date: Tue, 22 Jul 2025 12:06:49 -0300 Subject: [PATCH 01/15] add gas proven to public input --- crates/l2/prover/zkvm/interface/src/execution.rs | 11 +++++++++++ crates/l2/prover/zkvm/interface/src/io.rs | 3 +++ 2 files changed, 14 insertions(+) diff --git a/crates/l2/prover/zkvm/interface/src/execution.rs b/crates/l2/prover/zkvm/interface/src/execution.rs index e0713a602c..e7d06323ae 100644 --- a/crates/l2/prover/zkvm/interface/src/execution.rs +++ b/crates/l2/prover/zkvm/interface/src/execution.rs @@ -128,6 +128,7 @@ pub fn stateless_validation_l1( final_state_hash, last_block_hash, non_privileged_count, + total_gas_used, .. } = execute_stateless(blocks, db, elasticity_multiplier)?; Ok(ProgramOutput { @@ -142,6 +143,7 @@ pub fn stateless_validation_l1( last_block_hash, chain_id: chain_id.into(), non_privileged_count, + total_gas_used, }) } @@ -164,6 +166,7 @@ pub fn stateless_validation_l2( last_block_header, last_block_hash, non_privileged_count, + total_gas_used, } = execute_stateless(blocks, db, elasticity_multiplier)?; let (l1messages, privileged_transactions) = @@ -203,6 +206,7 @@ pub fn stateless_validation_l2( last_block_hash, chain_id: chain_id.into(), non_privileged_count, + total_gas_used, }) } @@ -214,6 +218,7 @@ struct StatelessResult { last_block_header: BlockHeader, last_block_hash: H256, non_privileged_count: U256, + total_gas_used: U256, } fn execute_stateless( @@ -263,6 +268,8 @@ fn execute_stateless( let mut acc_account_updates: HashMap = HashMap::new(); let mut acc_receipts = Vec::new(); let mut non_privileged_count = 0; + // Total gas used for the batch + let mut total_gas_used = 0; for block in blocks { // Validate the block validate_block( @@ -303,8 +310,11 @@ fn execute_stateless( non_privileged_count += block.body.transactions.len() - get_block_privileged_transactions(&block.body.transactions).len(); + validate_gas_used(&receipts, &block.header) .map_err(StatelessExecutionError::GasValidationError)?; + // TODO: Verify if this is correct + total_gas_used += block.header.gas_used; validate_receipts_root(&block.header, &receipts) .map_err(StatelessExecutionError::ReceiptsRootValidationError)?; // validate_requests_hash doesn't do anything for l2 blocks as this verifies l1 requests (messages, privileged transactions and consolidations) @@ -336,6 +346,7 @@ fn execute_stateless( last_block_header: last_block.header.clone(), last_block_hash, non_privileged_count: non_privileged_count.into(), + total_gas_used: total_gas_used.into(), }) } diff --git a/crates/l2/prover/zkvm/interface/src/io.rs b/crates/l2/prover/zkvm/interface/src/io.rs index f592780300..8001c8bf03 100644 --- a/crates/l2/prover/zkvm/interface/src/io.rs +++ b/crates/l2/prover/zkvm/interface/src/io.rs @@ -94,6 +94,8 @@ pub struct ProgramOutput { pub chain_id: U256, /// amount of non-privileged transactions pub non_privileged_count: U256, + /// total gas used in the batch + pub total_gas_used: U256, } impl ProgramOutput { @@ -110,6 +112,7 @@ impl ProgramOutput { self.last_block_hash.to_fixed_bytes(), self.chain_id.to_big_endian(), self.non_privileged_count.to_big_endian(), + self.total_gas_used.to_big_endian(), ] .concat() } From 687b82cad9f26d76649c14f6601291cf54387b85 Mon Sep 17 00:00:00 2001 From: juanbono Date: Tue, 22 Jul 2025 12:07:54 -0300 Subject: [PATCH 02/15] add simple gas tracking to OnchainProposer and many TODOs --- .../src/l1/based/OnChainProposer.sol | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/crates/l2/contracts/src/l1/based/OnChainProposer.sol b/crates/l2/contracts/src/l1/based/OnChainProposer.sol index aac81298c6..8859dd8d90 100644 --- a/crates/l2/contracts/src/l1/based/OnChainProposer.sol +++ b/crates/l2/contracts/src/l1/based/OnChainProposer.sol @@ -43,6 +43,12 @@ contract OnChainProposer is /// @dev The key is the batch number. mapping(uint256 => BatchCommitmentInfo) public batchCommitments; + /// @notice The addresses of the verified batches. + /// @dev The key is the batch number, the value is the address of the prover. + // TODO: consider replacing it with a Merkle tree or just capping the number of verified batches. + // TODO: Consider adding the amount of gasProven to the mapping, i.e. (uint256 => (address, uint256)). + mapping(uint256 => address) public verifiedBatches; + /// @notice The latest verified batch number. /// @dev This variable holds the batch number of the most recently verified batch. /// @dev All batches with a batch number less than or equal to `lastVerifiedBatch` are considered verified. @@ -305,12 +311,15 @@ contract OnChainProposer is function verifyBatch( uint256 batchNumber, //risc0 + // TODO: add gasProven to the RISC0 public inputs bytes memory risc0BlockProof, bytes calldata risc0Journal, //sp1 + // TODO: add gasProven to the SP1 public inputs bytes calldata sp1PublicValues, bytes memory sp1ProofBytes, //tdx + // TODO: add gasProven to the TDX public inputs bytes calldata tdxPublicValues, bytes memory tdxSignature ) external { @@ -339,6 +348,8 @@ contract OnChainProposer is ); } + uint256 gasProven = 0; + if (R0VERIFIER != DEV_MODE) { // If the verification fails, it will revert. _verifyPublicData(batchNumber, risc0Journal); @@ -347,8 +358,12 @@ contract OnChainProposer is RISC0_VERIFICATION_KEY, sha256(risc0Journal) ); + gasProven = uint256( + bytes32(risc0Journal[224:256]) + ); } + if (SP1VERIFIER != DEV_MODE) { // If the verification fails, it will revert. _verifyPublicData(batchNumber, sp1PublicValues[16:]); @@ -357,6 +372,9 @@ contract OnChainProposer is sp1PublicValues, sp1ProofBytes ); + gasProven = uint256( + bytes32(sp1PublicValues[16+224:16+256]) + ); } if (TDXVERIFIER != DEV_MODE) { @@ -367,6 +385,11 @@ contract OnChainProposer is lastVerifiedBatch = batchNumber; + // Update verified batches with the new batch + // TODO: Should we check that this prover is registered somewhere? + address message_sender = msg.sender; + verifiedBatches[batchNumber] = message_sender; + // Remove previous batch commitment as it is no longer needed. delete batchCommitments[batchNumber - 1]; @@ -489,6 +512,9 @@ contract OnChainProposer is uint256 nonPrivilegedTransactions = uint256( bytes32(publicData[192:224]) ); + + // TODO: consider checking the gasProven here. + require( !ICommonBridge(BRIDGE).hasExpiredPrivilegedTransactions() || nonPrivilegedTransactions == 0, From ec8f421365f048ec271f8a0cccd57cb697604a35 Mon Sep 17 00:00:00 2001 From: juanbono Date: Tue, 22 Jul 2025 18:21:33 -0300 Subject: [PATCH 03/15] add reward vault contract --- .../src/l1/based/OnChainProposer.sol | 2 +- .../l2/contracts/src/l1/based/RewardVault.sol | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 crates/l2/contracts/src/l1/based/RewardVault.sol diff --git a/crates/l2/contracts/src/l1/based/OnChainProposer.sol b/crates/l2/contracts/src/l1/based/OnChainProposer.sol index 8859dd8d90..39fb039c10 100644 --- a/crates/l2/contracts/src/l1/based/OnChainProposer.sol +++ b/crates/l2/contracts/src/l1/based/OnChainProposer.sol @@ -47,7 +47,7 @@ contract OnChainProposer is /// @dev The key is the batch number, the value is the address of the prover. // TODO: consider replacing it with a Merkle tree or just capping the number of verified batches. // TODO: Consider adding the amount of gasProven to the mapping, i.e. (uint256 => (address, uint256)). - mapping(uint256 => address) public verifiedBatches; + mapping(uint256 => (address, uint256)) public verifiedBatches; /// @notice The latest verified batch number. /// @dev This variable holds the batch number of the most recently verified batch. diff --git a/crates/l2/contracts/src/l1/based/RewardVault.sol b/crates/l2/contracts/src/l1/based/RewardVault.sol new file mode 100644 index 0000000000..8ad17a65b1 --- /dev/null +++ b/crates/l2/contracts/src/l1/based/RewardVault.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity =0.8.29; + +contract RewardVault { + address public onChainProposer; + address public rewardToken; + + constructor(address _onChainProposer, address _rewardToken) { + onChainProposer = _onChainProposer; + rewardToken = _rewardToken; + } + + + /// @notice Claims rewards for a list of batches. + /// @param _batchNumbers The list of batch numbers to claim rewards for. + function claimRewards(uint256[] calldata _batchNumbers) public { + // TODO: should we prevent a prover from claiming many times per day? + address sender = msg.sender; + + uint256 numberOfBatches = _batchNumbers.length; + IOnChainProposer prover = IOnChainProposer(onChainProposer); + uint256 totalGasProven = 0; + for (uint256 i = 0; i < numberOfBatches; i++) { + uint256 batchNumber = _batchNumbers[i]; + (address proverAddress, uint256 gasProven) = prover.verifiedBatches(batchNumber); + require(proverAddress == sender, "Sender is not the prover"); + totalGasProven += gasProven; + } + + // TODO: calculate the rewards for the prover + // TODO: transfer the rewards to the prover + } +} \ No newline at end of file From af045bb39bd228a1d9ce756f65e8a021f6d4420f Mon Sep 17 00:00:00 2001 From: juanbono Date: Tue, 22 Jul 2025 19:04:11 -0300 Subject: [PATCH 04/15] transfer tokens to prover --- .../contracts/src/l1/based/OnChainProposer.sol | 11 +++++++++++ .../l2/contracts/src/l1/based/RewardVault.sol | 18 ++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/crates/l2/contracts/src/l1/based/OnChainProposer.sol b/crates/l2/contracts/src/l1/based/OnChainProposer.sol index 39fb039c10..d889ed0474 100644 --- a/crates/l2/contracts/src/l1/based/OnChainProposer.sol +++ b/crates/l2/contracts/src/l1/based/OnChainProposer.sol @@ -47,6 +47,7 @@ contract OnChainProposer is /// @dev The key is the batch number, the value is the address of the prover. // TODO: consider replacing it with a Merkle tree or just capping the number of verified batches. // TODO: Consider adding the amount of gasProven to the mapping, i.e. (uint256 => (address, uint256)). + // TODO: Consider moving this mapping to a separate contract if needed. mapping(uint256 => (address, uint256)) public verifiedBatches; /// @notice The latest verified batch number. @@ -467,6 +468,16 @@ contract OnChainProposer is emit BatchVerified(lastVerifiedBatch); } + function getTotalGasProven() public view returns (uint256) { + uint256 totalGasProven = 0; + // TODO: we should only iterate through recent batches (i.e batches proven in the last day) + for (uint256 i = 0; i <= lastVerifiedBatch; i++) { + (_, uint256 gasProven) = verifiedBatches[i]; + totalGasProven += gasProven; + } + return totalGasProven; + } + function _verifyPublicData( uint256 batchNumber, bytes calldata publicData diff --git a/crates/l2/contracts/src/l1/based/RewardVault.sol b/crates/l2/contracts/src/l1/based/RewardVault.sol index 8ad17a65b1..e757a9d8e6 100644 --- a/crates/l2/contracts/src/l1/based/RewardVault.sol +++ b/crates/l2/contracts/src/l1/based/RewardVault.sol @@ -1,10 +1,16 @@ // SPDX-License-Identifier: MIT pragma solidity =0.8.29; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "./interfaces/IOnChainProposer.sol"; + contract RewardVault { address public onChainProposer; address public rewardToken; + // TODO: we should replace this value with a mechanism that changes over time. + uint public tokensUnlockedPerDay; + constructor(address _onChainProposer, address _rewardToken) { onChainProposer = _onChainProposer; rewardToken = _rewardToken; @@ -19,15 +25,19 @@ contract RewardVault { uint256 numberOfBatches = _batchNumbers.length; IOnChainProposer prover = IOnChainProposer(onChainProposer); - uint256 totalGasProven = 0; + uint256 gasProvenByClaimer = 0; for (uint256 i = 0; i < numberOfBatches; i++) { uint256 batchNumber = _batchNumbers[i]; (address proverAddress, uint256 gasProven) = prover.verifiedBatches(batchNumber); require(proverAddress == sender, "Sender is not the prover"); - totalGasProven += gasProven; + gasProvenByClaimer += gasProven; } - // TODO: calculate the rewards for the prover - // TODO: transfer the rewards to the prover + // calculate the rewards for the prover and transfer them + uint256 totalGasProven = prover.getTotalGasProven(); + uint256 dailyRewardPool = tokensUnlockedPerDay * 10 ** IERC20(rewardToken).decimals(); + uint256 totalRewards = dailyRewardPool * gasProvenByClaimer / totalGasProven; + + IERC20(rewardToken).transfer(sender, totalRewards); } } \ No newline at end of file From 433a280ebf5d003ea018feb96d0d61f08e284d78 Mon Sep 17 00:00:00 2001 From: juanbono Date: Tue, 22 Jul 2025 19:18:47 -0300 Subject: [PATCH 05/15] remove fixed TODOs --- crates/l2/contracts/src/l1/based/OnChainProposer.sol | 4 ---- 1 file changed, 4 deletions(-) diff --git a/crates/l2/contracts/src/l1/based/OnChainProposer.sol b/crates/l2/contracts/src/l1/based/OnChainProposer.sol index d889ed0474..59e1edca85 100644 --- a/crates/l2/contracts/src/l1/based/OnChainProposer.sol +++ b/crates/l2/contracts/src/l1/based/OnChainProposer.sol @@ -46,7 +46,6 @@ contract OnChainProposer is /// @notice The addresses of the verified batches. /// @dev The key is the batch number, the value is the address of the prover. // TODO: consider replacing it with a Merkle tree or just capping the number of verified batches. - // TODO: Consider adding the amount of gasProven to the mapping, i.e. (uint256 => (address, uint256)). // TODO: Consider moving this mapping to a separate contract if needed. mapping(uint256 => (address, uint256)) public verifiedBatches; @@ -312,15 +311,12 @@ contract OnChainProposer is function verifyBatch( uint256 batchNumber, //risc0 - // TODO: add gasProven to the RISC0 public inputs bytes memory risc0BlockProof, bytes calldata risc0Journal, //sp1 - // TODO: add gasProven to the SP1 public inputs bytes calldata sp1PublicValues, bytes memory sp1ProofBytes, //tdx - // TODO: add gasProven to the TDX public inputs bytes calldata tdxPublicValues, bytes memory tdxSignature ) external { From 95697e64b6cbe622ff61e40533fed6d4f25ca697 Mon Sep 17 00:00:00 2001 From: juanbono Date: Tue, 22 Jul 2025 19:25:05 -0300 Subject: [PATCH 06/15] remove TODO --- crates/l2/contracts/src/l1/based/RewardVault.sol | 2 +- crates/l2/prover/zkvm/interface/src/execution.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/l2/contracts/src/l1/based/RewardVault.sol b/crates/l2/contracts/src/l1/based/RewardVault.sol index e757a9d8e6..3edd01d00b 100644 --- a/crates/l2/contracts/src/l1/based/RewardVault.sol +++ b/crates/l2/contracts/src/l1/based/RewardVault.sol @@ -40,4 +40,4 @@ contract RewardVault { IERC20(rewardToken).transfer(sender, totalRewards); } -} \ No newline at end of file +} diff --git a/crates/l2/prover/zkvm/interface/src/execution.rs b/crates/l2/prover/zkvm/interface/src/execution.rs index e7d06323ae..1bbc83418e 100644 --- a/crates/l2/prover/zkvm/interface/src/execution.rs +++ b/crates/l2/prover/zkvm/interface/src/execution.rs @@ -313,7 +313,6 @@ fn execute_stateless( validate_gas_used(&receipts, &block.header) .map_err(StatelessExecutionError::GasValidationError)?; - // TODO: Verify if this is correct total_gas_used += block.header.gas_used; validate_receipts_root(&block.header, &receipts) .map_err(StatelessExecutionError::ReceiptsRootValidationError)?; From d55ab548f3ca709fcfbd13c7ee1fe4df56f05707 Mon Sep 17 00:00:00 2001 From: juanbono Date: Wed, 23 Jul 2025 11:54:20 -0300 Subject: [PATCH 07/15] fixes --- .../l2/contracts/src/l1/based/RewardVault.sol | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/crates/l2/contracts/src/l1/based/RewardVault.sol b/crates/l2/contracts/src/l1/based/RewardVault.sol index 3edd01d00b..12d0817d13 100644 --- a/crates/l2/contracts/src/l1/based/RewardVault.sol +++ b/crates/l2/contracts/src/l1/based/RewardVault.sol @@ -5,15 +5,17 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./interfaces/IOnChainProposer.sol"; contract RewardVault { - address public onChainProposer; - address public rewardToken; + IOnChainProposer public onChainProposer; + IERC20 public rewardToken; // TODO: we should replace this value with a mechanism that changes over time. - uint public tokensUnlockedPerDay; + uint256 public tokensUnlockedPerDay; - constructor(address _onChainProposer, address _rewardToken) { - onChainProposer = _onChainProposer; - rewardToken = _rewardToken; + constructor(address _onChainProposer, address _rewardToken, uint256 _tokensUnlockedPerDay) { + onChainProposer = IOnChainProposer(_onChainProposer); + rewardToken = IERC20(_rewardToken); + // TODO: remove this once the mechanism is in place. + tokensUnlockedPerDay = _tokensUnlockedPerDay; } @@ -24,20 +26,19 @@ contract RewardVault { address sender = msg.sender; uint256 numberOfBatches = _batchNumbers.length; - IOnChainProposer prover = IOnChainProposer(onChainProposer); uint256 gasProvenByClaimer = 0; for (uint256 i = 0; i < numberOfBatches; i++) { uint256 batchNumber = _batchNumbers[i]; - (address proverAddress, uint256 gasProven) = prover.verifiedBatches(batchNumber); + (address proverAddress, uint256 gasProven) = onChainProposer.verifiedBatches(batchNumber); require(proverAddress == sender, "Sender is not the prover"); gasProvenByClaimer += gasProven; } // calculate the rewards for the prover and transfer them - uint256 totalGasProven = prover.getTotalGasProven(); - uint256 dailyRewardPool = tokensUnlockedPerDay * 10 ** IERC20(rewardToken).decimals(); + uint256 totalGasProven = onChainProposer.getTotalGasProven(); + uint256 dailyRewardPool = tokensUnlockedPerDay * 10 ** rewardToken.decimals(); uint256 totalRewards = dailyRewardPool * gasProvenByClaimer / totalGasProven; - IERC20(rewardToken).transfer(sender, totalRewards); + rewardToken.transfer(sender, totalRewards); } } From 78b00567e343316a0f78d491c5fb582ac2afcc62 Mon Sep 17 00:00:00 2001 From: juanbono Date: Wed, 23 Jul 2025 17:01:23 -0300 Subject: [PATCH 08/15] compile new contract when deploying L2 contracts --- crates/l2/Makefile | 3 +++ crates/l2/contracts/bin/deployer/main.rs | 1 + .../src/l1/based/OnChainProposer.sol | 21 +++++++++++++++---- .../l2/contracts/src/l1/based/RewardVault.sol | 11 +++++----- .../l1/based/interfaces/IOnChainProposer.sol | 21 +++++++++++++++++++ 5 files changed, 48 insertions(+), 9 deletions(-) diff --git a/crates/l2/Makefile b/crates/l2/Makefile index 99eb426100..a8c5064e24 100644 --- a/crates/l2/Makefile +++ b/crates/l2/Makefile @@ -113,6 +113,9 @@ deploy-l1: ## ๐Ÿ“œ Deploys the L1 contracts --deposit-rich \ --private-keys-file-path ../../fixtures/keys/private_keys_l1.txt \ --genesis-l1-path ../../fixtures/genesis/l1-dev.json \ + # TODO: add a new target for based deployments + --deploy-based-contracts \ + --sequencer-registry-owner 0xacb3bb54d7c5295c158184044bdeedd9aa426607 \ --genesis-l2-path ../../fixtures/genesis/l2.json ## Same as deploy-l1 but does not do deposits for rich accounts since that doesn't make sense for deployments to devnets/testnets i.e Sepolia diff --git a/crates/l2/contracts/bin/deployer/main.rs b/crates/l2/contracts/bin/deployer/main.rs index f9d643f239..6f578b72dd 100644 --- a/crates/l2/contracts/bin/deployer/main.rs +++ b/crates/l2/contracts/bin/deployer/main.rs @@ -113,6 +113,7 @@ fn compile_contracts(opts: &DeployerOptions) -> Result<(), DeployerError> { "src/l1/based/OnChainProposer.sol", false, )?; + compile_contract(&opts.contracts_path, "src/l1/based/RewardVault.sol", false)?; } else { info!("Compiling OnChainProposer contract"); compile_contract(&opts.contracts_path, "src/l1/OnChainProposer.sol", false)?; diff --git a/crates/l2/contracts/src/l1/based/OnChainProposer.sol b/crates/l2/contracts/src/l1/based/OnChainProposer.sol index 59e1edca85..060db51126 100644 --- a/crates/l2/contracts/src/l1/based/OnChainProposer.sol +++ b/crates/l2/contracts/src/l1/based/OnChainProposer.sol @@ -47,7 +47,7 @@ contract OnChainProposer is /// @dev The key is the batch number, the value is the address of the prover. // TODO: consider replacing it with a Merkle tree or just capping the number of verified batches. // TODO: Consider moving this mapping to a separate contract if needed. - mapping(uint256 => (address, uint256)) public verifiedBatches; + mapping(uint256 => VerifiedBatchInfo) _verifiedBatches; /// @notice The latest verified batch number. /// @dev This variable holds the batch number of the most recently verified batch. @@ -385,7 +385,10 @@ contract OnChainProposer is // Update verified batches with the new batch // TODO: Should we check that this prover is registered somewhere? address message_sender = msg.sender; - verifiedBatches[batchNumber] = message_sender; + _verifiedBatches[batchNumber] = VerifiedBatchInfo( + message_sender, + gasProven + ); // Remove previous batch commitment as it is no longer needed. delete batchCommitments[batchNumber - 1]; @@ -464,12 +467,22 @@ contract OnChainProposer is emit BatchVerified(lastVerifiedBatch); } + // @inheritdoc IOnChainProposer + function verifiedBatches(uint256 batchNumber) public view returns (VerifiedBatchInfo memory) { + return _verifiedBatches[batchNumber]; + } + + // @inheritdoc IOnChainProposer + function addVerifiedBatch(uint256 batchNumber, address prover, uint256 gasProven) public { + _verifiedBatches[batchNumber] = VerifiedBatchInfo({prover: prover, gasProven: gasProven}); + } + + // @inheritdoc IOnChainProposer function getTotalGasProven() public view returns (uint256) { uint256 totalGasProven = 0; // TODO: we should only iterate through recent batches (i.e batches proven in the last day) for (uint256 i = 0; i <= lastVerifiedBatch; i++) { - (_, uint256 gasProven) = verifiedBatches[i]; - totalGasProven += gasProven; + totalGasProven += _verifiedBatches[i].gasProven; } return totalGasProven; } diff --git a/crates/l2/contracts/src/l1/based/RewardVault.sol b/crates/l2/contracts/src/l1/based/RewardVault.sol index 12d0817d13..3dda2d1742 100644 --- a/crates/l2/contracts/src/l1/based/RewardVault.sol +++ b/crates/l2/contracts/src/l1/based/RewardVault.sol @@ -29,16 +29,17 @@ contract RewardVault { uint256 gasProvenByClaimer = 0; for (uint256 i = 0; i < numberOfBatches; i++) { uint256 batchNumber = _batchNumbers[i]; - (address proverAddress, uint256 gasProven) = onChainProposer.verifiedBatches(batchNumber); - require(proverAddress == sender, "Sender is not the prover"); - gasProvenByClaimer += gasProven; + VerifiedBatchInfo memory verifiedBatchInfo = onChainProposer.verifiedBatches(batchNumber); + require(verifiedBatchInfo.prover == sender, "Sender is not the prover"); + gasProvenByClaimer += verifiedBatchInfo.gasProven; } // calculate the rewards for the prover and transfer them uint256 totalGasProven = onChainProposer.getTotalGasProven(); - uint256 dailyRewardPool = tokensUnlockedPerDay * 10 ** rewardToken.decimals(); + // TODO: we should use the decimals of the reward token instead of hardcoding 18. + uint256 dailyRewardPool = tokensUnlockedPerDay * 10 ** 18; uint256 totalRewards = dailyRewardPool * gasProvenByClaimer / totalGasProven; - rewardToken.transfer(sender, totalRewards); + rewardToken.transfer(sender totalRewards); } } diff --git a/crates/l2/contracts/src/l1/based/interfaces/IOnChainProposer.sol b/crates/l2/contracts/src/l1/based/interfaces/IOnChainProposer.sol index ee99942dac..e3678435d8 100644 --- a/crates/l2/contracts/src/l1/based/interfaces/IOnChainProposer.sol +++ b/crates/l2/contracts/src/l1/based/interfaces/IOnChainProposer.sol @@ -1,6 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity =0.8.29; +struct VerifiedBatchInfo { + address prover; + uint256 gasProven; +} + /// @title Interface for the OnChainProposer contract. /// @author LambdaClass /// @notice A OnChainProposer contract ensures the advancement of the L2. It is used @@ -88,4 +93,20 @@ interface IOnChainProposer { bytes[] calldata alignedPublicInputsList, bytes32[][] calldata alignedMerkleProofsList ) external; + + + /// @notice Get verified batch information for a specific batch number. + /// @param batchNumber The batch number to query. + /// @return The VerifiedBatchInfo struct containing prover address and gas proven. + function verifiedBatches(uint256 batchNumber) external view returns (VerifiedBatchInfo memory); + + /// @notice Add a verified batch to the list of verified batches. + /// @param batchNumber The batch number to add. + /// @param prover The prover address. + /// @param gasProven The amount of gas proven. + function addVerifiedBatch(uint256 batchNumber, address prover, uint256 gasProven) external; + + /// @notice Get the total gas proven across all verified batches. + /// @return The total amount of gas proven. + function getTotalGasProven() external view returns (uint256); } From 3887ef2a37c5cde874f85ad8787fca9d5b47a014 Mon Sep 17 00:00:00 2001 From: juanbono Date: Wed, 23 Jul 2025 17:38:02 -0300 Subject: [PATCH 09/15] add code for deployment --- crates/l2/Makefile | 2 +- crates/l2/contracts/bin/deployer/main.rs | 18 ++++++++++++++++++ .../l2/contracts/src/l1/based/RewardVault.sol | 11 ++++++----- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/crates/l2/Makefile b/crates/l2/Makefile index a8c5064e24..1ac111ebf8 100644 --- a/crates/l2/Makefile +++ b/crates/l2/Makefile @@ -98,6 +98,7 @@ clean-contract-deps: ## ๐Ÿงน Cleans the dependencies for the L1 contracts. restart-contract-deps: clean-contract-deps ## ๐Ÿ”„ Restarts the dependencies for the L1 contracts. +# TODO: add a new target for based deployments deploy-l1: ## ๐Ÿ“œ Deploys the L1 contracts COMPILE_CONTRACTS=true \ cargo run --release --bin ethrex_l2_l1_deployer --manifest-path contracts/Cargo.toml -- \ @@ -113,7 +114,6 @@ deploy-l1: ## ๐Ÿ“œ Deploys the L1 contracts --deposit-rich \ --private-keys-file-path ../../fixtures/keys/private_keys_l1.txt \ --genesis-l1-path ../../fixtures/genesis/l1-dev.json \ - # TODO: add a new target for based deployments --deploy-based-contracts \ --sequencer-registry-owner 0xacb3bb54d7c5295c158184044bdeedd9aa426607 \ --genesis-l2-path ../../fixtures/genesis/l2.json diff --git a/crates/l2/contracts/bin/deployer/main.rs b/crates/l2/contracts/bin/deployer/main.rs index 6f578b72dd..08cfb6c17d 100644 --- a/crates/l2/contracts/bin/deployer/main.rs +++ b/crates/l2/contracts/bin/deployer/main.rs @@ -389,6 +389,24 @@ async fn initialize_contracts( .await? }; info!(tx_hash = %format!("{initialize_tx_hash:#x}"), "SequencerRegistry initialized"); + + info!("Deploying RewardVault..."); + + let reward_vault_calldata = encode_calldata("initialize(address,address)", &[ + Value::Address(contract_addresses.on_chain_proposer_address), + Value::Address(Default::default()), /* TODO: set the reward token address */ + ])?; + + + let reward_vault_initialize_tx_hash = initialize_contract( + contract_addresses.on_chain_proposer_address, + reward_vault_calldata, + &deployer, + eth_client, + ) + .await?; + + info!(tx_hash = %format!("{reward_vault_initialize_tx_hash:#x}"), "RewardVault initialized"); } else { // Initialize only OnChainProposer without Based config let calldata_values = vec![ diff --git a/crates/l2/contracts/src/l1/based/RewardVault.sol b/crates/l2/contracts/src/l1/based/RewardVault.sol index 3dda2d1742..0c02f79eaf 100644 --- a/crates/l2/contracts/src/l1/based/RewardVault.sol +++ b/crates/l2/contracts/src/l1/based/RewardVault.sol @@ -1,21 +1,22 @@ // SPDX-License-Identifier: MIT pragma solidity =0.8.29; +import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./interfaces/IOnChainProposer.sol"; -contract RewardVault { +contract RewardVault is Initializable { IOnChainProposer public onChainProposer; IERC20 public rewardToken; // TODO: we should replace this value with a mechanism that changes over time. uint256 public tokensUnlockedPerDay; - constructor(address _onChainProposer, address _rewardToken, uint256 _tokensUnlockedPerDay) { + function initialize(address _onChainProposer, address _rewardToken) public initializer { onChainProposer = IOnChainProposer(_onChainProposer); rewardToken = IERC20(_rewardToken); - // TODO: remove this once the mechanism is in place. - tokensUnlockedPerDay = _tokensUnlockedPerDay; + // TODO: change this value to a mechanism that changes over time. + tokensUnlockedPerDay = 1_000_000; } @@ -40,6 +41,6 @@ contract RewardVault { uint256 dailyRewardPool = tokensUnlockedPerDay * 10 ** 18; uint256 totalRewards = dailyRewardPool * gasProvenByClaimer / totalGasProven; - rewardToken.transfer(sender totalRewards); + rewardToken.transfer(sender, totalRewards); } } From a8cf6534026acc5f8af662a77df25803cbf9a831 Mon Sep 17 00:00:00 2001 From: juanbono Date: Wed, 23 Jul 2025 18:19:11 -0300 Subject: [PATCH 10/15] finish deployment setup --- crates/l2/contracts/bin/deployer/main.rs | 27 ++++++++++++++++--- .../l2/contracts/src/l1/based/RewardVault.sol | 12 ++++++--- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/crates/l2/contracts/bin/deployer/main.rs b/crates/l2/contracts/bin/deployer/main.rs index 08cfb6c17d..2eab50c7f2 100644 --- a/crates/l2/contracts/bin/deployer/main.rs +++ b/crates/l2/contracts/bin/deployer/main.rs @@ -49,6 +49,7 @@ pub struct ContractAddresses { pub tdx_verifier_address: Address, pub sequencer_registry_address: Address, pub aligned_aggregator_address: Address, + pub reward_vault_address: Address, } #[tokio::main] @@ -166,6 +167,24 @@ async fn deploy_contracts( on_chain_proposer_deployment.implementation_tx_hash, ); + info!("Deploying RewardVault"); + + let reward_vault_deployment = deploy_with_proxy( + deployer, + eth_client, + &opts.contracts_path.join("solc_out/RewardVault.bin"), + &salt, + ) + .await?; + + info!( + "RewardVault deployed:\n Proxy -> address={:#x}, tx_hash={:#x}\n Impl -> address={:#x}, tx_hash={:#x}", + reward_vault_deployment.proxy_address, + reward_vault_deployment.proxy_tx_hash, + reward_vault_deployment.implementation_address, + reward_vault_deployment.implementation_tx_hash, + ); + info!("Deploying CommonBridge"); let bridge_deployment = deploy_with_proxy( @@ -266,6 +285,7 @@ async fn deploy_contracts( tdx_verifier_address, sequencer_registry_address: sequencer_registry_deployment.proxy_address, aligned_aggregator_address: opts.aligned_aggregator_address, + reward_vault_address: reward_vault_deployment.proxy_address, }) } @@ -392,14 +412,15 @@ async fn initialize_contracts( info!("Deploying RewardVault..."); - let reward_vault_calldata = encode_calldata("initialize(address,address)", &[ + let reward_vault_calldata = encode_calldata("initialize(address)", &[ Value::Address(contract_addresses.on_chain_proposer_address), - Value::Address(Default::default()), /* TODO: set the reward token address */ + // Value::Address(Default::default()), /* TODO: set the reward token address */ ])?; + info!("Initializing RewardVault"); let reward_vault_initialize_tx_hash = initialize_contract( - contract_addresses.on_chain_proposer_address, + contract_addresses.reward_vault_address, reward_vault_calldata, &deployer, eth_client, diff --git a/crates/l2/contracts/src/l1/based/RewardVault.sol b/crates/l2/contracts/src/l1/based/RewardVault.sol index 0c02f79eaf..c1afaf6a99 100644 --- a/crates/l2/contracts/src/l1/based/RewardVault.sol +++ b/crates/l2/contracts/src/l1/based/RewardVault.sol @@ -12,17 +12,20 @@ contract RewardVault is Initializable { // TODO: we should replace this value with a mechanism that changes over time. uint256 public tokensUnlockedPerDay; - function initialize(address _onChainProposer, address _rewardToken) public initializer { + bool public claimed; + + function initialize(address _onChainProposer /* address _rewardToken */) public initializer { onChainProposer = IOnChainProposer(_onChainProposer); - rewardToken = IERC20(_rewardToken); + // rewardToken = IERC20(_rewardToken); // TODO: change this value to a mechanism that changes over time. tokensUnlockedPerDay = 1_000_000; + claimed = false; } /// @notice Claims rewards for a list of batches. /// @param _batchNumbers The list of batch numbers to claim rewards for. - function claimRewards(uint256[] calldata _batchNumbers) public { + function claimRewards(uint256[] calldata _batchNumbers) external { // TODO: should we prevent a prover from claiming many times per day? address sender = msg.sender; @@ -41,6 +44,7 @@ contract RewardVault is Initializable { uint256 dailyRewardPool = tokensUnlockedPerDay * 10 ** 18; uint256 totalRewards = dailyRewardPool * gasProvenByClaimer / totalGasProven; - rewardToken.transfer(sender, totalRewards); + // rewardToken.transfer(sender, totalRewards); + claimed = true; } } From 5d002294cb0a108a18c4281741f39f838464ac4c Mon Sep 17 00:00:00 2001 From: juanbono Date: Thu, 24 Jul 2025 11:14:09 -0300 Subject: [PATCH 11/15] add based flag --- crates/l2/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/l2/Makefile b/crates/l2/Makefile index 1ac111ebf8..b9885dbb4b 100644 --- a/crates/l2/Makefile +++ b/crates/l2/Makefile @@ -155,6 +155,8 @@ init-l2-no-metrics: ## ๐Ÿš€ Initializes an L2 Lambda ethrex Client --committer.l1-private-key 0x385c546456b6a603a1cfcaa9ec9494ba4832da08dd6bcf4de9a71e4a01b74924 \ --proof-coordinator.l1-private-key 0x39725efee3fb28614de3bacaffe4cc4bd8c436257e2c8bb887c4b5c4be45e76d \ --proof-coordinator.addr ${PROOF_COORDINATOR_ADDRESS} \ + --based \ + --state-updater.sequencer-registry 0x8d7a798b208adfcaed7716424dbe768642736070 \ --proof-coordinator.tdx-private-key 0x39725efee3fb28614de3bacaffe4cc4bd8c436257e2c8bb887c4b5c4be45e76d init-metrics: ## ๐Ÿš€ Initializes Grafana and Prometheus with containers From 22b999276b398f28aafe854b488baefc3765e584 Mon Sep 17 00:00:00 2001 From: juanbono Date: Thu, 24 Jul 2025 17:05:17 -0300 Subject: [PATCH 12/15] add 1 day constraint when claiming --- .../src/l1/based/OnChainProposer.sol | 23 +++++++++++-------- .../l2/contracts/src/l1/based/RewardVault.sol | 10 +++++--- .../l1/based/interfaces/IOnChainProposer.sol | 7 +++++- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/crates/l2/contracts/src/l1/based/OnChainProposer.sol b/crates/l2/contracts/src/l1/based/OnChainProposer.sol index 060db51126..5100fca984 100644 --- a/crates/l2/contracts/src/l1/based/OnChainProposer.sol +++ b/crates/l2/contracts/src/l1/based/OnChainProposer.sol @@ -383,12 +383,8 @@ contract OnChainProposer is lastVerifiedBatch = batchNumber; // Update verified batches with the new batch - // TODO: Should we check that this prover is registered somewhere? address message_sender = msg.sender; - _verifiedBatches[batchNumber] = VerifiedBatchInfo( - message_sender, - gasProven - ); + addVerifiedBatch(batchNumber, message_sender, gasProven); // Remove previous batch commitment as it is no longer needed. delete batchCommitments[batchNumber - 1]; @@ -473,16 +469,25 @@ contract OnChainProposer is } // @inheritdoc IOnChainProposer - function addVerifiedBatch(uint256 batchNumber, address prover, uint256 gasProven) public { - _verifiedBatches[batchNumber] = VerifiedBatchInfo({prover: prover, gasProven: gasProven}); + function addVerifiedBatch(uint256 batchNumber, address prover, uint256 gasProven) internal { + _verifiedBatches[batchNumber] = VerifiedBatchInfo({ + prover: prover, + gasProven: gasProven, + verificationTimestamp: block.timestamp + }); } // @inheritdoc IOnChainProposer function getTotalGasProven() public view returns (uint256) { uint256 totalGasProven = 0; - // TODO: we should only iterate through recent batches (i.e batches proven in the last day) + uint256 oneDayAgo = block.timestamp - 1 days; + uint256 lastVerifiedBatch = lastVerifiedBatch(); + + // only take into account batches proven in the last day for (uint256 i = 0; i <= lastVerifiedBatch; i++) { - totalGasProven += _verifiedBatches[i].gasProven; + if (_verifiedBatches[i].verificationTimestamp >= oneDayAgo) { + totalGasProven += _verifiedBatches[i].gasProven; + } } return totalGasProven; } diff --git a/crates/l2/contracts/src/l1/based/RewardVault.sol b/crates/l2/contracts/src/l1/based/RewardVault.sol index c1afaf6a99..fb7e93cd06 100644 --- a/crates/l2/contracts/src/l1/based/RewardVault.sol +++ b/crates/l2/contracts/src/l1/based/RewardVault.sol @@ -3,11 +3,13 @@ pragma solidity =0.8.29; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import "./interfaces/IOnChainProposer.sol"; contract RewardVault is Initializable { IOnChainProposer public onChainProposer; - IERC20 public rewardToken; + // It must implement IERC20 and IERC20Metadata + address public rewardToken; // TODO: we should replace this value with a mechanism that changes over time. uint256 public tokensUnlockedPerDay; @@ -40,10 +42,12 @@ contract RewardVault is Initializable { // calculate the rewards for the prover and transfer them uint256 totalGasProven = onChainProposer.getTotalGasProven(); - // TODO: we should use the decimals of the reward token instead of hardcoding 18. - uint256 dailyRewardPool = tokensUnlockedPerDay * 10 ** 18; + uint256 dailyRewardPool = tokensUnlockedPerDay * 10 ** IERC20Metadata(rewardToken).decimals(); uint256 totalRewards = dailyRewardPool * gasProvenByClaimer / totalGasProven; + // TODO: mark the claimer as having claimed + // to prevent double claiming. + // rewardToken.transfer(sender, totalRewards); claimed = true; } diff --git a/crates/l2/contracts/src/l1/based/interfaces/IOnChainProposer.sol b/crates/l2/contracts/src/l1/based/interfaces/IOnChainProposer.sol index e3678435d8..d7253f8a96 100644 --- a/crates/l2/contracts/src/l1/based/interfaces/IOnChainProposer.sol +++ b/crates/l2/contracts/src/l1/based/interfaces/IOnChainProposer.sol @@ -1,9 +1,14 @@ // SPDX-License-Identifier: MIT pragma solidity =0.8.29; +/// @title Holds verified batch information. struct VerifiedBatchInfo { + /// @notice The address of the prover. address prover; + /// @notice The amount of gas proven for this batch. uint256 gasProven; + /// @notice The timestamp of the verification. + uint256 verificationTimestamp; } /// @title Interface for the OnChainProposer contract. @@ -104,7 +109,7 @@ interface IOnChainProposer { /// @param batchNumber The batch number to add. /// @param prover The prover address. /// @param gasProven The amount of gas proven. - function addVerifiedBatch(uint256 batchNumber, address prover, uint256 gasProven) external; + function addVerifiedBatch(uint256 batchNumber, address prover, uint256 gasProven) internal; /// @notice Get the total gas proven across all verified batches. /// @return The total amount of gas proven. From cb5326da6af292351bf9fd22ae30cdfd384ff5c1 Mon Sep 17 00:00:00 2001 From: juanbono Date: Thu, 24 Jul 2025 18:03:24 -0300 Subject: [PATCH 13/15] add checks and record claimed batches --- .../l2/contracts/src/l1/based/RewardVault.sol | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/crates/l2/contracts/src/l1/based/RewardVault.sol b/crates/l2/contracts/src/l1/based/RewardVault.sol index fb7e93cd06..2dbe1c235a 100644 --- a/crates/l2/contracts/src/l1/based/RewardVault.sol +++ b/crates/l2/contracts/src/l1/based/RewardVault.sol @@ -13,6 +13,8 @@ contract RewardVault is Initializable { // TODO: we should replace this value with a mechanism that changes over time. uint256 public tokensUnlockedPerDay; + + mapping(uint256 => bool) public claimedBatches; bool public claimed; @@ -30,13 +32,14 @@ contract RewardVault is Initializable { function claimRewards(uint256[] calldata _batchNumbers) external { // TODO: should we prevent a prover from claiming many times per day? address sender = msg.sender; - uint256 numberOfBatches = _batchNumbers.length; uint256 gasProvenByClaimer = 0; + for (uint256 i = 0; i < numberOfBatches; i++) { uint256 batchNumber = _batchNumbers[i]; VerifiedBatchInfo memory verifiedBatchInfo = onChainProposer.verifiedBatches(batchNumber); - require(verifiedBatchInfo.prover == sender, "Sender is not the prover"); + require(verifiedBatchInfo.prover == sender, "Sender must be the prover address"); + require(!claimedBatches[batchNumber], "Batch already claimed"); gasProvenByClaimer += verifiedBatchInfo.gasProven; } @@ -45,10 +48,11 @@ contract RewardVault is Initializable { uint256 dailyRewardPool = tokensUnlockedPerDay * 10 ** IERC20Metadata(rewardToken).decimals(); uint256 totalRewards = dailyRewardPool * gasProvenByClaimer / totalGasProven; - // TODO: mark the claimer as having claimed - // to prevent double claiming. - - // rewardToken.transfer(sender, totalRewards); - claimed = true; + // mark the batches as claimed, so they cannot be claimed again + for (uint256 i = 0; i < numberOfBatches; i++) { + claimedBatches[_batchNumbers[i]] = true; + } + + // TODO: transfer the tokens } } From 6f92a9b358991d044c795fba63905721919fe451 Mon Sep 17 00:00:00 2001 From: juanbono Date: Thu, 24 Jul 2025 18:04:44 -0300 Subject: [PATCH 14/15] remove completed TODOs --- crates/l2/contracts/src/l1/based/RewardVault.sol | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/crates/l2/contracts/src/l1/based/RewardVault.sol b/crates/l2/contracts/src/l1/based/RewardVault.sol index 2dbe1c235a..5e8fa0bce6 100644 --- a/crates/l2/contracts/src/l1/based/RewardVault.sol +++ b/crates/l2/contracts/src/l1/based/RewardVault.sol @@ -13,24 +13,20 @@ contract RewardVault is Initializable { // TODO: we should replace this value with a mechanism that changes over time. uint256 public tokensUnlockedPerDay; - - mapping(uint256 => bool) public claimedBatches; - bool public claimed; + /// @notice Keep record of which batches have been claimed. + mapping(uint256 => bool) public claimedBatches; function initialize(address _onChainProposer /* address _rewardToken */) public initializer { onChainProposer = IOnChainProposer(_onChainProposer); // rewardToken = IERC20(_rewardToken); // TODO: change this value to a mechanism that changes over time. tokensUnlockedPerDay = 1_000_000; - claimed = false; } - /// @notice Claims rewards for a list of batches. /// @param _batchNumbers The list of batch numbers to claim rewards for. function claimRewards(uint256[] calldata _batchNumbers) external { - // TODO: should we prevent a prover from claiming many times per day? address sender = msg.sender; uint256 numberOfBatches = _batchNumbers.length; uint256 gasProvenByClaimer = 0; From dddb786fbdc79922453159c4ee1e9c8c95cae086 Mon Sep 17 00:00:00 2001 From: juanbono Date: Thu, 24 Jul 2025 19:16:40 -0300 Subject: [PATCH 15/15] add reentrancy guard on claim method --- crates/l2/contracts/bin/deployer/main.rs | 5 +++++ crates/l2/contracts/src/l1/based/OnChainProposer.sol | 1 - crates/l2/contracts/src/l1/based/RewardVault.sol | 5 +++-- .../contracts/src/l1/based/interfaces/IOnChainProposer.sol | 6 ------ 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/crates/l2/contracts/bin/deployer/main.rs b/crates/l2/contracts/bin/deployer/main.rs index 2eab50c7f2..e5cc23439b 100644 --- a/crates/l2/contracts/bin/deployer/main.rs +++ b/crates/l2/contracts/bin/deployer/main.rs @@ -104,6 +104,11 @@ fn compile_contracts(opts: &DeployerOptions) -> Result<(), DeployerError> { )?; if opts.deploy_based_contracts { info!("Compiling based contracts"); + compile_contract( + &opts.contracts_path, + "lib/openzeppelin-contracts-upgradeable/contracts/utils/ReentrancyGuardUpgradeable.sol", + false + )?; compile_contract( &opts.contracts_path, "src/l1/based/SequencerRegistry.sol", diff --git a/crates/l2/contracts/src/l1/based/OnChainProposer.sol b/crates/l2/contracts/src/l1/based/OnChainProposer.sol index 5100fca984..3667bbda03 100644 --- a/crates/l2/contracts/src/l1/based/OnChainProposer.sol +++ b/crates/l2/contracts/src/l1/based/OnChainProposer.sol @@ -481,7 +481,6 @@ contract OnChainProposer is function getTotalGasProven() public view returns (uint256) { uint256 totalGasProven = 0; uint256 oneDayAgo = block.timestamp - 1 days; - uint256 lastVerifiedBatch = lastVerifiedBatch(); // only take into account batches proven in the last day for (uint256 i = 0; i <= lastVerifiedBatch; i++) { diff --git a/crates/l2/contracts/src/l1/based/RewardVault.sol b/crates/l2/contracts/src/l1/based/RewardVault.sol index 5e8fa0bce6..c6941329e2 100644 --- a/crates/l2/contracts/src/l1/based/RewardVault.sol +++ b/crates/l2/contracts/src/l1/based/RewardVault.sol @@ -1,12 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity =0.8.29; +import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import "./interfaces/IOnChainProposer.sol"; -contract RewardVault is Initializable { +contract RewardVault is Initializable, ReentrancyGuardUpgradeable { IOnChainProposer public onChainProposer; // It must implement IERC20 and IERC20Metadata address public rewardToken; @@ -26,7 +27,7 @@ contract RewardVault is Initializable { /// @notice Claims rewards for a list of batches. /// @param _batchNumbers The list of batch numbers to claim rewards for. - function claimRewards(uint256[] calldata _batchNumbers) external { + function claimRewards(uint256[] calldata _batchNumbers) external nonReentrant { address sender = msg.sender; uint256 numberOfBatches = _batchNumbers.length; uint256 gasProvenByClaimer = 0; diff --git a/crates/l2/contracts/src/l1/based/interfaces/IOnChainProposer.sol b/crates/l2/contracts/src/l1/based/interfaces/IOnChainProposer.sol index d7253f8a96..cee18e913d 100644 --- a/crates/l2/contracts/src/l1/based/interfaces/IOnChainProposer.sol +++ b/crates/l2/contracts/src/l1/based/interfaces/IOnChainProposer.sol @@ -105,12 +105,6 @@ interface IOnChainProposer { /// @return The VerifiedBatchInfo struct containing prover address and gas proven. function verifiedBatches(uint256 batchNumber) external view returns (VerifiedBatchInfo memory); - /// @notice Add a verified batch to the list of verified batches. - /// @param batchNumber The batch number to add. - /// @param prover The prover address. - /// @param gasProven The amount of gas proven. - function addVerifiedBatch(uint256 batchNumber, address prover, uint256 gasProven) internal; - /// @notice Get the total gas proven across all verified batches. /// @return The total amount of gas proven. function getTotalGasProven() external view returns (uint256);