Skip to content

Commit 602c301

Browse files
authored
Add tests for AccountERC7702Mock (#44)
1 parent 7d921fe commit 602c301

File tree

9 files changed

+241
-156
lines changed

9 files changed

+241
-156
lines changed

test/account/Account.behavior.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
const { ethers } = require('hardhat');
22
const { expect } = require('chai');
3-
const { impersonate } = require('../../lib/@openzeppelin-contracts/test/helpers/account');
4-
const {
5-
SIG_VALIDATION_SUCCESS,
6-
SIG_VALIDATION_FAILURE,
7-
} = require('../../lib/@openzeppelin-contracts/test/helpers/erc4337');
83
const { setBalance } = require('@nomicfoundation/hardhat-network-helpers');
4+
5+
const { impersonate } = require('@openzeppelin/contracts/test/helpers/account');
6+
const { SIG_VALIDATION_SUCCESS, SIG_VALIDATION_FAILURE } = require('@openzeppelin/contracts/test/helpers/erc4337');
97
const {
108
shouldSupportInterfaces,
11-
} = require('../../lib/@openzeppelin-contracts/test/utils/introspection/SupportsInterface.behavior');
9+
} = require('@openzeppelin/contracts/test/utils/introspection/SupportsInterface.behavior');
1210

1311
function shouldBehaveLikeAnAccountBase() {
1412
describe('entryPoint', function () {

test/account/AccountBase.test.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,29 @@
11
const { ethers } = require('hardhat');
2-
const { shouldBehaveLikeAnAccountBase, shouldBehaveLikeAnAccountBaseExecutor } = require('./Account.behavior');
32
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
43
const { ERC4337Helper } = require('../helpers/erc4337');
54
const { NonNativeSigner } = require('../helpers/signers');
65

6+
const { shouldBehaveLikeAnAccountBase, shouldBehaveLikeAnAccountBaseExecutor } = require('./Account.behavior');
7+
78
async function fixture() {
9+
// EOAs and environment
810
const [beneficiary, other] = await ethers.getSigners();
911
const target = await ethers.deployContract('CallReceiverMockExtended');
12+
13+
// ERC-4337 signer
1014
const signer = new NonNativeSigner({ sign: () => ({ serialized: '0x01' }) });
11-
const helper = new ERC4337Helper('$AccountBaseMock');
12-
const smartAccount = await helper.newAccount(['AccountBase', '1']);
15+
16+
// ERC-4337 account
17+
const helper = new ERC4337Helper();
18+
const env = await helper.wait();
19+
const mock = await helper.newAccount('$AccountBaseMock', ['AccountBase', '1']);
20+
1321
const signUserOp = async userOp => {
1422
userOp.signature = await signer.signMessage(userOp.hash());
1523
return userOp;
1624
};
1725

18-
return { ...helper, mock: smartAccount, signer, target, beneficiary, other, signUserOp };
26+
return { ...env, mock, signer, target, beneficiary, other, signUserOp };
1927
}
2028

2129
describe('AccountBase', function () {

test/account/AccountECDSA.test.js

Lines changed: 20 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,43 @@
11
const { ethers } = require('hardhat');
2+
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
3+
const { ERC4337Helper } = require('../helpers/erc4337');
4+
const { PackedUserOperation } = require('../helpers/eip712-types');
5+
26
const {
37
shouldBehaveLikeAnAccountBase,
48
shouldBehaveLikeAnAccountBaseExecutor,
59
shouldBehaveLikeAccountHolder,
610
} = require('./Account.behavior');
7-
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
8-
const { ERC4337Helper } = require('../helpers/erc4337');
911
const { shouldBehaveLikeERC7739Signer } = require('../utils/cryptography/ERC7739Signer.behavior');
10-
const { PackedUserOperation } = require('../helpers/eip712');
1112

1213
async function fixture() {
14+
// EOAs and environment
1315
const [beneficiary, other] = await ethers.getSigners();
1416
const target = await ethers.deployContract('CallReceiverMockExtended');
17+
18+
// ERC-4337 signer
1519
const signer = ethers.Wallet.createRandom();
16-
const helper = new ERC4337Helper('$AccountECDSAMock');
17-
const smartAccount = await helper.newAccount(['AccountECDSA', '1', signer]);
20+
21+
// ERC-4337 account
22+
const helper = new ERC4337Helper();
23+
const env = await helper.wait();
24+
const mock = await helper.newAccount('$AccountECDSAMock', ['AccountECDSA', '1', signer]);
25+
26+
// domain cannot be fetched using getDomain(mock) before the mock is deployed
1827
const domain = {
1928
name: 'AccountECDSA',
2029
version: '1',
21-
chainId: helper.chainId,
22-
verifyingContract: smartAccount.address,
30+
chainId: env.chainId,
31+
verifyingContract: mock.address,
2332
};
33+
2434
const signUserOp = async userOp => {
25-
const types = { PackedUserOperation };
26-
const packed = userOp.packed;
27-
const typedOp = {
28-
sender: packed.sender,
29-
nonce: packed.nonce,
30-
initCode: packed.initCode,
31-
callData: packed.callData,
32-
accountGasLimits: packed.accountGasLimits,
33-
preVerificationGas: packed.preVerificationGas,
34-
gasFees: packed.gasFees,
35-
paymasterAndData: packed.paymasterAndData,
36-
entrypoint: userOp.context.entrypoint.target,
37-
};
38-
userOp.signature = await signer.signTypedData(domain, types, typedOp);
35+
const typedOp = Object.assign(userOp.packed, { entrypoint: env.entrypoint.target });
36+
userOp.signature = await signer.signTypedData(domain, { PackedUserOperation }, typedOp);
3937
return userOp;
4038
};
4139

42-
return {
43-
...helper,
44-
domain,
45-
mock: smartAccount,
46-
signer,
47-
target,
48-
beneficiary,
49-
other,
50-
signUserOp,
51-
};
40+
return { ...env, mock, domain, signer, target, beneficiary, other, signUserOp };
5241
}
5342

5443
describe('AccountECDSA', function () {

test/account/AccountERC7702.test.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
const { ethers } = require('hardhat');
2+
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
3+
const { ERC4337Helper } = require('../helpers/erc4337');
4+
const { PackedUserOperation } = require('../helpers/eip712-types');
5+
6+
const {
7+
shouldBehaveLikeAnAccountBase,
8+
shouldBehaveLikeAnAccountBaseExecutor,
9+
shouldBehaveLikeAccountHolder,
10+
} = require('./Account.behavior');
11+
const { shouldBehaveLikeERC7739Signer } = require('../utils/cryptography/ERC7739Signer.behavior');
12+
13+
async function fixture() {
14+
// EOAs and environment
15+
const [beneficiary, other] = await ethers.getSigners();
16+
const target = await ethers.deployContract('CallReceiverMockExtended');
17+
18+
// ERC-4337 signer
19+
const signer = ethers.Wallet.createRandom();
20+
21+
// ERC-4337 account
22+
const helper = new ERC4337Helper();
23+
const env = await helper.wait();
24+
const mock = await helper.newAccount('$AccountERC7702Mock', ['AccountERC7702Mock', '1'], { erc7702signer: signer });
25+
26+
// domain cannot be fetched using getDomain(mock) before the mock is deployed
27+
const domain = {
28+
name: 'AccountERC7702Mock',
29+
version: '1',
30+
chainId: env.chainId,
31+
verifyingContract: mock.address,
32+
};
33+
34+
const signUserOp = async userOp => {
35+
const typedOp = Object.assign(userOp.packed, { entrypoint: env.entrypoint.target });
36+
userOp.signature = await signer.signTypedData(domain, { PackedUserOperation }, typedOp);
37+
return userOp;
38+
};
39+
40+
return { ...env, mock, domain, signer, target, beneficiary, other, signUserOp };
41+
}
42+
43+
describe('AccountERC7702', function () {
44+
beforeEach(async function () {
45+
Object.assign(this, await loadFixture(fixture));
46+
});
47+
48+
shouldBehaveLikeAnAccountBase();
49+
shouldBehaveLikeAnAccountBaseExecutor({ deployable: false });
50+
shouldBehaveLikeAccountHolder();
51+
52+
describe('ERC7739Signer', function () {
53+
beforeEach(async function () {
54+
this.mock = await this.mock.deploy();
55+
this.signTypedData = this.signer.signTypedData.bind(this.signer);
56+
});
57+
58+
shouldBehaveLikeERC7739Signer();
59+
});
60+
});

test/account/AccountP256.test.js

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,49 @@
11
const { ethers } = require('hardhat');
2+
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
3+
const { ERC4337Helper } = require('../helpers/erc4337');
4+
const { NonNativeSigner, P256SigningKey } = require('../helpers/signers');
5+
const { PackedUserOperation } = require('../helpers/eip712-types');
6+
27
const {
38
shouldBehaveLikeAnAccountBase,
49
shouldBehaveLikeAnAccountBaseExecutor,
510
shouldBehaveLikeAccountHolder,
611
} = require('./Account.behavior');
7-
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
8-
const { ERC4337Helper } = require('../helpers/erc4337');
9-
const { NonNativeSigner, P256SigningKey } = require('../helpers/signers');
1012
const { shouldBehaveLikeERC7739Signer } = require('../utils/cryptography/ERC7739Signer.behavior');
11-
const { PackedUserOperation } = require('../helpers/eip712');
1213

1314
async function fixture() {
15+
// EOAs and environment
1416
const [beneficiary, other] = await ethers.getSigners();
1517
const target = await ethers.deployContract('CallReceiverMockExtended');
18+
19+
// ERC-4337 signer
1620
const signer = new NonNativeSigner(P256SigningKey.random());
17-
const helper = new ERC4337Helper('$AccountP256Mock');
18-
const smartAccount = await helper.newAccount([
21+
22+
// ERC-4337 account
23+
const helper = new ERC4337Helper();
24+
const env = await helper.wait();
25+
const mock = await helper.newAccount('$AccountP256Mock', [
1926
'AccountP256',
2027
'1',
2128
signer.signingKey.publicKey.qx,
2229
signer.signingKey.publicKey.qy,
2330
]);
31+
32+
// domain cannot be fetched using getDomain(mock) before the mock is deployed
2433
const domain = {
2534
name: 'AccountP256',
2635
version: '1',
27-
chainId: helper.chainId,
28-
verifyingContract: smartAccount.address,
36+
chainId: env.chainId,
37+
verifyingContract: mock.address,
2938
};
39+
3040
const signUserOp = async userOp => {
31-
const types = { PackedUserOperation };
32-
const packed = userOp.packed;
33-
const typedOp = {
34-
sender: packed.sender,
35-
nonce: packed.nonce,
36-
initCode: packed.initCode,
37-
callData: packed.callData,
38-
accountGasLimits: packed.accountGasLimits,
39-
preVerificationGas: packed.preVerificationGas,
40-
gasFees: packed.gasFees,
41-
paymasterAndData: packed.paymasterAndData,
42-
entrypoint: userOp.context.entrypoint.target,
43-
};
44-
userOp.signature = await signer.signTypedData(domain, types, typedOp);
41+
const typedOp = Object.assign(userOp.packed, { entrypoint: env.entrypoint.target });
42+
userOp.signature = await signer.signTypedData(domain, { PackedUserOperation }, typedOp);
4543
return userOp;
4644
};
4745

48-
return { ...helper, domain, mock: smartAccount, signer, target, beneficiary, other, signUserOp };
46+
return { ...env, mock, domain, signer, target, beneficiary, other, signUserOp };
4947
}
5048

5149
describe('AccountP256', function () {

test/account/AccountRSA.test.js

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,49 @@
11
const { ethers } = require('hardhat');
2+
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
3+
const { ERC4337Helper } = require('../helpers/erc4337');
4+
const { NonNativeSigner, RSASHA256SigningKey } = require('../helpers/signers');
5+
const { PackedUserOperation } = require('../helpers/eip712-types');
6+
27
const {
38
shouldBehaveLikeAnAccountBase,
49
shouldBehaveLikeAnAccountBaseExecutor,
510
shouldBehaveLikeAccountHolder,
611
} = require('./Account.behavior');
7-
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
8-
const { ERC4337Helper } = require('../helpers/erc4337');
9-
const { NonNativeSigner, RSASHA256SigningKey } = require('../helpers/signers');
1012
const { shouldBehaveLikeERC7739Signer } = require('../utils/cryptography/ERC7739Signer.behavior');
11-
const { PackedUserOperation } = require('../helpers/eip712');
1213

1314
async function fixture() {
15+
// EOAs and environment
1416
const [beneficiary, other] = await ethers.getSigners();
1517
const target = await ethers.deployContract('CallReceiverMockExtended');
18+
19+
// ERC-4337 signer
1620
const signer = new NonNativeSigner(RSASHA256SigningKey.random());
17-
const helper = new ERC4337Helper('$AccountRSAMock');
18-
const smartAccount = await helper.newAccount([
21+
22+
// ERC-4337 account
23+
const helper = new ERC4337Helper();
24+
const env = await helper.wait();
25+
const mock = await helper.newAccount('$AccountRSAMock', [
1926
'AccountRSA',
2027
'1',
2128
signer.signingKey.publicKey.e,
2229
signer.signingKey.publicKey.n,
2330
]);
31+
32+
// domain cannot be fetched using getDomain(mock) before the mock is deployed
2433
const domain = {
2534
name: 'AccountRSA',
2635
version: '1',
27-
chainId: helper.chainId,
28-
verifyingContract: smartAccount.address,
36+
chainId: env.chainId,
37+
verifyingContract: mock.address,
2938
};
39+
3040
const signUserOp = async userOp => {
31-
const types = { PackedUserOperation };
32-
const packed = userOp.packed;
33-
const typedOp = {
34-
sender: packed.sender,
35-
nonce: packed.nonce,
36-
initCode: packed.initCode,
37-
callData: packed.callData,
38-
accountGasLimits: packed.accountGasLimits,
39-
preVerificationGas: packed.preVerificationGas,
40-
gasFees: packed.gasFees,
41-
paymasterAndData: packed.paymasterAndData,
42-
entrypoint: userOp.context.entrypoint.target,
43-
};
44-
userOp.signature = await signer.signTypedData(domain, types, typedOp);
41+
const typedOp = Object.assign(userOp.packed, { entrypoint: env.entrypoint.target });
42+
userOp.signature = await signer.signTypedData(domain, { PackedUserOperation }, typedOp);
4543
return userOp;
4644
};
4745

48-
return { ...helper, domain, mock: smartAccount, signer, target, beneficiary, other, signUserOp };
46+
return { ...env, domain, mock, signer, target, beneficiary, other, signUserOp };
4947
}
5048

5149
describe('AccountRSA', function () {

test/helpers/eip712-types.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const { formatType } = require('@openzeppelin/contracts/test/helpers/eip712-types');
2+
const { mapValues } = require('@openzeppelin/contracts/test/helpers/iterate');
3+
4+
module.exports = mapValues(
5+
{
6+
PackedUserOperation: {
7+
sender: 'address',
8+
nonce: 'uint256',
9+
initCode: 'bytes',
10+
callData: 'bytes',
11+
accountGasLimits: 'bytes32',
12+
preVerificationGas: 'uint256',
13+
gasFees: 'bytes32',
14+
paymasterAndData: 'bytes',
15+
entrypoint: 'address',
16+
},
17+
},
18+
formatType,
19+
);

test/helpers/eip712.js

Lines changed: 0 additions & 22 deletions
This file was deleted.

0 commit comments

Comments
 (0)