Skip to content

Commit

Permalink
feat(protocol): improve TaikoToken, BridgedERC20, and ERC20Vault (#16950
Browse files Browse the repository at this point in the history
)

Co-authored-by: d1onys1us <[email protected]>
Co-authored-by: d1onys1us <[email protected]>
Co-authored-by: David <[email protected]>
  • Loading branch information
4 people authored May 3, 2024
1 parent 4b4a502 commit 97a328e
Show file tree
Hide file tree
Showing 32 changed files with 9,337 additions and 11,508 deletions.
31 changes: 16 additions & 15 deletions .github/workflows/protocol.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ on:
jobs:
build:
runs-on: [taiko-runner]
permissions:
# Give the necessary permissions for stefanzweifel/git-auto-commit-action.
contents: write
steps:
- name: Cancel previous runs
uses: styfle/[email protected]
Expand All @@ -35,34 +38,32 @@ jobs:
working-directory: ./packages/protocol
run: forge fmt --check

- name: Unit Tests
- name: Unit tests
working-directory: ./packages/protocol
run: pnpm clean && pnpm test

- name: Generate Genesis
- name: Generate contract layout table
working-directory: ./packages/protocol
run: pnpm test:genesis
run: pnpm layout

- name: Commit contract layout table
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: "Add contract layout table"

# TODO: CompilerError: Stack too deep
# - name: Test Coverage
# working-directory: ./packages/protocol
# run: pnpm test:coverage
- name: Generate genesis
working-directory: ./packages/protocol
run: pnpm test:genesis

- name: Run snapshot (foundry)
- name: Run snapshot (Foundry)
working-directory: ./packages/protocol
run: pnpm snapshot

- name: Deploy L1 Contracts
- name: Deploy L1 contracts
working-directory: ./packages/protocol
run: |
anvil --hardfork cancun &
while ! nc -z localhost 8545; do
sleep 1
done
pnpm test:deploy
# - name: Upload coverage to Codecov
# uses: codecov/codecov-action@v3
# with:
# directory: ./packages/protocol/coverage
# flags: protocol
542 changes: 542 additions & 0 deletions packages/protocol/contract_layout.md

Large diffs are not rendered by default.

5 changes: 0 additions & 5 deletions packages/protocol/contracts/L1/TaikoEvents.sol
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,4 @@ abstract contract TaikoEvents {
/// @dev Emitted when proving has been paused
/// @param paused True if paused, false if unpaused.
event ProvingPaused(bool paused);

/// @dev Emitted when an Ethereum deposit is made.
/// @param deposit The Ethereum deposit information including recipient,
/// amount, and ID.
event EthDeposited(TaikoData.EthDeposit deposit);
}
97 changes: 0 additions & 97 deletions packages/protocol/contracts/L1/TaikoToken.sol

This file was deleted.

5 changes: 1 addition & 4 deletions packages/protocol/contracts/L2/DelegateOwner.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ contract DelegateOwner is EssentialContract, IMessageInvocable {
error DO_INVALID_TX_ID();
error DO_PERMISSION_DENIED();
error DO_TX_REVERTED();
error DO_UNSUPPORTED();

/// @notice Initializes the contract.
/// @param _realOwner The real owner on L1 that can send a cross-chain message to invoke
Expand Down Expand Up @@ -93,7 +92,5 @@ contract DelegateOwner is EssentialContract, IMessageInvocable {
emit OwnershipAccepted(target);
}

function _authorizePause(address, bool) internal pure override {
revert DO_UNSUPPORTED();
}
function _authorizePause(address, bool) internal pure override notImplemented { }
}
5 changes: 1 addition & 4 deletions packages/protocol/contracts/common/AddressManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ contract AddressManager is EssentialContract, IAddressManager {
);

error AM_ADDRESS_ALREADY_SET();
error AM_PAUSE_UNSUPPORTED();

/// @notice Initializes the contract.
/// @param _owner The owner of this contract. msg.sender will be used if this value is zero.
Expand Down Expand Up @@ -54,7 +53,5 @@ contract AddressManager is EssentialContract, IAddressManager {
return __addresses[_chainId][_name];
}

