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

Added balance at round getter functions #238

Merged
merged 3 commits into from
Aug 27, 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
20 changes: 20 additions & 0 deletions src/express-lane-auction/ExpressLaneAuction.sol
Original file line number Diff line number Diff line change
Expand Up @@ -255,11 +255,31 @@ contract ExpressLaneAuction is
return _balanceOf[account].balanceAtRound(roundTimingInfo.currentRound());
}

/// @inheritdoc IExpressLaneAuction
function balanceOfAtRound(address account, uint64 round) external view returns (uint256) {
if (round < roundTimingInfo.currentRound()) {
revert RoundTooOld(round, roundTimingInfo.currentRound());
}
return _balanceOf[account].balanceAtRound(round);
}

/// @inheritdoc IExpressLaneAuction
function withdrawableBalance(address account) external view returns (uint256) {
return _balanceOf[account].withdrawableBalanceAtRound(roundTimingInfo.currentRound());
}

/// @inheritdoc IExpressLaneAuction
function withdrawableBalanceAtRound(address account, uint64 round)
external
view
returns (uint256)
{
if (round < roundTimingInfo.currentRound()) {
revert RoundTooOld(round, roundTimingInfo.currentRound());
}
return _balanceOf[account].withdrawableBalanceAtRound(round);
}

