Skip to content
Draft
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
88 changes: 69 additions & 19 deletions contracts/core/EntryPoint.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import "../interfaces/IAccount.sol";
import "../interfaces/IAccountExecute.sol";
import "../interfaces/IPaymaster.sol";
import "../interfaces/IEntryPoint.sol";
import "../interfaces/ISscOpcodes.sol";

import "../utils/Exec.sol";
import "./StakeManager.sol";
Expand All @@ -28,8 +29,20 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard,

using UserOperationLib for PackedUserOperation;

int256 constant public SSC_STORAGE_SLOT_COST = 12800000000000000;
int256 constant public SSC_STORAGE_SLOT_REFUND = 12672000000000000;

int256 constant public SSC_ACCOUNT_COST = 12800000000000000;
int256 constant public SSC_ACCOUNT_REFUND = 12672000000000000;

int256 constant public SSC_CODE_CREATED_COST = 12800000000000000;
Comment on lines +32 to +38
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Have to set correct values


uint256 constant public SSC_MAX_SPEND_FACTOR = 10;

SenderCreator private immutable _senderCreator = new SenderCreator();

ISscOpcodes private immutable _ssc = ISscOpcodes(address(0x665e930982A9a03c844641d453a2C3462ED7Ff41));
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Deploying bytecode 0x60a2600b5f3960a25ff3fe600734156097565b600d6070565b63e7837508811460435763346527bf8114604c57638315b35381146055576386c3ee6e8114605e5763b7987bb481146067575f5ffd5bd0805f5260205ff35bd1805f5260205ff35bd2805f5260205ff35bd3805f5260205ff35bd4805f5260205ff35b5f7c01000000000000000000000000000000000000000000000000000000005f3504905090565b80609f575f5ffd5b5056 with salt 0x769a9f24a3e8cd02f97cdc25df023d91b7440615a2e6126d91057f41b87cb7b2 using CreateX.deployCreate2


function senderCreator() internal view virtual returns (SenderCreator) {
return _senderCreator;
}
Expand Down Expand Up @@ -174,10 +187,12 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard,
function handleOps(
PackedUserOperation[] calldata ops,
address payable beneficiary
) public nonReentrant {
) public nonReentrant payable {
uint256 opslen = ops.length;
UserOpInfo[] memory opInfos = new UserOpInfo[](opslen);

int256 preSSC = _netSSC();

unchecked {
for (uint256 i = 0; i < opslen; i++) {
UserOpInfo memory opInfo = opInfos[i];
Expand All @@ -200,7 +215,12 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard,
collected += _executeUserOp(i, ops[i], opInfos[i]);
}

_compensate(beneficiary, collected);
// this can be negative in cases of refunds
int256 netSSC = _netSSC() - preSSC;
// In case of negative netSSC msg.value must be higher than abs(netSSC)
uint256 sscCompensation = uint256(int256(msg.value) + netSSC);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The conversion would revert the whole bundle here in case of msg.value is smaller than the refund


_compensate(beneficiary, collected + sscCompensation);
}
}

Expand Down Expand Up @@ -303,23 +323,10 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard,
uint256 preOpGas;
}

/**
* Inner function to handle a UserOperation.
* Must be declared "external" to open a call context, but it can only be called by handleOps.
* @param callData - The callData to execute.
* @param opInfo - The UserOpInfo struct.
* @param context - The context bytes.
* @return actualGasCost - the actual cost in eth this UserOperation paid for gas
*/
function innerHandleOp(
bytes memory callData,
UserOpInfo memory opInfo,
bytes calldata context
) external returns (uint256 actualGasCost) {
uint256 preGas = gasleft();
function innerExecuteCall(MemoryUserOp memory mUserOp, bytes memory callData) external {
require(msg.sender == address(this), "AA92 internal call only");
MemoryUserOp memory mUserOp = opInfo.mUserOp;

int256 preSSC = _netSSC();
uint256 callGasLimit = mUserOp.callGasLimit;
unchecked {
// handleOps was called with gas limit too low. abort entire bundle.
Expand All @@ -335,12 +342,46 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard,
}
}
}
if (callData.length > 0) {
bool success = Exec.call(mUserOp.sender, 0, callData, callGasLimit);
if (!success) {
require(false, string(Exec.getReturnData(REVERT_REASON_MAX_LEN)));
} else {
int256 netSSC = _netSSC() - preSSC;
if (netSSC < 0) {
// increment deposit for the user's account
_incrementDeposit(mUserOp.sender, uint256(-netSSC));
} else {
require(uint256(netSSC) <= SSC_MAX_SPEND_FACTOR * callGasLimit * getUserOpGasPrice(mUserOp), "AA97 ssc max cost violation");
_decrementDeposit(mUserOp.sender, uint256(netSSC));
}
}
}
}

