-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Commit types folder that was initially ignore by .gitignore
- Loading branch information
1 parent
b4a70c5
commit 7bf74a2
Showing
1 changed file
with
143 additions
and
0 deletions.
There are no files selected for viewing
143 changes: 143 additions & 0 deletions
143
...ppelin-contracts-upgradeable-v5/lib/openzeppelin-contracts/contracts/utils/types/Time.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
// SPDX-License-Identifier: MIT | ||
// OpenZeppelin Contracts (last updated v5.0.0) (utils/types/Time.sol) | ||
|
||
pragma solidity ^0.8.20; | ||
|
||
import {Math} from "../math/Math.sol"; | ||
import {SafeCast} from "../math/SafeCast.sol"; | ||
|
||
/** | ||
* @dev This library provides helpers for manipulating time-related objects. | ||
* | ||
* It uses the following types: | ||
* - `uint48` for timepoints | ||
* - `uint32` for durations | ||
* | ||
* While the library doesn't provide specific types for timepoints and duration, it does provide: | ||
* - a `Delay` type to represent duration that can be programmed to change value automatically at a given point | ||
* - additional helper functions | ||
*/ | ||
library Time { | ||
using Time for *; | ||
|
||
/** | ||
* @dev Get the block timestamp as a Timepoint. | ||
*/ | ||
function timestamp() internal view returns (uint48) { | ||
return SafeCast.toUint48(block.timestamp); | ||
} | ||
|
||
/** | ||
* @dev Get the block number as a Timepoint. | ||
*/ | ||
function blockNumber() internal view returns (uint48) { | ||
return SafeCast.toUint48(block.number); | ||
} | ||
|
||
// ==================================================== Delay ===================================================== | ||
/** | ||
* @dev A `Delay` is a uint32 duration that can be programmed to change value automatically at a given point in the | ||
* future. The "effect" timepoint describes when the transitions happens from the "old" value to the "new" value. | ||
* This allows updating the delay applied to some operation while keeping some guarantees. | ||
* | ||
* In particular, the {update} function guarantees that if the delay is reduced, the old delay still applies for | ||
* some time. For example if the delay is currently 7 days to do an upgrade, the admin should not be able to set | ||
* the delay to 0 and upgrade immediately. If the admin wants to reduce the delay, the old delay (7 days) should | ||
* still apply for some time. | ||
* | ||
* | ||
* The `Delay` type is 112 bits long, and packs the following: | ||
* | ||
* ``` | ||
* | [uint48]: effect date (timepoint) | ||
* | | [uint32]: value before (duration) | ||
* ↓ ↓ ↓ [uint32]: value after (duration) | ||
* 0xAAAAAAAAAAAABBBBBBBBCCCCCCCC | ||
* ``` | ||
* | ||
* NOTE: The {get} and {withUpdate} functions operate using timestamps. Block number based delays are not currently | ||
* supported. | ||
*/ | ||
type Delay is uint112; | ||
|
||
/** | ||
* @dev Wrap a duration into a Delay to add the one-step "update in the future" feature | ||
*/ | ||
function toDelay(uint32 duration) internal pure returns (Delay) { | ||
return Delay.wrap(duration); | ||
} | ||
|
||
/** | ||
* @dev Get the value at a given timepoint plus the pending value and effect timepoint if there is a scheduled | ||
* change after this timepoint. If the effect timepoint is 0, then the pending value should not be considered. | ||
*/ | ||
function _getFullAt(Delay self, uint48 timepoint) | ||
private | ||
pure | ||
returns (uint32, uint32, uint48) | ||
{ | ||
(uint32 valueBefore, uint32 valueAfter, uint48 effect) = self.unpack(); | ||
return effect <= timepoint ? (valueAfter, 0, 0) : (valueBefore, valueAfter, effect); | ||
} | ||
|
||
/** | ||
* @dev Get the current value plus the pending value and effect timepoint if there is a scheduled change. If the | ||
* effect timepoint is 0, then the pending value should not be considered. | ||
*/ | ||
function getFull(Delay self) internal view returns (uint32, uint32, uint48) { | ||
return _getFullAt(self, timestamp()); | ||
} | ||
|
||
/** | ||
* @dev Get the current value. | ||
*/ | ||
function get(Delay self) internal view returns (uint32) { | ||
(uint32 delay,,) = self.getFull(); | ||
return delay; | ||
} | ||
|
||
/** | ||
* @dev Update a Delay object so that it takes a new duration after a timepoint that is automatically computed to | ||
* enforce the old delay at the moment of the update. Returns the updated Delay object and the timestamp when the | ||
* new delay becomes effective. | ||
*/ | ||
function withUpdate(Delay self, uint32 newValue, uint32 minSetback) | ||
internal | ||
view | ||
returns (Delay updatedDelay, uint48 effect) | ||
{ | ||
uint32 value = self.get(); | ||
uint32 setback = uint32(Math.max(minSetback, value > newValue ? value - newValue : 0)); | ||
effect = timestamp() + setback; | ||
return (pack(value, newValue, effect), effect); | ||
} | ||
|
||
/** | ||
* @dev Split a delay into its components: valueBefore, valueAfter and effect (transition timepoint). | ||
*/ | ||
function unpack(Delay self) | ||
internal | ||
pure | ||
returns (uint32 valueBefore, uint32 valueAfter, uint48 effect) | ||
{ | ||
uint112 raw = Delay.unwrap(self); | ||
|
||
valueAfter = uint32(raw); | ||
valueBefore = uint32(raw >> 32); | ||
effect = uint48(raw >> 64); | ||
|
||
return (valueBefore, valueAfter, effect); | ||
} | ||
|
||
/** | ||
* @dev pack the components into a Delay object. | ||
*/ | ||
function pack(uint32 valueBefore, uint32 valueAfter, uint48 effect) | ||
internal | ||
pure | ||
returns (Delay) | ||
{ | ||
return | ||
Delay.wrap((uint112(effect) << 64) | (uint112(valueBefore) << 32) | uint112(valueAfter)); | ||
} | ||
} |