Fix 5.2 audit L-05, N-03, N-04, N-05 and N-06 issues (#5308)

pull/5310/head^2
Hadrien Croubois 2 months ago committed by GitHub
parent ffca412299
commit ccb5f2d8ca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 11
      contracts/account/utils/draft-ERC4337Utils.sol
  2. 10
      contracts/account/utils/draft-ERC7579Utils.sol
  3. 2
      contracts/governance/extensions/GovernorCountingOverridable.sol
  4. 2
      contracts/governance/utils/VotesExtended.sol
  5. 2
      contracts/interfaces/draft-IERC4337.sol
  6. 4
      contracts/proxy/Clones.sol
  7. 2
      contracts/utils/Bytes.sol
  8. 4
      contracts/utils/CAIP10.sol
  9. 2
      contracts/utils/CAIP2.sol
  10. 4
      contracts/utils/NoncesKeyed.sol
  11. 7
      test/account/utils/draft-ERC4337Utils.test.js

@ -2,7 +2,7 @@
pragma solidity ^0.8.20; pragma solidity ^0.8.20;
import {IEntryPoint, PackedUserOperation} from "../../interfaces/draft-IERC4337.sol"; import {PackedUserOperation} from "../../interfaces/draft-IERC4337.sol";
import {Math} from "../../utils/math/Math.sol"; import {Math} from "../../utils/math/Math.sol";
import {Packing} from "../../utils/Packing.sol"; import {Packing} from "../../utils/Packing.sol";
@ -71,12 +71,7 @@ library ERC4337Utils {
return (aggregator_, block.timestamp < validAfter || validUntil < block.timestamp); return (aggregator_, block.timestamp < validAfter || validUntil < block.timestamp);
} }
/// @dev Computes the hash of a user operation with the current entrypoint and chainid. /// @dev Computes the hash of a user operation for a given entrypoint and chainid.
function hash(PackedUserOperation calldata self) internal view returns (bytes32) {
return hash(self, address(this), block.chainid);
}
/// @dev Sames as {hash}, but with a custom entrypoint and chainid.
function hash( function hash(
PackedUserOperation calldata self, PackedUserOperation calldata self,
address entrypoint, address entrypoint,
@ -129,7 +124,7 @@ library ERC4337Utils {
// Following values are "per gas" // Following values are "per gas"
uint256 maxPriorityFee = maxPriorityFeePerGas(self); uint256 maxPriorityFee = maxPriorityFeePerGas(self);
uint256 maxFee = maxFeePerGas(self); uint256 maxFee = maxFeePerGas(self);
return Math.ternary(maxFee == maxPriorityFee, maxFee, Math.min(maxFee, maxPriorityFee + block.basefee)); return Math.min(maxFee, maxPriorityFee + block.basefee);
} }
} }

