Skip to content

Commit de89798

Browse files
gonzaotcernestognw
andauthored
Add docs for the Time library (#5684)
Co-authored-by: Ernesto García <[email protected]>
1 parent ccde353 commit de89798

File tree

2 files changed

+81
-0
lines changed

2 files changed

+81
-0
lines changed

contracts/utils/README.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ Miscellaneous contracts and libraries containing utility functions you can use t
4949
* {AbstractSigner}: Abstract contract for internal signature validation in smart contracts.
5050
* {ERC7739}: An abstract contract to validate signatures following the rehashing scheme from `ERC7739Utils`.
5151
* {ERC7739Utils}: Utilities library that implements a defensive rehashing mechanism to prevent replayability of smart contract signatures based on ERC-7739.
52+
* {Time}: A library that provides helpers for manipulating time-related objects, including a `Delay` type.
5253

5354
[NOTE]
5455
====
@@ -170,3 +171,5 @@ Ethereum contracts have no native concept of an interface, so applications must
170171
{{CAIP10}}
171172

172173
{{Blockhash}}
174+
175+
{{Time}}

docs/modules/ROOT/pages/utilities.adoc

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,3 +405,81 @@ contract L1Inbox {
405405
----
406406

407407
IMPORTANT: After EIP-2935 activation, it takes 8,191 blocks to completely fill the history storage. Before that, only block hashes since the fork block will be available.
408+
409+
=== Time
410+
411+
The xref:api:utils.adoc#Time[`Time`] library provides helpers for manipulating time-related objects in a type-safe manner. It uses `uint48` for timepoints and `uint32` for durations, helping to reduce gas costs while providing adequate precision.
412+
413+
One of its key features is the `Delay` type, which represents a duration that can automatically change its value at a specified point in the future while maintaining delay guarantees. For example, when reducing a delay value (e.g., from 7 days to 1 day), the change only takes effect after the difference between the old and new delay (i.e. a 6 days) or a minimum setback period, preventing an attacker who gains admin access from immediately reducing security timeouts and executing sensitive operations. This is particularly useful for governance and security mechanisms where timelock periods need to be enforced.
414+
415+
Consider this example for using and safely updating Delays:
416+
[source,solidity]
417+
----
418+
// SPDX-License-Identifier: MIT
419+
pragma solidity ^0.8.27;
420+
421+
import {Time} from "contracts/utils/types/Time.sol";
422+
423+
contract MyDelayedContract {
424+
using Time for *;
425+
426+
Time.Delay private _delay;
427+
428+
constructor() {
429+
_delay = Time.toDelay(3 days);
430+
}
431+
432+
function schedule(bytes32 operationId) external {
433+
// Get the current `_delay` value, respecting any pending delay changes if they've taken effect
434+
uint32 currentDelay = _delay.get();
435+
uint48 executionTime = Time.timestamp() + currentDelay;
436+
437+
// ... schedule the operation at `executionTime`
438+
}
439+
440+
function execute(bytes32 operationId) external {
441+
uint48 executionTime = getExecutionTime(operationId);
442+
require(executionTime > 0, "Operation not scheduled");
443+
require(Time.timestamp() >= executionTime, "Delay not elapsed yet");
444+
445+
// ... execute the operation
446+
}
447+
448+
// Update the delay with `Time`'s safety mechanism
449+
function updateDelay(uint32 newDelay) external {
450+
(Time.Delay updatedDelay, uint48 effect) = _delay.withUpdate(
451+
newDelay, // The new delay value
452+
5 days // Minimum setback if reducing the delay
453+
);
454+
455+
_delay = updatedDelay;
456+
457+
// ... emit events
458+
}
459+
460+
// Get complete delay details including pending changes
461+
function getDelayDetails() external view returns (
462+
uint32 currentValue, // The current delay value
463+
uint32 pendingValue, // The pending delay value
464+
uint48 effectTime // The timepoint when the pending delay change takes effect
465+
) {
466+
return _delay.getFull();
467+
}
468+
}
469+
----
470+
471+
This pattern is used extensively in OpenZeppelin's xref:api:access.adoc#AccessManager[AccessManager] for implementing secure time-based access control. For example, when changing an admin delay:
472+
473+
[source,solidity]
474+
----
475+
// From AccessManager.sol
476+
function _setTargetAdminDelay(address target, uint32 newDelay) internal virtual {
477+
uint48 effect;
478+
(_targets[target].adminDelay, effect) = _targets[target].adminDelay.withUpdate(
479+
newDelay,
480+
minSetback()
481+
);
482+
483+
emit TargetAdminDelayUpdated(target, newDelay, effect);
484+
}
485+
----

0 commit comments

Comments
 (0)