Skip to content

Commit

Permalink
simulator should not be deployed
Browse files Browse the repository at this point in the history
  • Loading branch information
drortirosh committed Sep 6, 2023
1 parent c254faf commit a9caa9c
Show file tree
Hide file tree
Showing 10 changed files with 49 additions and 57 deletions.
8 changes: 8 additions & 0 deletions contracts/core/EntryPointSimulations.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ contract EntryPointSimulations is EntryPoint, IEntryPointSimulations {
// solhint-disable-next-line var-name-mixedcase
AggregatorStakeInfo private NOT_AGGREGATED = AggregatorStakeInfo(address(0), StakeInfo(0, 0));

/**
* simulation contract should not be deployed, and specifically, accounts should not trust
* it as entrypoint, since the simulation functions don't check the signatures
*/
constructor() {
require(block.number < 100, "should not be deployed");
}

/// @inheritdoc IEntryPointSimulations
function simulateValidation(
UserOperation calldata userOp
Expand Down
3 changes: 1 addition & 2 deletions gascalc/GasChecker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import {
AddressZero,
checkForGeth,
createAddress,
createAccountOwner,
deployActualEntryPoint
createAccountOwner
} from '../test/testutils'
import {
EntryPoint, EntryPoint__factory, SimpleAccountFactory,
Expand Down
42 changes: 22 additions & 20 deletions test/entrypoint.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import {
getAggregatedAccountInitCode,
decodeRevertReason
} from './testutils'
import { DefaultsForUserOp, fillAndSign, getUserOpHash } from './UserOp'
import { DefaultsForUserOp, fillAndSign, getUserOpHash, simulateValidation } from './UserOp'
import { UserOperation } from './UserOperation'
import { PopulatedTransaction } from 'ethers/lib/ethers'
import { ethers } from 'hardhat'
Expand Down Expand Up @@ -236,7 +236,7 @@ describe('EntryPoint', function () {
sender: await getAccountAddress(accountOwner1.address, simpleAccountFactory)
}, accountOwner1, entryPoint)
await fund(op1.sender)
await entryPoint.simulateValidation(op1, { gasLimit: 10e6 }).catch(e => e)
await simulateValidation(op1, entryPoint.address, { gasLimit: 10e6 }).catch(e => e)
const block = await ethers.provider.getBlock('latest')
const hash = block.transactions[0]
await checkForBannedOps(hash, false)
Expand Down Expand Up @@ -278,11 +278,11 @@ describe('EntryPoint', function () {
paymasterAndData: '0x'
}
try {
await entryPoint.callStatic.simulateValidation(userOp, { gasLimit: 1e6 })
await simulateValidation(userOp, entryPoint.address, { gasLimit: 1e6 })

console.log('after first simulation')
await ethers.provider.send('evm_mine', [])
await expect(entryPoint.simulateValidation(userOp, { gasLimit: 1e6 }))
await expect(simulateValidation(userOp, entryPoint.address, { gasLimit: 1e6 }))
.to.revertedWith('Revert after first validation')
// if we get here, it means the userOp passed first sim and reverted second
expect.fail(null, null, 'should fail on first simulation')
Expand All @@ -306,7 +306,7 @@ describe('EntryPoint', function () {
callData: badData.data!
}
const beneficiaryAddress = createAddress()
await entryPoint.callStatic.simulateValidation(badOp, { gasLimit: 3e5 })
await simulateValidation(badOp, entryPoint.address, { gasLimit: 3e5 })

const tx = await entryPoint.handleOps([badOp], beneficiaryAddress) // { gasLimit: 3e5 })
const receipt = await tx.wait()
Expand All @@ -328,13 +328,14 @@ describe('EntryPoint', function () {
}
const beneficiaryAddress = createAddress()
try {
await entryPoint.simulateValidation(badOp, { gasLimit: 1e6 })
await simulateValidation(badOp, entryPoint.address, { gasLimit: 1e6 })
throw new Error('should revert')
} catch (e: any) {
if ((e as Error).message.includes('ValidationResult')) {
const tx = await entryPoint.handleOps([badOp], beneficiaryAddress, { gasLimit: 1e6 })
await tx.wait()
} else {
expect(e.message).to.include('FailedOp(0, "AA23 reverted (or OOG)")')
expect(e.message).to.include('AA23 reverted (or OOG)')
}
}
})
Expand All @@ -352,13 +353,14 @@ describe('EntryPoint', function () {
}
const beneficiaryAddress = createAddress()
try {
await entryPoint.simulateValidation(badOp, { gasLimit: 1e6 })
await simulateValidation(badOp, entryPoint.address, { gasLimit: 1e6 })
throw new Error('should revert')
} catch (e: any) {
if ((e as Error).message.includes('ValidationResult')) {
const tx = await entryPoint.handleOps([badOp], beneficiaryAddress, { gasLimit: 1e6 })
await tx.wait()
} else {
expect(e.message).to.include('FailedOp(0, "AA23 reverted (or OOG)")')
expect(e.message).to.include('AA23 reverted (or OOG)')
}
}
})
Expand Down Expand Up @@ -660,13 +662,13 @@ describe('EntryPoint', function () {
verificationGasLimit: 5e5
}, accountOwner, entryPoint)
// must succeed with enough verification gas
await entryPoint.callStatic.simulateValidation(op0)
await simulateValidation(op0, entryPoint.address)

const op1 = await fillAndSign({
sender: account.address,
verificationGasLimit: 10000
}, accountOwner, entryPoint)
await expect(entryPoint.callStatic.simulateValidation(op1))
await expect(simulateValidation(op1, entryPoint.address))
.to.revertedWith('AA23 reverted (or OOG)')
})
})
Expand Down Expand Up @@ -784,7 +786,7 @@ describe('EntryPoint', function () {
verificationGasLimit: 76000
}, accountOwner2, entryPoint)

