Ernesto García 1 сар өмнө
parent
commit
519184ce6b

+ 24 - 24
certora/diff/access_manager_AccessManager.sol.patch

@@ -1,16 +1,16 @@
---- access/manager/AccessManager.sol	2023-10-05 12:17:09.694051809 -0300
-+++ access/manager/AccessManager.sol	2023-10-05 12:26:18.498688718 -0300
-@@ -6,7 +6,6 @@
+--- access/manager/AccessManager.sol	2025-08-16 15:15:34
++++ access/manager/AccessManager.sol	2025-08-16 15:17:51
+@@ -7,7 +7,6 @@
  import {IAccessManaged} from "./IAccessManaged.sol";
  import {Address} from "../../utils/Address.sol";
  import {Context} from "../../utils/Context.sol";
 -import {Multicall} from "../../utils/Multicall.sol";
  import {Math} from "../../utils/math/Math.sol";
  import {Time} from "../../utils/types/Time.sol";
- 
-@@ -57,7 +56,8 @@
-  * mindful of the danger associated with functions such as {{Ownable-renounceOwnership}} or
-  * {{AccessControl-renounceRole}}.
+ import {Hashes} from "../../utils/cryptography/Hashes.sol";
+@@ -59,7 +58,8 @@
+  * mindful of the danger associated with functions such as {Ownable-renounceOwnership} or
+  * {AccessControl-renounceRole}.
   */
 -contract AccessManager is Context, Multicall, IAccessManager {
 +// NOTE: The FV version of this contract doesn't include Multicall because CVL HAVOCs on any `delegatecall`.
@@ -18,7 +18,7 @@
      using Time for *;
  
      // Structure that stores the details for a target contract.
-@@ -105,7 +105,7 @@
+@@ -115,7 +115,7 @@
  
      // Used to identify operations that are currently being executed via {execute}.
      // This should be transient storage when supported by the EVM.
@@ -26,8 +26,8 @@
 +    bytes32 internal _executionId; // private → internal for FV
  
      /**
-      * @dev Check that the caller is authorized to perform the operation, following the restrictions encoded in
-@@ -253,6 +253,11 @@
+      * @dev Check that the caller is authorized to perform the operation.
+@@ -263,6 +263,11 @@
          _setGrantDelay(roleId, newDelay);
      }
  
@@ -39,28 +39,28 @@
      /**
       * @dev Internal version of {grantRole} without access control. Returns true if the role was newly granted.
       *
-@@ -287,6 +292,11 @@
-         return newMember;
-     }
+@@ -295,6 +300,11 @@
  
+         emit RoleGranted(roleId, account, executionDelay, since, newMember);
+         return newMember;
++    }
++
 +    // Exposed for FV
 +    function _getRoleGrantDelayFull(uint64 roleId) internal view virtual returns (uint32, uint32, uint48) {
 +        return _roles[roleId].grantDelay.getFull();
-+    }
-+
-     /**
-      * @dev Internal version of {revokeRole} without access control. This logic is also used by {renounceRole}.
-      * Returns true if the role was previously granted.
-@@ -586,7 +596,7 @@
+     }
+ 
      /**
-      * @dev Check if the current call is authorized according to admin logic.
+@@ -596,7 +606,7 @@
+      *
+      * WARNING: Carefully review the considerations of {AccessManaged-restricted} since they apply to this modifier.
       */
 -    function _checkAuthorized() private {
 +    function _checkAuthorized() internal virtual { // private → internal virtual for FV
          address caller = _msgSender();
          (bool immediate, uint32 delay) = _canCallSelf(caller, _msgData());
          if (!immediate) {
-@@ -609,7 +619,7 @@
+@@ -619,7 +629,7 @@
       */
      function _getAdminRestrictions(
          bytes calldata data
@@ -69,7 +69,7 @@
          if (data.length < 4) {
              return (false, 0, 0);
          }
-@@ -662,7 +672,7 @@
+@@ -672,7 +682,7 @@
          address caller,
          address target,
          bytes calldata data
@@ -78,7 +78,7 @@
          if (target == address(this)) {
              return _canCallSelf(caller, data);
          } else {
-@@ -716,14 +726,14 @@
+@@ -728,14 +738,14 @@
      /**
       * @dev Extracts the selector from calldata. Panics if data is not at least 4 bytes
       */
@@ -92,6 +92,6 @@
       */
 -    function _hashExecutionId(address target, bytes4 selector) private pure returns (bytes32) {
 +    function _hashExecutionId(address target, bytes4 selector) internal pure returns (bytes32) { // private → internal for FV
-         return keccak256(abi.encode(target, selector));
+         return Hashes.efficientKeccak256(bytes32(uint256(uint160(target))), selector);
      }
  }

+ 2 - 1
contracts/access/manager/AccessManager.sol

@@ -10,6 +10,7 @@ import {Context} from "../../utils/Context.sol";
 import {Multicall} from "../../utils/Multicall.sol";
 import {Math} from "../../utils/math/Math.sol";
 import {Time} from "../../utils/types/Time.sol";
+import {Hashes} from "../../utils/cryptography/Hashes.sol";
 
 /**
  * @dev AccessManager is a central contract to store the permissions of a system.
@@ -735,6 +736,6 @@ contract AccessManager is Context, Multicall, IAccessManager {
      * @dev Hashing function for execute protection
      */
     function _hashExecutionId(address target, bytes4 selector) private pure returns (bytes32) {
-        return keccak256(abi.encode(target, selector));
+        return Hashes.efficientKeccak256(bytes32(uint256(uint160(target))), selector);
     }
 }

+ 0 - 1
contracts/account/extensions/draft-AccountERC7579.sol

@@ -19,7 +19,6 @@ import {ERC7579Utils, Mode, CallType, ExecType} from "../../account/utils/draft-
 import {EnumerableSet} from "../../utils/structs/EnumerableSet.sol";
 import {Bytes} from "../../utils/Bytes.sol";
 import {Packing} from "../../utils/Packing.sol";
-import {Address} from "../../utils/Address.sol";
 import {Calldata} from "../../utils/Calldata.sol";
 import {Account} from "../Account.sol";
 

+ 0 - 1
contracts/mocks/account/AccountMock.sol

@@ -7,7 +7,6 @@ import {AccountERC7579} from "../../account/extensions/draft-AccountERC7579.sol"
 import {AccountERC7579Hooked} from "../../account/extensions/draft-AccountERC7579Hooked.sol";
 import {ERC721Holder} from "../../token/ERC721/utils/ERC721Holder.sol";
 import {ERC1155Holder} from "../../token/ERC1155/utils/ERC1155Holder.sol";
-import {ERC4337Utils} from "../../account/utils/draft-ERC4337Utils.sol";
 import {ERC7739} from "../../utils/cryptography/signers/draft-ERC7739.sol";
 import {ERC7821} from "../../account/extensions/draft-ERC7821.sol";
 import {MODULE_TYPE_VALIDATOR} from "../../interfaces/draft-IERC7579.sol";

+ 0 - 1
contracts/mocks/governance/GovernorNoncesKeyedMock.sol

@@ -6,7 +6,6 @@ import {Governor, Nonces} from "../../governance/Governor.sol";
 import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol";
 import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol";
 import {GovernorVotesQuorumFraction} from "../../governance/extensions/GovernorVotesQuorumFraction.sol";
-import {GovernorProposalGuardian} from "../../governance/extensions/GovernorProposalGuardian.sol";
 import {GovernorNoncesKeyed} from "../../governance/extensions/GovernorNoncesKeyed.sol";
 
 abstract contract GovernorNoncesKeyedMock is

+ 1 - 1
contracts/mocks/token/ERC20BridgeableMock.sol

@@ -2,7 +2,7 @@
 
 pragma solidity ^0.8.20;
 
-import {ERC20, ERC20Bridgeable} from "../../token/ERC20/extensions/draft-ERC20Bridgeable.sol";
+import {ERC20Bridgeable} from "../../token/ERC20/extensions/draft-ERC20Bridgeable.sol";
 
 abstract contract ERC20BridgeableMock is ERC20Bridgeable {
     address private _bridge;

+ 2 - 0
contracts/mocks/token/ERC20NoReturnMock.sol

@@ -6,6 +6,7 @@ import {ERC20} from "../../token/ERC20/ERC20.sol";
 
 abstract contract ERC20NoReturnMock is ERC20 {
     function transfer(address to, uint256 amount) public override returns (bool) {
+        // forge-lint: disable-next-line(erc20-unchecked-transfer)
         super.transfer(to, amount);
         assembly {
             return(0, 0)
@@ -13,6 +14,7 @@ abstract contract ERC20NoReturnMock is ERC20 {
     }
 
     function transferFrom(address from, address to, uint256 amount) public override returns (bool) {
+        // forge-lint: disable-next-line(erc20-unchecked-transfer)
         super.transferFrom(from, to, amount);
         assembly {
             return(0, 0)

+ 0 - 1
contracts/mocks/utils/cryptography/ERC7739Mock.sol

@@ -2,7 +2,6 @@
 
 pragma solidity ^0.8.24;
 
-import {ECDSA} from "../../../utils/cryptography/ECDSA.sol";
 import {ERC7739} from "../../../utils/cryptography/signers/draft-ERC7739.sol";
 import {SignerECDSA} from "../../../utils/cryptography/signers/SignerECDSA.sol";
 import {SignerP256} from "../../../utils/cryptography/signers/SignerP256.sol";

+ 1 - 1
contracts/token/ERC721/extensions/ERC721Wrapper.sol

@@ -36,7 +36,7 @@ abstract contract ERC721Wrapper is ERC721, IERC721Receiver {
             // This is an "unsafe" transfer that doesn't call any hook on the receiver. With underlying() being trusted
             // (by design of this contract) and no other contracts expected to be called from there, we are safe.
             // slither-disable-next-line reentrancy-no-eth
-            underlying().transferFrom(_msgSender(), address(this), tokenId);
+            underlying().transferFrom(_msgSender(), address(this), tokenId); // forge-lint: disable-line(erc20-unchecked-transfer)
             _safeMint(account, tokenId);
         }
 

+ 2 - 1
contracts/utils/cryptography/draft-ERC7739Utils.sol

@@ -4,6 +4,7 @@
 pragma solidity ^0.8.20;
 
 import {Calldata} from "../Calldata.sol";
+import {Hashes} from "./Hashes.sol";
 
 /**
  * @dev Utilities to process https://ercs.ethereum.org/ERCS/erc-7739[ERC-7739] typed data signatures
@@ -101,7 +102,7 @@ library ERC7739Utils {
      * This is used to simulates the `personal_sign` RPC method in the context of smart contracts.
      */
     function personalSignStructHash(bytes32 contents) internal pure returns (bytes32) {
-        return keccak256(abi.encode(PERSONAL_SIGN_TYPEHASH, contents));
+        return Hashes.efficientKeccak256(PERSONAL_SIGN_TYPEHASH, contents);
     }
 
     /**

+ 0 - 1
contracts/utils/cryptography/signers/draft-ERC7739.sol

@@ -8,7 +8,6 @@ import {EIP712} from "../EIP712.sol";
 import {ERC7739Utils} from "../draft-ERC7739Utils.sol";
 import {IERC1271} from "../../../interfaces/IERC1271.sol";
 import {MessageHashUtils} from "../MessageHashUtils.sol";
-import {ShortStrings} from "../../ShortStrings.sol";
 
 /**
  * @dev Validates signatures wrapping the message hash in a nested EIP712 type. See {ERC7739Utils}.

+ 4 - 0
foundry.toml

@@ -10,6 +10,10 @@ test = 'test'
 cache_path  = 'cache_forge'
 fs_permissions = [{ access = "read", path = "./node_modules/hardhat-predeploy/bin" }]
 
+[lint]
+exclude_lints = ["mixed-case-function", "asm-keccak256", "screaming-snake-case-immutable", "incorrect-shift", "mixed-case-variable"]
+ignore = ["./contracts/interfaces/**/*.sol", "./contracts/mocks/Stateless.sol"]
+
 [fuzz]
 runs = 5000
 max_test_rejects = 150000

+ 8 - 2
test/token/ERC721/extensions/ERC721Consecutive.t.sol

@@ -16,7 +16,7 @@ function toSingleton(address account) pure returns (address[] memory) {
 
 contract ERC721ConsecutiveTarget is StdUtils, ERC721Consecutive {
     uint96 private immutable _offset;
-    uint256 public totalMinted = 0;
+    uint256 private _totalMinted = 0;
 
     constructor(address[] memory receivers, uint256[] memory batches, uint256 startingId) ERC721("", "") {
         _offset = uint96(startingId);
@@ -24,10 +24,14 @@ contract ERC721ConsecutiveTarget is StdUtils, ERC721Consecutive {
             address receiver = receivers[i % receivers.length];
             uint96 batchSize = uint96(bound(batches[i], 0, _maxBatchSize()));
             _mintConsecutive(receiver, batchSize);
-            totalMinted += batchSize;
+            _totalMinted += batchSize;
         }
     }
 
+    function totalMinted() public view returns (uint256) {
+        return _totalMinted;
+    }
+
     function burn(uint256 tokenId) public {
         _burn(tokenId);
     }
@@ -138,6 +142,7 @@ contract ERC721ConsecutiveTest is Test {
         assertEq(token.balanceOf(accounts[1]), batches[1]);
 
         vm.prank(accounts[0]);
+        // forge-lint: disable-next-line(erc20-unchecked-transfer)
         token.transferFrom(accounts[0], accounts[1], tokenId0);
 
         assertEq(token.ownerOf(tokenId0), accounts[1]);
@@ -146,6 +151,7 @@ contract ERC721ConsecutiveTest is Test {
         assertEq(token.balanceOf(accounts[1]), batches[1] + 1);
 
         vm.prank(accounts[1]);
+        // forge-lint: disable-next-line(erc20-unchecked-transfer)
         token.transferFrom(accounts[1], accounts[0], tokenId1);
 
         assertEq(token.ownerOf(tokenId0), accounts[1]);