Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: prover escrow and 712-signed quotes #8877

Merged
merged 7 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ This imports relevant files including the interfaces used by the Aztec rollup. A

Create a basic ERC20 contract that can mint tokens to anyone. We will use this to test.

Create a file `PortalERC20.sol` in the same folder and add:
Create a file `TestERC20.sol` in the same folder and add:

#include_code contract /l1-contracts/test/portals/PortalERC20.sol solidity
#include_code contract /l1-contracts/test/TestERC20.sol solidity

Replace the openzeppelin import with this:

Expand Down
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"]
}
}
}
146 changes: 146 additions & 0 deletions l1-contracts/src/core/ProofCommitmentEscrow.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// 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";
import {Timestamp} from "@aztec/core/libraries/TimeMath.sol";

contract ProofCommitmentEscrow is IProofCommitmentEscrow {
using SafeERC20 for IERC20;

struct WithdrawRequest {
uint256 amount;
Timestamp executableAt;
}

address public immutable ROLLUP;
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 immutable token;

modifier onlyRollup() {
require(msg.sender == ROLLUP, Errors.ProofCommitmentEscrow__NotOwner(msg.sender));
_;
}

constructor(IERC20 _token, address _owner) {
token = _token;
ROLLUP = _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 {
just-mitch marked this conversation as resolved.
Show resolved Hide resolved
token.safeTransferFrom(msg.sender, address(this), _amount);

deposits[msg.sender] += _amount;

emit Deposit(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 {
require(
deposits[msg.sender] >= _amount,
Errors.ProofCommitmentEscrow__InsufficientBalance(deposits[msg.sender], _amount)
);

withdrawRequests[msg.sender] = WithdrawRequest({
amount: _amount,
executableAt: Timestamp.wrap(block.timestamp + WITHDRAW_DELAY)
});

emit StartWithdraw(msg.sender, _amount, withdrawRequests[msg.sender].executableAt);
}

/**
* @notice Execute a mature withdrawal request
*/
function executeWithdraw() external override {
just-mitch marked this conversation as resolved.
Show resolved Hide resolved
WithdrawRequest memory request = withdrawRequests[msg.sender];
require(
request.executableAt <= Timestamp.wrap(block.timestamp),
Errors.ProofCommitmentEscrow__WithdrawRequestNotReady(block.timestamp, request.executableAt)
);

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

emit ExecuteWithdraw(msg.sender, request.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(address _prover, uint256 _amount) external override onlyRollup {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Natspec should have the params etc. But think we are generally missing some of that. So seems like something that could be acceptable for now, and then lets create a big ass "update natspec" issue.

Created #8912

deposits[_prover] -= _amount;

emit StakeBond(_prover, _amount);
}

/**
* @notice Unstake the bonded tokens, returning them to the prover
*
* @dev Only callable by the owner
*/
function unstakeBond(address _prover, uint256 _amount) external override onlyRollup {
deposits[_prover] += _amount;

emit UnstakeBond(_prover, _amount);
}

/**
* @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(Timestamp _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 >= Timestamp.wrap(block.timestamp + WITHDRAW_DELAY)) {
return 0;
}

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

import {EIP712} from "@oz/utils/cryptography/EIP712.sol";
import {ECDSA} from "@oz/utils/cryptography/ECDSA.sol";

import {IProofCommitmentEscrow} from "@aztec/core/interfaces/IProofCommitmentEscrow.sol";
import {IInbox} from "@aztec/core/interfaces/messagebridge/IInbox.sol";
import {IOutbox} from "@aztec/core/interfaces/messagebridge/IOutbox.sol";
Expand All @@ -11,6 +14,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 @@ -32,9 +36,8 @@ import {Timestamp, Slot, Epoch, SlotLib, EpochLib} from "@aztec/core/libraries/T
* @notice Rollup contract that is concerned about readability and velocity of development
* not giving a damn about gas costs.
*/
contract Rollup is Leonidas, IRollup, ITestRollup {
contract Rollup is EIP712("Aztec Rollup", "1"), Leonidas, IRollup, ITestRollup {
using SafeCast for uint256;

using SlotLib for Slot;
using EpochLib for Epoch;

Expand Down Expand Up @@ -105,6 +108,15 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
setupEpoch();
}

function quoteToDigest(EpochProofQuoteLib.EpochProofQuote memory quote)
public
view
override(IRollup)
returns (bytes32)
{
return _hashTypedDataV4(EpochProofQuoteLib.hash(quote));
}

/**
* @notice Prune the pending chain up to the last proven block
*
Expand Down Expand Up @@ -169,7 +181,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 +336,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 All @@ -336,7 +348,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
// We don't currently unstake,
// but we will as part of https://github.com/AztecProtocol/aztec-packages/issues/8652.
// Blocked on submitting epoch proofs to this contract.
PROOF_COMMITMENT_ESCROW.stakeBond(_quote.quote.bondAmount, _quote.quote.prover);
PROOF_COMMITMENT_ESCROW.stakeBond(_quote.quote.prover, _quote.quote.bondAmount);

proofClaim = DataStructures.EpochProofClaim({
epochToProve: epochToProve,
Expand Down Expand Up @@ -559,11 +571,13 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
return publicInputs;
}

function validateEpochProofRightClaim(DataStructures.SignedEpochProofQuote calldata _quote)
function validateEpochProofRightClaim(EpochProofQuoteLib.SignedEpochProofQuote calldata _quote)
public
view
override(IRollup)
{
SignatureLib.verify(_quote.signature, _quote.quote.prover, quoteToDigest(_quote.quote));

Slot currentSlot = getCurrentSlot();
address currentProposer = getCurrentProposer();
Epoch epochToProve = getEpochToProve();
Expand Down
16 changes: 13 additions & 3 deletions l1-contracts/src/core/interfaces/IProofCommitmentEscrow.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,19 @@
// Copyright 2024 Aztec Labs.
pragma solidity >=0.8.27;

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

interface IProofCommitmentEscrow {
event Deposit(address indexed depositor, uint256 amount);
event StartWithdraw(address indexed withdrawer, uint256 amount, Timestamp executableAt);
event ExecuteWithdraw(address indexed withdrawer, uint256 amount);
event StakeBond(address indexed prover, uint256 amount);
event UnstakeBond(address indexed prover, uint256 amount);

function deposit(uint256 _amount) external;
function withdraw(uint256 _amount) external;
function stakeBond(uint256 _bondAmount, address _prover) external;
function unstakeBond(uint256 _bondAmount, address _prover) external;
function startWithdraw(uint256 _amount) external;
function executeWithdraw() external;
function stakeBond(address _prover, uint256 _amount) external;
function unstakeBond(address _prover, uint256 _amount) external;
function minBalanceAtTime(Timestamp _timestamp, address _prover) external view returns (uint256);
}
Loading
Loading