await entryPoint.callStatic.simulateValidation(op2, { gasPrice: 1e9 })
await simulateValidation(op2, entryPoint.address)

await fund(op1.sender)
await fund(account2.address)
Expand Down Expand Up @@ -967,7 +969,7 @@ describe('EntryPoint', function () {
})
it('simulateValidation should return aggregator and its stake', async () => {
await aggregator.addStake(entryPoint.address, 3, { value: TWO_ETH })
const { aggregatorInfo } = await entryPoint.callStatic.simulateValidation(userOp)
const { aggregatorInfo } = await simulateValidation(userOp, entryPoint.address)
expect(aggregatorInfo.aggregator).to.equal(aggregator.address)
expect(aggregatorInfo.stakeInfo.stake).to.equal(TWO_ETH)
expect(aggregatorInfo.stakeInfo.unstakeDelaySec).to.equal(3)
Expand Down Expand Up @@ -1008,7 +1010,7 @@ describe('EntryPoint', function () {
verificationGasLimit: 3e6,
callGasLimit: 1e6
}, account2Owner, entryPoint)
await expect(entryPoint.simulateValidation(op)).to.revertedWith('"AA30 paymaster not deployed"')
await expect(simulateValidation(op, entryPoint.address)).to.revertedWith('"AA30 paymaster not deployed"')
})