@ -22,19 +22,19 @@ library ERC7579Utils {
using Packing for *; using Packing for *;
/// @dev A single `call` execution. /// @dev A single `call` execution.
CallType constant CALLTYPE_SINGLE = CallType.wrap(0x00); CallType internal constant CALLTYPE_SINGLE = CallType.wrap(0x00);
/// @dev A batch of `call` executions. /// @dev A batch of `call` executions.
CallType constant CALLTYPE_BATCH = CallType.wrap(0x01); CallType internal constant CALLTYPE_BATCH = CallType.wrap(0x01);
/// @dev A `delegatecall` execution. /// @dev A `delegatecall` execution.
CallType constant CALLTYPE_DELEGATECALL = CallType.wrap(0xFF); CallType internal constant CALLTYPE_DELEGATECALL = CallType.wrap(0xFF);
/// @dev Default execution type that reverts on failure. /// @dev Default execution type that reverts on failure.
ExecType constant EXECTYPE_DEFAULT = ExecType.wrap(0x00); ExecType internal constant EXECTYPE_DEFAULT = ExecType.wrap(0x00);
/// @dev Execution type that does not revert on failure. /// @dev Execution type that does not revert on failure.
ExecType constant EXECTYPE_TRY = ExecType.wrap(0x01); ExecType internal constant EXECTYPE_TRY = ExecType.wrap(0x01);
/// @dev Emits when an {EXECTYPE_TRY} execution fails. /// @dev Emits when an {EXECTYPE_TRY} execution fails.
event ERC7579TryExecuteFail(uint256 batchExecutionIndex, bytes result); event ERC7579TryExecuteFail(uint256 batchExecutionIndex, bytes result);

@ -9,7 +9,7 @@ import {GovernorVotes} from "./GovernorVotes.sol";
/** /**
* @dev Extension of {Governor} which enables delegatees to override the vote of their delegates. This module requires a * @dev Extension of {Governor} which enables delegatees to override the vote of their delegates. This module requires a
* token token that inherits `VotesExtended`. * token that inherits {VotesExtended}.
*/ */
abstract contract GovernorCountingOverridable is GovernorVotes { abstract contract GovernorCountingOverridable is GovernorVotes {
bytes32 public constant OVERRIDE_BALLOT_TYPEHASH = bytes32 public constant OVERRIDE_BALLOT_TYPEHASH =

@ -6,7 +6,7 @@ import {Votes} from "./Votes.sol";
import {SafeCast} from "../../utils/math/SafeCast.sol"; import {SafeCast} from "../../utils/math/SafeCast.sol";
/** /**
* @dev Extension of {Votes} that adds exposes checkpoints for delegations and balances. * @dev Extension of {Votes} that adds checkpoints for delegations and balances.
*/ */
abstract contract VotesExtended is Votes { abstract contract VotesExtended is Votes {
using SafeCast for uint256; using SafeCast for uint256;

@ -11,7 +11,7 @@ pragma solidity ^0.8.20;
* - `callData` (`bytes`): The data to pass to the sender during the main execution call * - `callData` (`bytes`): The data to pass to the sender during the main execution call
* - `callGasLimit` (`uint256`): The amount of gas to allocate the main execution call * - `callGasLimit` (`uint256`): The amount of gas to allocate the main execution call
* - `verificationGasLimit` (`uint256`): The amount of gas to allocate for the verification step * - `verificationGasLimit` (`uint256`): The amount of gas to allocate for the verification step
* - `preVerificationGas` (`uint256`): Extra gas to pay the bunder * - `preVerificationGas` (`uint256`): Extra gas to pay the bundler
* - `maxFeePerGas` (`uint256`): Maximum fee per gas (similar to EIP-1559 max_fee_per_gas) * - `maxFeePerGas` (`uint256`): Maximum fee per gas (similar to EIP-1559 max_fee_per_gas)
* - `maxPriorityFeePerGas` (`uint256`): Maximum priority fee per gas (similar to EIP-1559 max_priority_fee_per_gas) * - `maxPriorityFeePerGas` (`uint256`): Maximum priority fee per gas (similar to EIP-1559 max_priority_fee_per_gas)
* - `paymaster` (`address`): Address of paymaster contract, (or empty, if account pays for itself) * - `paymaster` (`address`): Address of paymaster contract, (or empty, if account pays for itself)

@ -57,7 +57,7 @@ library Clones {
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
* *
* This function uses the create2 opcode and a `salt` to deterministically deploy * This function uses the create2 opcode and a `salt` to deterministically deploy
* the clone. Using the same `implementation` and `salt` multiple time will revert, since * the clone. Using the same `implementation` and `salt` multiple times will revert, since
* the clones cannot be deployed twice at the same address. * the clones cannot be deployed twice at the same address.
*/ */
function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
@ -163,7 +163,7 @@ library Clones {
* access the arguments within the implementation, use {fetchCloneArgs}. * access the arguments within the implementation, use {fetchCloneArgs}.
* *
* This function uses the create2 opcode and a `salt` to deterministically deploy the clone. Using the same * This function uses the create2 opcode and a `salt` to deterministically deploy the clone. Using the same
* `implementation` and `salt` multiple time will revert, since the clones cannot be deployed twice at the same * `implementation` and `salt` multiple times will revert, since the clones cannot be deployed twice at the same
* address. * address.
*/ */
function cloneDeterministicWithImmutableArgs( function cloneDeterministicWithImmutableArgs(

@ -27,7 +27,6 @@ library Bytes {
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf[Javascript's `Array.indexOf`] * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf[Javascript's `Array.indexOf`]
*/ */
function indexOf(bytes memory buffer, bytes1 s, uint256 pos) internal pure returns (uint256) { function indexOf(bytes memory buffer, bytes1 s, uint256 pos) internal pure returns (uint256) {
unchecked {
uint256 length = buffer.length; uint256 length = buffer.length;
for (uint256 i = pos; i < length; ++i) { for (uint256 i = pos; i < length; ++i) {
if (bytes1(_unsafeReadBytesOffset(buffer, i)) == s) { if (bytes1(_unsafeReadBytesOffset(buffer, i)) == s) {
@ -36,7 +35,6 @@ library Bytes {
} }
return type(uint256).max; return type(uint256).max;
} }
}
/** /**
* @dev Backward search for `s` in `buffer` * @dev Backward search for `s` in `buffer`

@ -2,10 +2,9 @@
pragma solidity ^0.8.24; pragma solidity ^0.8.24;
import {SafeCast} from "./math/SafeCast.sol";
import {Bytes} from "./Bytes.sol"; import {Bytes} from "./Bytes.sol";
import {CAIP2} from "./CAIP2.sol";
import {Strings} from "./Strings.sol"; import {Strings} from "./Strings.sol";
import {CAIP2} from "./CAIP2.sol";
/** /**
* @dev Helper library to format and parse CAIP-10 identifiers * @dev Helper library to format and parse CAIP-10 identifiers
@ -16,7 +15,6 @@ import {Strings} from "./Strings.sol";
* account_address: [-.%a-zA-Z0-9]{1,128} * account_address: [-.%a-zA-Z0-9]{1,128}
*/ */
library CAIP10 { library CAIP10 {
using SafeCast for uint256;
using Strings for address; using Strings for address;
using Bytes for bytes; using Bytes for bytes;

@ -2,7 +2,6 @@
pragma solidity ^0.8.24; pragma solidity ^0.8.24;
import {SafeCast} from "./math/SafeCast.sol";
import {Bytes} from "./Bytes.sol"; import {Bytes} from "./Bytes.sol";
import {Strings} from "./Strings.sol"; import {Strings} from "./Strings.sol";
@ -15,7 +14,6 @@ import {Strings} from "./Strings.sol";
* reference: [-_a-zA-Z0-9]{1,32} * reference: [-_a-zA-Z0-9]{1,32}
*/ */
library CAIP2 { library CAIP2 {
using SafeCast for uint256;
using Strings for uint256; using Strings for uint256;
using Bytes for bytes; using Bytes for bytes;

@ -4,7 +4,7 @@ pragma solidity ^0.8.20;
import {Nonces} from "./Nonces.sol"; import {Nonces} from "./Nonces.sol";
/** /**
* @dev Alternative to {Nonces}, that support key-ed nonces. * @dev Alternative to {Nonces}, that supports key-ed nonces.
* *
* Follows the https://eips.ethereum.org/EIPS/eip-4337#semi-abstracted-nonce-support[ERC-4337's semi-abstracted nonce system]. * Follows the https://eips.ethereum.org/EIPS/eip-4337#semi-abstracted-nonce-support[ERC-4337's semi-abstracted nonce system].
*/ */
@ -19,7 +19,7 @@ abstract contract NoncesKeyed is Nonces {
/** /**
* @dev Consumes the next unused nonce for an address and key. * @dev Consumes the next unused nonce for an address and key.
* *
* Returns the current value without the key prefix. Consumed nonce is increased, so calling this functions twice * Returns the current value without the key prefix. Consumed nonce is increased, so calling this function twice
* with the same arguments will return different (sequential) results. * with the same arguments will return different (sequential) results.
*/ */
function _useNonce(address owner, uint192 key) internal virtual returns (uint256) { function _useNonce(address owner, uint192 key) internal virtual returns (uint256) {

@ -133,13 +133,6 @@ describe('ERC4337Utils', function () {
}); });
describe('hash', function () { describe('hash', function () {
it('returns the user operation hash', async function () {
const userOp = new UserOperation({ sender: this.sender, nonce: 1 });
const chainId = await ethers.provider.getNetwork().then(({ chainId }) => chainId);
expect(this.utils.$hash(userOp.packed)).to.eventually.equal(userOp.hash(this.utils.target, chainId));
});
it('returns the operation hash with specified entrypoint and chainId', async function () { it('returns the operation hash with specified entrypoint and chainId', async function () {
const userOp = new UserOperation({ sender: this.sender, nonce: 1 }); const userOp = new UserOperation({ sender: this.sender, nonce: 1 });
const chainId = 0xdeadbeef; const chainId = 0xdeadbeef;

Loading…
Cancel
Save