-
Notifications
You must be signed in to change notification settings - Fork 298
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduces an escrow contract that is able to store test tokens from …
…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
1 parent
84e5e0c
commit 1cadafe
Showing
21 changed files
with
748 additions
and
91 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.