Skip to content

Commit

Permalink
Introduces an escrow contract that is able to store test tokens from …
Browse files Browse the repository at this point in the history
…provers.

The implementation allows the rollup contract to stake deposited bonds, and unstake them.

Provers may initiate withdraws which are not executable until 3 epochs after their initiation.

Proposers will use the minBalanceAtTime function to ensure that a prover has sufficient funds at the slot they would "cash in" the quote.

Additionally, the signatures used on the epoch proof quotes have been updated to use EIP 712 style signing and verification.
  • Loading branch information
just-mitch committed Sep 30, 2024
1 parent 84e5e0c commit 1cadafe
Show file tree
Hide file tree
Showing 21 changed files with 748 additions and 91 deletions.
4 changes: 2 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
"*.macros": "cpp",
"*.tpp": "cpp"
},
"solidity.compileUsingRemoteVersion": "v0.8.18",
"solidity.compileUsingRemoteVersion": "v0.8.27",
"solidity.formatter": "forge",
"search.exclude": {
"**/.yarn": true,
Expand Down Expand Up @@ -171,5 +171,5 @@
},
"files.trimTrailingWhitespace": true,
"cmake.sourceDirectory": "${workspaceFolder}/barretenberg/cpp",
"typescript.tsserver.maxTsServerMemory": 4096,
"typescript.tsserver.maxTsServerMemory": 4096
}
47 changes: 12 additions & 35 deletions l1-contracts/.solhint.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
{
"extends": "solhint:recommended",
"rules": {
"compiler-version": [
"error",
">=0.8.27"
],
"compiler-version": ["error", ">=0.8.27"],
"no-inline-assembly": "off",
"gas-custom-errors": "off",
"func-visibility": [
Expand All @@ -14,12 +11,8 @@
}
],
"no-empty-blocks": "off",
"no-unused-vars": [
"error"
],
"state-visibility": [
"error"
],
"no-unused-vars": ["error"],
"state-visibility": ["error"],
"not-rely-on-time": "off",
"const-name-snakecase": [
"error",
Expand All @@ -39,29 +32,13 @@
"allowPrefix": true
}
],
"private-func-leading-underscore": [
"error"
],
"private-vars-no-leading-underscore": [
"error"
],
"func-param-name-leading-underscore": [
"error"
],
"func-param-name-mixedcase": [
"error"
],
"strict-override": [
"error"
],
"strict-import": [
"error"
],
"ordering": [
"error"
],
"comprehensive-interface": [
"error"
]
"private-func-leading-underscore": ["error"],
"private-vars-no-leading-underscore": ["error"],
"func-param-name-leading-underscore": ["error"],
"func-param-name-mixedcase": ["error"],
"strict-override": ["error"],
"strict-import": ["error"],
"ordering": ["error"],
"comprehensive-interface": ["error"]
}
}
}
153 changes: 153 additions & 0 deletions l1-contracts/src/core/ProofCommitmentEscrow.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2024 Aztec Labs.
pragma solidity >=0.8.27;

import {SafeERC20} from "@oz/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "@oz/token/ERC20/IERC20.sol";

import {IProofCommitmentEscrow} from "@aztec/core/interfaces/IProofCommitmentEscrow.sol";
import {Errors} from "@aztec/core/libraries/Errors.sol";
import {Constants} from "@aztec/core/libraries/ConstantsGen.sol";

