Skip to content

Commit

Permalink
CDAuctioneer: test stubs for tracking of historical auction results
Browse files Browse the repository at this point in the history
  • Loading branch information
0xJem committed Jan 13, 2025
1 parent 135ffed commit 2663fb0
Show file tree
Hide file tree
Showing 10 changed files with 748 additions and 73 deletions.
40 changes: 39 additions & 1 deletion src/policies/CDAuctioneer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,16 @@ contract CDAuctioneer is IConvertibleDepositAuctioneer, Policy, RolesConsumer, R
/// @dev See `getTimeToExpiry()` for more information
uint48 internal _timeToExpiry;

/// @notice The index of the next auction result
uint8 internal _auctionResultsNextIndex;

/// @notice The number of days that auction results are tracked for
uint8 internal _auctionTrackingPeriod;

/// @notice The auction results, where a positive number indicates an over-subscription for the day.
/// @dev The length of this array is equal to the auction tracking period
int256[] internal _auctionResults;

// ========== SETUP ========== //

constructor(address kernel_, address cdFacility_) Policy(Kernel(kernel_)) {
Expand Down Expand Up @@ -399,6 +409,21 @@ contract CDAuctioneer is IConvertibleDepositAuctioneer, Policy, RolesConsumer, R
return _timeToExpiry;
}

/// @inheritdoc IConvertibleDepositAuctioneer
function getAuctionTrackingPeriod() external view override returns (uint8) {
return _auctionTrackingPeriod;
}

/// @inheritdoc IConvertibleDepositAuctioneer
function getAuctionResultsNextIndex() external view override returns (uint8) {
return _auctionResultsNextIndex;
}

/// @inheritdoc IConvertibleDepositAuctioneer
function getAuctionResults() external view override returns (int256[] memory) {
return _auctionResults;
}

// ========== ADMIN FUNCTIONS ========== //

function _setAuctionParameters(uint256 target_, uint256 tickSize_, uint256 minPrice_) internal {
Expand Down Expand Up @@ -489,6 +514,18 @@ contract CDAuctioneer is IConvertibleDepositAuctioneer, Policy, RolesConsumer, R
emit TickStepUpdated(newStep_);
}

function setAuctionTrackingPeriod(uint8 days_) external onlyRole(ROLE_ADMIN) {
// Value must be non-zero
if (days_ == 0) revert CDAuctioneer_InvalidParams("auction tracking period");

_auctionTrackingPeriod = days_;

// Emit event
emit AuctionTrackingPeriodUpdated(days_);
}

// ========== ACTIVATION/DEACTIVATION ========== //

/// @inheritdoc IConvertibleDepositAuctioneer
/// @dev This function will revert if:
/// - The caller does not have the ROLE_ADMIN role
Expand All @@ -501,7 +538,8 @@ contract CDAuctioneer is IConvertibleDepositAuctioneer, Policy, RolesConsumer, R
uint256 tickSize_,
uint256 minPrice_,
uint24 tickStep_,
uint48 timeToExpiry_
uint48 timeToExpiry_,
uint8 auctionTrackingPeriod_
) external onlyRole(ROLE_ADMIN) {
// If initialized, revert
if (initialized) revert CDAuctioneer_InvalidState();
Expand Down
42 changes: 40 additions & 2 deletions src/policies/interfaces/IConvertibleDepositAuctioneer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ interface IConvertibleDepositAuctioneer {
/// @param newMinPrice Minimum tick price
event AuctionParametersUpdated(uint256 newTarget, uint256 newTickSize, uint256 newMinPrice);

/// @notice Emitted when the auction result is recorded
///
/// @param ohmConvertible Amount of OHM that was converted
/// @param target Target for OHM sold per day
/// @param periodIndex The index of the auction result in the tracking period
event AuctionResult(uint256 ohmConvertible, uint256 target, uint8 periodIndex);

/// @notice Emitted when the time to expiry is updated
///
/// @param newTimeToExpiry Time to expiry
Expand All @@ -23,6 +30,11 @@ interface IConvertibleDepositAuctioneer {
/// @param newTickStep Percentage increase (decrease) per tick
event TickStepUpdated(uint24 newTickStep);

/// @notice Emitted when the auction tracking period is updated
///
/// @param newAuctionTrackingPeriod The number of days that auction results are tracked for
event AuctionTrackingPeriodUpdated(uint8 newAuctionTrackingPeriod);

/// @notice Emitted when the contract is activated
event Activated();

Expand Down Expand Up @@ -141,10 +153,26 @@ interface IConvertibleDepositAuctioneer {
/// @return token The token that is being bid
function bidToken() external view returns (address token);

/// @notice Get the number of days that auction results are tracked for
///
/// @return daysTracked The number of days that auction results are tracked for
function getAuctionTrackingPeriod() external view returns (uint8 daysTracked);

/// @notice Get the auction results for the tracking period
///
/// @return results The auction results, where a positive number indicates an over-subscription for the day.
function getAuctionResults() external view returns (int256[] memory results);

/// @notice Get the index of the next auction result
///
/// @return index The index where the next auction result will be stored
function getAuctionResultsNextIndex() external view returns (uint8 index);

// ========== ADMIN ========== //

/// @notice Update the auction parameters
/// @dev only callable by the auction admin
/// @dev This function is expected to be called periodically.
/// Only callable by the auction admin
///
/// @param target_ new target sale per day
/// @param tickSize_ new size per tick
Expand All @@ -170,6 +198,14 @@ interface IConvertibleDepositAuctioneer {
/// @param tickStep_ new tick step, in terms of `ONE_HUNDRED_PERCENT`
function setTickStep(uint24 tickStep_) external;

/// @notice Set the number of days that auction results are tracked for
/// @dev Only callable by the admin
///
/// @param days_ The number of days that auction results are tracked for
function setAuctionTrackingPeriod(uint8 days_) external;

// ========== ACTIVATION/DEACTIVATION ========== //

/// @notice Enables governance to initialize and activate the contract. This ensures that the contract is in a valid state when activated.
/// @dev Only callable by the admin role
///
Expand All @@ -178,12 +214,14 @@ interface IConvertibleDepositAuctioneer {
/// @param minPrice_ The minimum price that OHM can be sold for, in terms of the bid token
/// @param tickStep_ The tick step, in terms of `ONE_HUNDRED_PERCENT`
/// @param timeToExpiry_ The number of seconds between creation and expiry of convertible deposits
/// @param auctionTrackingPeriod_ The number of days that auction results are tracked for
function initialize(
uint256 target_,
uint256 tickSize_,
uint256 minPrice_,
uint24 tickStep_,
uint48 timeToExpiry_
uint48 timeToExpiry_,
uint8 auctionTrackingPeriod_
) external;

/// @notice Activate the contract functionality
Expand Down
11 changes: 10 additions & 1 deletion src/test/mocks/MockConvertibleDepositAuctioneer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ contract MockConvertibleDepositAuctioneer is IConvertibleDepositAuctioneer, Poli
uint256 tickSize_,
uint256 minPrice_,
uint24 tickStep_,
uint48 timeToExpiry_
uint48 timeToExpiry_,
uint8 auctionTrackingPeriod_
) external override {}

function requestPermissions()
Expand Down Expand Up @@ -72,4 +73,12 @@ contract MockConvertibleDepositAuctioneer is IConvertibleDepositAuctioneer, Poli
function getTickStep() external view override returns (uint24) {}

function getTimeToExpiry() external view override returns (uint48) {}

function getAuctionTrackingPeriod() external view override returns (uint8) {}

function getAuctionResults() external view override returns (int256[] memory) {}

function getAuctionResultsNextIndex() external view override returns (uint8) {}

function setAuctionTrackingPeriod(uint8 newPeriod) external override {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,15 @@ contract ConvertibleDepositAuctioneerTest is Test {
uint256 public constant MIN_PRICE = 15e18;
uint256 public constant TARGET = 20e9;
uint48 public constant TIME_TO_EXPIRY = 1 days;
uint8 public constant AUCTION_TRACKING_PERIOD = 7;

// Events
event Activated();
event TickStepUpdated(uint24 newTickStep);
event TimeToExpiryUpdated(uint48 newTimeToExpiry);
event AuctionParametersUpdated(uint256 newTarget, uint256 newTickSize, uint256 newMinPrice);
event AuctionTrackingPeriodUpdated(uint8 newAuctionTrackingPeriod);
event AuctionResult(uint256 ohmConvertible, uint256 target, uint8 periodIndex);

function setUp() public {
vm.warp(INITIAL_BLOCK);
Expand Down Expand Up @@ -127,6 +130,38 @@ contract ConvertibleDepositAuctioneerTest is Test {
assertEq(tick.lastUpdate, lastUpdate_, "previous tick lastUpdate");
}

function _assertDayState(uint256 deposits_, uint256 convertible_) internal {
IConvertibleDepositAuctioneer.Day memory day = auctioneer.getDayState();

assertEq(day.deposits, deposits_, "deposits");
assertEq(day.convertible, convertible_, "convertible");
}

function _assertAuctionResults(
int256 resultOne_,
int256 resultTwo_,
int256 resultThree_,
int256 resultFour_,
int256 resultFive_,
int256 resultSix_,
int256 resultSeven_
) internal {
int256[] memory auctionResults = auctioneer.getAuctionResults();

assertEq(auctionResults.length, 7, "auction results length");
assertEq(auctionResults[0], resultOne_, "result one");
assertEq(auctionResults[1], resultTwo_, "result two");
assertEq(auctionResults[2], resultThree_, "result three");
assertEq(auctionResults[3], resultFour_, "result four");
assertEq(auctionResults[4], resultFive_, "result five");
assertEq(auctionResults[5], resultSix_, "result six");
assertEq(auctionResults[6], resultSeven_, "result seven");
}

function _assertAuctionResultsNextIndex(uint8 nextIndex_) internal {
assertEq(auctioneer.getAuctionResultsNextIndex(), nextIndex_, "next index");
}

// ========== MODIFIERS ========== //

modifier givenContractActive() {
Expand Down Expand Up @@ -197,7 +232,14 @@ contract ConvertibleDepositAuctioneerTest is Test {

modifier givenInitialized() {
vm.prank(admin);
auctioneer.initialize(TARGET, TICK_SIZE, MIN_PRICE, TICK_STEP, TIME_TO_EXPIRY);
auctioneer.initialize(
TARGET,
TICK_SIZE,
MIN_PRICE,
TICK_STEP,
TIME_TO_EXPIRY,
AUCTION_TRACKING_PERIOD
);
_;
}

Expand All @@ -220,15 +262,19 @@ contract ConvertibleDepositAuctioneerTest is Test {
auctioneer.bid(deposit_);
}

modifier givenRecipientHasBid(uint256 deposit_) {
function _mintAndBid(address owner_, uint256 deposit_) internal {
// Mint
_mintReserveToken(recipient, deposit_);
_mintReserveToken(owner_, deposit_);

// Approve spending
_approveReserveTokenSpending(recipient, address(convertibleDepository), deposit_);
_approveReserveTokenSpending(owner_, address(convertibleDepository), deposit_);

// Bid
_bid(recipient, deposit_);
_bid(owner_, deposit_);
}

modifier givenRecipientHasBid(uint256 deposit_) {
_mintAndBid(recipient, deposit_);
_;
}
}
33 changes: 19 additions & 14 deletions src/test/policies/ConvertibleDepositAuctioneer/activate.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ contract ConvertibleDepositAuctioneerActivateTest is ConvertibleDepositAuctionee
// given the contract is not initialized
// [X] it reverts
// when the contract is already activated
// [X] the state is unchanged
// [X] it does not emit an event
// [X] it does not change the last update
// [X] it reverts
// when the contract is not activated
// [X] it activates the contract
// [X] it emits an event
// [X] it sets the last update to the current block timestamp
// [X] it resets the day state
// [X] it resets the auction results history and index

function test_callerDoesNotHaveEmergencyShutdownRole_reverts(address caller_) public {
// Ensure caller is not emergency address
Expand All @@ -43,23 +43,23 @@ contract ConvertibleDepositAuctioneerActivateTest is ConvertibleDepositAuctionee
auctioneer.activate();
}

function test_contractActivated() public givenInitialized {
uint48 lastUpdate = uint48(block.timestamp);

// Warp to change the block timestamp
vm.warp(lastUpdate + 1);
function test_contractActivated_reverts() public givenInitialized {
// Expect revert
vm.expectRevert(
abi.encodeWithSelector(IConvertibleDepositAuctioneer.CDAuctioneer_InvalidState.selector)
);

// Call function
vm.prank(emergency);
auctioneer.activate();

// Assert state
assertEq(auctioneer.locallyActive(), true);
// lastUpdate has not changed
assertEq(auctioneer.getPreviousTick().lastUpdate, lastUpdate);
}

function test_contractInactive() public givenInitialized givenContractInactive {
function test_contractInactive()
public
givenInitialized
givenRecipientHasBid(1e18)
givenContractInactive
{
uint48 lastUpdate = uint48(block.timestamp);
uint48 newBlock = lastUpdate + 1;

Expand All @@ -78,5 +78,10 @@ contract ConvertibleDepositAuctioneerActivateTest is ConvertibleDepositAuctionee
assertEq(auctioneer.locallyActive(), true);
// lastUpdate has changed
assertEq(auctioneer.getPreviousTick().lastUpdate, newBlock);
// Day state is reset
_assertDayState(0, 0);
// Auction results are reset
_assertAuctionResults(0, 0, 0, 0, 0, 0, 0);
_assertAuctionResultsNextIndex(0);
}
}
5 changes: 4 additions & 1 deletion src/test/policies/ConvertibleDepositAuctioneer/bid.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ contract ConvertibleDepositAuctioneerBidTest is ConvertibleDepositAuctioneerTest
// [X] it sets the current tick size to the standard tick size
// [X] it does not update the tick price
// when the bid is the first bid of the day
// [X] it resets the day's deposit and converted balances
// [X] the day state is not reset
// [X] it updates the day's deposit balance
// [X] it updates the day's converted balance
// [X] it sets the current tick size to the standard tick size
Expand Down Expand Up @@ -312,6 +312,9 @@ contract ConvertibleDepositAuctioneerBidTest is ConvertibleDepositAuctioneerTest
uint48 nextDay = uint48(block.timestamp) + 1 days;
vm.warp(nextDay);

// Mimic auction parameters being set
_setAuctionParameters(TARGET, TICK_SIZE, MIN_PRICE);

// Get the current tick for the new day
IConvertibleDepositAuctioneer.Tick memory beforeTick = auctioneer.getCurrentTick();

Expand Down
Loading

0 comments on commit 2663fb0

Please sign in to comment.