diff --git a/packages/protocol/contracts/layer1/based/LibBonds.sol b/packages/protocol/contracts/layer1/based/LibBonds.sol index 7103e752422..64aceb36e94 100644 --- a/packages/protocol/contracts/layer1/based/LibBonds.sol +++ b/packages/protocol/contracts/layer1/based/LibBonds.sol @@ -35,6 +35,7 @@ library LibBonds { event BondDebited(address indexed user, uint256 blockId, uint256 amount); error L1_INVALID_MSG_VALUE(); + error L1_ETH_NOT_PAID_AS_BOND(); /// @dev Deposits TAIKO tokens to be used as bonds. /// @param _state Pointer to the protocol's storage. @@ -48,7 +49,7 @@ library LibBonds { public { _state.bondBalance[msg.sender] += _amount; - _handleDeposit(_resolver, _amount); + _handleDeposit(_resolver, msg.sender, _amount); } /// @dev Withdraws TAIKO tokens. @@ -111,7 +112,8 @@ library LibBonds { _state.bondBalance[_user] = balance - _amount; } } else { - _handleDeposit(_resolver, _amount); + // Note that the following function call will revert if bond asset is Ether. + _handleDeposit(_resolver, _user, _amount); } emit BondDebited(_user, _blockId, _amount); } @@ -138,17 +140,18 @@ library LibBonds { /// @dev Handles the deposit of bond tokens or Ether. /// @param _resolver The address resolver. + /// @param _user The user who made the deposit /// @param _amount The amount of tokens or Ether to deposit. - function _handleDeposit(IAddressResolver _resolver, uint256 _amount) private { + function _handleDeposit(IAddressResolver _resolver, address _user, uint256 _amount) private { address bondToken = _bondToken(_resolver); if (bondToken != address(0)) { require(msg.value == 0, L1_INVALID_MSG_VALUE()); - IERC20(bondToken).transferFrom(msg.sender, address(this), _amount); + IERC20(bondToken).transferFrom(_user, address(this), _amount); } else { - require(msg.value == _amount, L1_INVALID_MSG_VALUE()); + require(msg.value == _amount, L1_ETH_NOT_PAID_AS_BOND()); } - emit BondDeposited(msg.sender, _amount); + emit BondDeposited(_user, _amount); } /// @dev Resolves the bond token address using the address resolver, returns address(0) if Ether diff --git a/packages/protocol/contracts/layer1/team/tokenunlock/TokenUnlock.sol b/packages/protocol/contracts/layer1/team/tokenunlock/TokenUnlock.sol index 5cdff124958..1a2dad9cf12 100644 --- a/packages/protocol/contracts/layer1/team/tokenunlock/TokenUnlock.sol +++ b/packages/protocol/contracts/layer1/team/tokenunlock/TokenUnlock.sol @@ -85,7 +85,7 @@ contract TokenUnlock is EssentialContract { ) external nonZeroAddr(_recipient) - nonZeroValue(uint256(_tgeTimestamp)) + nonZeroValue(_tgeTimestamp) initializer { if (_owner == _recipient) revert INVALID_PARAM(); diff --git a/packages/protocol/test/layer1/based/TaikoL1TestGroup11.t.sol b/packages/protocol/test/layer1/based/TaikoL1TestGroup11.t.sol new file mode 100644 index 00000000000..6f5feb65b58 --- /dev/null +++ b/packages/protocol/test/layer1/based/TaikoL1TestGroup11.t.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import "./TaikoL1TestGroupBase.sol"; + +contract TaikoL10TestGroup11 is TaikoL1TestGroupBase { + // Test summary: + // 1. Zachary proposes a block with a custom proposer in the block parameters + // 2. The proposal will revert as Zachary is not registered as the preconf task manager. + function test_taikoL1_group_11_case_1() external { + vm.warp(1_000_000); + printBlockAndTrans(0); + + giveEthAndTko(Zachary, 10_000 ether, 1000 ether); + + ITierProvider(tr).getTier(LibTiers.TIER_OPTIMISTIC); + + console2.log("====== Zachary proposes a block"); + + TaikoData.BlockParamsV2 memory params; + params.proposer = Alice; + proposeBlock(Zachary, params, LibProposing.L1_INVALID_CUSTOM_PROPOSER.selector); + } + + // Test summary: + // 1. Zachary proposes a block with a Alice as the proposer + // 2. Alice proves the block + // 3. Alice verifies the block to get back her bonds. + function test_taikoL1_group_11_case_2() external { + registerAddress("preconf_task_manager", Zachary); + + vm.warp(1_000_000); + printBlockAndTrans(0); + + giveEthAndTko(Zachary, 10_000 ether, 1000 ether); + giveEthAndTko(Alice, 10_000 ether, 1000 ether); + + ITierProvider.Tier memory tierOp = ITierProvider(tr).getTier(LibTiers.TIER_OPTIMISTIC); + + console2.log("====== Zachary proposes a block with Alice as the proposer"); + + TaikoData.BlockParamsV2 memory params; + params.proposer = Alice; + TaikoData.BlockMetadataV2 memory meta = proposeBlock(Zachary, params, ""); + + assertEq(totalTkoBalance(tko, L1, Zachary), 10_000 ether); + assertEq(totalTkoBalance(tko, L1, Alice), 10_000 ether - L1.getConfig().livenessBond); + + console2.log("====== Alice proves the block"); + // Prove the block + bytes32 blockHash = bytes32(uint256(10_000)); + bytes32 stateRoot = bytes32(uint256(20_000)); + + mineAndWrap(10 seconds); + proveBlock(Alice, meta, GENESIS_BLOCK_HASH, blockHash, stateRoot, meta.minTier, ""); + + assertEq(totalTkoBalance(tko, L1, Zachary), 10_000 ether); + assertEq(totalTkoBalance(tko, L1, Alice), 10_000 ether - tierOp.validityBond); + + printBlockAndTrans(meta.id); + + console2.log("====== Alice's block is verified"); + mineAndWrap(7 days); + verifyBlock(1); + + assertEq(totalTkoBalance(tko, L1, Zachary), 10_000 ether); + assertEq(totalTkoBalance(tko, L1, Alice), 10_000 ether); + } +} diff --git a/packages/protocol/test/layer1/based/TaikoL1TestGroupBase.sol b/packages/protocol/test/layer1/based/TaikoL1TestGroupBase.sol index 6accc380dc8..5948876c131 100644 --- a/packages/protocol/test/layer1/based/TaikoL1TestGroupBase.sol +++ b/packages/protocol/test/layer1/based/TaikoL1TestGroupBase.sol @@ -46,21 +46,6 @@ abstract contract TaikoL1TestGroupBase is TaikoL1TestBase { return L1.proposeBlockV2(abi.encode(params), new bytes(10)); } - function proposeBlockV2( - address proposer, - TaikoData.BlockParamsV2 memory params, - bytes4 revertReason - ) - internal - returns (TaikoData.BlockMetadataV2 memory) - { - bytes memory txList = new bytes(10); - - vm.prank(proposer); - if (revertReason != "") vm.expectRevert(revertReason); - return L1.proposeBlockV2(abi.encode(params), txList); - } - function proveBlock( address prover, TaikoData.BlockMetadataV2 memory meta,