Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
e76d230a
Unverified
Commit
e76d230a
authored
Sep 08, 2023
by
Maurelian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(ctb): Add the delay.
parent
2c7cfb80
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
84 additions
and
20 deletions
+84
-20
DelayedVetoable.sol
packages/contracts-bedrock/src/universal/DelayedVetoable.sol
+46
-11
DelayedVetoable.t.sol
packages/contracts-bedrock/test/DelayedVetoable.t.sol
+38
-9
No files found.
packages/contracts-bedrock/src/universal/DelayedVetoable.sol
View file @
e76d230a
...
...
@@ -5,17 +5,36 @@ pragma solidity ^0.8.15;
import { console } from "forge-std/console.sol";
contract DelayedVetoable {
/// @notice Error for when attempting to forward too early.
error ForwardingEarly();
/// @notice Error for the target is not set.
error TargetUnitialized();
/// @notice An event that is emitted when a call is initiated.
/// @param callHash The hash of the call data.
/// @param data The data of the initiated call.
event Initiated(bytes32 indexed callHash, bytes data);
/// @notice An event that is emitted each time a call is forwarded.
/// @param data The address of the implementation contract
event Forwarded(bytes data);
/// @param callHash The hash of the call data.
/// @param data The data forwarded to the target.
event Forwarded(bytes32 indexed callHash, bytes data);
/// @notice The address that all calls are forwarded to after the delay.
address internal _target;
/// @notice The time that a call was initiated.
mapping(bytes32 => uint256) internal _queuedAt;
/// @notice The time to wait before forwarding a call.
uint256 internal _delay;
/// @notice Sets the target admin during contract deployment.
/// @param target Address of the target.
constructor(address target) {
constructor(address target
, uint256 delay
) {
_target = target;
_delay = delay;
}
/// @notice Used when no data is passed to the contract.
...
...
@@ -30,16 +49,32 @@ contract DelayedVetoable {
/// @notice Handles forwards the call to the target.
function _handleCall() internal {
require(_target != address(0), "DelayedVetoable: target not initialized");
if (_target == address(0)) {
revert TargetUnitialized();
}
bytes32 callHash = keccak256(msg.data);
if (_queuedAt[callHash] == 0) {
_queuedAt[callHash] = block.timestamp;
emit Initiated(callHash, msg.data);
} else if (_queuedAt[callHash] + _delay < block.timestamp) {
// Not enough time has passed, so we'll revert.
revert ForwardingEarly();
} else {
// sufficient time has passed.
// Delete the call to prevent replays
delete _queuedAt[callHash];
emit Forwarded(msg.data);
(bool success,) = _target.call(msg.data);
assembly {
// Success == 0 means a revert. We'll revert too and pass the data up.
if iszero(success) { revert(0x0, returndatasize()) }
// Forward the call
emit Forwarded(callHash, msg.data);
(bool success,) = _target.call(msg.data);
assembly {
// Success == 0 means a revert. We'll revert too and pass the data up.
if iszero(success) { revert(0x0, returndatasize()) }
// Otherwise we'll just return and pass the data up.
return(0x0, returndatasize())
// Otherwise we'll just return and pass the data up.
return(0x0, returndatasize())
}
}
}
}
packages/contracts-bedrock/test/DelayedVetoable.t.sol
View file @
e76d230a
...
...
@@ -5,38 +5,67 @@ import { CommonTest, Reverter } from "./CommonTest.t.sol";
import { DelayedVetoable } from "../src/universal/DelayedVetoable.sol";
contract DelayedVetoable_Init is CommonTest {
event Forwarded(bytes data);
event Initiated(bytes32 indexed callHash, bytes data);
event Forwarded(bytes32 indexed callHash, bytes data);
address target = address(0xabba);
uint256 delay = 14 days;
DelayedVetoable delayedVetoable;
Reverter reverter;
function setUp() public override {
super.setUp();
delayedVetoable = new DelayedVetoable({
target: address(target)
target: address(target),
delay: delay
});
reverter = new Reverter();
}
}
contract DelayedVetoable_HandleCall_Test is DelayedVetoable_Init {
function testFuzz_handleCall_succeeds(bytes memory data) external {
vm.expectCall(target, data);
function testFuzz_handleCall_initiation_succeeds(bytes memory data) external {
vm.expectEmit(true, false, false, true, address(delayedVetoable));
emit
Forwarded(
data);
emit
Initiated(keccak256(data),
data);
(bool success,) = address(delayedVetoable).call(data);
assert(success);
}
function testFuzz_handleCall_forwarding_succeeds(bytes memory data) external {
// Initiate the call
(bool success,) = address(delayedVetoable).call(data);
vm.warp(block.timestamp + delay);
vm.expectEmit(true, false, false, true, address(delayedVetoable));
emit Forwarded(keccak256(data), data);
vm.expectCall({ callee: target, data: data });
(success,) = address(delayedVetoable).call(data);
assert(success);
}
}
contract DelayedVetoable_HandleCall_TestFail is DelayedVetoable_Init {
function test_handleCall_reverts() external {
vm.expectCall(target, NON_ZERO_DATA);
function test_handleCall_forwardingTooSoon_reverts(bytes memory data) external {
(bool success,) = address(delayedVetoable).call(data);
vm.expectRevert();
// including data will call the fallback
(bool success,) = address(delayedVetoable).call(NON_ZERO_DATA);
(success,) = address(delayedVetoable).call(data);
assertFalse(success);
}
function test_handleCall_forwardingTargetReverts_reverts(bytes memory data) external {
vm.etch(target, address(reverter).code);
(bool success,) = address(delayedVetoable).call(data);
vm.warp(block.timestamp + delay);
vm.expectEmit(true, false, false, true, address(delayedVetoable));
emit Forwarded(keccak256(data), data);
vm.expectCall({ callee: target, data: data });
(success,) = address(delayedVetoable).call(data);
assertFalse(success);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment