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 99 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
99 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
10c9224
Merge branch 'develop' into express-lane-auction
gzeoneth Oct 2, 2024
738c3dc
chore: format
gzeoneth Oct 24, 2024
1078d09
Revert "chore: format"
gzeoneth Oct 24, 2024
bec7d62
v2.1.1-beta.0
gzeoneth Oct 24, 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
249 changes: 249 additions & 0 deletions src/express-lane-auction/Balance.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
// SPDX-License-Identifier: UNLICENSED
// CHRIS: TODO: choose sol version and license
pragma solidity ^0.8.9;

import "./Errors.sol";

struct Balance2 {
uint256 balance;
uint64 withdrawalRound;
}

library Balance2Lib {
function increase(Balance2 storage bal, uint256 amount) internal {
if (amount == 0) {
revert ZeroAmount();
}

// there is no balance in this account
// initialize the round to show that the before balance is the correct one
if (bal.balance == 0) {
bal.withdrawalRound = type(uint64).max;
}

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

// always increase the balance before
bal.balance += amount;
}

// CHRIS: TODO: this whole interplay is complicated, it should be really should it?
function reduce(Balance2 storage bal, uint256 amount, uint64 round) internal {
if (balanceAtRound(bal, round) < amount) {
// CHRIS: TODO: could just check both before and after and then we dont require the round?
revert InsufficientBalance(amount, balanceAtRound(bal, round));
}

// is there a withdrawal in progress
bal.balance -= amount;

if (bal.withdrawalRound != type(uint64).max) {
// pending withdrawal in progress, rest it if we hit zero
if (bal.balance == 0) {
bal.withdrawalRound = type(uint64).max;
}
}
}

function initiateReduce(Balance2 storage bal, uint256 amount, uint64 round) internal {
if (amount == 0) {
revert ZeroAmount();
}

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

if (bal.balance < amount) {
revert InsufficientBalance(amount, bal.balance);
}

// it will show up in the next round, and be withdrawable at round + 2
bal.withdrawalRound = round + 2;
}

function finalizeReduce(Balance2 storage bal, uint64 round) internal returns (uint256) {
uint256 withdrawableBal = withdrawableBalanceAtRound(bal, round);
if (withdrawableBal == 0) {
// should be WithdrawalNotInProgress
revert NothingToWithdraw();
}

// CHRIS: TODO: double storage pull again
bal.withdrawalRound = type(uint64).max;
bal.balance = 0;

return withdrawableBal;
}

function balanceAtRound(Balance2 storage bal, uint64 round) internal view returns (uint256) {
if (bal.withdrawalRound != type(uint64).max && round >= bal.withdrawalRound) {
return bal.balance;
} else {
return 0;
}
}

function withdrawableBalanceAtRound(Balance2 storage bal, uint64 round)
internal
view
returns (uint256)
{
if (bal.withdrawalRound != type(uint64).max && round > bal.withdrawalRound) {
return bal.balance;
} else {
return 0;
}
}
}

// this system only works if we're happy to do 3 lookups for empty val
// actually, in this case we can, we dont really want this huh
struct Balance {
// CHRIS: TODO: set to uint64
uint256 balanceBeforeRound;
uint64 round;
uint256 balanceAfterRound;
}

// Do we forsee a world where the bidding round and the controlling round have different lengths?
// bidding round < controlling round - this is fine and can be enforced by the auctioneer offchain
// controlling round < bidding round - this is more awkward.
// CHRIS: TODO: raise this in the tx-ordering channel. Will we ever want controlling round < bidding round. Where the bidding rounds would now be overlapping.

// CHRIS: TODO: we should set the controlling round to be r, and the bidding round to be r-1
// CHRIS: TODO: lets separate the two. The controlling round is r. The bidding period happens to correspond to a r
// CHRIS: TODO: "The controlling round r is sold during the bidding round r-1."
// CHRIS: TODO: "In round r-1 parties bid for control of round r".

// CHRIS: TODO: docs for these and at least the overall logic as to why this is a separate lib
// CHRIS: TODO: what guarantees should be held here?
// CHRIS: TODO: one thing to test is what these functions do before round 0, also what about unitialised balances
// CHRIS: TODO: we can recognise an unitialised balance as it has 0,0,0 - which is something that an intiialized balance never has

// we collect these balance related functions together so that we can see the possible ways in which a
// balance can be updated

// ordering
// it should be possible to call any of these in any order - particularly the updating functions
// and never end up in an inconsistent state so we keep them all together so we can reason about that

library BalanceLib {
function isPendingReduction(Balance storage bal) internal view returns (bool, uint64) {
uint64 reductionRound = bal.round;
return (reductionRound != type(uint64).max, reductionRound);
}

function increase(Balance storage bal, uint256 amount) internal {
if (amount == 0) {
revert ZeroAmount();
}

// there is no balance in this account
// initialize the round to show that the before balance is the correct one
if (bal.balanceBeforeRound == 0) {
bal.round = type(uint64).max;
}

// always increase the balance before
bal.balanceBeforeRound += amount;

// a withdrawal may be pending, in this case adding funds
// should increase the balance before and the balance after
(bool isPendingR,) = isPendingReduction(bal);
if (isPendingR) {
// CHRIS:TODO: could this be a bit trickier than it looks? increasing the after value at an arbitrary time?
bal.balanceAfterRound += amount;
}
}

// CHRIS: TODO: this whole interplay is complicated, it should be really should it?
function reduce(Balance storage bal, uint256 amount, uint64 round) internal {
if (balanceAtRound(bal, round) < amount) {
// CHRIS: TODO: could just check both before and after and then we dont require the round?
revert InsufficientBalance(amount, balanceAtRound(bal, round));
}

// is there a withdrawal in progress
gzeoneth marked this conversation as resolved.
Show resolved Hide resolved
uint256 balRound = bal.round;
if (balRound != type(uint64).max) {
// reduce the before amount
bal.balanceBeforeRound -= amount;

// update the balance after, this determines how much we'll later be able to withdraw
if (bal.balanceAfterRound >= amount) {
bal.balanceAfterRound -= amount;
} else {
bal.balanceAfterRound = 0;
}

// if we ever get to 0 it means the pending withdrawal was wiped out
// so this cancels the pending withdrawal completely
if (bal.balanceBeforeRound == 0) {
bal.round = type(uint64).max;
}
} else {
// no withdrawal in progress
bal.balanceBeforeRound -= amount;
}
}

function initiateReduce(Balance storage bal, uint256 amount, uint64 round) internal {
if (amount == 0) {
revert ZeroAmount();
}

if (bal.round != type(uint64).max) {
revert WithdrawalInProgress(bal.balanceBeforeRound - bal.balanceAfterRound);
}

if (bal.balanceBeforeRound < amount) {
revert InsufficientBalance(amount, bal.balanceBeforeRound);
}

// CHRIS: TODO: would be nice to put all this together into an update call, then we can test it never can be called twice
bal.balanceAfterRound = bal.balanceBeforeRound - amount;
// it will show up in the next round, and be withdrawable at round + 2
bal.round = round + 2;
}

function finalizeReduce(Balance storage bal, uint64 round) internal returns (uint256) {
uint256 withdrawableBal = withdrawableBalanceAtRound(bal, round);
// CHRIS: TODO: could also check that there is no withdrawal in progress
if (withdrawableBal == 0) {
// should be WithdrawalNotInProgress
revert NothingToWithdraw();
}

// CHRIS: TODO: double storage pull again
bal.round = type(uint64).max;
bal.balanceBeforeRound = bal.balanceAfterRound;
bal.balanceAfterRound = 0;

return withdrawableBal;
}

function balanceAtRound(Balance storage bal, uint64 round) internal view returns (uint256) {
if (bal.round != type(uint64).max && round >= bal.round) {
return bal.balanceAfterRound;
} else {
return bal.balanceBeforeRound;
}
}

function withdrawableBalanceAtRound(Balance storage bal, uint64 round)
internal
view
returns (uint256)
{
if (bal.round != type(uint64).max && round >= bal.round) {
return bal.balanceBeforeRound - bal.balanceAfterRound;
} else {
return 0;
}
}
}
62 changes: 62 additions & 0 deletions src/express-lane-auction/ELCRound.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// SPDX-License-Identifier: UNLICENSED
// CHRIS: TODO: choose sol version and license
pragma solidity ^0.8.9;

import "./Errors.sol";

struct ELCRound {
address expressLaneController;
uint64 round;
}

// CHRIS: TODO: consider all usages of the these during initialization
// CHRIS: TODO: Invariant: not possible for the rounds in latest rounds to have the same value
library LatestELCRoundsLib {
// CHRIS: TODO: what values do these functions have during init?


// CHRIS: TODO: this isnt efficient to do on storage - we may need to return the index or something
function latestELCRound(ELCRound[2] memory rounds)
public
pure
returns (ELCRound memory, uint8)
{
ELCRound memory latestRound = rounds[0];
uint8 index = 0;
if (latestRound.round < rounds[1].round) {
latestRound = rounds[1];
index = 1;
}
return (latestRound, index);
}

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 {
revert RoundNotResolved(round);
gzeoneth marked this conversation as resolved.
Show resolved Hide resolved
}
}

function setResolvedRound(
ELCRound[2] storage latestResolvedRounds,
uint64 round,
address expressLaneController
) internal {
(ELCRound memory lastRoundResolved, uint8 index) = latestELCRound(latestResolvedRounds);
// Invariant: lastAuctionRound.round should never be > round if called during resolve auction except during initialization
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);
}
Fixed Show fixed Hide fixed
}
24 changes: 24 additions & 0 deletions src/express-lane-auction/Errors.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// CHRIS: TODO: update license
// SPDX-License-Identifier: UNLICENSED
// CHRIS: TODO: choose sol version
pragma solidity ^0.8.9;

// CHRIS: TODO: docs and see if al these are actually used
error InsufficientBalance(uint256 amountRequested, uint256 balance);
error InsufficientBalanceAcc(address acount, uint256 amountRequested, uint256 balance);
error RoundDurationTooShort();
error NothingToWithdraw();
error ZeroAmount();
error ZeroBiddingToken();
error WithdrawalInProgress(uint256 amountInWithdrawal);
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(uint256 round, uint256 currentRound);
error RoundNotResolved(uint256 round);
error NotExpressLaneController(uint64 round, address controller, address sender);
6 changes: 6 additions & 0 deletions src/express-lane-auction/Events.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// CHRIS: TODO: update license
// SPDX-License-Identifier: UNLICENSED
// CHRIS: TODO: choose sol version
pragma solidity ^0.8.9;

// CHRIS: TODO: update solidity version then put the events in here
Loading
Loading