Skip to content

Commit

Permalink
Allow bonds deposits and withdrawal
Browse files Browse the repository at this point in the history
  • Loading branch information
dantaik committed Jul 3, 2024
1 parent 71eea3f commit 10d633e
Show file tree
Hide file tree
Showing 16 changed files with 299 additions and 161 deletions.
3 changes: 2 additions & 1 deletion packages/protocol/contracts/L1/TaikoData.sol
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ library TaikoData {
bytes32 __reserve1;
SlotA slotA; // slot 5
SlotB slotB; // slot 6
uint256[44] __gap;
mapping(address account => uint256 bond) bondBalance;
uint256[43] __gap;
}
}
31 changes: 17 additions & 14 deletions packages/protocol/contracts/L1/TaikoL1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,11 @@ contract TaikoL1 is EssentialContract, ITaikoL1, TaikoEvents, TaikoErrors {
returns (TaikoData.BlockMetadata memory meta_, TaikoData.EthDeposit[] memory deposits_)
{
TaikoData.Config memory config = getConfig();
TaikoToken tko = TaikoToken(resolve(LibStrings.B_TAIKO_TOKEN, false));

(meta_, deposits_) = LibProposing.proposeBlock(state, tko, config, this, _params, _txList);
(meta_, deposits_) = LibProposing.proposeBlock(state, config, this, _params, _txList);

if (LibUtils.shouldVerifyBlocks(config, meta_.id, true) && !state.slotB.provingPaused) {
LibVerifying.verifyBlocks(state, tko, config, this, config.maxBlocksToVerify);
LibVerifying.verifyBlocks(state, config, this, config.maxBlocksToVerify);
}
}

Expand All @@ -100,12 +99,10 @@ contract TaikoL1 is EssentialContract, ITaikoL1, TaikoEvents, TaikoErrors {
emitEventForClient
{
TaikoData.Config memory config = getConfig();
TaikoToken tko = TaikoToken(resolve(LibStrings.B_TAIKO_TOKEN, false));

LibProving.proveBlock(state, tko, config, this, _blockId, _input);
LibProving.proveBlock(state, config, this, _blockId, _input);

if (LibUtils.shouldVerifyBlocks(config, _blockId, false)) {
LibVerifying.verifyBlocks(state, tko, config, this, config.maxBlocksToVerify);
LibVerifying.verifyBlocks(state, config, this, config.maxBlocksToVerify);
}
}

Expand All @@ -117,13 +114,19 @@ contract TaikoL1 is EssentialContract, ITaikoL1, TaikoEvents, TaikoErrors {
nonReentrant
emitEventForClient
{
LibVerifying.verifyBlocks(
state,
TaikoToken(resolve(LibStrings.B_TAIKO_TOKEN, false)),
getConfig(),
this,
_maxBlocksToVerify
);
LibVerifying.verifyBlocks(state, getConfig(), this, _maxBlocksToVerify);
}

function depositBond(uint256 _amount) external {
LibBonds.depositBond(state, this, _amount);
}

function withdrawBond(uint256 _amount) external {
LibBonds.withdrawBond(state, this, _amount);
}

function bondBalanceOf(address _user) external view returns (uint256) {
return LibBonds.bondBalanceOf(state, _user);
}

/// @notice Gets the details of a block.
Expand Down
77 changes: 77 additions & 0 deletions packages/protocol/contracts/L1/libs/LibBonds.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import "../../common/IAddressResolver.sol";
import "../../common/LibStrings.sol";
import "../TaikoData.sol";

/// @title LibBonds
/// @notice A library that offers helper functions to handle bonds.
/// @custom:security-contact [email protected]
library LibBonds {
event BondCredited(address indexed user, uint256 amount);
event BondDedited(address indexed user, uint256 amount);

function depositBond(
TaikoData.State storage _state,
IAddressResolver _resolver,
uint256 _amount
)
internal
{
IERC20 tko = IERC20(_resolver.resolve(LibStrings.B_TAIKO_TOKEN, false));
tko.transferFrom(msg.sender, address(this), _amount);
_state.bondBalance[msg.sender] += _amount;
}

function withdrawBond(
TaikoData.State storage _state,
IAddressResolver _resolver,
uint256 _amount
)
internal
{
_state.bondBalance[msg.sender] -= _amount;
IERC20 tko = IERC20(_resolver.resolve(LibStrings.B_TAIKO_TOKEN, false));
tko.transfer(msg.sender, _amount);
}

function debitBond(
TaikoData.State storage _state,
IAddressResolver _resolver,
address _user,
uint256 _amount
)
internal
{
uint256 balance = _state.bondBalance[_user];

if (balance >= _amount) {
unchecked {
_state.bondBalance[_user] = balance - _amount;
}
} else {
IERC20 tko = IERC20(_resolver.resolve(LibStrings.B_TAIKO_TOKEN, false));
tko.transferFrom(_user, address(this), _amount);
}
emit BondDedited(_user, _amount);
}

function creditBond(TaikoData.State storage _state, address _user, uint256 _amount) internal {
_state.bondBalance[_user] += _amount;
emit BondCredited(_user, _amount);
}

function bondBalanceOf(
TaikoData.State storage _state,
address _user
)
internal
view
returns (uint256)
{
return _state.bondBalance[_user];
}
}
5 changes: 2 additions & 3 deletions packages/protocol/contracts/L1/libs/LibProposing.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity 0.8.24;
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "../../libs/LibAddress.sol";
import "../../libs/LibNetwork.sol";
import "./LibBonds.sol";
import "./LibUtils.sol";

/// @title LibProposing
Expand Down Expand Up @@ -53,15 +54,13 @@ library LibProposing {

/// @dev Proposes a Taiko L2 block.
/// @param _state Current TaikoData.State.
/// @param _tko The taiko token.
/// @param _config Actual TaikoData.Config.
/// @param _resolver Address resolver interface.
/// @param _data Encoded data bytes containing the block params.
/// @param _txList Transaction list bytes (if not blob).
/// @return meta_ The constructed block's metadata.
function proposeBlock(
TaikoData.State storage _state,
TaikoToken _tko,
TaikoData.Config memory _config,
IAddressResolver _resolver,
bytes calldata _data,
Expand Down Expand Up @@ -188,7 +187,7 @@ library LibProposing {
++_state.slotB.numBlocks;
}

_tko.transferFrom(msg.sender, address(this), _config.livenessBond);
LibBonds.debitBond(_state, _resolver, msg.sender, _config.livenessBond);

// Bribe the block builder. Unlock 1559-tips, this tip is only made
// if this transaction succeeds.
Expand Down
23 changes: 10 additions & 13 deletions packages/protocol/contracts/L1/libs/LibProving.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity 0.8.24;

import "../../verifiers/IVerifier.sol";
import "./LibBonds.sol";
import "./LibUtils.sol";

/// @title LibProving
Expand All @@ -16,7 +17,6 @@ library LibProving {
TaikoData.SlotB b;
ITierProvider.Tier tier;
ITierProvider.Tier minTier;
TaikoToken tko;
bytes32 metaHash;
address assignedProver;
bytes32 stateRoot;
Expand Down Expand Up @@ -89,7 +89,6 @@ library LibProving {

/// @dev Proves or contests a block transition.
/// @param _state Current TaikoData.State.
/// @param _tko The taiko token.
/// @param _config Actual TaikoData.Config.
/// @param _resolver Address resolver interface.
/// @param _blockId The index of the block to prove. This is also used to
Expand All @@ -98,7 +97,6 @@ library LibProving {
/// TaikoData.TierProof) tuple.
function proveBlock(
TaikoData.State storage _state,
TaikoToken _tko,
TaikoData.Config memory _config,
IAddressResolver _resolver,
uint64 _blockId,
Expand All @@ -122,7 +120,6 @@ library LibProving {
}

Local memory local;
local.tko = _tko;
local.b = _state.slotB;

// Check that the block has been proposed but has not yet been verified.
Expand Down Expand Up @@ -232,7 +229,7 @@ library LibProving {
// Handles the case when an incoming tier is higher than the current transition's tier.
// Reverts when the incoming proof tries to prove the same transition
// (L1_ALREADY_PROVED).
_overrideWithHigherProof(blk, ts, tran, proof, local);
_overrideWithHigherProof(_state, _resolver, blk, ts, tran, proof, local);

emit TransitionProved({
blockId: local.blockId,
Expand Down Expand Up @@ -278,7 +275,7 @@ library LibProving {

// _checkIfContestable(/*_state,*/ tier.cooldownWindow, ts.timestamp);
// Burn the contest bond from the prover.
_tko.transferFrom(msg.sender, address(this), local.tier.contestBond);
LibBonds.debitBond(_state, _resolver, msg.sender, local.tier.contestBond);

// We retain the contest bond within the transition, just in
// case this configuration is altered to a different value
Expand Down Expand Up @@ -383,6 +380,8 @@ library LibProving {
// validity bond `V` ratio is `C/V = 21/(32*r)`, and if `r` set at 10%, the C/V ratio will be
// 6.5625.
function _overrideWithHigherProof(
TaikoData.State storage _state,
IAddressResolver _resolver,
TaikoData.Block storage _blk,
TaikoData.TransitionState memory _ts,
TaikoData.Transition memory _tran,
Expand All @@ -400,13 +399,13 @@ library LibProving {
reward = _rewardAfterFriction(_ts.contestBond);

// We return the validity bond back, but the original prover doesn't get any reward.
_local.tko.transfer(_ts.prover, _ts.validityBond);
LibBonds.creditBond(_state, _ts.prover, _ts.validityBond);
} else {
// The contested transition is proven to be invalid, contester wins the game.
// Contester gets 3/4 of reward, the new prover gets 1/4.
reward = _rewardAfterFriction(_ts.validityBond) >> 2;

_local.tko.transfer(_ts.contester, _ts.contestBond + reward * 3);
LibBonds.creditBond(_state, _ts.contester, _ts.contestBond + reward * 3);
}
} else {
if (_local.sameTransition) revert L1_ALREADY_PROVED();
Expand All @@ -425,19 +424,17 @@ library LibProving {
if (_local.assignedProver == msg.sender) {
reward += _local.livenessBond;
} else {
_local.tko.transfer(_local.assignedProver, _local.livenessBond);
LibBonds.creditBond(_state, _local.assignedProver, _local.livenessBond);
}
}
}
}

unchecked {
if (reward > _local.tier.validityBond) {
_local.tko.transfer(msg.sender, reward - _local.tier.validityBond);
LibBonds.creditBond(_state, msg.sender, reward - _local.tier.validityBond);
} else if (reward < _local.tier.validityBond) {
_local.tko.transferFrom(
msg.sender, address(this), _local.tier.validityBond - reward
);
LibBonds.debitBond(_state, _resolver, msg.sender, _local.tier.validityBond - reward);
}
}

Expand Down
1 change: 0 additions & 1 deletion packages/protocol/contracts/L1/libs/LibUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import "../../common/IAddressResolver.sol";
import "../../common/LibStrings.sol";
import "../../tko/TaikoToken.sol";
import "../../libs/LibMath.sol";
import "../tiers/ITierProvider.sol";
import "../tiers/ITierRouter.sol";
Expand Down
17 changes: 2 additions & 15 deletions packages/protocol/contracts/L1/libs/LibVerifying.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity 0.8.24;

import "../../signal/ISignalService.sol";
import "./LibUtils.sol";
import "./LibBonds.sol";

/// @title LibVerifying
/// @notice A library for handling block verification in the Taiko protocol.
Expand All @@ -27,7 +28,6 @@ library LibVerifying {
}

// Warning: Any errors defined here must also be defined in TaikoErrors.sol.
error L1_BATCH_TRANSFER_FAILED();
error L1_BLOCK_MISMATCH();
error L1_INVALID_CONFIG();
error L1_TRANSITION_ID_ZERO();
Expand All @@ -36,7 +36,6 @@ library LibVerifying {
/// @dev Verifies up to N blocks.
function verifyBlocks(
TaikoData.State storage _state,
TaikoToken _tko,
TaikoData.Config memory _config,
IAddressResolver _resolver,
uint64 _maxBlocksToVerify
Expand Down Expand Up @@ -71,9 +70,6 @@ library LibVerifying {
// - blockId and numBlocksVerified values incremented will still be OK in the
// next 584K years if we verifying one block per every second

address[] memory provers = new address[](_maxBlocksToVerify);
uint256[] memory bonds = new uint256[](_maxBlocksToVerify);

unchecked {
++local.blockId;

Expand Down Expand Up @@ -122,8 +118,7 @@ library LibVerifying {
local.blockHash = ts.blockHash;
local.prover = ts.prover;

provers[local.numBlocksVerified] = local.prover;
bonds[local.numBlocksVerified] = ts.validityBond;
LibBonds.creditBond(_state, local.prover, ts.validityBond);

// Note: We exclusively address the bonds linked to the
// transition used for verification. While there may exist
Expand Down Expand Up @@ -160,14 +155,6 @@ library LibVerifying {
_state.slotB.lastVerifiedBlockId = lastVerifiedBlockId;
_state.blocks[local.slot].verifiedTransitionId = local.lastVerifiedTransitionId;

// Resize the provers and bonds array
uint256 newLen = local.numBlocksVerified;
assembly {
mstore(provers, newLen)
mstore(bonds, newLen)
}
if (!_tko.batchTransfer(provers, bonds)) revert L1_BATCH_TRANSFER_FAILED();

if (local.syncStateRoot != 0) {
_state.slotA.lastSyncedBlockId = local.syncBlockId;
_state.slotA.lastSynecdAt = uint64(block.timestamp);
Expand Down
24 changes: 0 additions & 24 deletions packages/protocol/contracts/tko/TaikoToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,28 +27,4 @@ contract TaikoToken is TaikoTokenBase {
// Mint 1 billion tokens
_mint(_recipient, 1_000_000_000 ether);
}

/// @notice Batch transfers tokens
/// @param recipients The list of addresses to transfer tokens to.
/// @param amounts The list of amounts for transfer.
/// @return true if the transfer is successful.
function batchTransfer(
address[] calldata recipients,
uint256[] calldata amounts
)
external
returns (bool)
{
if (recipients.length != amounts.length) revert TT_INVALID_PARAM();
for (uint256 i; i < recipients.length; ++i) {
_transfer(msg.sender, recipients[i], amounts[i]);
}
return true;
}

function delegates(address account) public view virtual override returns (address) {
// Special checks to avoid reading from storage slots
if (account == _TAIKO_L1 || account == _ERC20_VAULT) return address(0);
else return super.delegates(account);
}
}
Loading

0 comments on commit 10d633e

Please sign in to comment.