diff --git a/src/TwabController.sol b/src/TwabController.sol index d6fc375..b16b211 100644 --- a/src/TwabController.sol +++ b/src/TwabController.sol @@ -179,7 +179,7 @@ contract TwabController { * @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); + return TwabLib.isShutdownAt(timestamp, PERIOD_LENGTH, PERIOD_OFFSET); } /** @@ -187,7 +187,7 @@ contract TwabController { * @return The largest timestamp at which the TwabController can record a new observation. */ function lastObservationAt() external view returns (uint256) { - return TwabLib.lastObservationAt(PERIOD_OFFSET); + return TwabLib.lastObservationAt(PERIOD_LENGTH, PERIOD_OFFSET); } /** diff --git a/src/libraries/TwabLib.sol b/src/libraries/TwabLib.sol index 2193c28..5f074dd 100644 --- a/src/libraries/TwabLib.sol +++ b/src/libraries/TwabLib.sol @@ -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 <= lastObservationAt(PERIOD_OFFSET); + block.timestamp <= lastObservationAt(PERIOD_LENGTH, PERIOD_OFFSET); accountDetails.balance += _amount; accountDetails.delegateBalance += _delegateAmount; @@ -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 <= lastObservationAt(PERIOD_OFFSET); + block.timestamp <= lastObservationAt(PERIOD_LENGTH, PERIOD_OFFSET); unchecked { accountDetails.balance -= _amount; @@ -251,7 +251,7 @@ library TwabLib { return 0; } // if this is for an overflowed time period, return 0 - if (isShutdownAt(_targetTime, PERIOD_OFFSET)) { + if (isShutdownAt(_targetTime, PERIOD_LENGTH, PERIOD_OFFSET)) { return 0; } ObservationLib.Observation memory prevOrAtObservation = _getPreviousOrAtObservation( @@ -271,9 +271,10 @@ library TwabLib { */ function isShutdownAt( uint256 timestamp, + uint32 PERIOD_LENGTH, uint32 PERIOD_OFFSET ) internal pure returns (bool) { - return timestamp > lastObservationAt(PERIOD_OFFSET); + return timestamp > lastObservationAt(PERIOD_LENGTH, PERIOD_OFFSET); } /** @@ -282,9 +283,10 @@ library TwabLib { * @return The largest timestamp at which the TwabController can record a new observation. */ function lastObservationAt( + uint32 PERIOD_LENGTH, uint32 PERIOD_OFFSET ) internal pure returns (uint256) { - return uint256(PERIOD_OFFSET) + type(uint32).max; + return uint256(PERIOD_OFFSET) + (type(uint32).max / PERIOD_LENGTH) * PERIOD_LENGTH; } /** @@ -311,7 +313,7 @@ library TwabLib { } // if the range extends into the shutdown period, return 0 - if (isShutdownAt(_endTime, PERIOD_OFFSET)) { + if (isShutdownAt(_endTime, PERIOD_LENGTH, PERIOD_OFFSET)) { return 0; } diff --git a/test/TwabController.t.sol b/test/TwabController.t.sol index 1ea19dd..8c2caed 100644 --- a/test/TwabController.t.sol +++ b/test/TwabController.t.sol @@ -148,12 +148,13 @@ contract TwabControllerTest is BaseTest { 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/PERIOD_LENGTH)*PERIOD_LENGTH + uint256(PERIOD_OFFSET)), false, "at end of last period"); + assertEq(twabController.isShutdownAt(type(uint32).max + uint256(PERIOD_OFFSET)), true, "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); + assertEq(twabController.lastObservationAt(), uint256(PERIOD_OFFSET) + (type(uint32).max/PERIOD_LENGTH)*PERIOD_LENGTH); } function testGetBalanceAt_beforeHistoryStarted() public { @@ -948,6 +949,18 @@ contract TwabControllerTest is BaseTest { assertEq(twabController.delegateOf(mockVault, alice), bob); } + function testMint_lastObservation() public { + vm.startPrank(mockVault); + uint96 _amount = 1000e18; + uint lastAt = twabController.lastObservationAt(); + console2.log("LAST AT", lastAt); + vm.warp(lastAt); + twabController.mint(alice, _amount); + vm.warp(lastAt + PERIOD_LENGTH); + assertEq(twabController.getBalanceAt(mockVault, alice, lastAt), _amount); + vm.stopPrank(); + } + function testMint_toZero() public { vm.startPrank(mockVault); diff --git a/test/TwabLib.t.sol b/test/TwabLib.t.sol index f1de561..386b947 100644 --- a/test/TwabLib.t.sol +++ b/test/TwabLib.t.sol @@ -35,7 +35,7 @@ contract TwabLibTest is BaseTest { /* ============ increaseBalances ============ */ function testIncreaseBalance_endOfTimerange() public { - uint256 timestamp = PERIOD_OFFSET + uint256(type(uint32).max); + uint256 timestamp = twabLibMock.lastObservationAt(); vm.warp(timestamp); twabLibMock.increaseBalances(1000e18, 1000e18); vm.warp(uint256(type(uint48).max)); @@ -45,7 +45,7 @@ contract TwabLibTest is BaseTest { function testDecreaseBalance_endOfTimerange() public { vm.warp(PERIOD_OFFSET); twabLibMock.increaseBalances(1000e18, 1000e18); - uint256 timestamp = PERIOD_OFFSET + uint256(type(uint32).max); + uint256 timestamp = twabLibMock.lastObservationAt(); vm.warp(timestamp); twabLibMock.decreaseBalances(100e18, 100e18, "revert message"); vm.warp(uint256(type(uint48).max)); @@ -734,7 +734,7 @@ contract TwabLibTest is BaseTest { function testGetBalanceAt_endOfTimerange() public { twabLibMock.increaseBalances(0, 1e18); vm.warp(type(uint48).max); - assertEq(twabLibMock.getBalanceAt(PERIOD_OFFSET + uint256(type(uint32).max)), 1e18); + assertEq(twabLibMock.getBalanceAt(twabLibMock.lastObservationAt()), 1e18); } function testGetBalanceAt_outOfTimerange() public { diff --git a/test/invariants/handlers/TwabControllerHandler.sol b/test/invariants/handlers/TwabControllerHandler.sol index 26c60d2..87b95a3 100644 --- a/test/invariants/handlers/TwabControllerHandler.sol +++ b/test/invariants/handlers/TwabControllerHandler.sol @@ -320,7 +320,6 @@ contract TwabControllerHandler is CommonBase, StdCheats, StdUtils { function reduceFullRangeTwabs() external view returns (uint256, uint256) { uint256 vaultAcc = 0; uint256 actorAcc = 0; - ObservationLib.Observation memory newestActorObservation; ObservationLib.Observation memory newestObservation; // For Each Vault diff --git a/test/mocks/TwabLibMock.sol b/test/mocks/TwabLibMock.sol index 0d96793..f68f06d 100644 --- a/test/mocks/TwabLibMock.sol +++ b/test/mocks/TwabLibMock.sol @@ -160,4 +160,9 @@ contract TwabLibMock { bool isSafe = TwabLib.hasFinalized(PERIOD_LENGTH, PERIOD_OFFSET, _timestamp); return isSafe; } + + function lastObservationAt() external view returns (uint) { + uint result = TwabLib.lastObservationAt(PERIOD_LENGTH, PERIOD_OFFSET); + return result; + } }