contract ProofCommitmentEscrow is IProofCommitmentEscrow {
using SafeERC20 for IERC20;

struct Stake {
uint256 amount;
address prover;
}

struct WithdrawRequest {
uint256 amount;
uint256 executableAt;
}

address public immutable OWNER;
uint256 public constant WITHDRAW_DELAY =
Constants.ETHEREUM_SLOT_DURATION * Constants.AZTEC_EPOCH_DURATION * 3;
mapping(address => uint256) public deposits;
mapping(address => WithdrawRequest) public withdrawRequests;
IERC20 public token;
Stake public stake;

modifier onlyOwner() {
if (msg.sender != OWNER) {
revert Errors.ProofCommitmentEscrow__NotOwner(msg.sender);
}
_;
}

modifier hasBalance(address _prover, uint256 _amount) {
if (deposits[_prover] < _amount) {
revert Errors.ProofCommitmentEscrow__InsufficientBalance(deposits[_prover], _amount);
}
_;
}

constructor(IERC20 _token, address _owner) {
token = _token;
OWNER = _owner;
}

/**
* @notice Deposit tokens into the escrow
*
* @dev The caller must have approved the token transfer
*
* @param _amount The amount of tokens to deposit
*/
function deposit(uint256 _amount) external override {
token.safeTransferFrom(msg.sender, address(this), _amount);

deposits[msg.sender] += _amount;
}

/**
* @notice Start a withdrawal request
*
* @dev The caller must have sufficient balance
* The withdrawal request will be executable after a delay
* Subsequent calls to this function will overwrite the previous request
*
* @param _amount - The amount of tokens to withdraw
*/
function startWithdraw(uint256 _amount) external override hasBalance(msg.sender, _amount) {
withdrawRequests[msg.sender] =
WithdrawRequest({amount: _amount, executableAt: block.timestamp + WITHDRAW_DELAY});
}

/**
* @notice Execute a mature withdrawal request
*/
function executeWithdraw() external override {
WithdrawRequest storage request = withdrawRequests[msg.sender];
if (request.executableAt > block.timestamp) {
revert Errors.ProofCommitmentEscrow__WithdrawRequestNotReady(
block.timestamp, request.executableAt
);
}

uint256 amount = request.amount;

delete withdrawRequests[msg.sender];
deposits[msg.sender] -= amount;
token.safeTransfer(msg.sender, amount);
}

/**
* @notice Stake an amount of previously deposited tokens
*
* @dev Only callable by the owner
* The prover must have sufficient balance
* The prover's balance will be reduced by the bond amount
*/
function stakeBond(uint256 _amount, address _prover)
external
override
onlyOwner
hasBalance(_prover, _amount)
{
deposits[_prover] -= _amount;
stake = Stake({amount: _amount, prover: _prover});
}

/**
* @notice Unstake the bonded tokens, returning them to the prover
*
* @dev Only callable by the owner
*/
function unstakeBond() external override onlyOwner {
deposits[stake.prover] += stake.amount;
delete stake;
}

/**
* @notice Get the minimum balance of a prover at a given timestamp.
*
* @dev Returns 0 if the timestamp is beyond the WITHDRAW_DELAY from the current block timestamp
*
* @param _timestamp The timestamp at which to check the balance
* @param _prover The address of the prover
*
* @return The balance of the prover at the given timestamp, compensating for withdrawal requests that have matured by that time
*/
function minBalanceAtTime(uint256 _timestamp, address _prover)
external
view
override
returns (uint256)
{
// If the timestamp is beyond the WITHDRAW_DELAY, the minimum possible balance is 0;
// the prover could issue a withdraw request in this block for the full amount,
// and execute it exactly WITHDRAW_DELAY later.
if (_timestamp >= block.timestamp + WITHDRAW_DELAY) {
return 0;
}

uint256 balance = deposits[_prover];
if (withdrawRequests[_prover].executableAt <= _timestamp) {
balance -= withdrawRequests[_prover].amount;
}
return balance;
}
}
10 changes: 5 additions & 5 deletions l1-contracts/src/core/Rollup.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2023 Aztec Labs.
// Copyright 2024 Aztec Labs.
pragma solidity >=0.8.27;

import {IProofCommitmentEscrow} from "@aztec/core/interfaces/IProofCommitmentEscrow.sol";
Expand All @@ -11,6 +11,7 @@ import {IVerifier} from "@aztec/core/interfaces/IVerifier.sol";

import {Constants} from "@aztec/core/libraries/ConstantsGen.sol";
import {DataStructures} from "@aztec/core/libraries/DataStructures.sol";
import {EpochProofQuoteLib} from "@aztec/core/libraries/EpochProofQuoteLib.sol";
import {Errors} from "@aztec/core/libraries/Errors.sol";
import {HeaderLib} from "@aztec/core/libraries/HeaderLib.sol";
import {TxsDecoder} from "@aztec/core/libraries/TxsDecoder.sol";
Expand All @@ -34,7 +35,6 @@ import {Timestamp, Slot, Epoch, SlotLib, EpochLib} from "@aztec/core/libraries/T
*/
contract Rollup is Leonidas, IRollup, ITestRollup {
using SafeCast for uint256;

using SlotLib for Slot;
using EpochLib for Epoch;

Expand Down Expand Up @@ -169,7 +169,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
bytes32[] memory _txHashes,
SignatureLib.Signature[] memory _signatures,
bytes calldata _body,
DataStructures.SignedEpochProofQuote calldata _quote
EpochProofQuoteLib.SignedEpochProofQuote calldata _quote
) external override(IRollup) {
propose(_header, _archive, _blockHash, _txHashes, _signatures, _body);
claimEpochProofRight(_quote);
Expand Down Expand Up @@ -324,7 +324,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
return TxsDecoder.decode(_body);
}

