Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AA-184: Remove second postOp retry #311

Merged
merged 30 commits into from
Oct 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ebbf21a
Makes comments and formatting consistent
gigamesh Mar 3, 2023
64cbdf6
@inheritdoc IEntryPoint
gigamesh Mar 4, 2023
d43bc94
Reverts contracts/test/TestHelpers.sol
gigamesh Mar 6, 2023
105d122
fix: entrypoint does not revert even first postOp reverts with short …
leekt May 30, 2023
3a6b0a5
lint
leekt May 30, 2023
66688cb
gas-report
leekt May 30, 2023
b56ef7b
Merge branch 'next_v0.7' into gigamesh/comments
forshtat Jun 25, 2023
74ed53b
Update IEntryPoint.sol - add missing 'INonceManager'
forshtat Jun 25, 2023
649daf8
Update EntryPoint.sol - fix lint errors
forshtat Jun 25, 2023
aa20d5d
Update gas-checker.txt manually
forshtat Jun 25, 2023
e3111fe
Update gas-checker.txt - add newline for the 'diff'
forshtat Jun 25, 2023
10f0502
Merge pull request #235 from gigamesh/gigamesh/comments
forshtat Jun 25, 2023
6a5ce09
Merge branch 'next_v0.7' into develop
forshtat Jun 25, 2023
8116f81
Update gas-checker.txt manually
forshtat Jun 25, 2023
74a3c37
Merge pull request #293 from leekt/develop
forshtat Jun 25, 2023
f96de6c
Remove "postOp" retry call mode and adjust tests
forshtat Jun 26, 2023
4b76a32
Update gas-calc
forshtat Jun 26, 2023
8903ae1
Update gas-checker.txt
forshtat Jun 26, 2023
ce519f6
Merge branch 'develop' of github.com:eth-infinitism/account-abstracti…
forshtat Oct 18, 2023
9bd5263
Bump 'yarn.lock' versions
forshtat Oct 18, 2023
a218f79
Bump node version for Github Actions
forshtat Oct 18, 2023
318a7ac
Weird
forshtat Oct 18, 2023
0f24290
Disable new solhint rules
forshtat Oct 18, 2023
83cb4e2
Uncomment TestCounter deployment
forshtat Oct 18, 2023
53eda99
Fix
forshtat Oct 18, 2023
ba64217
Fix gas checks
forshtat Oct 18, 2023
30d24ac
Use up to two times 'verificationGasLimit' in the 'requiredGas' calcu…
forshtat Oct 18, 2023
ea127b7
Fix gas checks
forshtat Oct 20, 2023
3f93724
Rename '_handlePostOp' to '_postExecution'
forshtat Oct 22, 2023
d140003
Fix gas checks
forshtat Oct 22, 2023
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
8 changes: 4 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
steps:
- uses: actions/setup-node@v1
with:
node-version: '14'
node-version: '16'
- uses: actions/checkout@v1
- uses: actions/cache@v2
with:
Expand All @@ -40,7 +40,7 @@ jobs:
steps:
- uses: actions/setup-node@v1
with:
node-version: '14'
node-version: '16'
- uses: actions/checkout@v1
- uses: actions/cache@v2
with:
Expand All @@ -55,7 +55,7 @@ jobs:
steps:
- uses: actions/setup-node@v1
with:
node-version: '14'
node-version: '16'
- uses: actions/checkout@v1
- uses: actions/cache@v2
with:
Expand All @@ -69,7 +69,7 @@ jobs:
steps:
- uses: actions/setup-node@v1
with:
node-version: '14'
node-version: '16'
- uses: actions/checkout@v1
- uses: actions/cache@v2
with:
Expand Down
4 changes: 4 additions & 0 deletions .solhint.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
"rules": {
"compiler-version": ["error",">=0.7.5"],
"func-visibility": ["off",{"ignoreConstructors":true}],
"custom-errors": ["off"],
"explicit-types": ["off"],
"no-global-import": ["off"],
"immutable-vars-naming": ["off"],
"mark-callable-contracts": ["off"]
}
}
22 changes: 4 additions & 18 deletions contracts/core/EntryPoint.sol
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard,
}

