Skip to content

Commit

Permalink
Extracting UserOperationLib from UserOpertaion.sol and moving to core/
Browse files Browse the repository at this point in the history
  • Loading branch information
shahafn committed Oct 3, 2023
1 parent 465f223 commit 205ee15
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 89 deletions.
1 change: 1 addition & 0 deletions contracts/core/BaseAccount.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pragma solidity ^0.8.12;
import "../interfaces/IAccount.sol";
import "../interfaces/IEntryPoint.sol";
import "./Helpers.sol";
import "./UserOperationLib.sol";

/**
* Basic account implementation.
Expand Down
5 changes: 3 additions & 2 deletions contracts/core/EntryPoint.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import "./StakeManager.sol";
import "./SenderCreator.sol";
import "./Helpers.sol";
import "./NonceManager.sol";
import "./UserOperationLib.sol";

// we also require '@gnosis.pm/safe-contracts' and both libraries have 'IERC165.sol', leading to conflicts
import "@openzeppelin/contracts/utils/introspection/ERC165.sol" as OpenZeppelin;
Expand Down Expand Up @@ -598,11 +599,11 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard,
outOpInfo,
requiredPreFund
);

if (!_validateAndUpdateNonce(mUserOp.sender, mUserOp.nonce)) {
revert FailedOp(opIndex, "AA25 invalid account nonce");
}

// A "marker" where account opcode validation is done and paymaster opcode validation
// is about to start (used only by off-chain simulateValidation).
numberMarker();
Expand Down
90 changes: 90 additions & 0 deletions contracts/core/UserOperationLib.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;

import "../interfaces/UserOperation.sol";
import {calldataKeccak} from "./Helpers.sol";

/**
* Utility functions helpful when working with UserOperation structs.
*/
library UserOperationLib {
/**
* Get sender from user operation data.
* @param userOp - The user operation data.
*/
function getSender(
UserOperation calldata userOp
) internal pure returns (address) {
address data;
//read sender from userOp, which is first userOp member (saves 800 gas...)
assembly {
data := calldataload(userOp)
}
return address(uint160(data));
}

/**
* Relayer/block builder might submit the TX with higher priorityFee,
* but the user should not pay above what he signed for.
* @param userOp - The user operation data.
*/
function gasPrice(
UserOperation calldata userOp
) internal view returns (uint256) {
unchecked {
uint256 maxFeePerGas = userOp.maxFeePerGas;
uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas;
if (maxFeePerGas == maxPriorityFeePerGas) {
//legacy mode (for networks that don't support basefee opcode)
return maxFeePerGas;
}
return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee);
}
}

/**
* Pack the user operation data into bytes for hashing.
* @param userOp - The user operation data.
*/
function pack(
UserOperation calldata userOp
) internal pure returns (bytes memory ret) {
address sender = getSender(userOp);
uint256 nonce = userOp.nonce;
bytes32 hashInitCode = calldataKeccak(userOp.initCode);
bytes32 hashCallData = calldataKeccak(userOp.callData);
uint256 callGasLimit = userOp.callGasLimit;
uint256 verificationGasLimit = userOp.verificationGasLimit;
uint256 preVerificationGas = userOp.preVerificationGas;
uint256 maxFeePerGas = userOp.maxFeePerGas;
uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas;
bytes32 hashPaymasterAndData = calldataKeccak(userOp.paymasterAndData);

return abi.encode(
sender, nonce,
hashInitCode, hashCallData,
callGasLimit, verificationGasLimit, preVerificationGas,
maxFeePerGas, maxPriorityFeePerGas,
hashPaymasterAndData
);
}

/**
* Hash the user operation data.
* @param userOp - The user operation data.
*/
function hash(
UserOperation calldata userOp
) internal pure returns (bytes32) {
return keccak256(pack(userOp));
}

