-
Notifications
You must be signed in to change notification settings - Fork 11.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
coded pauseFor(uint time)
functionality for Pausable.sol
#5378
Comments
This seems like a reasonable feature request to me. Feel free to make a PR and we will try to have more constructive comments there. |
This would probably be a good fit for a contribution to the community repository: https://github.com/openZeppelin/openzeppelin-community-contracts |
IMO uint48 private _pausedUntil;
function _pauseUntil(uint48 until) internal virtual whenNotPaused {
// checks ?
_pausedUntil = until;
// emit event
}
function _unpause() internal virtual override {
super._unpause(); // includes whenPaused
_pausedUntil = 0;
}
function paused() public view virtual overide returns (bool) {
return _paused || _pausedUntil > clock(); // from IERC6372
} |
Hi @Amxx and @arr00 thanks for the feedback and I'm glad my idea was deemed useful. 2 things.
Also I like the specifying the deadline instead of the duration of the pause, changing the name from I've been developing a bit more to adapt to this improvements and also use the mentioned IERC6372. But I found myself a compatibility issue with some inheritance mock on that uses If I implement the clock like this it will give inheritance tree linearization errors at compile time for some mocks. So I thought of creating a new That is the cleanest solution I've thought so far on how to arrange the new
|
Please make a PR to the community repo ! |
Done :D |
Summary 📓
I've re-factored, in a backwards compatible way, the
Pausable.sol
contract to allow developers to optionally support apauseFor(uint time)
functionality.All tested and coded in this fork: my fork
Motivation 🧐
It is common to use the
Pausable.sol
contract in a project with some special permissions to 1 or more addresses.However, as of now it exists the danger of pausing forever. The simplest example is if the only permissioned address losses its private key while the contract was paused.
Another more complex real-example I came across while auditing and which motivated me to propose this change is the following:
Conclusion 🔚
As protocols evolve in complexity and more complex role structures and permissions are created, the risk of pausing something forever won't be lower but higher. Thus, I consider useful this re-factored
Pausable.sol
contract to allow developers to optionally support apauseFor()
functionality.Technical Details 💻
The amount of state slots used remains unchanged. Only the first one. And new values do not override previous values as:
Previous values: 0 or 1 on the least significant bit.
New values: 0 or 1 on the least significant bit, and the remaining 248 bytes are used for duration amounts when using
pauseFor()
.This makes proxies who desire to implement this functionality easily updateable.
As per the usual
Pasuable.sol
, all new functionalities have been created using internal functions, thus if the project usingPausable.sol
thinks they do not need the extrapauseFor()
functionality they can just never call it and the compiler won't include it in the final bytecode.How it works ⚙️
_pauseFor(uint time)
: Allows the addresses capable of pausing to pause for "at most"time
seconds if the contract is not paused already.This action can be unpaused anytime by
_unpause()
or ONLY WHEN TIME HAS ELAPSED by_unpauseAfterPausedFor()
.It is up to the project to decide if to allow earlier unpausing of
_pauseFor()
through_unapuse()
or not. If not done the code will be paused until the time has elapsed.Ideally the projects should make
_unpauseAfterPausedFor()
callable by anyone, this function allows unpausing actions started withpauseFor(uint time)
aftertime
seconds have passed.Code changes 📜
0️⃣ The only state
bool private _paused;
now isuint256 private _pausedInfo;
with the back-wards compatible structure explained earlier.1️⃣ 3 functions, 1 event and 1 error added are:
function _pauseFor(uint256 time) internal virtual whenNotPaused
function _unpauseAfterPausedFor() internal virtual whenPaused
function _unpauseDeadline() internal view virtual returns (uint256)
event PausedFor(address account, uint256 duration);
error PauseDurationNotElapsed();
2️⃣
SafeCast.sol
library is now used to safelytoUint248()
when manipulating slot data-structure.3️⃣ For readability when manipulating the slot, 2 constants have been added to the file:
uint8 constant PAUSED = 1;
uint8 constant PAUSE_DURATION_OFFSET = 8;
4️⃣ None already existing functions were deleted, they have only been modified to adapt to the new data structure in the slot.
5️⃣ New test cases have been added to account for new
pauseFor()
execution flows:pasuedFor
and then unpaused with classic_unpause()
interactions.pasuedFor
and then unpaused with_unpauseAfterPausedFor()
interactions.pausedFor
and then classic_pause
interactions._pause
and thenpauseFor
interactions._pause
and then_unpauseAfterPausedFor
interactions._unpause()
and thenpauseFor
interactions._unpause()
and then_unpauseAfterPausedFor
interactions.The text was updated successfully, but these errors were encountered: