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

Express lane auction contracts #214

Open
wants to merge 95 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
6875293
Added express lane auction contracts draft
yahgwai Jul 3, 2024
e1738b8
Updated express lane interface and added more tests
yahgwai Jul 18, 2024
bdae989
Addressed more todos
yahgwai Jul 18, 2024
b20f9e9
Merge branch 'develop' into express-lane-auction
yahgwai Jul 18, 2024
5e90ab3
Renamed auctioneer to auction clerk
yahgwai Jul 18, 2024
abc71fa
Updates from spec
yahgwai Jul 19, 2024
f7a0019
Balance2 usage and addressed more todos
yahgwai Jul 22, 2024
97e387c
Updated to safeTransfer
yahgwai Jul 22, 2024
9d9c199
Fixed strick equality
yahgwai Jul 22, 2024
a3bf984
Added testing comments
yahgwai Jul 22, 2024
424f0ac
Formatting
yahgwai Jul 22, 2024
46f20c3
Added slither exceptions
yahgwai Jul 23, 2024
522391c
Test updates and internal lib function
yahgwai Jul 24, 2024
521da55
Added resolvedRounds public and set latestResolvedRound internal
yahgwai Jul 24, 2024
ef2fb0b
Use access control enumerable
yahgwai Jul 24, 2024
1690451
Use functions internally, make others external
yahgwai Jul 24, 2024
f830383
Formatting
yahgwai Jul 24, 2024
60f6080
Dont reset withdrawal round after finalized withdrawal - just on deposit
yahgwai Jul 24, 2024
8251c24
Added domain comment
yahgwai Jul 24, 2024
d1ac7d3
Added domain value to express lane auction
yahgwai Jul 25, 2024
e4697d7
Added todos based on code review
yahgwai Jul 25, 2024
eb63042
Docs updates
yahgwai Jul 25, 2024
54e7aca
Beginnings of separate balance testing
yahgwai Jul 26, 2024
a2fbc1d
Finished balance tests
yahgwai Jul 29, 2024
261e1b0
Added elc round specific tests
yahgwai Jul 30, 2024
92e64ef
Docs and testing for resolved rounds
yahgwai Jul 30, 2024
89fbaa3
Cleaned todos in testing file
yahgwai Jul 31, 2024
5300676
Addressed more todos
yahgwai Aug 1, 2024
2f647c8
Formatting
yahgwai Aug 2, 2024
971ab70
Slither updates
yahgwai Aug 2, 2024
fa50fbf
Added transferrer setting first draft
yahgwai Aug 2, 2024
01c3669
Updates from slither mutate
yahgwai Aug 5, 2024
30b4dd0
Set transferrer into interface
yahgwai Aug 5, 2024
777b58e
Merge branch 'express-lane-auction-2' into express-lane-auction-3
yahgwai Aug 5, 2024
97e698d
Added alternative transferors and tests
yahgwai Aug 5, 2024
a63bdee
Comment update
yahgwai Aug 5, 2024
2def378
Removed todo
yahgwai Aug 5, 2024
9565035
Added round timing setter
yahgwai Aug 6, 2024
424d732
Remove comment
yahgwai Aug 6, 2024
ee70432
Removed unneeded admin roles
yahgwai Aug 6, 2024
a599fa1
Removed struct params usage
yahgwai Aug 6, 2024
52b983f
Merge from base
yahgwai Aug 6, 2024
74821a2
Merge from base
yahgwai Aug 6, 2024
fad469d
Delete todo
yahgwai Aug 6, 2024
2cc0bf3
Merge from base
yahgwai Aug 6, 2024
314d593
Merge from base
yahgwai Aug 6, 2024
87d578a
Added 712 signing
yahgwai Aug 8, 2024
f2e1e4f
Formatting and test update
yahgwai Aug 8, 2024
5afd437
fix: lint
gzeoneth Aug 13, 2024
795ea3e
Updated NotTransferor address to match NotExpressLaneController
yahgwai Aug 15, 2024
4301639
Formatting
yahgwai Aug 15, 2024
926b264
Added bid const hash
yahgwai Aug 15, 2024
e0fb4ed
Comment update
yahgwai Aug 15, 2024
d1cce13
Merge pull request #226 from OffchainLabs/express-lane-auction-round-…
yahgwai Aug 15, 2024
89dbece
Merge from express-lane-auction-2
yahgwai Aug 15, 2024
e4d85e1
Merge pull request #227 from OffchainLabs/express-lane-auction-712
yahgwai Aug 15, 2024
ae50531
Merge from express-lane-auction-2
yahgwai Aug 15, 2024
d4043bd
Merge pull request #224 from OffchainLabs/express-lane-auction-3
yahgwai Aug 15, 2024
b3a281b
Merge pull request #222 from OffchainLabs/express-lane-auction-2
yahgwai Aug 15, 2024
1bbd922
test: fix
gzeoneth Aug 15, 2024
d145c07
Factor out round timing interval interanl
yahgwai Aug 15, 2024
4274a31
Merge branch 'express-lane-auction' of https://github.com/OffchainLab…
yahgwai Aug 15, 2024
e54bf02
Refactored the round timing info setting to use shared internal func
yahgwai Aug 15, 2024
1ae3d10
CR updates
yahgwai Aug 15, 2024
d6fbc49
More updates from CR
yahgwai Aug 15, 2024
29f449a
Update src/express-lane-auction/ExpressLaneAuction.sol
yahgwai Aug 15, 2024
34b5da7
Merge from remote
yahgwai Aug 15, 2024
d9c8dc9
Updated shadow variable name
yahgwai Aug 15, 2024
5f288d7
Added int offset
yahgwai Aug 15, 2024
c8de1f8
Updated round timing tests
yahgwai Aug 16, 2024
70e22a7
Updated comment
yahgwai Aug 16, 2024
fb5fe04
Updated comments
yahgwai Aug 16, 2024
180262a
Merge pull request #237 from OffchainLabs/express-lane-auction-int-of…
yahgwai Aug 16, 2024
bc7a334
Updates from goran's cr
yahgwai Aug 17, 2024
fbc5565
Slither update
yahgwai Aug 17, 2024
acf77b7
Formatting
yahgwai Aug 17, 2024
0134e49
Merge from develop
yahgwai Aug 17, 2024
5766ac5
Removed set beneficiary
yahgwai Aug 19, 2024
e33c353
Updated comment
yahgwai Aug 19, 2024
9dc19d2
Public to external
yahgwai Aug 20, 2024
a41681e
Added balance at round functions
yahgwai Aug 21, 2024
35e3a46
Added specific boundary conditions for balance test as fuzzing seemed…
yahgwai Aug 21, 2024
a93c464
Merge branch 'express-lane-auction' into express-lane-auction-balance…
gzeoneth Aug 21, 2024
93272e0
Removed out of date comment
yahgwai Aug 21, 2024
13854a5
Balance updates from audit review
yahgwai Aug 22, 2024
4445b48
minor typo fixes in comments
leeederek Aug 22, 2024
94d1194
Added a burner contract in case the dao decides to burn the funds ins…
yahgwai Aug 22, 2024
94a72ab
Merge pull request #239 from leeederek/patch-1
yahgwai Aug 23, 2024
a40ba2e
Merge pull request #238 from OffchainLabs/express-lane-auction-balanc…
yahgwai Aug 27, 2024
893f40d
Burner tests
yahgwai Aug 27, 2024
e3b24b7
Added comment
yahgwai Aug 27, 2024
e4dd36a
Merge pull request #242 from OffchainLabs/express-lane-auction-burn
yahgwai Aug 27, 2024
f1f862f
Comment update
yahgwai Aug 27, 2024
84ade50
Merge pull request #243 from OffchainLabs/express-lane-auction-audit-fix
yahgwai Aug 27, 2024
a9c5cfb
Merge branch 'develop' into express-lane-auction
gzeoneth Sep 12, 2024
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: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ deployments/
scripts/config.ts
forge-cache/
out/
.env
.env
lcov.info
output_directory
2 changes: 1 addition & 1 deletion slither.db.json