/**
* The minimum of two numbers.
* @param a - First number.
* @param b - Second number.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
}
87 changes: 0 additions & 87 deletions contracts/interfaces/UserOperation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ pragma solidity ^0.8.12;

/* solhint-disable no-inline-assembly */

import {calldataKeccak} from "../core/Helpers.sol";

/**
* User Operation struct
* @param sender - The sender account of this request.
Expand Down Expand Up @@ -34,88 +32,3 @@ struct UserOperation {
bytes paymasterAndData;
bytes signature;
}

/**
* Utility functions helpful when working with UserOperation structs.
*/
library UserOperationLib {
/**
* Get sender from user operation data.
* @param userOp - The user operation data.
*/
function getSender(
UserOperation calldata userOp
) internal pure returns (address) {
address data;
//read sender from userOp, which is first userOp member (saves 800 gas...)
assembly {
data := calldataload(userOp)
}
return address(uint160(data));
}

/**
* Relayer/block builder might submit the TX with higher priorityFee,
* but the user should not pay above what he signed for.
* @param userOp - The user operation data.
*/
function gasPrice(
UserOperation calldata userOp
) internal view returns (uint256) {
unchecked {
uint256 maxFeePerGas = userOp.maxFeePerGas;
uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas;
if (maxFeePerGas == maxPriorityFeePerGas) {
//legacy mode (for networks that don't support basefee opcode)
return maxFeePerGas;
}
return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee);
}
}

/**
* Pack the user operation data into bytes for hashing.
* @param userOp - The user operation data.
*/
function pack(
UserOperation calldata userOp
) internal pure returns (bytes memory ret) {
address sender = getSender(userOp);
uint256 nonce = userOp.nonce;
bytes32 hashInitCode = calldataKeccak(userOp.initCode);
bytes32 hashCallData = calldataKeccak(userOp.callData);
uint256 callGasLimit = userOp.callGasLimit;
uint256 verificationGasLimit = userOp.verificationGasLimit;
uint256 preVerificationGas = userOp.preVerificationGas;
uint256 maxFeePerGas = userOp.maxFeePerGas;
uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas;
bytes32 hashPaymasterAndData = calldataKeccak(userOp.paymasterAndData);

return abi.encode(
sender, nonce,
hashInitCode, hashCallData,
callGasLimit, verificationGasLimit, preVerificationGas,
maxFeePerGas, maxPriorityFeePerGas,
hashPaymasterAndData
);
}

/**
* Hash the user operation data.
* @param userOp - The user operation data.
*/
function hash(
UserOperation calldata userOp
) internal pure returns (bytes32) {
return keccak256(pack(userOp));
}

/**
* The minimum of two numbers.
* @param a - First number.
* @param b - Second number.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
}
1 change: 1 addition & 0 deletions contracts/samples/DepositPaymaster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import "../core/BasePaymaster.sol";
import "../core/UserOperationLib.sol";
import "./IOracle.sol";

/**
Expand Down
1 change: 1 addition & 0 deletions contracts/samples/VerifyingPaymaster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pragma solidity ^0.8.12;
/* solhint-disable no-inline-assembly */

import "../core/BasePaymaster.sol";
import "../core/UserOperationLib.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
/**
* A sample paymaster that uses external service to decide whether to pay for the UserOp.
Expand Down
1 change: 1 addition & 0 deletions contracts/samples/bls/BLSSignatureAggregator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma abicoder v2;

import "../../interfaces/IAggregator.sol";
import "../../interfaces/IEntryPoint.sol";
import "../../core/UserOperationLib.sol";
import {BLSOpen} from "./lib/BLSOpen.sol";
import "./IBLSAccount.sol";
import "./BLSHelper.sol";
Expand Down
1 change: 1 addition & 0 deletions contracts/test/TestUtil.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity ^0.8.12;

import "../interfaces/UserOperation.sol";
import "../core/UserOperationLib.sol";

contract TestUtil {
using UserOperationLib for UserOperation;
Expand Down

0 comments on commit 205ee15

Please sign in to comment.