function claimEpochProofRight(DataStructures.SignedEpochProofQuote calldata _quote)
function claimEpochProofRight(EpochProofQuoteLib.SignedEpochProofQuote calldata _quote)
public
override(IRollup)
{
Expand Down Expand Up @@ -559,7 +559,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
return publicInputs;
}

function validateEpochProofRightClaim(DataStructures.SignedEpochProofQuote calldata _quote)
function validateEpochProofRightClaim(EpochProofQuoteLib.SignedEpochProofQuote calldata _quote)
public
view
override(IRollup)
Expand Down
11 changes: 9 additions & 2 deletions l1-contracts/src/core/interfaces/IProofCommitmentEscrow.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@ pragma solidity >=0.8.27;

interface IProofCommitmentEscrow {
function deposit(uint256 _amount) external;
function withdraw(uint256 _amount) external;

function startWithdraw(uint256 _amount) external;

function executeWithdraw() external;

function stakeBond(uint256 _bondAmount, address _prover) external;
function unstakeBond(uint256 _bondAmount, address _prover) external;

function unstakeBond() external;

function minBalanceAtTime(uint256 _timestamp, address _prover) external view returns (uint256);
}
7 changes: 4 additions & 3 deletions l1-contracts/src/core/interfaces/IRollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {IOutbox} from "@aztec/core/interfaces/messagebridge/IOutbox.sol";

import {SignatureLib} from "@aztec/core/libraries/crypto/SignatureLib.sol";
import {DataStructures} from "@aztec/core/libraries/DataStructures.sol";
import {EpochProofQuoteLib} from "@aztec/core/libraries/EpochProofQuoteLib.sol";

import {Timestamp, Slot, Epoch} from "@aztec/core/libraries/TimeMath.sol";

Expand All @@ -30,7 +31,7 @@ interface IRollup {

function prune() external;

function claimEpochProofRight(DataStructures.SignedEpochProofQuote calldata _quote) external;
function claimEpochProofRight(EpochProofQuoteLib.SignedEpochProofQuote calldata _quote) external;

function propose(
bytes calldata _header,
Expand All @@ -48,7 +49,7 @@ interface IRollup {
bytes32[] memory _txHashes,
SignatureLib.Signature[] memory _signatures,
bytes calldata _body,
DataStructures.SignedEpochProofQuote calldata _quote
EpochProofQuoteLib.SignedEpochProofQuote calldata _quote
) external;

function submitEpochRootProof(
Expand Down Expand Up @@ -98,7 +99,7 @@ interface IRollup {
function getEpochToProve() external view returns (Epoch);
function nextEpochToClaim() external view returns (Epoch);
function getEpochForBlock(uint256 blockNumber) external view returns (Epoch);
function validateEpochProofRightClaim(DataStructures.SignedEpochProofQuote calldata _quote)
function validateEpochProofRightClaim(EpochProofQuoteLib.SignedEpochProofQuote calldata _quote)
external
view;
function getEpochProofPublicInputs(
Expand Down
32 changes: 2 additions & 30 deletions l1-contracts/src/core/libraries/DataStructures.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2023 Aztec Labs.
// Copyright 2024 Aztec Labs.
pragma solidity >=0.8.27;

import {SignatureLib} from "@aztec/core/libraries/crypto/SignatureLib.sol";

import {Slot, Epoch} from "@aztec/core/libraries/TimeMath.sol";
import {Epoch} from "@aztec/core/libraries/TimeMath.sol";

/**
* @title Data Structures Library
Expand Down Expand Up @@ -77,32 +75,6 @@ library DataStructures {
bool ignoreSignatures;
}

/**
* @notice Struct encompassing an epoch proof quote
* @param epochToProve - The epoch number to prove
* @param validUntilSlot - The deadline of the quote, denoted in L2 slots
* @param bondAmount - The size of the bond
* @param prover - The address of the prover
* @param basisPointFee - The fee measured in basis points
*/
struct EpochProofQuote {
Epoch epochToProve;
Slot validUntilSlot;
uint256 bondAmount;
address prover;
uint32 basisPointFee;
}

/**
* @notice A signed quote for the epoch proof
* @param quote - The Epoch Proof Quote
* @param signature - A signature on the quote
*/
struct SignedEpochProofQuote {
EpochProofQuote quote;
SignatureLib.Signature signature;
}

/**
* @notice Struct containing the Epoch Proof Claim
* @param epochToProve - the epoch that the bond provider is claiming to prove
Expand Down
Loading

0 comments on commit 1cadafe

Please sign in to comment.