Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@
[submodule "lib/safe-utils"]
path = lib/safe-utils
url = https://github.com/Recon-Fuzz/safe-utils
[submodule "lib/openzeppelin-contracts"]
path = lib/openzeppelin-contracts
url = https://github.com/Openzeppelin/openzeppelin-contracts
Comment thread
PierrickGT marked this conversation as resolved.
26 changes: 26 additions & 0 deletions foundry.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"lib/forge-std": {
"branch": {
"name": "v1",
"rev": "1801b0541f4fda118a10798fd3486bb7051c5dd6"
}
},
"lib/openzeppelin-contracts": {
"tag": {
"name": "v5.5.0",
"rev": "fcbae5394ae8ad52d8e580a3477db99814b9d565"
}
},
"lib/openzeppelin-contracts-upgradeable": {
"branch": {
"name": "release-v5.3",
"rev": "60b305a8f3ff0c7688f02ac470417b6bbf1c4d27"
}
},
"lib/safe-utils": {
"tag": {
"name": "v0.0.19",
"rev": "5310d6cd9c9d3146decfa3f8a17ac3edbeb40ca4"
}
}
}
11 changes: 11 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ test = "test"
script = "script"
out = "out"
libs = ["lib"]
remappings = ["safe-smart-account/=lib/safe-utils/lib/safe-smart-account/contracts/"]
cache = true
cache_path = "cache"
broadcast = "broadcast"
Expand All @@ -29,6 +30,16 @@ runs = 512
depth = 25
fail_on_revert = true

[profile.ci]
optimizer = true

[profile.ci.fuzz]
runs = 10_000

[profile.ci.invariant]
runs = 512
depth = 250

[profile.production]
evm_version = "cancun"
optimizer = true
Expand Down
2 changes: 1 addition & 1 deletion lib/forge-std
Submodule forge-std updated 65 files
+1 −0 .github/CODEOWNERS
+6 −0 .github/dependabot.yml
+98 −101 .github/workflows/ci.yml
+6 −1 .github/workflows/sync.yml
+2 −2 CONTRIBUTING.md
+14 −12 README.md
+12 −0 RELEASE_CHECKLIST.md
+11 −14 foundry.toml
+2 −2 package.json
+2 −12 scripts/vm.py
+24 −11 src/Base.sol
+60 −0 src/Config.sol
+477 −0 src/LibVariable.sol
+3 −2 src/Script.sol
+170 −60 src/StdAssertions.sol
+39 −7 src/StdChains.sol
+23 −15 src/StdCheats.sol
+632 −0 src/StdConfig.sol
+30 −0 src/StdConstants.sol
+2 −2 src/StdError.sol
+2 −4 src/StdInvariant.sol
+4 −12 src/StdJson.sol
+6 −2 src/StdMath.sol
+13 −11 src/StdStorage.sol
+2 −2 src/StdStyle.sol
+4 −12 src/StdToml.sol
+5 −31 src/StdUtils.sol
+3 −4 src/Test.sol
+486 −64 src/Vm.sol
+10 −19 src/console.sol
+2 −2 src/console2.sol
+3 −3 src/interfaces/IERC1155.sol
+2 −2 src/interfaces/IERC165.sol
+2 −2 src/interfaces/IERC20.sol
+3 −3 src/interfaces/IERC4626.sol
+72 −0 src/interfaces/IERC6909.sol
+3 −3 src/interfaces/IERC721.sol
+144 −0 src/interfaces/IERC7540.sol
+241 −0 src/interfaces/IERC7575.sol
+3 −8 src/interfaces/IMulticall3.sol
+0 −234 src/mocks/MockERC20.sol
+0 −231 src/mocks/MockERC721.sol
+691 −1,380 src/safeconsole.sol
+44 −0 test/CommonBase.t.sol
+381 −0 test/Config.t.sol
+452 −0 test/LibVariable.t.sol
+2 −6 test/StdAssertions.t.sol
+30 −31 test/StdChains.t.sol
+62 −42 test/StdCheats.t.sol
+38 −0 test/StdConstants.t.sol
+3 −4 test/StdError.t.sol
+2 −2 test/StdJson.t.sol
+8 −8 test/StdMath.t.sol
+44 −30 test/StdStorage.t.sol
+2 −2 test/StdStyle.t.sol
+2 −2 test/StdToml.t.sol
+13 −13 test/StdUtils.t.sol
+4 −4 test/Vm.t.sol
+3 −5 test/compilation/CompilationScript.sol
+3 −5 test/compilation/CompilationScriptBase.sol
+3 −5 test/compilation/CompilationTest.sol
+3 −5 test/compilation/CompilationTestBase.sol
+81 −0 test/fixtures/config.toml
+0 −441 test/mocks/MockERC20.t.sol
+0 −721 test/mocks/MockERC721.t.sol
1 change: 1 addition & 0 deletions lib/openzeppelin-contracts
Submodule openzeppelin-contracts added at fcbae5
2 changes: 1 addition & 1 deletion lib/safe-utils
2 changes: 2 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions script/ChainsBase.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.8.20 <0.9.0;

