diff --git a/packages/protocol/contracts/layer1/based/LibBonds.sol b/packages/protocol/contracts/layer1/based/LibBonds.sol index 6916e169344..a793b93dac9 100644 --- a/packages/protocol/contracts/layer1/based/LibBonds.sol +++ b/packages/protocol/contracts/layer1/based/LibBonds.sol @@ -11,6 +11,16 @@ import "./TaikoData.sol"; /// @notice A library that offers helper functions to handle bonds. /// @custom:security-contact security@taiko.xyz library LibBonds { + /// @dev Emitted when tokens are deposited into a user's bond balance. + /// @param user The address of the user who deposited the tokens. + /// @param amount The amount of tokens deposited. + event BondDeposited(address indexed user, uint256 amount); + + /// @dev Emitted when tokens are withdrawn from a user's bond balance. + /// @param user The address of the user who withdrew the tokens. + /// @param amount The amount of tokens withdrawn. + event BondWithdrawn(address indexed user, uint256 amount); + /// @dev Emitted when a token is credited back to a user's bond balance. /// @param user The address of the user whose bond balance is credited. /// @param blockId The ID of the block to credit for. @@ -34,6 +44,7 @@ library LibBonds { ) internal { + emit BondDeposited(msg.sender, _amount); _state.bondBalance[msg.sender] += _amount; _tko(_resolver).transferFrom(msg.sender, address(this), _amount); } @@ -49,6 +60,7 @@ library LibBonds { ) internal { + emit BondWithdrawn(msg.sender, _amount); _state.bondBalance[msg.sender] -= _amount; _tko(_resolver).transfer(msg.sender, _amount); } @@ -76,6 +88,7 @@ library LibBonds { _state.bondBalance[_user] = balance - _amount; } } else { + emit BondDeposited(msg.sender, _amount); _tko(_resolver).transferFrom(_user, address(this), _amount); } emit BondDebited(_user, _blockId, _amount); diff --git a/packages/protocol/contracts/layer1/based/LibData.sol b/packages/protocol/contracts/layer1/based/LibData.sol index 3a7d80be281..7fd6c80d5c6 100644 --- a/packages/protocol/contracts/layer1/based/LibData.sol +++ b/packages/protocol/contracts/layer1/based/LibData.sol @@ -8,7 +8,7 @@ import "./TaikoData.sol"; /// @notice A library that offers helper functions. /// @custom:security-contact security@taiko.xyz library LibData { - function blockV2toV1(TaikoData.BlockV2 memory _v2) + function blockV2ToV1(TaikoData.BlockV2 memory _v2) internal pure returns (TaikoData.Block memory) @@ -25,7 +25,7 @@ library LibData { }); } - function verifierContextV2toV1(IVerifier.ContextV2 memory _v2) + function verifierContextV2ToV1(IVerifier.ContextV2 memory _v2) internal pure returns (IVerifier.Context memory) diff --git a/packages/protocol/contracts/layer1/based/LibProposing.sol b/packages/protocol/contracts/layer1/based/LibProposing.sol index 794502705fd..eaaaf453256 100644 --- a/packages/protocol/contracts/layer1/based/LibProposing.sol +++ b/packages/protocol/contracts/layer1/based/LibProposing.sol @@ -14,6 +14,8 @@ import "./LibVerifying.sol"; library LibProposing { using LibAddress for address; + uint256 internal constant SECONDS_PER_BLOCK = 12; + struct Local { TaikoData.SlotB b; TaikoData.BlockParamsV2 params; @@ -177,8 +179,8 @@ library LibProposing { // The other constraint is that the timestamp needs to be larger than or equal the // one in the previous L2 block. if ( - local.params.timestamp + _config.maxAnchorHeightOffset * 12 < block.timestamp - || local.params.timestamp > block.timestamp + local.params.timestamp + _config.maxAnchorHeightOffset * SECONDS_PER_BLOCK + < block.timestamp || local.params.timestamp > block.timestamp || local.params.timestamp < parentBlk.proposedAt ) { revert L1_INVALID_TIMESTAMP(); @@ -200,8 +202,8 @@ library LibProposing { anchorBlockHash: blockhash(local.params.anchorBlockId), difficulty: keccak256(abi.encode("TAIKO_DIFFICULTY", local.b.numBlocks)), blobHash: 0, // to be initialized below - // To make sure each L2 block can be exexucated deterministiclly by the client - // without referering to its metadata on Ethereum, we need to encode + // To make sure each L2 block can be executed deterministically by the client + // without referring to its metadata on Ethereum, we need to encode // config.sharingPctg into the extraData. extraData: _encodeBaseFeeConfig(_config.baseFeeConfig), coinbase: local.params.coinbase, diff --git a/packages/protocol/contracts/layer1/based/LibProving.sol b/packages/protocol/contracts/layer1/based/LibProving.sol index 9ac1df7a0dc..cf7513cdd78 100644 --- a/packages/protocol/contracts/layer1/based/LibProving.sol +++ b/packages/protocol/contracts/layer1/based/LibProving.sol @@ -307,7 +307,7 @@ library LibProving { if (_batchProof.tier == 0) { // In the case of per-transition proof, we verify the proof. IVerifier(_resolver.resolve(local.tier.verifierName, false)).verifyProof( - LibData.verifierContextV2toV1(ctx_), ctx_.tran, local.proof + LibData.verifierContextV2ToV1(ctx_), ctx_.tran, local.proof ); } } @@ -368,7 +368,6 @@ library LibProving { revert L1_CANNOT_CONTEST(); } - // _checkIfContestable(/*_state,*/ tier.cooldownWindow, ts.timestamp); // Burn the contest bond from the prover. LibBonds.debitBond( _state, _resolver, msg.sender, local.blockId, local.tier.contestBond @@ -518,7 +517,7 @@ library LibProving { if (_local.sameTransition) revert L1_ALREADY_PROVED(); // The code below will be executed if - // - 1) the transition is proved for the fist time, or + // - 1) the transition is proved for the first time, or // - 2) the transition is contested. reward = _rewardAfterFriction(_ts.validityBond); diff --git a/packages/protocol/contracts/layer1/based/LibUtils.sol b/packages/protocol/contracts/layer1/based/LibUtils.sol index 47211e45d61..1043ea3ea75 100644 --- a/packages/protocol/contracts/layer1/based/LibUtils.sol +++ b/packages/protocol/contracts/layer1/based/LibUtils.sol @@ -16,6 +16,8 @@ import "./TaikoData.sol"; library LibUtils { using LibMath for uint256; + uint256 internal constant SECONDS_IN_MINUTE = 60; + /// @dev Emitted when a block is verified. /// @param blockId The ID of the verified block. /// @param prover The prover whose transition is used for verifying the @@ -26,7 +28,6 @@ library LibUtils { uint256 indexed blockId, address indexed prover, bytes32 blockHash, uint16 tier ); - error L1_BLOCK_MISMATCH(); error L1_INVALID_BLOCK_ID(); error L1_INVALID_PARAMS(); error L1_INVALID_GENESIS_HASH(); @@ -47,6 +48,8 @@ library LibUtils { TaikoData.BlockV2 storage blk = _state.blocks[0]; blk.nextTransitionId = 2; blk.proposedAt = uint64(block.timestamp); + // TODO: + // blk.proposedIn = uint64(block.number); blk.verifiedTransitionId = 1; blk.metaHash = bytes32(uint256(1)); // Give the genesis metahash a non-zero value. @@ -122,7 +125,7 @@ library LibUtils { TaikoData.State storage _state, TaikoData.Config memory _config, uint64 _blockId, - uint32 _tid + uint24 _tid ) internal view @@ -231,7 +234,8 @@ library LibUtils { returns (bool) { unchecked { - uint256 deadline = _tsTimestamp.max(_lastUnpausedAt) + _windowMinutes * 60; + uint256 deadline = + _tsTimestamp.max(_lastUnpausedAt) + _windowMinutes * SECONDS_IN_MINUTE; return block.timestamp >= deadline; } } diff --git a/packages/protocol/contracts/layer1/based/TaikoData.sol b/packages/protocol/contracts/layer1/based/TaikoData.sol index bd6748ca07f..cbda24eb9ac 100644 --- a/packages/protocol/contracts/layer1/based/TaikoData.sol +++ b/packages/protocol/contracts/layer1/based/TaikoData.sol @@ -225,7 +225,7 @@ library TaikoData { // Ring buffer for transitions mapping( uint64 blockId_mod_blockRingBufferSize - => mapping(uint32 transitionId => TransitionState ts) + => mapping(uint24 transitionId => TransitionState ts) ) transitions; bytes32 __reserve1; // Used as a ring buffer for Ether deposits SlotA slotA; // slot 5 diff --git a/packages/protocol/contracts/layer1/based/TaikoEvents.sol b/packages/protocol/contracts/layer1/based/TaikoEvents.sol index 72a7ed589bf..f7cde269bb3 100644 --- a/packages/protocol/contracts/layer1/based/TaikoEvents.sol +++ b/packages/protocol/contracts/layer1/based/TaikoEvents.sol @@ -11,10 +11,26 @@ import "./TaikoData.sol"; /// L1 libraries. /// @custom:security-contact security@taiko.xyz abstract contract TaikoEvents { - /// @dev Emitted when token is credited back to a user's bond balance. + /// @dev Emitted when tokens are deposited into a user's bond balance. + /// @param user The address of the user who deposited the tokens. + /// @param amount The amount of tokens deposited. + event BondDeposited(address indexed user, uint256 amount); + + /// @dev Emitted when tokens are withdrawn from a user's bond balance. + /// @param user The address of the user who withdrew the tokens. + /// @param amount The amount of tokens withdrawn. + event BondWithdrawn(address indexed user, uint256 amount); + + /// @dev Emitted when a token is credited back to a user's bond balance. + /// @param user The address of the user whose bond balance is credited. + /// @param blockId The ID of the block to credit for. + /// @param amount The amount of tokens credited. event BondCredited(address indexed user, uint256 blockId, uint256 amount); - /// @dev Emitted when token is debited from a user's bond balance. + /// @dev Emitted when a token is debited from a user's bond balance. + /// @param user The address of the user whose bond balance is debited. + /// @param blockId The ID of the block to debit for. + /// @param amount The amount of tokens debited. event BondDebited(address indexed user, uint256 blockId, uint256 amount); /// @dev DEPRECATED but used by node/client for syncing old blocks diff --git a/packages/protocol/contracts/layer1/based/TaikoL1.sol b/packages/protocol/contracts/layer1/based/TaikoL1.sol index 62040a923bb..053f848b91e 100644 --- a/packages/protocol/contracts/layer1/based/TaikoL1.sol +++ b/packages/protocol/contracts/layer1/based/TaikoL1.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; +import "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol"; import "src/shared/common/EssentialContract.sol"; import "./LibData.sol"; import "./LibProposing.sol"; @@ -24,8 +25,6 @@ contract TaikoL1 is EssentialContract, ITaikoL1, TaikoEvents { uint256[50] private __gap; - error L1_INVALID_PARAMS(); - modifier whenProvingNotPaused() { if (state.slotB.provingPaused) revert LibProving.L1_PROVING_PAUSED(); _; @@ -177,7 +176,7 @@ contract TaikoL1 is EssentialContract, ITaikoL1, TaikoEvents { /// @return blk_ The block. function getBlock(uint64 _blockId) external view returns (TaikoData.Block memory blk_) { (TaikoData.BlockV2 memory blk,) = LibUtils.getBlock(state, getConfig(), _blockId); - blk_ = LibData.blockV2toV1(blk); + blk_ = LibData.blockV2ToV1(blk); } /// @inheritdoc ITaikoL1 @@ -226,7 +225,8 @@ contract TaikoL1 is EssentialContract, ITaikoL1, TaikoEvents { view returns (TaikoData.TransitionState memory) { - return LibUtils.getTransition(state, getConfig(), _blockId, _tid); + return + LibUtils.getTransition(state, getConfig(), _blockId, SafeCastUpgradeable.toUint24(_tid)); } /// @notice Returns information about the last verified block. diff --git a/packages/protocol/contracts/layer1/verifiers/compose/ComposeVerifier.sol b/packages/protocol/contracts/layer1/verifiers/compose/ComposeVerifier.sol index 345d354cbd2..50345be7a4c 100644 --- a/packages/protocol/contracts/layer1/verifiers/compose/ComposeVerifier.sol +++ b/packages/protocol/contracts/layer1/verifiers/compose/ComposeVerifier.sol @@ -19,7 +19,6 @@ abstract contract ComposeVerifier is EssentialContract, IVerifier { bytes proof; } - error CV_DUPLICATE_SUBPROOF(); error CV_INVALID_CALLER(); error CV_INVALID_SUB_VERIFIER(); error CV_INVALID_SUBPROOF_LENGTH(); @@ -87,7 +86,7 @@ abstract contract ComposeVerifier is EssentialContract, IVerifier { if (subProofs.length != numSubProofs_) revert CV_INVALID_SUBPROOF_LENGTH(); for (uint256 i; i < subProofs.length; ++i) { - if (subProofs[i].verifier == address(0)) revert CV_DUPLICATE_SUBPROOF(); + if (subProofs[i].verifier == address(0)) revert CV_INVALID_SUB_VERIFIER(); // find the verifier bool verifierFound; diff --git a/packages/protocol/contracts/layer2/based/TaikoL2.sol b/packages/protocol/contracts/layer2/based/TaikoL2.sol index 2d64a3f9229..3242c551264 100644 --- a/packages/protocol/contracts/layer2/based/TaikoL2.sol +++ b/packages/protocol/contracts/layer2/based/TaikoL2.sol @@ -231,7 +231,9 @@ contract TaikoL2 is EssentialContract, IBlockHash { emit Anchored(parentHash, parentGasExcess); } - /// @notice Withdraw token or Ether from this address + /// @notice Withdraw token or Ether from this address. + /// Note: This contract receives a portion of L2 base fees, while the remainder is directed to + /// L2 block's coinbase address. /// @param _token Token address or address(0) if Ether. /// @param _to Withdraw to address. function withdraw( diff --git a/packages/protocol/test/layer1/based/TaikoL1LibProvingWithTiers.t.sol b/packages/protocol/test/layer1/based/TaikoL1LibProvingWithTiers.t.sol index a984997b3a9..9bdfc3dc9db 100644 --- a/packages/protocol/test/layer1/based/TaikoL1LibProvingWithTiers.t.sol +++ b/packages/protocol/test/layer1/based/TaikoL1LibProvingWithTiers.t.sol @@ -542,7 +542,7 @@ contract TaikoL1LibProvingWithTiers is TaikoL1TestBase { blockHash, stateRoot, LibTiers.TIER_SGX, - LibUtils.L1_BLOCK_MISMATCH.selector + LibProving.L1_BLOCK_MISMATCH.selector ); parentHash = blockHash;