delegatecall based proxy with an enforced delay
ds-pause allows authorized users to schedule function calls that can only be executed once some
predetermined waiting period has elapsed. The configurable delay attribute sets the minimum wait
time.
ds-pause is designed to be used as a component in a governance system, to give affected parties
time to respond to decisions. If those affected by governance decisions have e.g. exit or veto
rights, then the pause can serve as an effective check on governance power.
A plan describes a single delegatecall operation and a unix timestamp eta before which it
cannot be executed.
A plan consists of:
usr: address todelegatecallintotag: the expected codehash ofusrfax:calldatato useeta: first possible time of execution (as seconds since unix epoch)
Each plan has a unique id, defined as keccack256(abi.encode(usr, tag, fax, eta))
Plans can be manipulated in the following ways:
plot: schedule aplanexec: execute aplandrop: cancel aplan
A break of any of the following would be classified as a critical issue. Please submit bug reports to [email protected].
high level
- There is no way to bypass the delay
- The code executed by the
delegatecallcannot directly modify storage on the pause - The pause will always retain ownership of it's
proxy
admin
authority,owner, anddelaycan only be changed if an authorized user plots aplanto do so
plot
- A
plancan only be plotted if itsetais afterblock.timestamp + delay - A
plancan only be plotted by authorized users
exec
- A
plancan only be executed if it has previously been plotted - A
plancan only be executed once it'setahas passed - A
plancan only be executed if itstagmatchesextcodehash(usr) - A
plancan only be executed once - A
plancan be executed by anyone
drop
- A
plancan only be dropped by authorized users
In order to protect the internal storage of the pause from malicious writes during plan execution,
we perform the actual delegatecall operation in a seperate contract with an isolated storage
context (DSPauseProxy). Each pause has it's own individual proxy.
This means that plan's are executed with the identity of the proxy, and when integrating the
pause into some auth scheme, you probably want to trust the pause's proxy and not the pause
itself.
// construct the pause
uint delay = 2 days;
address owner = address(0);
DSAuthority authority = new DSAuthority();
DSPause pause = new DSPause(delay, owner, authority);
// plot the plan
address usr = address(0x0);
bytes32 tag; assembly { tag := extcodehash(usr) }
bytes memory fax = abi.encodeWithSignature("sig()");
uint eta = now + delay;
pause.plot(usr, tag, fax, eta);// wait until block.timestamp is at least now + delay...
// and then execute the plan
bytes memory out = pause.exec(usr, tag, fax, eta);pause.t.sol: unit testsintegration.t.sol: usage examples / integation tests