function _authorizePause(address, bool) internal pure override {
revert AM_PAUSE_UNSUPPORTED();
}
function _authorizePause(address, bool) internal pure override notImplemented { }
}
15 changes: 11 additions & 4 deletions packages/protocol/contracts/common/EssentialContract.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ abstract contract EssentialContract is UUPSUpgradeable, Ownable2StepUpgradeable,
error REENTRANT_CALL();
error INVALID_PAUSE_STATUS();
error ZERO_ADDR_MANAGER();
error FUNC_NOT_IMPLEMENTED();

/// @dev Modifier that ensures the caller is the owner or resolved address of a given name.
/// @param _name The name to check against.
Expand All @@ -47,6 +48,11 @@ abstract contract EssentialContract is UUPSUpgradeable, Ownable2StepUpgradeable,
_;
}

modifier notImplemented() {
revert FUNC_NOT_IMPLEMENTED();
_;
}

modifier nonReentrant() {
if (_loadReentryLock() == _TRUE) revert REENTRANT_CALL();
_storeReentryLock(_TRUE);
Expand Down Expand Up @@ -91,6 +97,10 @@ abstract contract EssentialContract is UUPSUpgradeable, Ownable2StepUpgradeable,
return __paused == _TRUE;
}

function inNonReentrant() public view returns (bool) {
return _loadReentryLock() == _TRUE;
}

/// @notice Initializes the contract.
/// @param _owner The owner of this contract. msg.sender will be used if this value is zero.
/// @param _addressManager The address of the {AddressManager} contract.
Expand All @@ -101,6 +111,7 @@ abstract contract EssentialContract is UUPSUpgradeable, Ownable2StepUpgradeable,
}

function __Essential_init(address _owner) internal virtual onlyInitializing {
__Context_init();
_transferOwnership(_owner == address(0) ? msg.sender : _owner);
__paused = _FALSE;
}
Expand Down Expand Up @@ -141,8 +152,4 @@ abstract contract EssentialContract is UUPSUpgradeable, Ownable2StepUpgradeable,
reentry_ = __reentry;
}
}

