From 1920521a2478d1e31745742f1ddbb296cdd98f6f Mon Sep 17 00:00:00 2001 From: Daniel Wang <99078276+dantaik@users.noreply.github.com> Date: Mon, 4 Nov 2024 10:02:22 +0800 Subject: [PATCH] feat(protocol): allow any ERC20 tokens or Ether to be used as bonds (#18380) --- .../contracts/layer1/based/ITaikoL1.sol | 6 +- .../contracts/layer1/based/LibBonds.sol | 59 +++++++++++++------ .../contracts/layer1/based/LibProposing.sol | 12 ++-- .../contracts/layer1/based/LibProving.sol | 26 ++++---- .../contracts/layer1/based/LibUtils.sol | 24 ++++---- .../contracts/layer1/based/LibVerifying.sol | 10 ++-- .../contracts/layer1/based/TaikoL1.sol | 2 +- .../mainnet/addrcache/RollupAddressCache.sol | 3 + .../layer1/provers/GuardianProver.sol | 24 +++++--- .../contracts/layer1/provers/ProverSet.sol | 26 ++++++-- .../layer1/team/tokenunlock/TokenUnlock.sol | 6 ++ .../contracts/shared/common/LibStrings.sol | 1 + .../script/layer1/DeployProtocolOnL1.s.sol | 6 +- .../test/layer1/based/MockTaikoL1.sol | 2 +- .../test/layer1/based/TaikoL1TestBase.sol | 3 +- .../layer1/team/tokenunlock/TokenUnlock.t.sol | 1 + 16 files changed, 135 insertions(+), 76 deletions(-) diff --git a/packages/protocol/contracts/layer1/based/ITaikoL1.sol b/packages/protocol/contracts/layer1/based/ITaikoL1.sol index fbd2eca8185..a3d1d02e660 100644 --- a/packages/protocol/contracts/layer1/based/ITaikoL1.sol +++ b/packages/protocol/contracts/layer1/based/ITaikoL1.sol @@ -56,11 +56,11 @@ interface ITaikoL1 { /// @param _pause True to pause, false to unpause. function pauseProving(bool _pause) external; - /// @notice Deposits Taiko token to be used as bonds. + /// @notice Deposits bond ERC20 token or Ether. /// @param _amount The amount of Taiko token to deposit. - function depositBond(uint256 _amount) external; + function depositBond(uint256 _amount) external payable; - /// @notice Withdraws Taiko tokens. + /// @notice Withdraws bond ERC20 token or Ether. /// @param _amount Amount of Taiko tokens to withdraw. function withdrawBond(uint256 _amount) external; diff --git a/packages/protocol/contracts/layer1/based/LibBonds.sol b/packages/protocol/contracts/layer1/based/LibBonds.sol index 1f06b0485a6..7103e752422 100644 --- a/packages/protocol/contracts/layer1/based/LibBonds.sol +++ b/packages/protocol/contracts/layer1/based/LibBonds.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.24; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "src/shared/common/IAddressResolver.sol"; +import "src/shared/common/LibAddress.sol"; import "src/shared/common/LibStrings.sol"; import "./TaikoData.sol"; @@ -33,9 +34,11 @@ library LibBonds { /// @param amount The amount of tokens debited. event BondDebited(address indexed user, uint256 blockId, uint256 amount); + error L1_INVALID_MSG_VALUE(); + /// @dev Deposits TAIKO tokens to be used as bonds. - /// @param _state The current state of TaikoData. - /// @param _resolver The address resolver interface. + /// @param _state Pointer to the protocol's storage. + /// @param _resolver The address resolver. /// @param _amount The amount of tokens to deposit. function depositBond( TaikoData.State storage _state, @@ -44,14 +47,13 @@ library LibBonds { ) public { - emit BondDeposited(msg.sender, _amount); _state.bondBalance[msg.sender] += _amount; - _tko(_resolver).transferFrom(msg.sender, address(this), _amount); + _handleDeposit(_resolver, _amount); } /// @dev Withdraws TAIKO tokens. - /// @param _state The current state of TaikoData. - /// @param _resolver The address resolver interface. + /// @param _state Pointer to the protocol's storage. + /// @param _resolver The address resolver. /// @param _amount The amount of tokens to withdraw. function withdrawBond( TaikoData.State storage _state, @@ -62,11 +64,17 @@ library LibBonds { { emit BondWithdrawn(msg.sender, _amount); _state.bondBalance[msg.sender] -= _amount; - _tko(_resolver).transfer(msg.sender, _amount); + + address bondToken = _bondToken(_resolver); + if (bondToken != address(0)) { + IERC20(bondToken).transfer(msg.sender, _amount); + } else { + LibAddress.sendEtherAndVerify(msg.sender, _amount); + } } /// @dev Gets a user's current TAIKO token bond balance. - /// @param _state The current state of TaikoData. + /// @param _state Pointer to the protocol's storage. /// @param _user The address of the user. /// @return The current token balance. function bondBalanceOf( @@ -81,8 +89,8 @@ library LibBonds { } /// @dev Debits TAIKO tokens as bonds. - /// @param _state The current state of TaikoData. - /// @param _resolver The address resolver interface. + /// @param _state Pointer to the protocol's storage. + /// @param _resolver The address resolver. /// @param _user The address of the user to debit. /// @param _blockId The ID of the block to debit for. /// @param _amount The amount of tokens to debit. @@ -103,14 +111,13 @@ library LibBonds { _state.bondBalance[_user] = balance - _amount; } } else { - emit BondDeposited(msg.sender, _amount); - _tko(_resolver).transferFrom(_user, address(this), _amount); + _handleDeposit(_resolver, _amount); } emit BondDebited(_user, _blockId, _amount); } /// @dev Credits TAIKO tokens to a user's bond balance. - /// @param _state The current state of TaikoData. + /// @param _state Pointer to the protocol's storage. /// @param _user The address of the user to credit. /// @param _blockId The ID of the block to credit for. /// @param _amount The amount of tokens to credit. @@ -129,10 +136,26 @@ library LibBonds { emit BondCredited(_user, _blockId, _amount); } - /// @dev Resolves the TAIKO token address using the address resolver. - /// @param _resolver The address resolver interface. - /// @return tko_ The IERC20 interface of the TAIKO token. - function _tko(IAddressResolver _resolver) private view returns (IERC20) { - return IERC20(_resolver.resolve(LibStrings.B_TAIKO_TOKEN, false)); + /// @dev Handles the deposit of bond tokens or Ether. + /// @param _resolver The address resolver. + /// @param _amount The amount of tokens or Ether to deposit. + function _handleDeposit(IAddressResolver _resolver, 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); + } else { + require(msg.value == _amount, L1_INVALID_MSG_VALUE()); + } + emit BondDeposited(msg.sender, _amount); + } + + /// @dev Resolves the bond token address using the address resolver, returns address(0) if Ether + /// is used as bond asset. + /// @param _resolver The address resolver. + /// @return The IERC20 interface of the TAIKO token. + function _bondToken(IAddressResolver _resolver) private view returns (address) { + return _resolver.resolve(LibStrings.B_BOND_TOKEN, true); } } diff --git a/packages/protocol/contracts/layer1/based/LibProposing.sol b/packages/protocol/contracts/layer1/based/LibProposing.sol index 1e220e1b8e1..81f8c199fe1 100644 --- a/packages/protocol/contracts/layer1/based/LibProposing.sol +++ b/packages/protocol/contracts/layer1/based/LibProposing.sol @@ -46,9 +46,9 @@ library LibProposing { error L1_UNEXPECTED_PARENT(); /// @dev Proposes multiple Taiko L2 blocks. - /// @param _state The current state of the Taiko protocol. + /// @param _state Pointer to the protocol's storage. /// @param _config The configuration parameters for the Taiko protocol. - /// @param _resolver The address resolver interface. + /// @param _resolver The address resolver. /// @param _paramsArr An array of encoded data bytes containing the block parameters. /// @param _txListArr An array of transaction list bytes (if not blob). /// @return metas_ An array of metadata objects for the proposed L2 blocks (version 2). @@ -82,9 +82,9 @@ library LibProposing { } /// @dev Proposes a single Taiko L2 block. - /// @param _state The current state of the Taiko protocol. + /// @param _state Pointer to the protocol's storage. /// @param _config The configuration parameters for the Taiko protocol. - /// @param _resolver The address resolver interface. + /// @param _resolver The address resolver. /// @param _params Encoded data bytes containing the block parameters. /// @param _txList Transaction list bytes (if not blob). /// @return meta_ The metadata of the proposed block (version 2). @@ -108,9 +108,9 @@ library LibProposing { } /// @dev Proposes a single Taiko L2 block. - /// @param _state The current state of the Taiko protocol. + /// @param _state Pointer to the protocol's storage. /// @param _config The configuration parameters for the Taiko protocol. - /// @param _resolver The address resolver interface. + /// @param _resolver The address resolver. /// @param _params Encoded data bytes containing the block parameters. /// @param _txList Transaction list bytes (if not blob). /// @return meta_ The metadata of the proposed block (version 2). diff --git a/packages/protocol/contracts/layer1/based/LibProving.sol b/packages/protocol/contracts/layer1/based/LibProving.sol index c455434ae31..c568814ad4d 100644 --- a/packages/protocol/contracts/layer1/based/LibProving.sol +++ b/packages/protocol/contracts/layer1/based/LibProving.sol @@ -80,7 +80,7 @@ library LibProving { error L1_PROVING_PAUSED(); /// @dev Pauses or unpauses the proving process. - /// @param _state Current TaikoData.State. + /// @param _state Pointer to the protocol's storage. /// @param _pause The pause status. function pauseProving(TaikoData.State storage _state, bool _pause) public { require(_state.slotB.provingPaused != _pause, L1_INVALID_PAUSE_STATUS()); @@ -93,9 +93,9 @@ library LibProving { } /// @dev Proves or contests multiple Taiko L2 blocks. - /// @param _state Current TaikoData.State. - /// @param _config Actual TaikoData.Config. - /// @param _resolver Address resolver interface. + /// @param _state Pointer to the protocol's storage. + /// @param _config The protocol's configuration. + /// @param _resolver The address resolver. /// @param _blockIds The index of the block to prove. This is also used to select the right /// implementation version. /// @param _inputs A list of abi-encoded (TaikoData.BlockMetadataV2, TaikoData.Transition, @@ -152,9 +152,9 @@ library LibProving { } /// @dev Proves or contests a single Taiko L2 block. - /// @param _state Current TaikoData.State. - /// @param _config Actual TaikoData.Config. - /// @param _resolver Address resolver interface. + /// @param _state Pointer to the protocol's storage. + /// @param _config The protocol's configuration. + /// @param _resolver The address resolver. /// @param _blockId The index of the block to prove. This is also used to select the right /// implementation version. /// @param _input An abi-encoded (TaikoData.BlockMetadataV2, TaikoData.Transition, @@ -173,9 +173,9 @@ library LibProving { } /// @dev Proves or contests a single Taiko L2 block. - /// @param _state Current TaikoData.State. - /// @param _config Actual TaikoData.Config. - /// @param _resolver Address resolver interface. + /// @param _state Pointer to the protocol's storage. + /// @param _config The protocol's configuration. + /// @param _resolver The address resolver. /// @param _blockId The index of the block to prove. This is also used to select the right /// implementation version. /// @param _input An abi-encoded (TaikoData.BlockMetadataV2, TaikoData.Transition, @@ -393,7 +393,7 @@ library LibProving { } /// @dev Handle the transition initialization logic. - /// @param _state Current TaikoData.State. + /// @param _state Pointer to the protocol's storage. /// @param _blk Current TaikoData.BlockV2. /// @param _tran Current TaikoData.Transition. /// @param _local Current Local struct. @@ -459,8 +459,8 @@ library LibProving { /// @dev Handles what happens when either the first transition is being proven or there is a /// higher tier proof incoming. - /// @param _state Current TaikoData.State. - /// @param _resolver Address resolver interface. + /// @param _state Pointer to the protocol's storage. + /// @param _resolver The address resolver. /// @param _blk Current TaikoData.BlockV2. /// @param _ts Current TaikoData.TransitionState. /// @param _tran Current TaikoData.Transition. diff --git a/packages/protocol/contracts/layer1/based/LibUtils.sol b/packages/protocol/contracts/layer1/based/LibUtils.sol index 535f07cedb5..def7f9ca00c 100644 --- a/packages/protocol/contracts/layer1/based/LibUtils.sol +++ b/packages/protocol/contracts/layer1/based/LibUtils.sol @@ -1,8 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - import "src/shared/common/IAddressResolver.sol"; import "src/shared/common/LibStrings.sol"; import "src/shared/common/LibMath.sol"; @@ -66,8 +64,8 @@ library LibUtils { } /// @dev Retrieves a block's block hash and state root. - /// @param _state Current TaikoData.State. - /// @param _config Actual TaikoData.Config. + /// @param _state Pointer to the protocol's storage. + /// @param _config The protocol's configuration. /// @param _blockId Id of the block. /// @return blockHash_ The block's block hash. /// @return stateRoot_ The block's storage root. @@ -95,8 +93,8 @@ library LibUtils { /// @dev Gets the state transitions for a batch of block. For transition that doesn't exist, the /// corresponding transition state will be empty. - /// @param _state Current TaikoData.State. - /// @param _config Actual TaikoData.Config. + /// @param _state Pointer to the protocol's storage. + /// @param _config The protocol's configuration. /// @param _blockIds Id array of the blocks. /// @param _parentHashes Parent hashes of the blocks. /// @return transitions_ The state transition pointer array. @@ -124,8 +122,8 @@ library LibUtils { /// @dev Retrieves the transition with a given parentHash. /// @dev This function will revert if the transition is not found. - /// @param _state Current TaikoData.State. - /// @param _config Actual TaikoData.Config. + /// @param _state Pointer to the protocol's storage. + /// @param _config The protocol's configuration. /// @param _blockId Id of the block. /// @param _parentHash Parent hash of the block. /// @return The state transition pointer. @@ -148,8 +146,8 @@ library LibUtils { } /// @dev Retrieves a block based on its ID. - /// @param _state Current TaikoData.State. - /// @param _config Actual TaikoData.Config. + /// @param _state Pointer to the protocol's storage. + /// @param _config The protocol's configuration. /// @param _blockId Id of the block. /// @return blk_ The block storage pointer. /// @return slot_ The slot value. @@ -169,8 +167,8 @@ library LibUtils { /// @dev Retrieves the transition with a transition ID. /// @dev This function will revert if the transition is not found. - /// @param _state Current TaikoData.State. - /// @param _config Actual TaikoData.Config. + /// @param _state Pointer to the protocol's storage. + /// @param _config The protocol's configuration. /// @param _blockId Id of the block. /// @param _tid The transition id. /// @return The state transition pointer. @@ -193,7 +191,7 @@ library LibUtils { /// @dev Retrieves the ID of the transition with a given parentHash. This function will return 0 /// if the transition is not found. - /// @param _state Current TaikoData.State. + /// @param _state Pointer to the protocol's storage. /// @param _blk The block storage pointer. /// @param _slot The slot value. /// @param _parentHash The parent hash of the block. diff --git a/packages/protocol/contracts/layer1/based/LibVerifying.sol b/packages/protocol/contracts/layer1/based/LibVerifying.sol index e0d72d02ec8..a4a8833f0aa 100644 --- a/packages/protocol/contracts/layer1/based/LibVerifying.sol +++ b/packages/protocol/contracts/layer1/based/LibVerifying.sol @@ -31,9 +31,9 @@ library LibVerifying { error L1_TRANSITION_ID_ZERO(); /// @dev Verifies up to N blocks. - /// @param _state The current state of TaikoData. - /// @param _config The configuration of TaikoData. - /// @param _resolver The address resolver interface. + /// @param _state Pointer to the protocol's storage. + /// @param _config The protocol's configuration. + /// @param _resolver The address resolver. /// @param _maxBlocksToVerify The maximum number of blocks to verify. function verifyBlocks( TaikoData.State storage _state, @@ -175,8 +175,8 @@ library LibVerifying { } /// @dev Retrieves the prover of a verified block. - /// @param _state The current state of TaikoData. - /// @param _config The configuration of TaikoData. + /// @param _state Pointer to the protocol's storage. + /// @param _config The protocol's configuration. /// @param _blockId The ID of the block. /// @return The address of the prover. function getVerifiedBlockProver( diff --git a/packages/protocol/contracts/layer1/based/TaikoL1.sol b/packages/protocol/contracts/layer1/based/TaikoL1.sol index f96916cbd09..0a1175e5fce 100644 --- a/packages/protocol/contracts/layer1/based/TaikoL1.sol +++ b/packages/protocol/contracts/layer1/based/TaikoL1.sol @@ -144,7 +144,7 @@ contract TaikoL1 is EssentialContract, ITaikoL1, TaikoEvents { } /// @inheritdoc ITaikoL1 - function depositBond(uint256 _amount) external whenNotPaused { + function depositBond(uint256 _amount) external payable whenNotPaused { LibBonds.depositBond(state, this, _amount); } diff --git a/packages/protocol/contracts/layer1/mainnet/addrcache/RollupAddressCache.sol b/packages/protocol/contracts/layer1/mainnet/addrcache/RollupAddressCache.sol index d69989ba6ad..cf5877f94d1 100644 --- a/packages/protocol/contracts/layer1/mainnet/addrcache/RollupAddressCache.sol +++ b/packages/protocol/contracts/layer1/mainnet/addrcache/RollupAddressCache.sol @@ -21,6 +21,9 @@ contract RollupAddressCache is AddressCache { return (false, address(0)); } + if (_name == LibStrings.B_BOND_TOKEN) { + return (true, 0x10dea67478c5F8C5E2D90e5E9B26dBe60c54d800); + } if (_name == LibStrings.B_TAIKO_TOKEN) { return (true, 0x10dea67478c5F8C5E2D90e5E9B26dBe60c54d800); } diff --git a/packages/protocol/contracts/layer1/provers/GuardianProver.sol b/packages/protocol/contracts/layer1/provers/GuardianProver.sol index 5a8f136efa8..542dc25481e 100644 --- a/packages/protocol/contracts/layer1/provers/GuardianProver.sol +++ b/packages/protocol/contracts/layer1/provers/GuardianProver.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.24; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "src/shared/common/EssentialContract.sol"; +import "src/shared/common/LibAddress.sol"; import "src/shared/common/LibStrings.sol"; import "../verifiers/IVerifier.sol"; import "../based/ITaikoL1.sol"; @@ -83,6 +84,7 @@ contract GuardianProver is IVerifier, EssentialContract { /// @param enabled True if TaikoL1 proving auto-pause is enabled. event ProvingAutoPauseEnabled(bool indexed enabled); + error GP_BOND_NOT_ERC20(); error GP_INVALID_GUARDIAN(); error GP_INVALID_GUARDIAN_SET(); error GP_INVALID_MIN_GUARDIANS(); @@ -153,21 +155,27 @@ contract GuardianProver is IVerifier, EssentialContract { /// @notice Enables unlimited allowance for Taiko L1 contract. /// @param _enable True if unlimited allowance is approved, false to set the allowance to 0. - function enableTaikoTokenAllowance(bool _enable) external onlyOwner { - address tko = resolve(LibStrings.B_TAIKO_TOKEN, false); + function enableBondAllowance(bool _enable) external onlyOwner { + address bondToken = resolve(LibStrings.B_BOND_TOKEN, true); + require(bondToken != address(0), GP_BOND_NOT_ERC20()); + address taiko = resolve(LibStrings.B_TAIKO, false); - IERC20(tko).approve(taiko, _enable ? type(uint256).max : 0); + IERC20(bondToken).approve(taiko, _enable ? type(uint256).max : 0); } - /// @notice Withdraws Taiko Token to a given address. + /// @notice Withdraws bond asset to a given address. /// @param _to The recipient address. /// @param _amount The amount of Taiko token to withdraw. Use 0 for all balance. - function withdrawTaikoToken(address _to, uint256 _amount) external onlyOwner { + function withdrawBond(address _to, uint256 _amount) external onlyOwner { require(_to != address(0), GV_ZERO_ADDRESS()); - IERC20 tko = IERC20(resolve(LibStrings.B_TAIKO_TOKEN, false)); - uint256 amount = _amount == 0 ? tko.balanceOf(address(this)) : _amount; - tko.transfer(_to, amount); + address bondToken = resolve(LibStrings.B_BOND_TOKEN, true); + if (bondToken != address(0)) { + uint256 amount = _amount == 0 ? IERC20(bondToken).balanceOf(address(this)) : _amount; + IERC20(bondToken).transfer(_to, amount); + } else { + LibAddress.sendEtherAndVerify(_to, address(this).balance); + } } /// @notice Called by guardians to approve a guardian proof (version 2). diff --git a/packages/protocol/contracts/layer1/provers/ProverSet.sol b/packages/protocol/contracts/layer1/provers/ProverSet.sol index ca7098d6a98..d557aba553c 100644 --- a/packages/protocol/contracts/layer1/provers/ProverSet.sol +++ b/packages/protocol/contracts/layer1/provers/ProverSet.sol @@ -29,6 +29,7 @@ contract ProverSet is EssentialContract, IERC1271 { event ProverEnabled(address indexed prover, bool indexed enabled); error INVALID_STATUS(); + error INVALID_BOND_TOKEN(); error PERMISSION_DENIED(); error NOT_FIRST_PROPOSAL(); @@ -57,11 +58,17 @@ contract ProverSet is EssentialContract, IERC1271 { { __Essential_init(_owner, _rollupAddressManager); admin = _admin; - IERC20(tkoToken()).approve(taikoL1(), type(uint256).max); + + address _bondToken = bondToken(); + if (_bondToken != address(0)) { + IERC20(_bondToken).approve(taikoL1(), type(uint256).max); + } } function approveAllowance(address _address, uint256 _allowance) external onlyOwner { - IERC20(tkoToken()).approve(_address, _allowance); + address _bondToken = bondToken(); + require(_bondToken != address(0), INVALID_BOND_TOKEN()); + IERC20(_bondToken).approve(_address, _allowance); } /// @notice Enables or disables a prover. @@ -74,7 +81,12 @@ contract ProverSet is EssentialContract, IERC1271 { /// @notice Withdraws Taiko tokens back to the admin address. function withdrawToAdmin(uint256 _amount) external onlyAuthorized { - IERC20(tkoToken()).transfer(admin, _amount); + address _bondToken = bondToken(); + if (_bondToken != address(0)) { + IERC20(_bondToken).transfer(admin, _amount); + } else { + LibAddress.sendEtherAndVerify(admin, _amount); + } } /// @notice Withdraws ETH back to the owner address. @@ -142,7 +154,9 @@ contract ProverSet is EssentialContract, IERC1271 { /// @notice Delegates token voting right to a delegatee. /// @param _delegatee The delegatee to receive the voting right. function delegate(address _delegatee) external onlyAuthorized nonReentrant { - ERC20VotesUpgradeable(tkoToken()).delegate(_delegatee); + address _bondToken = bondToken(); + require(_bondToken != address(0), INVALID_BOND_TOKEN()); + ERC20VotesUpgradeable(_bondToken).delegate(_delegatee); } // This function is necessary for this contract to become an assigned prover. @@ -164,7 +178,7 @@ contract ProverSet is EssentialContract, IERC1271 { return resolve(LibStrings.B_TAIKO, false); } - function tkoToken() internal view virtual returns (address) { - return resolve(LibStrings.B_TAIKO_TOKEN, false); + function bondToken() internal view virtual returns (address) { + return resolve(LibStrings.B_BOND_TOKEN, true); } } diff --git a/packages/protocol/contracts/layer1/team/tokenunlock/TokenUnlock.sol b/packages/protocol/contracts/layer1/team/tokenunlock/TokenUnlock.sol index 7dce22a5b95..5cdff124958 100644 --- a/packages/protocol/contracts/layer1/team/tokenunlock/TokenUnlock.sol +++ b/packages/protocol/contracts/layer1/team/tokenunlock/TokenUnlock.sol @@ -60,6 +60,7 @@ contract TokenUnlock is EssentialContract { error NOT_WITHDRAWABLE(); error NOT_PROVER_SET(); error PERMISSION_DENIED(); + error TAIKO_TOKEN_NOT_USED_AS_BOND_TOKEN(); modifier onlyRecipient() { if (msg.sender != recipient) revert PERMISSION_DENIED(); @@ -110,6 +111,11 @@ contract TokenUnlock is EssentialContract { /// @notice Create a new prover set. function createProverSet() external onlyRecipient returns (address proverSet_) { + require( + resolve(LibStrings.B_BOND_TOKEN, false) == resolve(LibStrings.B_TAIKO_TOKEN, false), + TAIKO_TOKEN_NOT_USED_AS_BOND_TOKEN() + ); + bytes memory data = abi.encodeCall(ProverSet.init, (owner(), address(this), addressManager)); proverSet_ = address(new ERC1967Proxy(resolve(LibStrings.B_PROVER_SET, false), data)); diff --git a/packages/protocol/contracts/shared/common/LibStrings.sol b/packages/protocol/contracts/shared/common/LibStrings.sol index b4e6093bfbe..d7058f2de39 100644 --- a/packages/protocol/contracts/shared/common/LibStrings.sol +++ b/packages/protocol/contracts/shared/common/LibStrings.sol @@ -5,6 +5,7 @@ pragma solidity ^0.8.24; /// @custom:security-contact security@taiko.xyz library LibStrings { bytes32 internal constant B_AUTOMATA_DCAP_ATTESTATION = bytes32("automata_dcap_attestation"); + bytes32 internal constant B_BOND_TOKEN = bytes32("bond_token"); bytes32 internal constant B_BRIDGE = bytes32("bridge"); bytes32 internal constant B_BRIDGE_WATCHDOG = bytes32("bridge_watchdog"); bytes32 internal constant B_BRIDGED_ERC1155 = bytes32("bridged_erc1155"); diff --git a/packages/protocol/script/layer1/DeployProtocolOnL1.s.sol b/packages/protocol/script/layer1/DeployProtocolOnL1.s.sol index 085fbd47b2e..de02f6254c7 100644 --- a/packages/protocol/script/layer1/DeployProtocolOnL1.s.sol +++ b/packages/protocol/script/layer1/DeployProtocolOnL1.s.sol @@ -155,7 +155,10 @@ contract DeployProtocolOnL1 is DeployCapability { ), registerTo: sharedAddressManager }); + } else { + register(sharedAddressManager, "taiko_token", taikoToken); } + register(sharedAddressManager, "bond_token", taikoToken); // Deploy Bridging contracts deployProxy({ @@ -274,6 +277,7 @@ contract DeployProtocolOnL1 is DeployCapability { // --------------------------------------------------------------- // Register shared contracts in the new rollup copyRegister(rollupAddressManager, _sharedAddressManager, "taiko_token"); + copyRegister(rollupAddressManager, _sharedAddressManager, "bond_token"); copyRegister(rollupAddressManager, _sharedAddressManager, "signal_service"); copyRegister(rollupAddressManager, _sharedAddressManager, "bridge"); @@ -340,7 +344,7 @@ contract DeployProtocolOnL1 is DeployCapability { data: abi.encodeCall(GuardianProver.init, (address(0), rollupAddressManager)) }); - GuardianProver(guardianProverMinority).enableTaikoTokenAllowance(true); + GuardianProver(guardianProverMinority).enableBondAllowance(true); address guardianProver = deployProxy({ name: "guardian_prover", diff --git a/packages/protocol/test/layer1/based/MockTaikoL1.sol b/packages/protocol/test/layer1/based/MockTaikoL1.sol index 2deb5cef503..82e50637655 100644 --- a/packages/protocol/test/layer1/based/MockTaikoL1.sol +++ b/packages/protocol/test/layer1/based/MockTaikoL1.sol @@ -39,7 +39,7 @@ contract MockTaikoL1 is ITaikoL1 { function pauseProving(bool _pause) external virtual { } - function depositBond(uint256 _amount) external virtual { } + function depositBond(uint256 _amount) external payable virtual { } function withdrawBond(uint256 _amount) external virtual { } diff --git a/packages/protocol/test/layer1/based/TaikoL1TestBase.sol b/packages/protocol/test/layer1/based/TaikoL1TestBase.sol index b199dc59c7a..49c0d6e32df 100644 --- a/packages/protocol/test/layer1/based/TaikoL1TestBase.sol +++ b/packages/protocol/test/layer1/based/TaikoL1TestBase.sol @@ -105,11 +105,12 @@ abstract contract TaikoL1TestBase is TaikoTest { registerTo: address(addressManager) }) ); + registerAddress("bond_token", address(tko)); L1.init(address(0), address(addressManager), GENESIS_BLOCK_HASH, false); mine(1); - gp.enableTaikoTokenAllowance(true); + gp.enableBondAllowance(true); printVariables("init "); } diff --git a/packages/protocol/test/layer1/team/tokenunlock/TokenUnlock.t.sol b/packages/protocol/test/layer1/team/tokenunlock/TokenUnlock.t.sol index be96bb0a957..1bac31403c8 100644 --- a/packages/protocol/test/layer1/team/tokenunlock/TokenUnlock.t.sol +++ b/packages/protocol/test/layer1/team/tokenunlock/TokenUnlock.t.sol @@ -48,6 +48,7 @@ contract TestTokenUnlock is TaikoTest { }) ); + addressManager.setAddress(uint64(block.chainid), "bond_token", address(tko)); addressManager.setAddress(uint64(block.chainid), "taiko_token", address(tko)); addressManager.setAddress(uint64(block.chainid), "assignment_hook", assignmentHook); addressManager.setAddress(uint64(block.chainid), "taiko", taikoL1);