/**
* Inner function to handle a UserOperation.
* Must be declared "external" to open a call context, but it can only be called by handleOps.
* @param callData - The callData to execute.
* @param opInfo - The UserOpInfo struct.
* @param context - The context bytes.
* @return actualGasCost - the actual cost in eth this UserOperation paid for gas
*/
function innerHandleOp(
bytes memory callData,
UserOpInfo memory opInfo,
bytes calldata context
) external returns (uint256 actualGasCost) {
uint256 preGas = gasleft();
require(msg.sender == address(this), "AA92 internal call only");
MemoryUserOp memory mUserOp = opInfo.mUserOp;

IPaymaster.PostOpMode mode = IPaymaster.PostOpMode.opSucceeded;
if (callData.length > 0) {
bool success = Exec.call(mUserOp.sender, 0, callData, callGasLimit);
(bool success, bytes memory result) = address(this).call(
abi.encodeWithSelector(this.innerExecuteCall.selector, mUserOp, callData)
);
if (!success) {
bytes memory result = Exec.getReturnData(REVERT_REASON_MAX_LEN);
if (result.length > 0) {
emit UserOperationRevertReason(
opInfo.userOpHash,
Expand Down Expand Up @@ -413,6 +454,15 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard,
}
}

/**
* Calculates total ssc cost / refund
*/
function _netSSC() internal view returns (int256) {
return int256(_ssc.accountsCreated()) * SSC_ACCOUNT_COST - int256(_ssc.accountsCleared()) * SSC_ACCOUNT_REFUND
+ int256(_ssc.slotsCreated()) * SSC_STORAGE_SLOT_COST - int256(_ssc.slotsCleared()) * SSC_STORAGE_SLOT_REFUND
+ int256(_ssc.codeCreated()) * SSC_CODE_CREATED_COST;
}

/**
* Create sender smart contract account if init code is provided.
* @param opIndex - The operation index.
Expand Down
16 changes: 16 additions & 0 deletions contracts/core/StakeManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,22 @@ abstract contract StakeManager is IStakeManager {
return newAmount;
}

/**
* Increments an account's deposit.
* @param account - The account to increment.
* @param amount - The amount to increment by.
* @return the updated deposit of this account
*/
function _decrementDeposit(address account, uint256 amount) internal returns (uint256) {
unchecked {
DepositInfo storage info = deposits[account];
require(info.deposit >= amount, "cannot decrement stake");
uint256 newAmount = info.deposit - amount;
info.deposit = newAmount;
return newAmount;
}
}

/**
* Add to the deposit of the given account.
* @param account - The account to add to.
Expand Down
2 changes: 1 addition & 1 deletion contracts/interfaces/IEntryPoint.sol
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ interface IEntryPoint is IStakeManager, INonceManager {
function handleOps(
PackedUserOperation[] calldata ops,
address payable beneficiary
) external;
) external payable;

/**
* Execute a batch of UserOperation with Aggregators
Expand Down
10 changes: 10 additions & 0 deletions contracts/interfaces/ISscOpcodes.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;

interface ISscOpcodes {
function accountsCreated() external view returns (uint256); // D0
function accountsCleared() external view returns (uint256); // D1
function slotsCreated() external view returns (uint256); // D2
function slotsCleared() external view returns (uint256); // D3
function codeCreated() external view returns (uint256); // D4
}
Loading