uint256 actualGas = preGas - gasleft() + opInfo.preOpGas;
collected = _handlePostOp(
collected = _postExecution(
opIndex,
IPaymaster.PostOpMode.postOpReverted,
opInfo,
Expand Down Expand Up @@ -290,7 +290,7 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard,
unchecked {
uint256 actualGas = preGas - gasleft() + opInfo.preOpGas;
// Note: opIndex is ignored (relevant only if mode==postOpReverted, which is only possible outside of innerHandleOp)
return _handlePostOp(0, mode, opInfo, context, actualGas);
return _postExecution(0, mode, opInfo, context, actualGas);
}
}

Expand Down Expand Up @@ -340,7 +340,7 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard,
unchecked {
// When using a Paymaster, the verificationGasLimit is used also to as a limit for the postOp call.
// Our security model might call postOp eventually twice.
uint256 mul = mUserOp.paymaster != address(0) ? 3 : 1;
uint256 mul = mUserOp.paymaster != address(0) ? 2 : 1;
uint256 requiredGas = mUserOp.callGasLimit +
mUserOp.verificationGasLimit *
mul +
Expand Down Expand Up @@ -640,7 +640,7 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard,
* @param context - The context returned in validatePaymasterUserOp.
* @param actualGas - The gas used so far by this user operation.
*/
function _handlePostOp(
function _postExecution(
uint256 opIndex,
IPaymaster.PostOpMode mode,
UserOpInfo memory opInfo,
Expand All @@ -664,20 +664,6 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard,
IPaymaster(paymaster).postOp{
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we still need mode here?

Copy link
Contributor

Choose a reason for hiding this comment

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

in case the PostOp reverts, the "outer" postExecution will report the error (success=false), but there is no indication that it was a paymaster (postOp) that reverted, instead of user-code that reverted.
I suggest emit PostOpRevertReason to report it.
(technically, it is not here, but at the "catch" of the innerHandleOp)

gas: mUserOp.verificationGasLimit
}(mode, context, actualGasCost);
} else {
try
IPaymaster(paymaster).postOp{
gas: mUserOp.verificationGasLimit
}(mode, context, actualGasCost)
// solhint-disable-next-line no-empty-blocks
{} catch Error(string memory reason) {
revert FailedOp(
opIndex,
string.concat("AA50 postOp reverted: ", reason)
);
} catch {
revert FailedOp(opIndex, "AA50 postOp revert");
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion contracts/interfaces/IPaymaster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ interface IPaymaster {
// User op reverted. Still has to pay for gas.
opReverted,
// User op succeeded, but caused postOp to revert.
// Now it's a 2nd call, after user's op was deliberately reverted.
// Only used internally in the EntryPoint - Paymasters will not be called again.
postOpReverted
}

Expand Down
11 changes: 3 additions & 8 deletions contracts/samples/DepositPaymaster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -151,18 +151,13 @@ contract DepositPaymaster is BasePaymaster {
* this time in *postOpReverted* mode.
* In this mode, we use the deposit to pay (which we validated to be large enough)
*/
function _postOp(PostOpMode mode, bytes calldata context, uint256 actualGasCost) internal override {
function _postOp(PostOpMode, bytes calldata context, uint256 actualGasCost) internal override {

(address account, IERC20 token, uint256 gasPricePostOp, uint256 maxTokenCost, uint256 maxCost) = abi.decode(context, (address, IERC20, uint256, uint256, uint256));
//use same conversion rate as used for validation.
uint256 actualTokenCost = (actualGasCost + COST_OF_POST * gasPricePostOp) * maxTokenCost / maxCost;
if (mode != PostOpMode.postOpReverted) {
// attempt to pay with tokens:
token.safeTransferFrom(account, address(this), actualTokenCost);
} else {
//in case above transferFrom failed, pay with deposit:
balances[token][account] -= actualTokenCost;
}
// attempt to pay with tokens:
token.safeTransferFrom(account, address(this), actualTokenCost);
balances[token][owner()] += actualTokenCost;
}
}
8 changes: 1 addition & 7 deletions contracts/samples/TokenPaymaster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,9 @@ contract TokenPaymaster is BasePaymaster, UniswapHelper, OracleHelper {

/// @notice Performs post-operation tasks, such as updating the token price and refunding excess tokens.
/// @dev This function is called after a user operation has been executed or reverted.
/// @param mode The post-operation mode (either successful or reverted).
/// @param context The context containing the token amount and user sender address.
/// @param actualGasCost The actual gas cost of the transaction.
function _postOp(PostOpMode mode, bytes calldata context, uint256 actualGasCost) internal override {
function _postOp(PostOpMode, bytes calldata context, uint256 actualGasCost) internal override {
unchecked {
uint256 priceMarkup = tokenPaymasterConfig.priceMarkup;
(
Expand All @@ -163,11 +162,6 @@ contract TokenPaymaster is BasePaymaster, UniswapHelper, OracleHelper {
address userOpSender
) = abi.decode(context, (uint256, uint256, uint256, address));
uint256 gasPrice = getGasPrice(maxFeePerGas, maxPriorityFeePerGas);
if (mode == PostOpMode.postOpReverted) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe change _handlePostOp() to _postExecution()? It's no longer handling post op only

emit PostOpReverted(userOpSender, preCharge);
// Do nothing here to not revert the whole bundle and harm reputation
return;
}
uint256 _cachedPrice = updateCachedPrice(false);
// note: as price is in ether-per-token and we want more tokens increasing it means dividing it by markup
uint256 cachedPriceWithMarkup = _cachedPrice * PRICE_DENOMINATOR / priceMarkup;
Expand Down
2 changes: 2 additions & 0 deletions contracts/test/BrokenBlsAccount.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// SPDX-License-Identifier: GPL-3.0

/* solhint-disable one-contract-per-file */
pragma solidity ^0.8.12;

import "@openzeppelin/contracts/utils/Create2.sol";
Expand Down
5 changes: 1 addition & 4 deletions contracts/test/TestPaymasterRevertCustomError.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@ contract TestPaymasterRevertCustomError is BasePaymaster {
context = abi.encodePacked(userOp.sender);
}

function _postOp(PostOpMode mode, bytes calldata, uint256) internal pure override {
if(mode == PostOpMode.postOpReverted) {
return;
}
function _postOp(PostOpMode, bytes calldata, uint256) internal pure override {

revert CustomError();
}
Expand Down
5 changes: 2 additions & 3 deletions deploy/1_deploy_entrypoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ const deployEntryPoint: DeployFunction = async function (hre: HardhatRuntimeEnvi
deterministicDeployment: true
})
console.log('==entrypoint addr=', ret.address)
/*

const entryPointAddress = ret.address
const w = await hre.deployments.deploy(
'SimpleAccount', {
from,
args: [entryPointAddress, from],
args: [entryPointAddress],
gasLimit: 2e6,
deterministicDeployment: true
})
Expand All @@ -33,7 +33,6 @@ const deployEntryPoint: DeployFunction = async function (hre: HardhatRuntimeEnvi
deterministicDeployment: true
})
console.log('==testCounter=', t.address)
*/
}

export default deployEntryPoint
2 changes: 1 addition & 1 deletion hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const config: HardhatUserConfig = {
mocha: {
timeout: 10000
},

// @ts-ignore
etherscan: {
apiKey: process.env.ETHERSCAN_API_KEY
}
Expand Down
26 changes: 13 additions & 13 deletions reports/gas-checker.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,36 @@
╔══════════════════════════╤════════╗
║ gas estimate "simple" │ 29014 ║
╟──────────────────────────┼────────╢
║ gas estimate "big tx 5k" │ 125248
║ gas estimate "big tx 5k" │ 125260
╚══════════════════════════╧════════╝

╔════════════════════════════════╤═══════╤═══════════════╤════════════════╤═════════════════════╗
║ handleOps description │ count │ total gasUsed │ per UserOp gas │ per UserOp overhead ║
║ │ │ │ (delta for │ (compared to ║
║ │ │ │ one UserOp) │ account.exec()) ║
╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢
║ simple │ 1 │ 81954 │ │ ║
║ simple │ 1 │ 81838 │ │ ║
╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢
║ simple - diff from previous │ 2 │ │ 4418715173
║ simple - diff from previous │ 2 │ │ 4409515081
╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢
║ simple │ 10 │ 479898 │ │ ║
║ simple │ 10 │ 478810 │ │ ║
╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢
║ simple - diff from previous │ 11 │ │ 4427115257
║ simple - diff from previous │ 11 │ │ 4413115117
╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢
║ simple paymaster │ 1 │ 88237 │ │ ║
║ simple paymaster │ 1 │ 88109 │ │ ║
╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢
║ simple paymaster with diff │ 2 │ │ 4320014186
║ simple paymaster with diff │ 2 │ │ 4309614082
╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢
║ simple paymaster │ 10 │ 477146 │ │ ║
║ simple paymaster │ 10 │ 476022 │ │ ║
╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢
║ simple paymaster with diff │ 11 │ │ 4327114257
║ simple paymaster with diff │ 11 │ │ 4315514141
╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢
║ big tx 5k │ 1 │ 182975 │ │ ║
║ big tx 5k │ 1 │ 182895 │ │ ║
╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢
║ big tx - diff from previous │ 2 │ │ 14471019462
║ big tx - diff from previous │ 2 │ │ 14459419334
╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢
║ big tx 5k │ 10 │ 1485530 │ │ ║
║ big tx 5k │ 10 │ 1484454 │ │ ║
╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢
║ big tx - diff from previous │ 11 │ │ 14478319535
║ big tx - diff from previous │ 11 │ │ 14461919359
╚════════════════════════════════╧═══════╧═══════════════╧════════════════╧═════════════════════╝

3 changes: 2 additions & 1 deletion test/entrypoint.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ import {
TestSignatureAggregator__factory,
MaliciousAccount__factory,
TestWarmColdAccount__factory,
TestPaymasterRevertCustomError__factory,
IEntryPoint__factory,
SimpleAccountFactory__factory,
IStakeManager__factory,
INonceManager__factory,
EntryPoint__factory,
TestPaymasterRevertCustomError__factory, EntryPoint
EntryPoint
} from '../typechain'
import {
AddressZero,
Expand Down
14 changes: 9 additions & 5 deletions test/paymaster.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,14 +231,13 @@ describe('EntryPoint with paymaster', function () {
expect(await paymaster.allowance(account2.address, account.address)).to.eq(ethers.constants.MaxUint256)
})

it('griefing attempt should cause handleOp to revert', async () => {
it('griefing attempt in postOp should cause the execution part of UserOp to revert', async () => {
// account1 is approved to withdraw going to withdraw account2's balance

const account2Balance = await paymaster.balanceOf(account2.address)
const transferCost = parseEther('1').sub(account2Balance)
const withdrawAmount = account2Balance.sub(transferCost.mul(0))
const withdrawTokens = paymaster.interface.encodeFunctionData('transferFrom', [account2.address, account.address, withdrawAmount])
// const withdrawTokens = paymaster.interface.encodeFunctionData('transfer', [account.address, parseEther('0.1')])
const execFromEntryPoint = account.interface.encodeFunctionData('execute', [paymaster.address, 0, withdrawTokens])

const userOp1 = await fillAndSign({
Expand All @@ -255,12 +254,17 @@ describe('EntryPoint with paymaster', function () {
callGasLimit: 1e6
}, accountOwner, entryPoint)

await expect(
entryPoint.handleOps([
const rcpt =
await entryPoint.handleOps([
userOp1,
userOp2
], beneficiaryAddress)
).to.be.revertedWith('transfer amount exceeds balance')

const transferEvents = await paymaster.queryFilter(paymaster.filters.Transfer(), rcpt.blockHash)
const [log1, log2] = await entryPoint.queryFilter(entryPoint.filters.UserOperationEvent(), rcpt.blockHash)
expect(log1.args.success).to.eq(true)
expect(log2.args.success).to.eq(false)
expect(transferEvents.length).to.eq(2)
})
})
})
Expand Down
Loading
Loading