/// @notice Common EVM chain IDs shared across M0 protocol repos.
library ChainsBase {
// Mainnet
uint256 internal constant ETHEREUM = 1;

// Testnet
uint256 internal constant ETHEREUM_SEPOLIA = 11155111;

function isHub(uint256 chainId_) internal pure returns (bool) {
return chainId_ == ETHEREUM || chainId_ == ETHEREUM_SEPOLIA;
}
}
9 changes: 9 additions & 0 deletions script/DeployUtils.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.8.20 <0.9.0;

/// @notice Shared deployment constants for M0 protocol repos.
abstract contract DeployUtils {
/// @dev Same address for all EVM chains.
address internal constant _SWAP_FACILITY = 0xB6807116b3B1B321a390594e31ECD6e0076f6278;
}
48 changes: 48 additions & 0 deletions script/TimelockBatchBase.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// SPDX-License-Identifier: UNLICENSED

pragma solidity >=0.8.20 <0.9.0;

import {
TimelockController
} from "../lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/governance/TimelockController.sol";
import { Script } from "../lib/forge-std/src/Script.sol";

abstract contract TimelockBatchBase is Script {
address[] internal _timelockTargets;
uint256[] internal _timelockValues;
bytes[] internal _timelockPayloads;

function _addToTimelockBatch(address target_, bytes memory payload_) internal {
_timelockTargets.push(target_);
_timelockValues.push(0);
_timelockPayloads.push(payload_);
}

function _addToTimelockBatch(address target_, uint256 value_, bytes memory payload_) internal {
_timelockTargets.push(target_);
_timelockValues.push(value_);
_timelockPayloads.push(payload_);
}

function _getScheduleBatchCallData(
bytes32 predecessor,
bytes32 salt,
uint256 delay
) internal view returns (bytes memory) {
return abi.encodeCall(
TimelockController.scheduleBatch,
(_timelockTargets, _timelockValues, _timelockPayloads, predecessor, salt, delay)
);
}

function _simulateBatch(address timelock_) internal {
vm.startPrank(timelock_);

for (uint256 i = 0; i < _timelockTargets.length; i++) {
(bool success, ) = _timelockTargets[i].call{ value: _timelockValues[i] }(_timelockPayloads[i]);
require(success, "Simulation failed");
Comment on lines +42 to +43
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message 'Simulation failed' is too generic and doesn't provide information about which call failed or why. Consider including the target address and index in the error message to aid debugging.

Copilot uses AI. Check for mistakes.
Comment on lines +42 to +43
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The low-level call does not capture or handle the return data when the call fails. Consider capturing the return data to provide more context about failures, especially since this is a simulation function meant for testing.

Suggested change
(bool success, ) = _timelockTargets[i].call{ value: _timelockValues[i] }(_timelockPayloads[i]);
require(success, "Simulation failed");
(bool success, bytes memory returndata) =
_timelockTargets[i].call{ value: _timelockValues[i] }(_timelockPayloads[i]);
if (!success) {
if (returndata.length > 0) {
// Bubble up revert reason from the called contract
assembly {
revert(add(returndata, 32), mload(returndata))
}
} else {
revert("Simulation failed");
}
}

Copilot uses AI. Check for mistakes.
}

vm.stopPrank();
}
}
Loading