Skip to content

Commit b2d46b7

Browse files
authored
Fix recoverable account (#187)
* fix recoverable account * try fix test * try fix test 2
1 parent daef710 commit b2d46b7

9 files changed

Lines changed: 477 additions & 395 deletions

File tree

.github/workflows/coverage.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ jobs:
1717
coverage:
1818
runs-on: ubuntu-latest
1919
if: ${{ !contains(github.event.head_commit.message, 'chore(release):') }}
20+
strategy:
21+
matrix:
22+
node-version: [22]
2023
steps:
2124
- name: Checkout the repository
2225
uses: actions/checkout@v5

.github/workflows/tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
if: ${{ github.event_name == 'workflow_dispatch' || !contains(github.event.head_commit.message, 'chore(release):') }}
2121
strategy:
2222
matrix:
23-
node-version: [24]
23+
node-version: [22]
2424
steps:
2525
- name: Checkout the repository
2626
uses: actions/checkout@v5

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## [patch]
4+
5+
- Fixed `RecoverableAccount` execution gas estimation revert.
6+
37
## [3.3.1]
48

59
- Fixed `viaIR` compilation.

contracts/account-abstraction/ARecoverableAccount.sol

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,12 @@ abstract contract ARecoverableAccount is IAccount, Initializable, AAccountRecove
185185
PackedUserOperation calldata userOp_,
186186
bytes32 userOpHash_
187187
) internal virtual returns (uint256 validationData_) {
188+
// For gas estimation bundler sets signature as empty
189+
// and we need to avoid reverting in this case
190+
if (userOp_.signature.length < 65) {
191+
return SIG_VALIDATION_FAILED;
192+
}
193+
188194
address recovered_ = ECDSA.recover(userOpHash_, userOp_.signature);
189195

190196
if (recovered_ == address(this) || recovered_ == trustedExecutor()) {

package-lock.json

Lines changed: 440 additions & 385 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
"eslint": "^9.35.0",
6565
"eslint-plugin-promise": "^7.2.1",
6666
"ethers": "^6.15.0",
67-
"hardhat": "^3.0.15",
67+
"hardhat": "3.0.16",
6868
"husky": "^9.1.7",
6969
"jiti": "^2.5.1",
7070
"merkletreejs": "^0.5.2",

test/account-abstraction/RecoverableAccount.test.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ describe("RecoverableAccount", () => {
4747
return ethers.Signature.from(signature).serialized;
4848
}
4949

50-
function packTwoUint128(a, b) {
50+
function packTwoUint128(a: bigint, b: bigint) {
5151
const maxUint128 = (1n << 128n) - 1n;
5252

5353
if (a > maxUint128 || b > maxUint128) {
@@ -254,7 +254,7 @@ describe("RecoverableAccount", () => {
254254

255255
const transferData = token.interface.encodeFunctionData("transfer", [FIRST.address, transferAmount]);
256256

257-
calls = [[await token.getAddress(), 0, transferData]];
257+
calls = [[await token.getAddress(), 0n, transferData]];
258258

259259
executionData = ethers.AbiCoder.defaultAbiCoder().encode(["tuple(address,uint256,bytes)[]"], [calls]);
260260

@@ -515,5 +515,20 @@ describe("RecoverableAccount", () => {
515515
.to.be.revertedWithCustomError(account, "NotAnEntryPoint")
516516
.withArgs(DELEGATED.address);
517517
});
518+
519+
it("should not revert if signature length is less than 65 bytes", async () => {
520+
const userOp = await getUserOp();
521+
522+
userOp.signature = "0x";
523+
524+
const userOpHash = await entryPoint.getUserOpHash(userOp);
525+
526+
await networkHelpers.impersonateAccount(await entryPoint.getAddress());
527+
await networkHelpers.setBalance(await entryPoint.getAddress(), wei(1));
528+
const entryPointAccount = await ethers.provider.getSigner(await entryPoint.getAddress());
529+
530+
await expect(account.connect(entryPointAccount).validateUserOp(userOp, userOpHash, 1n)).to.be.eventually
531+
.fulfilled;
532+
});
518533
});
519534
});

test/libs/crypto/ECDSA512.test.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,7 @@ describe("ECDSA512", () => {
3131
"0x43f800fbeaf9238c58af795bcdad04bc49cd850c394d3382953356b023210281757b30e19218a37cbd612086fbc158caa8b4e1acb2ec00837e5d941f342fb3cc";
3232

3333
it("should verify the signature", async () => {
34-
// Added very big gasLimit for the coverage to pass
35-
expect(await ecdsa512.verifyBrainpoolP512r1WithoutHashing(message, signature, pubKey, { gasLimit: 300000000 })).to
36-
.be.true;
34+
expect(await ecdsa512.verifyBrainpoolP512r1WithoutHashing(message, signature, pubKey)).to.be.true;
3735
});
3836
});
3937
});

test/libs/data-structures/CartesianMerkleTree.test.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ describe("CartesianMerkleTree", () => {
299299
const treapleRoot: string = await treaple.getUintRoot();
300300

301301
for (let i = 0; i < keysCount; i++) {
302-
const randIndex = Math.floor(Math.random() * (Number(await treaple.getUintNodesCount()) - 1)) + 1;
302+
const randIndex = Math.floor(Math.random() * (Number(await treaple.getUintNodesCount()) - 1));
303303
const proof = await treaple.getUintProof(keys[randIndex], 40);
304304

305305
await verifyCMTProof(proof, treapleRoot, keys[randIndex], true, true);
@@ -624,7 +624,7 @@ describe("CartesianMerkleTree", () => {
624624
const treapleRoot: string = await treaple.getBytes32Root();
625625

626626
for (let i = 0; i < keysCount; i++) {
627-
const randIndex = Math.floor(Math.random() * (Number(await treaple.getBytes32NodesCount()) - 1)) + 1;
627+
const randIndex = Math.floor(Math.random() * (Number(await treaple.getBytes32NodesCount()) - 1));
628628
const proof = await treaple.getBytes32Proof(keys[randIndex], 40);
629629

630630
await verifyCMTProof(proof, treapleRoot, keys[randIndex], true, true);
@@ -733,6 +733,7 @@ describe("CartesianMerkleTree", () => {
733733
break;
734734
}
735735
}
736+
736737
const currentNode = await treaple.getAddressNode(randIndex);
737738
const currentNodeKey = `0x${currentNode.key.slice(26)}`;
738739

@@ -757,7 +758,7 @@ describe("CartesianMerkleTree", () => {
757758
const treapleRoot: string = await treaple.getAddressRoot();
758759

759760
for (let i = 0; i < keysCount; i++) {
760-
const randIndex = Math.floor(Math.random() * (Number(await treaple.getAddressNodesCount()) - 1)) + 1;
761+
const randIndex = Math.floor(Math.random() * (Number(await treaple.getAddressNodesCount()) - 1));
761762
const proof = await treaple.getAddressProof(keys[randIndex], 40);
762763

763764
await verifyCMTProof(proof, treapleRoot, keys[randIndex], true, true);

0 commit comments

Comments
 (0)