Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
cf4270b
feat: implement configureTimelockGuard function
maurelian Sep 8, 2025
290ec17
feat: implement clearTimelockGuard function
maurelian Sep 8, 2025
ef1ccbd
refactor: extract guard checking logic to internal helper function
maurelian Sep 8, 2025
a95ed01
feat: implement cancellationThreshold function
maurelian Sep 9, 2025
a5054e6
feat: add placeholder functions for remaining TimelockGuard functiona…
maurelian Sep 9, 2025
6084abe
Self review fixes
maurelian Sep 9, 2025
e3121ca
Fix warnings on unimplemented functions
maurelian Sep 9, 2025
d117aa7
Fix names of test functions
maurelian Sep 9, 2025
56e366d
Satisfy semgrep by removing revert with string
maurelian Sep 9, 2025
4c79044
Remove arg names from unimplemented functions
maurelian Sep 9, 2025
3de308e
Snapshots
maurelian Sep 9, 2025
052e4e6
Add interface
maurelian Sep 9, 2025
54d5e92
Simplify cancellationThreshold() getter
maurelian Sep 10, 2025
afdbaf1
Replace _getGuard with isGuardEnabled
maurelian Sep 10, 2025
3f82d24
Allow a timelock delay of zero
maurelian Sep 10, 2025
cea893e
TimelockGuard: Add scheduleTransaction()
maurelian Sep 11, 2025
c90de48
Add todo note
maurelian Sep 11, 2025
c17a782
Pseudocode draft of a non-nested timelock
Sep 15, 2025
0d31d51
Remove signatures field from ExecTransactionParams
maurelian Sep 15, 2025
0562482
Refactor tests with improve utils (_getDummyTx, _getSignaturesForTx)
maurelian Sep 15, 2025
227f9eb
Test for TransactionCancelled event
maurelian Sep 15, 2025
e7f90ce
Further improve util functions
maurelian Sep 15, 2025
5b1cfcc
Add approve hash test case
maurelian Sep 15, 2025
756cdff
fix warnings
maurelian Sep 15, 2025
bac2f8a
Use correct typing for Safe addresses
maurelian Sep 15, 2025
e92ed3f
Add additional scheduleTransaction tests
maurelian Sep 15, 2025
18f54e6
Enable specifying which safeInstance in utility functions
maurelian Sep 15, 2025
6782b1b
Change cancelTransaction to accept a tx hash
maurelian Sep 15, 2025
4fccd48
Add increaseCancellationThreshold to cancelTransaction
maurelian Sep 15, 2025
b792e04
Add configured boolean to guard config
maurelian Sep 15, 2025
3f407e1
Fix signature reuse vulnerability in cancelTransaction
maurelian Sep 16, 2025
37da3d5
Move signature verification before existence check in scheduleTransac…
maurelian Sep 16, 2025
43d7871
Remove unused console.logs
maurelian Sep 16, 2025
8c9fbf1
Fix increaseCancellationThreshold inputs
maurelian Sep 16, 2025
b28d653
Separate cancellation threshold events from transaction cancellation
maurelian Sep 17, 2025
4fff3d1
Remove unused _txHash argument from resetCancellation function
maurelian Sep 17, 2025
56238e8
Update ITimelockGuard to match implementation
maurelian Sep 17, 2025
1856abc
Use configured flag instead of timelockDelay check in clearTimelockGuard
maurelian Sep 17, 2025
4a9f2e2
Add configuration check to scheduleTransaction and fix test names
maurelian Sep 17, 2025
486ab05
Implement checkTransaction
maurelian Sep 18, 2025
bf20466
Add itest placeholder contract
maurelian Sep 18, 2025
ca166ef
Add comment to checkAfterExecution body
maurelian Sep 18, 2025
8b621c4
pre-pr checks
maurelian Sep 18, 2025
04ad47d
Remove GuardConfig.configured boolean field
maurelian Sep 18, 2025
b977666
Remove clearTimelockGuard
maurelian Sep 18, 2025
581cab0
Refactor: Add TransactionBuilder library
maurelian Sep 19, 2025
c84267d
Add unreachable AlreadyExecuted error
maurelian Sep 19, 2025
733a6e1
Add integration tests
maurelian Sep 19, 2025
5770509
Add getPendingTransactions function and tests
maurelian Sep 19, 2025
572d6cf
Add tests for getScheduledTransaction
maurelian Sep 19, 2025
c8b655c
Add _ prefix in front of internal mappings
maurelian Sep 22, 2025
df3daa6
Rename viewTimelockGuard to timelockSafeConfigurationper specs
maurelian Sep 22, 2025
072c1b4
Add maxCancellationThreshold
maurelian Sep 22, 2025
487b098
Improve names on getter functions
maurelian Sep 23, 2025
93256f2
Remove @dev tags with invariants
maurelian Sep 23, 2025
daad53b
Update configureTimelockGuard to accept and validate signatures outsi…
maurelian Sep 24, 2025
75bc23b
Refactor: use a single struct to store all state for a given Safe
maurelian Sep 23, 2025
a5ea6ee
Do not unnecessarily reset cancellation threshold when config set to 0
maurelian Sep 24, 2025
4d26c46
Revert "Update configureTimelockGuard to accept and validate signatur…
maurelian Sep 24, 2025
5fc7d25
Move timelockDelay out of unnecessary struct
maurelian Sep 24, 2025
f8ac2f8
Add top level detail natspec, reorder functions by vis and mutability
maurelian Sep 24, 2025
0a77d01
Remove test that does not conform to spec
maurelian Sep 24, 2025
34b77e5
Add cancelTransactionOnSafe to interface as reverting function
maurelian Sep 24, 2025
2b16f8e
Add many more comments
maurelian Sep 24, 2025
e55f7a1
Apply suggestions from code review
maurelian Sep 25, 2025
4add3cd
Fix ITimelockGuard iface to match impl
maurelian Sep 25, 2025
374824c
Rename arguments for consistency
maurelian Sep 25, 2025
c615461
Add/fixup @param on events
maurelian Sep 25, 2025
16ac7c3
Small fixes
maurelian Sep 25, 2025
5df4668
Fix ITimelockGuard declaration
maurelian Sep 25, 2025
2694a95
Improve names on getter functions
maurelian Sep 25, 2025
c96b476
Move ExecTransactionParams into TimelockGuard.sol
maurelian Sep 25, 2025
e7e8016
Address comment nits
maurelian Sep 26, 2025
1912649
Add TimelockGuard_MaxCancellationThreshold_Test and _deploySafe helper
maurelian Sep 26, 2025
ba9ac1c
Fix up iface and comment typos
maurelian Sep 26, 2025
45ad7b9
Fix storage lookup in test
maurelian Sep 26, 2025
5f3dca6
Add enum Transaction state and remove cancelled/executed booleans
maurelian Sep 26, 2025
0ef9df5
add /// @custom:field on ScheduledTransaction struct
maurelian Sep 26, 2025
2bb1971
add /// @custom:field on ExecTransactionParams struct
maurelian Sep 26, 2025
f3905ee
Add SemverComp to enforce minimum Safe version
maurelian Sep 26, 2025
c7e9eb4
Rename empty function to signCancellationForSafe
maurelian Sep 26, 2025
0d5dac0
Fix location of external view functions
maurelian Sep 26, 2025
24f20a1
Add some more comments where helpful.
maurelian Sep 26, 2025
5b68fb4
Further expand on the maxCancellationThreshold rationale
maurelian Sep 26, 2025
2daf9a1
Clarify blocking threshold
maurelian Sep 26, 2025
f5618ac
iFace fixes
maurelian Sep 26, 2025
1d709b3
Fix iface
maurelian Sep 26, 2025
ee0cde7
Move update of tx state, event emission and cancellationThreshold int…
maurelian Sep 26, 2025
fa7c6d6
Simplified comment
maurelian Sep 26, 2025
de6e131
remove unclear comments
maurelian Sep 26, 2025
93e0ca9
fix semgrep sol-style-use-abi-encodecall
maurelian Sep 30, 2025
433c048
snapshots
maurelian Sep 30, 2025
82eb756
Add course of actions table
maurelian Oct 1, 2025
f768b54
Remove unnecessary address arg from signCancellation
maurelian Oct 2, 2025
3374a34
Merge branch 'develop' into jm/timelock-single-struct
maurelian Oct 2, 2025
d9f2f86
Fix test names
maurelian Oct 2, 2025
db0f5af
Fix test name validation
maurelian Oct 2, 2025
a19dbc0
Remove enabled guard check from configureTimelockGuard
maurelian Oct 2, 2025
06ae5e2
Allow <ContractName>_Integration_Test in tests
maurelian Oct 2, 2025
05362ab
Add isExcludedTest in checkContractNameFilePath()
maurelian Oct 2, 2025
7972739
Update semver-lock
maurelian Oct 2, 2025
ab455d3
Merge branch 'develop' into jm/timelock-single-struct
maurelian Oct 3, 2025
40f24d5
Fix typo
maurelian Oct 3, 2025
8997094
fix typo in tests
maurelian Oct 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions packages/contracts-bedrock/interfaces/safe/ITimelockGuard.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;