Large diffs are not rendered by default.

142 changes: 142 additions & 0 deletions src/express-lane-auction/Balance.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

import "./Errors.sol";

/// @notice Account balance and the round at which it can be withdrawn
/// Balances are withdrawn as part of a two step process - initiation and finalization
/// This is so that a bidder can't withdraw their balance after making a bid
/// Instead, if they initiate their withdrawal in round r, they must wait until the beginning of
/// round r+2 before they can withdraw the balance. In the mean time their balance can be used to
/// resolve an auction if it is part of a valid bid, however the auctioneer may choose to
/// reject bids from accounts with an initiated balance withdrawal
struct Balance {
/// @notice The amount of balance in the account
uint256 balance;
/// @notice The round at which all of the balance can be withdrawn
/// Is set to uint64.max when no withdrawal has been intiated
uint64 withdrawalRound;
}

/// @notice Balance mutation and view functionality. This is in it's own library so that we can
// reason about and test how the different ways balance mutations interact with each other
library BalanceLib {
/// @notice The available balance at the supplied round. Returns 0 if a withdrawal has been initiated and has
/// past the withdrawal round.
/// @param bal The balance to query
/// @param round The round to check the balance in
function balanceAtRound(Balance storage bal, uint64 round) internal view returns (uint256) {
return bal.balance - withdrawableBalanceAtRound(bal, round);
}

/// @notice The withdrawable balance at the supplied round. If a withdrawal has been initiated, the
/// supplied round is past the withdrawal round and has yet to be finalized, then the balance
/// of this account is returned. Otherwise 0.
/// @param bal The balance to query
/// @param round The round to check the withdrawable balance in
function withdrawableBalanceAtRound(Balance storage bal, uint64 round)
internal
view
returns (uint256)
{
return round >= bal.withdrawalRound ? bal.balance : 0;
}

/// @notice Increase a balance by a specified amount
/// Will cancel a withdrawal if called after a withdrawal has been initiated
/// @param bal The balance info
/// @param amount The amount to increase the balance by
function increase(Balance storage bal, uint256 amount) internal {
// no point increasing if no amount is being supplied
if (amount == 0) {
revert ZeroAmount();
}

// if the balance have never been used before then balance and withdrawal round will be 0
// in this case we initialize the balance by setting the withdrawal round into the future
// if a withdrawal for the balance has been initialized (withdrawal round != 0 and != max)
// then we cancel that initiated withdrawal. We do this since if a increase is being made that
// means a user wishes to increase their balance, not withdraw it.
if (bal.withdrawalRound != type(uint64).max) {
bal.withdrawalRound = type(uint64).max;
}

bal.balance += amount;
}

/// @notice Reduce a balance immediately. The balance must already be greater than the amount
/// and a withdrawal has been initiated for this balance it must be occuring in
/// a round after the supplied round. Withdrawals earlier than that will block this reduce.
/// @param bal The balance to reduce
/// @param amount The amount to reduce by
/// @param round The round to check withdrawals against. A withdrawal after this round will be ignored
/// and the balance reduced anyway, withdrawals before or on this round will be respected
/// and the reduce will revert
function reduce(
Balance storage bal,
uint256 amount,
uint64 round
) internal {
uint256 balRnd = balanceAtRound(bal, round);
// we add a zero check since it's possible for the amount to be zero
// but even in that case the user must have some balance
// to enforce that parties that havent done the deposit step cannot take part in the auction
if (balRnd == 0 || balRnd < amount) {
revert InsufficientBalance(amount, balRnd);
}

bal.balance -= amount;
}

/// @notice Initiate a withdrawal. A withdrawal is a reduction of the full amount.
/// Withdrawal is a two step process initialization and finalization. Finalization is only
/// after the supplied round parameter. The expected usage is to specify a round that is 2
/// in the future to ensure that the balance cannot be reduced unexpectedly without notice.
// An external observer can see that a withdrawal has been initiated, and will therefore
/// be able to take it into account and not rely on the balance being there.
/// In the case of the auction contract this allows the bidders to withdraw their
/// balance, but an auctioneer will know not to accept there bids in the mean time
/// @param bal The balance to iniate a reduction on
/// @param round The round that the withdrawal will be available in. Cannot be specified as the max round
function initiateWithdrawal(Balance storage bal, uint64 round) internal {
if (bal.balance == 0) {
revert ZeroAmount();
}

if (round == type(uint64).max) {
// we use max round to specify that a withdrawal is not taking place
// so we dont allow it as a withdrawal round. In practice max round should never
// be reached so this isnt an issue, we just put this here as an additional
// safety check
revert WithdrawalMaxRound();
}

if (bal.withdrawalRound != type(uint64).max) {
revert WithdrawalInProgress();
}

bal.withdrawalRound = round;
}

/// @notice Finalize an already initialized withdrawal. Reduces the balance to 0.
/// Can only be called two round after the withdrawal was initiated.
/// @param bal The balance to finalize
/// @param round The round to check whether withdrawal is valid in. Usually the current round. Cannot be max round.
function finalizeWithdrawal(Balance storage bal, uint64 round) internal returns (uint256) {
if (round == type(uint64).max) {
// we use max round to specify that a withdrawal is not taking place
// so we dont allow it as a withdrawal round. In practice max round should never
// be reached so this isnt an issue, we just put this here as an additional
// safety check
revert WithdrawalMaxRound();
}

uint256 withdrawableBalance = withdrawableBalanceAtRound(bal, round);
if (withdrawableBalance == 0) {
revert NothingToWithdraw();
}

bal.balance = 0;
return withdrawableBalance;
}
}
25 changes: 25 additions & 0 deletions src/express-lane-auction/Burner.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