/// @inheritdoc IExpressLaneAuction
function deposit(uint256 amount) external {
_balanceOf[msg.sender].increase(amount);
Expand Down
22 changes: 22 additions & 0 deletions src/express-lane-auction/IExpressLaneAuction.sol
Original file line number Diff line number Diff line change
Expand Up @@ -312,11 +312,33 @@ interface IExpressLaneAuction is IAccessControlEnumerableUpgradeable, IERC165Upg
/// @param account The specified account
function balanceOf(address account) external view returns (uint256);

/// @notice Get what the balance will be at some future round
/// Since withdrawals are scheduled for future rounds it is possible to see that a balance
/// will reduce at some future round, this method provides a way to query that.
/// Specifically this will return 0 if the withdrawal round has been set, and is < the supplied round
/// Will revert if a round from the past is supplied
/// @param account The specified account
/// @param round The round to query the balance at
function balanceOfAtRound(address account, uint64 round) external view returns (uint256);

/// @notice The amount of balance that can currently be withdrawn via the finalize method
/// This balance only increases current round + 2 after a withdrawal is initiated
/// @param account The account the check the withdrawable balance for
function withdrawableBalance(address account) external view returns (uint256);

/// @notice The amount of balance that can currently be withdrawn via the finalize method
/// Since withdrawals are scheduled for future rounds it is possible to see that a withdrawal balance
/// will increase at some future round, this method provides a way to query that.
/// Specifically this will return 0 unless the withdrawal round has been set, and is >= the supplied round
/// Will revert if a round from the past is supplied
/// This balance only increases current round + 2 after a withdrawal is initiated
/// @param account The account the check the withdrawable balance for
/// @param round The round to query the withdrawable balance at
function withdrawableBalanceAtRound(address account, uint64 round)
external
view
returns (uint256);

/// @notice Deposit an amount of ERC20 token to the auction to make bids with
/// Deposits must be submitted prior to bidding.
/// When withdrawing the full balance must be withdrawn. This is done via a two step process
Expand Down
256 changes: 251 additions & 5 deletions test/foundry/ExpressLaneAuction.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,254 @@ contract ExpressLaneAuctionTest is Test {
vm.stopPrank();
}

function testBalanceOf() public {
(MockERC20 erc20, IExpressLaneAuction auction) = deploy();
erc20.transfer(bidders[0].addr, bidders[0].amount);

uint64 currentRound = auction.currentRound();
vm.expectRevert(
abi.encodeWithSelector(RoundTooOld.selector, currentRound - 1, currentRound)
);
auction.balanceOfAtRound(bidders[0].addr, currentRound - 1);
vm.expectRevert(
abi.encodeWithSelector(RoundTooOld.selector, currentRound - 1, currentRound)
);
auction.withdrawableBalanceAtRound(bidders[0].addr, currentRound - 1);

vm.prank(bidders[0].addr);
erc20.approve(address(auction), 20);

vm.expectEmit(true, true, true, true);
emit Deposit(bidders[0].addr, 20);
vm.prank(bidders[0].addr);
auction.deposit(20);
assertEq(auction.balanceOf(bidders[0].addr), 20, "First balance");
assertEq(
auction.balanceOfAtRound(bidders[0].addr, currentRound),
20,
"First balance at round"
);
assertEq(
auction.balanceOfAtRound(bidders[0].addr, currentRound + 1),
20,
"First balance at round + 1"
);
assertEq(
auction.balanceOfAtRound(bidders[0].addr, currentRound + 2),
20,
"First balance at round + 2"
);
assertEq(
auction.balanceOfAtRound(bidders[0].addr, currentRound + 3),
20,
"First balance at round + 3"
);
assertEq(
auction.withdrawableBalanceAtRound(bidders[0].addr, currentRound),
0,
"First withdrawable balance at round"
);
assertEq(
auction.withdrawableBalanceAtRound(bidders[0].addr, currentRound + 1),
0,
"First withdrawable balance at round + 1"
);
assertEq(
auction.withdrawableBalanceAtRound(bidders[0].addr, currentRound + 2),
0,
"First withdrawable balance at round + 2"
);
assertEq(
auction.withdrawableBalanceAtRound(bidders[0].addr, currentRound + 3),
0,
"First withdrawable balance at round + 3"
);
assertEq(
erc20.balanceOf(bidders[0].addr),
bidders[0].amount - 20,
"First bidders[0].addr erc20 balance"
);
assertEq(erc20.balanceOf(address(auction)), 20, "First auction erc20 balance");

// resolve the auction
vm.warp(block.timestamp + roundDuration - roundDuration / 4);

bytes32 h0 = auction.getBidHash(currentRound + 1, bidders[0].elc, minReservePrice + 1);
Bid memory bid0 = Bid({
amount: minReservePrice + 1,
expressLaneController: bidders[0].elc,
signature: sign(bidders[0].privKey, h0)
});

vm.prank(auctioneer);
auction.resolveSingleBidAuction(bid0);

assertEq(
auction.balanceOfAtRound(bidders[0].addr, currentRound),
20 - minReservePrice,
"Second balance at round"
);
assertEq(
auction.balanceOfAtRound(bidders[0].addr, currentRound + 1),
20 - minReservePrice,
"Second balance at round + 1"
);
assertEq(
auction.balanceOfAtRound(bidders[0].addr, currentRound + 2),
20 - minReservePrice,
"Second balance at round + 2"
);
assertEq(
auction.balanceOfAtRound(bidders[0].addr, currentRound + 3),
20 - minReservePrice,
"Second balance at round + 3"
);
assertEq(
auction.withdrawableBalanceAtRound(bidders[0].addr, currentRound),
0,
"Second withdrawable balance at round"
);
assertEq(
auction.withdrawableBalanceAtRound(bidders[0].addr, currentRound + 1),
0,
"Second withdrawable balance at round + 1"
);
assertEq(
auction.withdrawableBalanceAtRound(bidders[0].addr, currentRound + 2),
0,
"Second withdrawable balance at round + 2"
);
assertEq(
auction.withdrawableBalanceAtRound(bidders[0].addr, currentRound + 3),
0,
"Second withdrawable balance at round + 3"
);

vm.prank(bidders[0].addr);
auction.initiateWithdrawal();

assertEq(
auction.balanceOfAtRound(bidders[0].addr, currentRound),
20 - minReservePrice,
"Third balance at round"
);
assertEq(
auction.balanceOfAtRound(bidders[0].addr, currentRound + 1),
20 - minReservePrice,
"Third balance at round + 1"
);
assertEq(
auction.balanceOfAtRound(bidders[0].addr, currentRound + 2),
0,
"Third balance at round + 2"
);
assertEq(
auction.balanceOfAtRound(bidders[0].addr, currentRound + 3),
0,
"Third balance at round + 3"
);
assertEq(
auction.withdrawableBalanceAtRound(bidders[0].addr, currentRound),
0,
"Third withdrawable balance at round"
);
assertEq(
auction.withdrawableBalanceAtRound(bidders[0].addr, currentRound + 1),
0,
"Third withdrawable balance at round + 1"
);
assertEq(
auction.withdrawableBalanceAtRound(bidders[0].addr, currentRound + 2),
20 - minReservePrice,
"Third withdrawable balance at round + 2"
);
assertEq(
auction.withdrawableBalanceAtRound(bidders[0].addr, currentRound + 3),
20 - minReservePrice,
"Third withdrawable balance at round + 3"
);

vm.warp(block.timestamp + roundDuration);

assertEq(
auction.balanceOfAtRound(bidders[0].addr, currentRound + 1),
20 - minReservePrice,
"Fourth balance at round + 1"
);
assertEq(
auction.balanceOfAtRound(bidders[0].addr, currentRound + 2),
0,
"Fourth balance at round + 2"
);
assertEq(
auction.balanceOfAtRound(bidders[0].addr, currentRound + 3),
0,
"Fourth balance at round + 3"
);
assertEq(
auction.withdrawableBalanceAtRound(bidders[0].addr, currentRound + 1),
0,
"Fourth withdrawable balance at round + 1"
);
assertEq(
auction.withdrawableBalanceAtRound(bidders[0].addr, currentRound + 2),
20 - minReservePrice,
"Fourth withdrawable balance at round + 2"
);
assertEq(
auction.withdrawableBalanceAtRound(bidders[0].addr, currentRound + 3),
20 - minReservePrice,
"Fourth withdrawable balance at round + 3"
);

vm.warp(block.timestamp + roundDuration);

assertEq(
auction.balanceOfAtRound(bidders[0].addr, currentRound + 2),
0,
"Fifth balance at round + 2"
);
assertEq(
auction.balanceOfAtRound(bidders[0].addr, currentRound + 3),
0,
"Fifth balance at round + 3"
);
assertEq(
auction.withdrawableBalanceAtRound(bidders[0].addr, currentRound + 2),
20 - minReservePrice,
"Fifth withdrawable balance at round + 2"
);
assertEq(
auction.withdrawableBalanceAtRound(bidders[0].addr, currentRound + 3),
20 - minReservePrice,
"Fifth withdrawable balance at round + 3"
);

vm.prank(bidders[0].addr);
auction.finalizeWithdrawal();

assertEq(
auction.balanceOfAtRound(bidders[0].addr, currentRound + 2),
0,
"Sixth balance at round + 2"
);
assertEq(
auction.balanceOfAtRound(bidders[0].addr, currentRound + 3),
0,
"Sixth balance at round + 3"
);
assertEq(
auction.withdrawableBalanceAtRound(bidders[0].addr, currentRound + 2),
0,
"Sixth withdrawable balance at round + 2"
);
assertEq(
auction.withdrawableBalanceAtRound(bidders[0].addr, currentRound + 3),
0,
"Sixth withdrawable balance at round + 3"
);
}

function testCurrentRound() public {
(, IExpressLaneAuction auction) = deploy();
vm.warp(1);
Expand Down Expand Up @@ -1743,7 +1991,6 @@ contract ExpressLaneAuctionTest is Test {
vm.stopPrank();

address newBeneficiary = vm.addr(9090);
address newBeneficiary2 = vm.addr(9091);

bytes memory revertString = abi.encodePacked(
"AccessControl: account ",
Expand Down Expand Up @@ -1812,16 +2059,15 @@ contract ExpressLaneAuctionTest is Test {
})
);

uint64 longDuration = 86401;
(uint64 start, ) = auction.roundTimestamps(auction.currentRound() + 1);
int64 newOffset = int64(start - longDuration * 24);
int64 newOffset = int64(start - 86401 * 24);

vm.prank(roundTimingSetter);
vm.expectRevert(abi.encodeWithSelector(RoundTooLong.selector, longDuration));
vm.expectRevert(abi.encodeWithSelector(RoundTooLong.selector, 86401));
auction.setRoundTimingInfo(
RoundTimingInfo({
offsetTimestamp: newOffset,
roundDurationSeconds: longDuration,
roundDurationSeconds: 86401,
auctionClosingSeconds: 10,
reserveSubmissionSeconds: 20
})
Expand Down
36 changes: 36 additions & 0 deletions test/foundry/ExpressLaneBalance.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,42 @@ contract ExpressLaneBalanceTest is Test {
}
}

function testInitiateWithdrawalBoundaries() public {
testInitiateWithdrawal(0, 0, 0);
testInitiateWithdrawal(0, 0, 10);
testInitiateWithdrawal(0, 0, type(uint64).max);
testInitiateWithdrawal(0, 10, 0);
testInitiateWithdrawal(0, 10, 5);
testInitiateWithdrawal(0, 10, 10);
testInitiateWithdrawal(0, 10, 15);
testInitiateWithdrawal(0, 10, type(uint64).max);
testInitiateWithdrawal(0, type(uint64).max, 0);
testInitiateWithdrawal(0, type(uint64).max, 10);
testInitiateWithdrawal(0, type(uint64).max, type(uint64).max);
testInitiateWithdrawal(10, 0, 0);
testInitiateWithdrawal(10, 0, 10);
testInitiateWithdrawal(10, 0, type(uint64).max);
testInitiateWithdrawal(10, 10, 0);
testInitiateWithdrawal(10, 10, 5);
testInitiateWithdrawal(10, 10, 10);
testInitiateWithdrawal(10, 10, 15);
testInitiateWithdrawal(10, 10, type(uint64).max);
testInitiateWithdrawal(10, type(uint64).max, 0);
testInitiateWithdrawal(10, type(uint64).max, 10);
testInitiateWithdrawal(10, type(uint64).max, type(uint64).max);
testInitiateWithdrawal(type(uint256).max, 0, 0);
testInitiateWithdrawal(type(uint256).max, 0, 10);
testInitiateWithdrawal(type(uint256).max, 0, type(uint64).max);
testInitiateWithdrawal(type(uint256).max, 10, 0);
testInitiateWithdrawal(type(uint256).max, 10, 5);
testInitiateWithdrawal(type(uint256).max, 10, 10);
testInitiateWithdrawal(type(uint256).max, 10, 15);
testInitiateWithdrawal(type(uint256).max, 10, type(uint64).max);
testInitiateWithdrawal(type(uint256).max, type(uint64).max, 0);
testInitiateWithdrawal(type(uint256).max, type(uint64).max, 10);
testInitiateWithdrawal(type(uint256).max, type(uint64).max, type(uint64).max);
}

function testInitiateWithdrawal(
uint256 initialBalance,
uint64 initialRound,
Expand Down
Loading