it('should fail if paymaster has no deposit', async function () {
Expand Down Expand Up @@ -1067,7 +1069,7 @@ describe('EntryPoint', function () {
initCode: getAccountInitCode(anOwner.address, simpleAccountFactory)
}, anOwner, entryPoint)

const { paymasterInfo } = await entryPoint.callStatic.simulateValidation(op)
const { paymasterInfo } = await simulateValidation(op, entryPoint.address)
const {
stake: simRetStake,
unstakeDelaySec: simRetDelay
Expand Down Expand Up @@ -1098,7 +1100,7 @@ describe('EntryPoint', function () {
const userOp = await fillAndSign({
sender: account.address
}, sessionOwner, entryPoint)
const ret = await entryPoint.callStatic.simulateValidation(userOp)
const ret = await simulateValidation(userOp, entryPoint.address)
expect(ret.returnInfo.validUntil).to.eql(now + 60)
expect(ret.returnInfo.validAfter).to.eql(100)
})
Expand All @@ -1109,7 +1111,7 @@ describe('EntryPoint', function () {
const userOp = await fillAndSign({
sender: account.address
}, expiredOwner, entryPoint)
const ret = await entryPoint.callStatic.simulateValidation(userOp)
const ret = await simulateValidation(userOp, entryPoint.address)
expect(ret.returnInfo.validUntil).eql(now - 60)
expect(ret.returnInfo.validAfter).to.eql(123)
})
Expand All @@ -1132,7 +1134,7 @@ describe('EntryPoint', function () {
sender: account.address,
paymasterAndData: hexConcat([paymaster.address, timeRange])
}, ethersSigner, entryPoint)
const ret = await entryPoint.callStatic.simulateValidation(userOp)
const ret = await simulateValidation(userOp, entryPoint.address)
expect(ret.returnInfo.validUntil).to.eql(now + 60)
expect(ret.returnInfo.validAfter).to.eql(123)
})
Expand All @@ -1143,7 +1145,7 @@ describe('EntryPoint', function () {
sender: account.address,
paymasterAndData: hexConcat([paymaster.address, timeRange])
}, ethersSigner, entryPoint)
const ret = await entryPoint.callStatic.simulateValidation(userOp)
const ret = await simulateValidation(userOp, entryPoint.address)
expect(ret.returnInfo.validUntil).to.eql(now - 60)
expect(ret.returnInfo.validAfter).to.eql(321)
})
Expand All @@ -1166,7 +1168,7 @@ describe('EntryPoint', function () {

async function simulateWithPaymasterParams (after: number, until: number): Promise<any> {
const userOp = await createOpWithPaymasterParams(owner, after, until)
const ret = await entryPoint.callStatic.simulateValidation(userOp)
const ret = await simulateValidation(userOp, entryPoint.address)
return ret.returnInfo
}

Expand Down
7 changes: 3 additions & 4 deletions test/entrypointsimulations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@ import {
createAccount,
createAccountOwner,
createAddress,
deployActualEntryPoint,
fund,
getAccountAddress,
getAccountInitCode,
getBalance
getBalance, deployEntryPoint
} from './testutils'

import { fillAndSign, simulateHandleOp, simulateValidation } from './UserOp'
Expand All @@ -35,7 +34,7 @@ describe('EntryPointSimulations', function () {
let epSimulation: EntryPointSimulations

before(async function () {
entryPoint = await deployActualEntryPoint()
entryPoint = await deployEntryPoint()
epSimulation = await new EntryPointSimulations__factory(provider.getSigner()).deploy()

accountOwner = createAccountOwner();
Expand All @@ -47,7 +46,7 @@ describe('EntryPointSimulations', function () {
// await checkStateDiffSupported()
})

describe('Simulation Contract Sannity checks', () => {
describe('Simulation Contract Sanity checks', () => {
const addr = createAddress()

// coverage skews gas checks.
Expand Down
4 changes: 2 additions & 2 deletions test/paymaster.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
createAccount,
getAccountAddress
} from './testutils'
import { fillAndSign } from './UserOp'
import { fillAndSign, simulateValidation } from './UserOp'
import { hexConcat, parseEther } from 'ethers/lib/utils'
import { UserOperation } from './UserOperation'
import { hexValue } from '@ethersproject/bytes'
Expand Down Expand Up @@ -140,7 +140,7 @@ describe('EntryPoint with paymaster', function () {
// paymaster is the token, so no need for "approve" or any init function...

const snapshot = await ethers.provider.send('evm_snapshot', [])
await entryPoint.simulateValidation(createOp, { gasLimit: 5e6 }).catch(e => e.message)
await simulateValidation(createOp, entryPoint.address, { gasLimit: 5e6 }).catch(e => e.message)
const [tx] = await ethers.provider.getBlock('latest').then(block => block.transactions)
await checkForBannedOps(tx, true)
await ethers.provider.send('evm_revert', [snapshot])
Expand Down
4 changes: 2 additions & 2 deletions test/samples/TokenPaymaster.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
OracleHelper as OracleHelperNamespace,
UniswapHelper as UniswapHelperNamespace
} from '../../typechain/contracts/samples/TokenPaymaster'
import { checkForGeth, createAccount, createAccountOwner, deployActualEntryPoint, fund } from '../testutils'
import { checkForGeth, createAccount, createAccountOwner, deployEntryPoint, fund } from '../testutils'

import { fillUserOp, signUserOp } from '../UserOp'

Expand Down Expand Up @@ -72,7 +72,7 @@ describe('TokenPaymaster', function () {
let weth: TestWrappedNativeToken

before(async function () {
entryPoint = await deployActualEntryPoint()
entryPoint = await deployEntryPoint()
weth = await new TestWrappedNativeToken__factory(ethersSigner).deploy()
testUniswap = await new TestUniswap__factory(ethersSigner).deploy(weth.address)
factory = await new SimpleAccountFactory__factory(ethersSigner).deploy(entryPoint.address)
Expand Down
5 changes: 2 additions & 3 deletions test/simple-wallet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,10 @@ import {
createAccount,
createAddress,
createAccountOwner,
deployActualEntryPoint,
getBalance,
isDeployed,
ONE_ETH,
HashZero
HashZero, deployEntryPoint
} from './testutils'
import { fillUserOpDefaults, getUserOpHash, packUserOp, signUserOp } from './UserOp'
import { parseEther } from 'ethers/lib/utils'
Expand All @@ -33,7 +32,7 @@ describe('SimpleAccount', function () {
const ethersSigner = ethers.provider.getSigner()

before(async function () {
entryPoint = await deployActualEntryPoint().then(e => e.address)
entryPoint = await deployEntryPoint().then(e => e.address)
accounts = await ethers.provider.listAccounts()
// ignore in geth.. this is just a sanity test. should be refactored to use a single-account mode..
if (accounts.length < 2) this.skip()
Expand Down
19 changes: 2 additions & 17 deletions test/testutils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ import {
SimpleAccountFactory__factory,
SimpleAccount__factory,
SimpleAccountFactory,
TestAggregatedAccountFactory,
EntryPointSimulations__factory,
EntryPointSimulations
TestAggregatedAccountFactory
} from '../typechain'
import { BytesLike } from '@ethersproject/bytes'
import { expect } from 'chai'
Expand Down Expand Up @@ -245,25 +243,12 @@ export async function checkForBannedOps (txHash: string, checkPaymaster: boolean
}
}

/**
* This deploys the EntryPoint that does not contain the simulation functions, as will be deployed to real networks.
*/
export async function deployActualEntryPoint (provider = ethers.provider): Promise<EntryPoint> {
export async function deployEntryPoint (provider = ethers.provider): Promise<EntryPoint> {
const create2factory = new Create2Factory(provider)
const addr = await create2factory.deploy(EntryPoint__factory.bytecode, 0, process.env.COVERAGE != null ? 20e6 : 8e6)
return EntryPoint__factory.connect(addr, provider.getSigner())
}

/**
* Deploying the entry point with simulation code is required for testing as hardhat does not support state overrides.
* TODO: remove this once hardhat fixes the issue: https://github.com/NomicFoundation/hardhat/issues/2513
*/
export async function deployEntryPoint (provider = ethers.provider): Promise<EntryPointSimulations> {
const create2factory = new Create2Factory(provider)
const addr = await create2factory.deploy(EntryPointSimulations__factory.bytecode, 0, process.env.COVERAGE != null ? 20e6 : 8e6)
return EntryPointSimulations__factory.connect(addr, provider.getSigner())
}

export async function isDeployed (addr: string): Promise<boolean> {
const code = await ethers.provider.getCode(addr)
return code.length > 2
Expand Down
10 changes: 5 additions & 5 deletions test/verifying_paymaster.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
createAccountOwner, createAddress,
deployEntryPoint
} from './testutils'
import { fillAndSign } from './UserOp'
import { fillAndSign, simulateValidation } from './UserOp'
import { arrayify, defaultAbiCoder, hexConcat, parseEther } from 'ethers/lib/utils'
import { UserOperation } from './UserOperation'

Expand Down Expand Up @@ -57,15 +57,15 @@ describe('EntryPoint with VerifyingPaymaster', function () {
sender: account.address,
paymasterAndData: hexConcat([paymaster.address, defaultAbiCoder.encode(['uint48', 'uint48'], [MOCK_VALID_UNTIL, MOCK_VALID_AFTER]), '0x1234'])
}, accountOwner, entryPoint)
await expect(entryPoint.callStatic.simulateValidation(userOp)).to.be.revertedWith('invalid signature length in paymasterAndData')
await expect(simulateValidation(userOp, entryPoint.address)).to.be.revertedWith('invalid signature length in paymasterAndData')
})

it('should reject on invalid signature', async () => {
const userOp = await fillAndSign({
sender: account.address,
paymasterAndData: hexConcat([paymaster.address, defaultAbiCoder.encode(['uint48', 'uint48'], [MOCK_VALID_UNTIL, MOCK_VALID_AFTER]), '0x' + '00'.repeat(65)])
}, accountOwner, entryPoint)
await expect(entryPoint.callStatic.simulateValidation(userOp)).to.be.revertedWith('ECDSA: invalid signature')
await expect(simulateValidation(userOp, entryPoint.address)).to.be.revertedWith('ECDSA: invalid signature')
})

describe('with wrong signature', () => {
Expand All @@ -80,7 +80,7 @@ describe('EntryPoint with VerifyingPaymaster', function () {
})

it('should return signature error (no revert) on wrong signer signature', async () => {
const ret = await entryPoint.callStatic.simulateValidation(wrongSigUserOp)
const ret = await simulateValidation(wrongSigUserOp, entryPoint.address)
expect(ret.returnInfo.sigFailed).to.be.true
})

Expand All @@ -100,7 +100,7 @@ describe('EntryPoint with VerifyingPaymaster', function () {
...userOp1,
paymasterAndData: hexConcat([paymaster.address, defaultAbiCoder.encode(['uint48', 'uint48'], [MOCK_VALID_UNTIL, MOCK_VALID_AFTER]), sig])
}, accountOwner, entryPoint)
const res = await entryPoint.callStatic.simulateValidation(userOp)
const res = await simulateValidation(userOp, entryPoint.address)
expect(res.returnInfo.sigFailed).to.be.false
expect(res.returnInfo.validAfter).to.be.equal(ethers.BigNumber.from(MOCK_VALID_AFTER))
expect(res.returnInfo.validUntil).to.be.equal(ethers.BigNumber.from(MOCK_VALID_UNTIL))
Expand Down
4 changes: 2 additions & 2 deletions test/y.bls.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
} from '../typechain'
import { ethers } from 'hardhat'
import { createAddress, deployEntryPoint, fund, ONE_ETH } from './testutils'
import { DefaultsForUserOp, fillUserOp } from './UserOp'
import { DefaultsForUserOp, fillUserOp, simulateValidation } from './UserOp'
import { expect } from 'chai'
import { keccak256 } from 'ethereumjs-util'
import { hashToPoint } from '@thehubbleproject/bls/dist/mcl'
Expand Down Expand Up @@ -190,7 +190,7 @@ describe('bls account', function () {
const sigParts = signer3.sign(requestHash)
userOp.signature = hexConcat(sigParts)

const { aggregatorInfo } = await entrypoint.callStatic.simulateValidation(userOp)
const { aggregatorInfo } = await simulateValidation(userOp, entrypoint.address)
expect(aggregatorInfo.aggregator).to.eq(blsAgg.address)
expect(aggregatorInfo.stakeInfo.stake).to.eq(ONE_ETH)
expect(aggregatorInfo.stakeInfo.unstakeDelaySec).to.eq(2)
Expand Down

0 comments on commit a9caa9c

Please sign in to comment.