library Enum {
type Operation is uint8;
}

interface ITimelockGuard {
enum TransactionState {
NotScheduled,
Pending,
Cancelled,
Executed
}
struct ScheduledTransaction {
uint256 executionTime;
TransactionState state;
ExecTransactionParams params;
}

struct ExecTransactionParams {
address to;
uint256 value;
bytes data;
Enum.Operation operation;
uint256 safeTxGas;
uint256 baseGas;
uint256 gasPrice;
address gasToken;
address payable refundReceiver;
}

error TimelockGuard_GuardNotConfigured();
error TimelockGuard_GuardNotEnabled();
error TimelockGuard_GuardStillEnabled();
error TimelockGuard_InvalidTimelockDelay();
error TimelockGuard_TransactionAlreadyCancelled();
error TimelockGuard_TransactionAlreadyScheduled();
error TimelockGuard_TransactionNotScheduled();
error TimelockGuard_TransactionNotReady();
error TimelockGuard_TransactionAlreadyExecuted();
error TimelockGuard_InvalidVersion();

event CancellationThresholdUpdated(address indexed safe, uint256 oldThreshold, uint256 newThreshold);
event GuardConfigured(address indexed safe, uint256 timelockDelay);
event TransactionCancelled(address indexed safe, bytes32 indexed txHash);
event TransactionScheduled(address indexed safe, bytes32 indexed txHash, uint256 executionTime);
event TransactionExecuted(address indexed safe, bytes32 txHash);
event Message(string message);

function cancelTransaction(address _safe, bytes32 _txHash, uint256 _nonce, bytes memory _signatures) external;
function signCancellation(bytes32 _txHash) external;
function cancellationThreshold(address _safe) external view returns (uint256);
function checkTransaction(
address _to,
uint256 _value,
bytes memory _data,
Enum.Operation _operation,
uint256 _safeTxGas,
uint256 _baseGas,
uint256 _gasPrice,
address _gasToken,
address payable _refundReceiver,
bytes memory _signatures,
address _msgSender
)
external;
function checkAfterExecution(bytes32, bool) external;
function configureTimelockGuard(uint256 _timelockDelay) external;
function scheduledTransaction(
address _safe,
bytes32 _txHash
)
external
view
returns (ScheduledTransaction memory);
function safeConfigs(address) external view returns (uint256 timelockDelay);
function scheduleTransaction(
address _safe,
uint256 _nonce,
ExecTransactionParams memory _params,
bytes memory _signatures
)
external;
function version() external view returns (string memory);
function timelockConfiguration(address _safe) external view returns (uint256 timelockDelay);
function maxCancellationThreshold(address _safe) external view returns (uint256);
function pendingTransactions(address _safe)
external
view
returns (ScheduledTransaction[] memory);
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,5 +92,6 @@ contracts = [
"OptimismPortal2_MigrateLiquidity_Test", # Interop tests hosted in the OptimismPortal2 test file
"OptimismPortal2_MigrateToSuperRoots_Test", # Interop tests hosted in the OptimismPortal2 test file
"OptimismPortal2_UpgradeInterop_Test", # Interop tests hosted in the OptimismPortal2 test file
"TransactionBuilder", # Transaction builder helper library in TimelockGuard test file
"Constants_Test", # Invalid naming pattern - doesn't specify function or Uncategorized
]
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,12 @@ func checkTestStructure(artifact *solc.ForgeArtifact) []error {

func checkTestMethodName(artifact *solc.ForgeArtifact, contractName string, functionName string, _ string) []error {
// Check for uncategorized test pattern
if functionName == "Uncategorized" {
// Pattern: <ContractName>_Uncategorized_Test
return nil
allowedFunctionNames := []string{"Uncategorized", "Integration"}
for _, allowed := range allowedFunctionNames {
if functionName == allowed {
// Pattern: <ContractName>_Uncategorized_Test or <ContractName>_Integration_Test
return nil
}
}
// Pattern: <ContractName>_<FunctionName>_Test - validate function exists
if !checkFunctionExists(artifact, functionName) {
Expand Down Expand Up @@ -250,6 +253,11 @@ func checkSrcPath(artifact *solc.ForgeArtifact) bool {
// Validates that contract name matches the file path
func checkContractNameFilePath(artifact *solc.ForgeArtifact) bool {
for filePath, contractName := range artifact.Metadata.Settings.CompilationTarget {

if isExcludedTest(contractName) {
continue
}

// Split contract name to get the base contract name (before first underscore)
contractParts := strings.Split(contractName, "_")
// Split file path to get individual path components
Expand Down
Loading