Skip to content

Commit

Permalink
Merge pull request #30 from GenerationSoftware/gen-1082-add-emergency…
Browse files Browse the repository at this point in the history
…-shutdown-mode-to-the-prize-pool

Added public functions to check whether shutdown
  • Loading branch information
asselstine committed Jan 30, 2024
2 parents bc3d860 + 8f024f3 commit 258ab89
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 10 deletions.
19 changes: 19 additions & 0 deletions src/TwabController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,25 @@ contract TwabController {

/* ============ External Read Functions ============ */

/**
* @notice Returns whether the TwabController has been shutdown at the given timestamp
* If the twab is queried at or after this time, whether an absolute timestamp or time range, it will return 0.
* @dev This function will return true for any timestamp after the lastObservationAt()
* @param timestamp The timestamp to check
* @return True if the TwabController is shutdown at the given timestamp, false otherwise.
*/
function isShutdownAt(uint256 timestamp) external view returns (bool) {
return TwabLib.isShutdownAt(timestamp, PERIOD_OFFSET);
}

/**
* @notice Computes the timestamp after which no more observations will be made.
* @return The largest timestamp at which the TwabController can record a new observation.
*/
function lastObservationAt() external view returns (uint256) {
return TwabLib.lastObservationAt(PERIOD_OFFSET);
}

/**
* @notice Loads the current TWAB Account data for a specific vault stored for a user.
* @dev Note this is a very expensive function
Expand Down
44 changes: 34 additions & 10 deletions src/libraries/TwabLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ library TwabLib {
// record a new observation if the delegateAmount is non-zero and time has not overflowed.
isObservationRecorded =
_delegateAmount != uint96(0) &&
(block.timestamp - PERIOD_OFFSET) <= type(uint32).max;
block.timestamp <= lastObservationAt(PERIOD_OFFSET);

accountDetails.balance += _amount;
accountDetails.delegateBalance += _delegateAmount;
Expand Down Expand Up @@ -172,7 +172,7 @@ library TwabLib {
// record a new observation if the delegateAmount is non-zero and time has not overflowed.
isObservationRecorded =
_delegateAmount != uint96(0) &&
(block.timestamp - PERIOD_OFFSET) <= type(uint32).max;
block.timestamp <= lastObservationAt(PERIOD_OFFSET);

unchecked {
accountDetails.balance -= _amount;
Expand Down Expand Up @@ -250,19 +250,43 @@ library TwabLib {
if (_targetTime < PERIOD_OFFSET) {
return 0;
}
uint256 offsetTargetTime = _targetTime - PERIOD_OFFSET;
// if this is for an overflowed time period, return 0
if (offsetTargetTime > type(uint32).max) {
if (isShutdownAt(_targetTime, PERIOD_OFFSET)) {
return 0;
}
ObservationLib.Observation memory prevOrAtObservation = _getPreviousOrAtObservation(
_observations,
_accountDetails,
PeriodOffsetRelativeTimestamp.wrap(uint32(offsetTargetTime))
PeriodOffsetRelativeTimestamp.wrap(uint32(_targetTime - PERIOD_OFFSET))
);
return prevOrAtObservation.balance;
}

/**
* @notice Returns whether the TwabController has been shutdown at the given timestamp
* If the twab is queried at or after this time, whether an absolute timestamp or time range, it will return 0.
* @param timestamp The timestamp to check
* @param PERIOD_OFFSET The offset of the first period
* @return True if the TwabController is shutdown at the given timestamp, false otherwise.
*/
function isShutdownAt(
uint256 timestamp,
uint32 PERIOD_OFFSET
) internal pure returns (bool) {
return timestamp > lastObservationAt(PERIOD_OFFSET);
}

/**
* @notice Computes the largest timestamp at which the TwabController can record a new observation.
* @param PERIOD_OFFSET The offset of the first period
* @return The largest timestamp at which the TwabController can record a new observation.
*/
function lastObservationAt(
uint32 PERIOD_OFFSET
) internal pure returns (uint256) {
return uint256(PERIOD_OFFSET) + type(uint32).max;
}

/**
* @notice Looks up a users TWAB for a time range. The time must be before the current overwrite period.
* @dev If the timestamps in the range are not exact matches of observations, the balance is extrapolated using the previous observation.
Expand All @@ -286,14 +310,14 @@ library TwabLib {
revert InvalidTimeRange(_startTime, _endTime);
}

uint256 offsetStartTime = _startTime - PERIOD_OFFSET;
uint256 offsetEndTime = _endTime - PERIOD_OFFSET;

// if the either time has overflowed, then return 0.
if (offsetStartTime > type(uint32).max || offsetEndTime > type(uint32).max) {
// if the range extends into the shutdown period, return 0
if (isShutdownAt(_endTime, PERIOD_OFFSET)) {
return 0;
}

uint256 offsetStartTime = _startTime - PERIOD_OFFSET;
uint256 offsetEndTime = _endTime - PERIOD_OFFSET;

ObservationLib.Observation memory endObservation = _getPreviousOrAtObservation(
_observations,
_accountDetails,
Expand Down
11 changes: 11 additions & 0 deletions test/TwabController.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,17 @@ contract TwabControllerTest is BaseTest {
vm.stopPrank();
}

function testIsShutdownAt() public {
assertEq(twabController.isShutdownAt(PERIOD_OFFSET), false, "at beginning");
assertEq(twabController.isShutdownAt(PERIOD_OFFSET + PERIOD_LENGTH), false, "after first period");
assertEq(twabController.isShutdownAt(type(uint32).max + uint256(PERIOD_OFFSET)), false, "at end");
assertEq(twabController.isShutdownAt(type(uint32).max + uint256(PERIOD_OFFSET) + 1), true, "after end");
}

function testLastObservationAt() public {
assertEq(twabController.lastObservationAt(), uint256(PERIOD_OFFSET) + type(uint32).max);
}

function testGetBalanceAt_beforeHistoryStarted() public {
// ensure times are finalized
vm.warp(PERIOD_OFFSET + PERIOD_LENGTH);
Expand Down

0 comments on commit 258ab89

Please sign in to comment.