import {
ERC20BurnableUpgradeable
} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol";
import "./Errors.sol";

/// @notice A simple contract that can burn any tokens that are transferred to it
/// Token must support the ERC20BurnableUpgradeable.burn(uint256) interface
contract Burner {
ERC20BurnableUpgradeable public immutable token;

constructor(address _token) {
if (_token == address(0)) {
revert ZeroAddress();
}
token = ERC20BurnableUpgradeable(_token);
}

/// @notice Can be called at any time by anyone to burn any tokens held by this burner
function burn() external {
token.burn(token.balanceOf(address(this)));
}
}
73 changes: 73 additions & 0 deletions src/express-lane-auction/ELCRound.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

import "./Errors.sol";

/// @notice When an auction round is resolved a new express lane controller is chosen for that round
/// An elc round stores that selected express lane controller against the round number
struct ELCRound {
/// @notice The express lane controller for this round
address expressLaneController;
/// @notice The round number
uint64 round;
}

/// @notice Latest resolved express lane controller auction rounds
// Only the two latest resolved rounds are stored
library LatestELCRoundsLib {
/// @notice The last resolved express lane controller round, and its index in the array
/// @param rounds The stored resolved rounds
/// @return The last resolved elc round
/// @return The index of that last resolved round within the supplied array
function latestELCRound(ELCRound[2] storage rounds)
internal
view
returns (ELCRound storage, uint8)
{
ELCRound storage latestRound = rounds[0];
uint8 index = 0;
if (latestRound.round < rounds[1].round) {
latestRound = rounds[1];
index = 1;
}
return (latestRound, index);
yahgwai marked this conversation as resolved.
Show resolved Hide resolved
}

/// @notice Finds the elc round that matches the supplied round. Reverts if no matching round found.
/// @param latestResolvedRounds The resolved elc rounds
/// @param round The round number to find a resolved round for
function resolvedRound(ELCRound[2] storage latestResolvedRounds, uint64 round)
internal
view
returns (ELCRound storage)
{
if (latestResolvedRounds[0].round == round) {
return latestResolvedRounds[0];
} else if (latestResolvedRounds[1].round == round) {
return latestResolvedRounds[1];
} else {
// not resolved or too old
revert RoundNotResolved(round);
gzeoneth marked this conversation as resolved.
Show resolved Hide resolved
}
}

/// @notice Set a resolved round into the array, overwriting the oldest resolved round
/// in the array.
/// @param latestResolvedRounds The resolved rounds aray
/// @param round The round to resolve
/// @param expressLaneController The new express lane controller for that round
function setResolvedRound(
ELCRound[2] storage latestResolvedRounds,
uint64 round,
address expressLaneController
) internal {
(ELCRound storage lastRoundResolved, uint8 index) = latestELCRound(latestResolvedRounds);
if (lastRoundResolved.round >= round) {
revert RoundAlreadyResolved(round);
}

// dont replace the newest round, use the oldest slot
uint8 oldestRoundIndex = index ^ 1;
latestResolvedRounds[oldestRoundIndex] = ELCRound(expressLaneController, round);
}
}
31 changes: 31 additions & 0 deletions src/express-lane-auction/Errors.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

