Skip to content

Commit

Permalink
Use hardhat impersonating signer to make calls on behalf of the Entry…
Browse files Browse the repository at this point in the history
…Point
  • Loading branch information
forshtat committed Dec 19, 2024
1 parent f393000 commit afeca9a
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 15 deletions.
3 changes: 2 additions & 1 deletion test/UserOp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,9 @@ export async function fillUserOp (op: Partial<UserOperation>, entryPoint?: Entry
}
if (op1.verificationGasLimit == null) {
if (provider == null) throw new Error('no entrypoint/provider')
const senderCreator = await entryPoint?.senderCreator()
const initEstimate = await provider.estimateGas({
from: entryPoint?.address,
from: senderCreator,
to: initAddr,
data: initCallData,
gasLimit: 10e6
Expand Down
2 changes: 1 addition & 1 deletion test/entrypoint.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -840,7 +840,7 @@ describe('EntryPoint', function () {
const senderCreator = SenderCreator__factory.connect(senderCreatorAddress, ethersSigner)
await expect(
senderCreator.createSender('0xdeadbeef', { gasLimit: 1000000 })
).to.be.revertedWith('AAxx should call from EntryPoint')
).to.be.revertedWith('AA97 should call from EntryPoint')
})

it('should reject create if sender address is wrong', async () => {
Expand Down
1 change: 1 addition & 0 deletions test/entrypointsimulations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ describe('EntryPointSimulations', function () {
const { proxy: account } = await createAccount(ethersSigner, await accountOwner.getAddress(), entryPoint.address)
const sender = createAddress()
const op1 = await fillSignAndPack({
verificationGasLimit: 150000, // providing default value as gas estimation will fail
initCode: hexConcat([
account.address,
account.interface.encodeFunctionData('execute', [sender, 0, '0x'])
Expand Down
35 changes: 24 additions & 11 deletions test/simple-wallet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ethers } from 'hardhat'
import { expect } from 'chai'
import {
ERC1967Proxy__factory,
EntryPoint,
SimpleAccount,
SimpleAccountFactory__factory,
SimpleAccount__factory,
Expand All @@ -12,27 +13,29 @@ import {
TestUtil__factory
} from '../typechain'
import {
HashZero,
ONE_ETH,
createAccount,
createAddress,
createAccountOwner,
createAddress,
deployEntryPoint,
getBalance,
isDeployed,
ONE_ETH,
HashZero, deployEntryPoint
isDeployed
} from './testutils'
import { fillUserOpDefaults, getUserOpHash, encodeUserOp, signUserOp, packUserOp } from './UserOp'
import { parseEther } from 'ethers/lib/utils'
import { UserOperation } from './UserOperation'
import { JsonRpcProvider } from '@ethersproject/providers'

describe('SimpleAccount', function () {
let entryPoint: string
let entryPoint: EntryPoint
let accounts: string[]
let testUtil: TestUtil
let accountOwner: Wallet
const ethersSigner = ethers.provider.getSigner()

before(async function () {
entryPoint = await deployEntryPoint().then(e => e.address)
entryPoint = await deployEntryPoint()
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 All @@ -41,12 +44,12 @@ describe('SimpleAccount', function () {
})

it('owner should be able to call transfer', async () => {
const { proxy: account } = await createAccount(ethers.provider.getSigner(), accounts[0], entryPoint)
const { proxy: account } = await createAccount(ethers.provider.getSigner(), accounts[0], entryPoint.address)
await ethersSigner.sendTransaction({ from: accounts[0], to: account.address, value: parseEther('2') })
await account.execute(accounts[2], ONE_ETH, '0x')
})
it('other account should not be able to call transfer', async () => {
const { proxy: account } = await createAccount(ethers.provider.getSigner(), accounts[0], entryPoint)
const { proxy: account } = await createAccount(ethers.provider.getSigner(), accounts[0], entryPoint.address)
await expect(account.connect(ethers.provider.getSigner(1)).execute(accounts[2], ONE_ETH, '0x'))
.to.be.revertedWith('account: not Owner or EntryPoint')
})
Expand All @@ -62,7 +65,7 @@ describe('SimpleAccount', function () {
let account: SimpleAccount
let counter: TestCounter
before(async () => {
({ proxy: account } = await createAccount(ethersSigner, await ethersSigner.getAddress(), entryPoint))
({ proxy: account } = await createAccount(ethersSigner, await ethersSigner.getAddress(), entryPoint.address))
counter = await new TestCounter__factory(ethersSigner).deploy()
})

Expand Down Expand Up @@ -155,9 +158,19 @@ describe('SimpleAccount', function () {
})

context('SimpleAccountFactory', () => {
it('sanity: check deployer', async () => {
it('should reject calls coming from any address that is not SenderCreator', async () => {
const ownerAddr = createAddress()
const deployer = await new SimpleAccountFactory__factory(ethersSigner).deploy(entryPoint)
let deployer = await new SimpleAccountFactory__factory(ethersSigner).deploy(entryPoint.address)
await expect(deployer.createAccount(ownerAddr, 1234))
.to.be.revertedWith('only callable from SenderCreator')

// switch deployer contract to an impersonating signer
const senderCreator = await entryPoint.senderCreator()
await (ethersSigner.provider as JsonRpcProvider).send('hardhat_impersonateAccount', [senderCreator])
await (ethersSigner.provider as JsonRpcProvider).send('hardhat_setBalance', [senderCreator, parseEther('100').toHexString()])
const senderCreatorSigner = await ethers.getSigner(senderCreator)
deployer = deployer.connect(senderCreatorSigner)

const target = await deployer.callStatic.createAccount(ownerAddr, 1234)
expect(await isDeployed(target)).to.eq(false)
await deployer.createAccount(ownerAddr, 1234)
Expand Down
11 changes: 9 additions & 2 deletions test/testutils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { ethers } from 'hardhat'
import {
arrayify,
hexConcat, hexDataSlice,
hexConcat,
hexDataSlice,
hexlify,
hexZeroPad,
Interface,
Expand All @@ -20,6 +21,7 @@ import {
TestAggregatedAccountFactory, TestPaymasterRevertCustomError__factory, TestERC20__factory
} from '../typechain'
import { BytesLike, Hexable } from '@ethersproject/bytes'
import { JsonRpcProvider } from '@ethersproject/providers'
import { expect } from 'chai'
import { Create2Factory } from '../src/Create2Factory'
import { debugTransaction } from './debugTx'
Expand Down Expand Up @@ -298,7 +300,12 @@ export async function createAccount (
}> {
const accountFactory = _factory ?? await new SimpleAccountFactory__factory(ethersSigner).deploy(entryPoint)
const implementation = await accountFactory.accountImplementation()
await accountFactory.createAccount(accountOwner, 0)
const entryPointContract = EntryPoint__factory.connect(entryPoint, ethersSigner)
const senderCreator = await entryPointContract.senderCreator()
await (ethersSigner.provider as JsonRpcProvider).send('hardhat_impersonateAccount', [senderCreator])
await (ethersSigner.provider as JsonRpcProvider).send('hardhat_setBalance', [senderCreator, parseEther('100').toHexString()])
const senderCreatorSigner = await ethers.getSigner(senderCreator)
await accountFactory.connect(senderCreatorSigner).createAccount(accountOwner, 0)
const accountAddress = await accountFactory.getAddress(accountOwner, 0)
const proxy = SimpleAccount__factory.connect(accountAddress, ethersSigner)
return {
Expand Down

0 comments on commit afeca9a

Please sign in to comment.