Skip to content

Commit

Permalink
Also Move Testing Utilies To Local Bundler Package
Browse files Browse the repository at this point in the history
  • Loading branch information
nlordell committed Mar 18, 2024
1 parent a00c264 commit 8b25fd7
Show file tree
Hide file tree
Showing 29 changed files with 609 additions and 753 deletions.
3 changes: 1 addition & 2 deletions examples/4337-gas-metering/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"alchemy:erc721": "tsx ./alchemy/alchemy.ts erc721",
"alchemy:erc721:paymaster": "tsx ./alchemy/alchemy.ts erc721 paymaster=true",
"alchemy": "tsx ./alchemy/alchemy.ts",
"build": "npx rimraf dist && tsc",
"build": "rimraf dist && tsc",
"fmt": "prettier --ignore-path .gitignore --write .",
"fmt:check": "prettier --check .",
"lint": "eslint ./alchemy && eslint ./gelato && eslint ./pimlico && eslint ./utils",
Expand Down Expand Up @@ -60,7 +60,6 @@
},
"devDependencies": {
"@types/node": "20.11.18",
"rimraf": "^5.0.5",
"tsx": "4.7.1",
"typescript": "^5.3.3"
}
Expand Down
11 changes: 5 additions & 6 deletions modules/4337/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
],
"scripts": {
"build": "npm run build:sol && npm run build:ts",
"build:ts": "npx rimraf dist && tsc",
"build:sol": "npx rimraf build && hardhat compile",
"build:ts": "rimraf dist && tsc",
"build:sol": "rimraf build typechain-types && hardhat compile",
"test": "hardhat test --deploy-fixture",
"test:4337": "4337-local-bundler-test",
"test:4337:upstream": "USE_UPSTREAM_BUNDLER=1 4337-local-bundler-test",
Expand All @@ -31,9 +31,7 @@
"lint:ts": "eslint ./src --fix && eslint ./test --fix",
"fmt": "prettier --write ./contracts/**/*.sol",
"fmt:check": "prettier --check ./**/*.sol",
"prepack": "npm run build",
"prepublish": "npm run build",
"postinstall": "npm run build"
"prepare": "npm run build"
},
"repository": {
"type": "git",
Expand All @@ -55,6 +53,7 @@
"@nomicfoundation/hardhat-toolbox": "^4.0.0",
"@openzeppelin/contracts": "^5.0.2",
"@safe-global/safe-4337-local-bundler": "^0.0.0",
"@safe-global/safe-4337-provider": "^0.0.0",
"@simplewebauthn/server": "9.0.0",
"@types/chai": "^4.3.11",
"@types/mocha": "^10.0.6",
Expand All @@ -75,7 +74,7 @@
},
"overrides": {
"@safe-global/safe-contracts": {
"ethers": "^6.11.0"
"ethers": "^6.11.1"
}
},
"dependencies": {
Expand Down
60 changes: 4 additions & 56 deletions modules/4337/src/utils/safe.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { AddressLike, JsonRpcProvider, Provider, Signer, ethers } from 'ethers'
import { MultiProvider4337, RpcProvider } from '@safe-global/safe-4337-provider'
import { Provider, Signer, ethers } from 'ethers'

// Import from Safe contracts repo once it is upgraded to ethers v6 and can be installed via npm
import { MetaTransaction, SafeSignature, SignedSafeTransaction, buildSignatureBytes } from './execution'
import { PackedUserOperation, UserOperation, EIP712_SAFE_OPERATION_TYPE, packGasParameters, unpackUserOperation } from './userOp'

export { MultiProvider4337 }

const AddressOne = '0x0000000000000000000000000000000000000001'

const INTERFACES = new ethers.Interface([
Expand Down Expand Up @@ -91,61 +94,6 @@ const actionCalldata = (action: MetaTransaction): string => {
return INTERFACES.encodeFunctionData('executeUserOp', [action.to, action.value, action.data, action.operation])
}

export interface RpcProvider extends Provider {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
send(method: string, params: unknown[]): Promise<any>
}

export class MultiProvider4337 extends JsonRpcProvider {
generalProvider: RpcProvider
constructor(aaProviderUrl: string, generalProvider: RpcProvider) {
super(aaProviderUrl)
this.generalProvider = generalProvider
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
send(method: string, params: unknown[]): Promise<any> {
if (
[
'eth_supportedEntryPoints',
'eth_estimateUserOperationGas',
'eth_sendUserOperation',
'eth_getUserOperationByHash',
'eth_getUserOperationReceipt',
].indexOf(method) >= 0
) {
return super.send(method, params)
} else {
return this.generalProvider.send(method, params)
}
}

public async sendUserOperation(userOp: UserOperation, entryPoint: AddressLike): Promise<string> {
const jsonUserOp = {
sender: ethers.getAddress(userOp.sender),
nonce: ethers.toBeHex(userOp.nonce),
callData: ethers.hexlify(userOp.callData),
callGasLimit: ethers.toBeHex(userOp.callGasLimit),
verificationGasLimit: ethers.toBeHex(userOp.verificationGasLimit),
preVerificationGas: ethers.toBeHex(userOp.preVerificationGas),
maxFeePerGas: ethers.toBeHex(userOp.maxFeePerGas),
maxPriorityFeePerGas: ethers.toBeHex(userOp.maxPriorityFeePerGas),
signature: ethers.hexlify(userOp.signature),
} as Record<string, unknown>
if (userOp.factory) {
jsonUserOp.factory = ethers.getAddress(userOp.factory)
jsonUserOp.factoryData = ethers.hexlify(userOp.factoryData!)
}
if (userOp.paymaster) {
jsonUserOp.paymaster = ethers.getAddress(userOp.paymaster)
jsonUserOp.paymasterVerificationGasLimit = ethers.toBeHex(userOp.paymasterVerificationGasLimit!)
jsonUserOp.paymasterPostOpGasLimit = ethers.toBeHex(userOp.paymasterPostOpGasLimit!)
jsonUserOp.paymasterData = ethers.hexlify(userOp.paymasterData!)
}
return await super.send('eth_sendUserOperation', [jsonUserOp, await ethers.resolveAddress(entryPoint, this)])
}
}

export class Safe4337Operation {
private safe: Safe4337
private action: MetaTransaction
Expand Down
21 changes: 2 additions & 19 deletions modules/4337/src/utils/userOp.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { UserOperation } from '@safe-global/safe-4337-provider'
import { BigNumberish, BytesLike, Contract, Signer, ethers } from 'ethers'
import { PackedUserOperationStruct as PackedUserOperation } from '../../typechain-types/contracts/Safe4337Module'
import { SafeSignature } from './execution'

export { PackedUserOperation }
export { PackedUserOperation, UserOperation }

type OptionalExceptFor<T, TRequired extends keyof T = keyof T> = Partial<Pick<T, Exclude<keyof T, TRequired>>> &
Required<Pick<T, TRequired>>
Expand All @@ -15,24 +16,6 @@ export type SafeUserOperation = {
} & GasParameters &
Omit<PackedUserOperation, 'sender' | 'signature' | keyof PackedGasParameters>

export type UserOperation = {
sender: string
nonce: BigNumberish
factory?: string
factoryData?: BytesLike
callData: BytesLike
callGasLimit: BigNumberish
verificationGasLimit: BigNumberish
preVerificationGas: BigNumberish
maxFeePerGas: BigNumberish
maxPriorityFeePerGas: BigNumberish
paymaster?: string
paymasterVerificationGasLimit?: BigNumberish
paymasterPostOpGasLimit?: BigNumberish
paymasterData?: BytesLike
signature: BytesLike
}

export const EIP712_SAFE_OPERATION_TYPE = {
SafeOp: [
{ type: 'address', name: 'safe' },
Expand Down
4 changes: 2 additions & 2 deletions modules/4337/test/e2e/4337NestedSafe.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { bundlerRpc, prepareAccounts, waitForUserOp } from '@safe-global/safe-4337-local-bundler'
import { expect } from 'chai'
import { deployments, ethers, network } from 'hardhat'
import {
Expand All @@ -20,7 +21,6 @@ import {
} from '../../src/utils/userOp'
import { chainId } from '../utils/encoding'
import { Safe4337 } from '../../src/utils/safe'
import { BUNDLER_MNEMONIC, bundlerRpc, prepareAccounts, waitForUserOp } from '../utils/e2e'
import { BigNumberish, Signer } from 'ethers'
import { assert } from 'console'

Expand Down Expand Up @@ -299,7 +299,7 @@ describe('Nested Safes With An Execution Initiated by a Leaf 4337 Safe [@4337]',

const setupTests = async () => {
const { SafeModuleSetup, EntryPoint, HariWillibaldToken, Safe4337Module, SafeL2, SafeProxyFactory } = await deployments.run()
const [user, user2, user3] = await prepareAccounts(BUNDLER_MNEMONIC, 3)
const [user, user2, user3] = await prepareAccounts({ count: 3 })
const bundler = bundlerRpc()

const entryPoint = new ethers.Contract(EntryPoint.address, EntryPoint.abi, ethers.provider)
Expand Down
2 changes: 1 addition & 1 deletion modules/4337/test/e2e/LocalBundler.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { bundlerRpc, prepareAccounts, waitForUserOp } from '@safe-global/safe-4337-local-bundler'
import { expect } from 'chai'
import { deployments, ethers, network } from 'hardhat'
import { buildSignatureBytes } from '../../src/utils/execution'
import { buildRpcUserOperationFromSafeUserOperation, buildSafeUserOpTransaction, signSafeOp } from '../../src/utils/userOp'
import { chainId, timestamp } from '../utils/encoding'
import { Safe4337 } from '../../src/utils/safe'
import { bundlerRpc, prepareAccounts, waitForUserOp } from '../utils/e2e'

describe('Local Bundler [@4337]', () => {
before(function () {
Expand Down
3 changes: 2 additions & 1 deletion modules/4337/test/e2e/SingletonSigners.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { bundlerRpc, prepareAccounts, waitForUserOp } from '@safe-global/safe-4337-local-bundler'
import { expect } from 'chai'
import { deployments, ethers, network } from 'hardhat'
import { buildSignatureBytes } from '../../src/utils/execution'
Expand All @@ -6,7 +7,7 @@ import {
buildRpcUserOperationFromSafeUserOperation,
buildSafeUserOpTransaction,
} from '../../src/utils/userOp'
import { bundlerRpc, encodeMultiSendTransactions, prepareAccounts, waitForUserOp } from '../utils/e2e'
import { encodeMultiSendTransactions } from '../utils/encoding'

describe('Singleton Signers [@4337]', () => {
before(function () {
Expand Down
2 changes: 1 addition & 1 deletion modules/4337/test/e2e/UniqueSigner.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { bundlerRpc, prepareAccounts, waitForUserOp } from '@safe-global/safe-4337-local-bundler'
import { expect } from 'chai'
import { deployments, ethers, network } from 'hardhat'
import { bundlerRpc, prepareAccounts, waitForUserOp } from '../utils/e2e'
import { chainId } from '../utils/encoding'
import { packGasParameters, unpackUserOperation } from '../../src/utils/userOp'

Expand Down
2 changes: 1 addition & 1 deletion modules/4337/test/e2e/WebAuthnSigner.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { bundlerRpc, prepareAccounts, waitForUserOp } from '@safe-global/safe-4337-local-bundler'
import { expect } from 'chai'
import { deployments, ethers, network } from 'hardhat'
import { bundlerRpc, prepareAccounts, waitForUserOp } from '../utils/e2e'
import { chainId } from '../utils/encoding'
import {
UserVerificationRequirement,
Expand Down
3 changes: 2 additions & 1 deletion modules/4337/test/e2e/WebAuthnSingletonSigner.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { bundlerRpc, prepareAccounts, waitForUserOp } from '@safe-global/safe-4337-local-bundler'
import { expect } from 'chai'
import { deployments, ethers, network } from 'hardhat'
import { bundlerRpc, encodeMultiSendTransactions, prepareAccounts, waitForUserOp } from '../utils/e2e'
import { encodeMultiSendTransactions } from '../utils/encoding'
import {
UserVerificationRequirement,
WebAuthnCredentials,
Expand Down
16 changes: 16 additions & 0 deletions modules/4337/test/utils/encoding.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { AddressLike, BigNumberish, BytesLike } from 'ethers'
import { ethers } from 'hardhat'

export const Erc20 = [
Expand Down Expand Up @@ -25,3 +26,18 @@ export const timestamp = async () => {
}
return block.timestamp
}

export interface MultiSendTransaction {
op: 0 | 1
to: AddressLike
value?: BigNumberish
data: BytesLike
}

export function encodeMultiSendTransactions(transactions: MultiSendTransaction[]) {
return ethers.concat(
transactions.map(({ op, to, value, data }) =>
ethers.solidityPacked(['uint8', 'address', 'uint256', 'uint256', 'bytes'], [op, to, value ?? 0, ethers.dataLength(data), data]),
),
)
}
1 change: 0 additions & 1 deletion modules/allowances/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
"hardhat": "^2.21.0",
"hardhat-deploy": "^0.12.1",
"hardhat-gas-reporter": "^1.0.10",
"rimraf": "^5.0.5",
"solhint": "4.1.1",
"solidity-coverage": "^0.8.7",
"ts-node": "^10.9.2",
Expand Down
9 changes: 5 additions & 4 deletions modules/passkey/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
],
"scripts": {
"build": "npm run build:sol && npm run build:ts",
"build:sol": "npx rimraf build && hardhat compile",
"build:ts": "npx rimraf dist && tsc",
"build:sol": "rimraf build typechain-types && hardhat compile",
"build:ts": "rimraf dist && tsc",
"coverage": "hardhat coverage",
"fmt": "prettier --write .",
"fmt:check": "prettier --check .",
Expand All @@ -38,7 +38,8 @@
"lint:ts": "eslint .",
"test": "hardhat test",
"test:4337": "4337-local-bundler-test",
"test:4337:upstream": "USE_UPSTREAM_BUNDLER=1 4337-local-bundler-test"
"test:4337:upstream": "USE_UPSTREAM_BUNDLER=1 4337-local-bundler-test",
"prepare": "npm run build -w ../4337 && npm run build"
},
"devDependencies": {
"@account-abstraction/contracts": "^0.7.0",
Expand All @@ -55,7 +56,7 @@
},
"overrides": {
"@safe-global/safe-contracts": {
"ethers": "^6.11.0"
"ethers": "^6.11.1"
}
},
"dependencies": {
Expand Down
9 changes: 5 additions & 4 deletions modules/passkey/test/4337/WebAuthnSigner.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { expect } from 'chai'
import { deployments, ethers, network } from 'hardhat'
import { packGasParameters, unpackUserOperation } from '@safe-global/safe-4337/dist/src/utils/userOp'
import { bundlerRpc, prepareAccounts, waitForUserOp } from '../utils/e2e'
import { chainId } from '../utils/encoding'
import { bundlerRpc, prepareAccounts, waitForUserOp } from '@safe-global/safe-4337-local-bundler'
import { WebAuthnCredentials, decodePublicKey, encodeWebAuthnSignature } from '../utils/webauthn'

describe('WebAuthn Signers [@4337]', () => {
Expand Down Expand Up @@ -64,6 +63,8 @@ describe('WebAuthn Signers [@4337]', () => {
webAuthnVerifier,
SafeL2,
} = await setupTests()

const { chainId } = await ethers.provider.getNetwork()
const webAuthnVerifierAddress = await webAuthnVerifier.getAddress()

const credential = navigator.credentials.create({
Expand Down Expand Up @@ -95,7 +96,7 @@ describe('WebAuthn Signers [@4337]', () => {
fallbackHandler: module.target,
}
const safeInitHash = ethers.TypedDataEncoder.hash(
{ verifyingContract: await signerLaunchpad.getAddress(), chainId: await chainId() },
{ verifyingContract: await signerLaunchpad.getAddress(), chainId },
{
SafeInit: [
{ type: 'address', name: 'singleton' },
Expand Down Expand Up @@ -171,7 +172,7 @@ describe('WebAuthn Signers [@4337]', () => {
entryPoint: entryPoint.target,
}
const safeInitOpHash = ethers.TypedDataEncoder.hash(
{ verifyingContract: await signerLaunchpad.getAddress(), chainId: await chainId() },
{ verifyingContract: await signerLaunchpad.getAddress(), chainId },
{
SafeInitOp: [
{ type: 'bytes32', name: 'userOpHash' },
Expand Down
56 changes: 0 additions & 56 deletions modules/passkey/test/utils/e2e.ts

This file was deleted.

Loading

0 comments on commit 8b25fd7

Please sign in to comment.