error InsufficientBalance(uint256 amountRequested, uint256 balance);
error InsufficientBalanceAcc(address account, uint256 amountRequested, uint256 balance);
error RoundDurationTooShort();
error NothingToWithdraw();
error ZeroAmount();
error ZeroBiddingToken();
error WithdrawalInProgress();
error WithdrawalMaxRound();
error RoundAlreadyResolved(uint64 round);
error SameBidder();
error BidsWrongOrder();
error TieBidsWrongOrder();
error AuctionNotClosed();
error ReservePriceTooLow(uint256 reservePrice, uint256 minReservePrice);
error ReservePriceNotMet(uint256 bidAmount, uint256 reservePrice);
error ReserveBlackout();
error RoundTooOld(uint64 round, uint64 currentRound);
error RoundNotResolved(uint64 round);
error NotExpressLaneController(uint64 round, address controller, address sender);
error FixedTransferor(uint64 fixedUntilRound);
error NotTransferor(uint64 round, address expectedTransferor, address msgSender);
error InvalidNewRound(uint64 currentRound, uint64 newRound);
error InvalidNewStart(uint64 currentStart, uint64 newStart);
error RoundTooLong(uint64 roundDurationSeconds);
error ZeroAuctionClosingSeconds();
error NegativeOffset();
error NegativeRoundStart(int64 roundStart);
error ZeroAddress();
Loading
Loading