function inNonReentrant() public view returns (bool) {
return _loadReentryLock() == _TRUE;
}
}
5 changes: 1 addition & 4 deletions packages/protocol/contracts/signal/SignalService.sol
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ contract SignalService is EssentialContract, ISignalService {
error SS_INVALID_VALUE();
error SS_SIGNAL_NOT_FOUND();
error SS_UNAUTHORIZED();
error SS_UNSUPPORTED();

modifier nonZeroApp(address _app) {
if (_app == address(0)) revert SS_INVALID_SENDER();
Expand Down Expand Up @@ -220,9 +219,7 @@ contract SignalService is EssentialContract, ISignalService {
);
}

function _authorizePause(address, bool) internal pure override {
revert SS_UNSUPPORTED();
}
function _authorizePause(address, bool) internal pure override notImplemented { }

function _syncChainData(
uint64 _chainId,
Expand Down
59 changes: 59 additions & 0 deletions packages/protocol/contracts/tko/BridgedTaikoToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import "../tokenvault/IBridgedERC20.sol";
import "./TaikoTokenBase.sol";

/// @title BridgedTaikoToken
/// @notice The TaikoToken on L2 to support checkpoints and voting. For testnets, we do not need to
/// use this contract.
/// @custom:security-contact [email protected]
contract BridgedTaikoToken is TaikoTokenBase, IBridgedERC20 {
/// @notice Initializes the contract.
/// @param _owner The owner of this contract. msg.sender will be used if this value is zero.
/// @param _addressManager The address manager address.
function init(address _owner, address _addressManager) external initializer {
__Essential_init(_owner, _addressManager);
__ERC20_init("Taiko Token", "TKO");
__ERC20Votes_init();
__ERC20Permit_init("Taiko Token");
}

function mint(
address _account,
uint256 _amount
)
external
override
whenNotPaused
onlyFromOwnerOrNamed(LibStrings.B_ERC20_VAULT)
nonReentrant
{
_mint(_account, _amount);
}

function burn(uint256 _amount)
external
override
whenNotPaused
onlyFromOwnerOrNamed(LibStrings.B_ERC20_VAULT)
nonReentrant
{
_burn(msg.sender, _amount);
}

function owner() public view override(IBridgedERC20, OwnableUpgradeable) returns (address) {
return OwnableUpgradeable.owner();
}

/// @notice Gets the canonical token's address and chain ID.
/// @return The canonical token's address.
/// @return The canonical token's chain ID.
function canonical() public pure returns (address, uint256) {
// 0x10dea67478c5F8C5E2D90e5E9B26dBe60c54d800 is the TKO's mainnet address,
// 1 is the Ethereum's network id.
return (0x10dea67478c5F8C5E2D90e5E9B26dBe60c54d800, 1);
}

function changeMigrationStatus(address, bool) public pure notImplemented { }
}
25 changes: 25 additions & 0 deletions packages/protocol/contracts/tko/TaikoToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import "./TaikoTokenBase.sol";

/// @title TaikoToken
/// @notice The TaikoToken (TKO), in the protocol is used for prover collateral
/// in the form of bonds. It is an ERC20 token with 18 decimal places of precision.
/// @dev Labeled in AddressResolver as "taiko_token"
/// @dev On Ethereum, this contract is deployed behind a proxy at
/// 0x10dea67478c5F8C5E2D90e5E9B26dBe60c54d800 (token.taiko.eth)
/// @custom:security-contact [email protected]
contract TaikoToken is TaikoTokenBase {
/// @notice Initializes the contract.
/// @param _owner The owner of this contract. msg.sender will be used if this value is zero.
/// @param _recipient The address to receive initial token minting.
function init(address _owner, address _recipient) public initializer {
__Essential_init(_owner);
__ERC20_init("Taiko Token", "TKO");
__ERC20Votes_init();
__ERC20Permit_init("Taiko Token");
// Mint 1 billion tokens
_mint(_recipient, 1_000_000_000 ether);
}
}
32 changes: 32 additions & 0 deletions packages/protocol/contracts/tko/TaikoTokenBase.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20VotesUpgradeable.sol";
import "../common/EssentialContract.sol";
import "../common/LibStrings.sol";

/// @notice TaikoToken was `EssentialContract, ERC20SnapshotUpgradeable, ERC20VotesUpgradeable`.
/// We use this contract to take 50 more slots to remove `ERC20SnapshotUpgradeable` from the parent
/// contract list.
/// We can simplify the code since we no longer need to maintain upgradability with Hekla.
abstract contract TaikoTokenBase0 is EssentialContract {
// solhint-disable var-name-mixedcase
uint256[50] private __slots_previously_used_by_ERC20SnapshotUpgradeable;
}

/// @title TaikoTokenBase
/// @notice The base contract for both the canonical and the bridged Taiko token.
/// @custom:security-contact [email protected]
abstract contract TaikoTokenBase is TaikoTokenBase0, ERC20VotesUpgradeable {
uint256[50] private __gap;

function clock() public view override returns (uint48) {
return SafeCastUpgradeable.toUint48(block.timestamp);
}

// solhint-disable-next-line func-name-mixedcase
function CLOCK_MODE() public pure override returns (string memory) {
// See https://eips.ethereum.org/EIPS/eip-6372
return "mode=timestamp";
}
}
1 change: 0 additions & 1 deletion packages/protocol/contracts/tokenvault/BaseNFTVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ abstract contract BaseNFTVault is BaseVault {

error VAULT_INVALID_TOKEN();
error VAULT_INVALID_AMOUNT();
error VAULT_INVALID_TO();
error VAULT_INTERFACE_NOT_SUPPORTED();
error VAULT_TOKEN_ARRAY_MISMATCH();
error VAULT_MAX_TOKEN_PER_TXN_EXCEEDED();
Expand Down
Loading

0 comments on commit 97a328e

Please sign in to comment.