Skip to content

Commit be91f8f

Browse files
ernestognwericglau
andauthored
Add WebAuthn signer to Accounts (#718)
Co-authored-by: Eric Lau <[email protected]>
1 parent e3c6e2d commit be91f8f

File tree

11 files changed

+3831
-2070
lines changed

11 files changed

+3831
-2070
lines changed

.changeset/young-readers-cover.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@openzeppelin/wizard': patch
3+
'@openzeppelin/wizard-common': patch
4+
'@openzeppelin/contracts-mcp': patch
5+
---
6+
7+
Solidity account signer: Add `WebAuthn` to the list of signers available.

packages/common/src/ai/descriptions/solidity.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,11 @@ export const solidityAccountDescriptions = {
6969
signer: `Defines the signature verification algorithm used by the account to verify user operations. Options:
7070
- ECDSA: Standard Ethereum signature validation using secp256k1, validates signatures against a specified owner address
7171
- EIP7702: Special ECDSA validation using account's own address as signer, enables EOAs to delegate execution rights
72+
- Multisig: ERC-7913 multisignature requiring minimum number of signatures from authorized signers
73+
- MultisigWeighted: ERC-7913 weighted multisignature where signers have different voting weights
7274
- P256: NIST P-256 curve (secp256r1) validation for integration with Passkeys and HSMs
7375
- RSA: RSA PKCS#1 v1.5 signature validation (RFC8017) for PKI systems and HSMs
74-
- Multisig: ERC-7913 multisignature requiring minimum number of signatures from authorized signers
75-
- MultisigWeighted: ERC-7913 weighted multisignature where signers have different voting weights`,
76+
- WebAuthn: Web Authentication (WebAuthn) assertion validation for integration with Passkeys and HSMs on top of P256`,
7677
batchedExecution:
7778
'Whether to implement a minimal batching interface for the account to allow multiple operations to be executed in a single transaction following the ERC-7821 standard.',
7879
ERC7579Modules:

packages/core/solidity/src/account.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { account } from '.';
44
import type { AccountOptions } from './account';
55
import { buildAccount } from './account';
66
import { printContract } from './print';
7+
import { SignerOptions } from './signer';
78

89
/**
910
* Tests external API for equivalence with internal API
@@ -61,7 +62,7 @@ function format(upgradeable: false | 'uups' | 'transparent') {
6162
}
6263
}
6364

64-
for (const signer of [false, 'ECDSA', 'EIP7702', 'P256', 'RSA', 'Multisig', 'MultisigWeighted'] as const) {
65+
for (const signer of SignerOptions) {
6566
for (const upgradeable of [false, 'uups', 'transparent'] as const) {
6667
if (signer === 'EIP7702' && !!upgradeable) continue;
6768

packages/core/solidity/src/account.test.ts.md

Lines changed: 3751 additions & 2045 deletions
Large diffs are not rendered by default.
1.68 KB
Binary file not shown.

packages/core/solidity/src/account.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -247,12 +247,16 @@ function overrideRawSignatureValidation(c: ContractBuilder, opts: AccountOptions
247247
const signerBaseName = signers[opts.signer].name;
248248
const signerName = opts.upgradeable ? upgradeableName(signerBaseName) : signerBaseName;
249249

250-
c.addImportOnly({
251-
name: 'AbstractSigner',
252-
path: '@openzeppelin/contracts/utils/cryptography/signers/AbstractSigner.sol',
253-
transpiled: false,
254-
});
255-
c.addOverride({ name: 'AbstractSigner', transpiled: false }, signerFunctions._rawSignatureValidation);
250+
// WebAuthnSigner depends inherits from P256Signer, so the AbstractSigner override is handled by `addSigner`
251+
if (opts.signer !== 'WebAuthn') {
252+
c.addImportOnly({
253+
name: 'AbstractSigner',
254+
path: '@openzeppelin/contracts/utils/cryptography/signers/AbstractSigner.sol',
255+
transpiled: false,
256+
});
257+
c.addOverride({ name: 'AbstractSigner', transpiled: false }, signerFunctions._rawSignatureValidation);
258+
}
259+
256260
c.addOverride({ name: 'AccountERC7579' }, signerFunctions._rawSignatureValidation);
257261
c.setFunctionComments(
258262
[

packages/core/solidity/src/generate/account.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const account = {
88
signatureValidation: [false, 'ERC1271', 'ERC7739'] as const,
99
ERC721Holder: [false, true] as const,
1010
ERC1155Holder: [false, true] as const,
11-
signer: ['ECDSA', 'EIP7702', 'P256', 'RSA', 'Multisig', 'MultisigWeighted'] as const,
11+
signer: ['ECDSA', 'EIP7702', 'Multisig', 'MultisigWeighted', 'P256', 'RSA', 'WebAuthn'] as const,
1212
batchedExecution: [false, true] as const,
1313
ERC7579Modules: [false, 'AccountERC7579', 'AccountERC7579Hooked'] as const,
1414
access: [false] as const,

packages/core/solidity/src/signer.ts

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,16 @@ import { OptionsError } from './error';
33
import type { Upgradeable } from './set-upgradeable';
44
import { defineFunctions } from './utils/define-functions';
55

6-
export const SignerOptions = [false, 'ECDSA', 'EIP7702', 'P256', 'RSA', 'Multisig', 'MultisigWeighted'] as const;
6+
export const SignerOptions = [
7+
false,
8+
'ECDSA',
9+
'EIP7702',
10+
'Multisig',
11+
'MultisigWeighted',
12+
'P256',
13+
'RSA',
14+
'WebAuthn',
15+
] as const;
716
export type SignerOptions = (typeof SignerOptions)[number];
817

918
export function addSigner(c: ContractBuilder, signer: SignerOptions, upgradeable: Upgradeable): void {
@@ -34,6 +43,26 @@ export function addSigner(c: ContractBuilder, signer: SignerOptions, upgradeable
3443
);
3544
break;
3645
}
46+
case 'WebAuthn': {
47+
signerArgs.P256.forEach(arg => c.addConstructorArgument(arg));
48+
c.addParent(
49+
signers.P256,
50+
signerArgs.P256.map(arg => ({ lit: arg.name })),
51+
);
52+
c.addParent(signers[signer]);
53+
c.addImportOnly({
54+
name: 'AbstractSigner',
55+
path: '@openzeppelin/contracts/utils/cryptography/signers/AbstractSigner.sol',
56+
transpiled: false,
57+
});
58+
c.addOverride({ name: 'AbstractSigner', transpiled: false }, signerFunctions._rawSignatureValidation);
59+
c.addOverride({ name: 'SignerP256' }, signerFunctions._rawSignatureValidation);
60+
break;
61+
}
62+
default: {
63+
const _: never = signer;
64+
throw new Error('Unknown signer');
65+
}
3766
}
3867
}
3968

@@ -46,6 +75,14 @@ export const signers = {
4675
name: 'SignerEIP7702',
4776
path: '@openzeppelin/contracts/utils/cryptography/signers/SignerEIP7702.sol',
4877
},
78+
Multisig: {
79+
name: 'MultiSignerERC7913',
80+
path: '@openzeppelin/contracts/utils/cryptography/signers/MultiSignerERC7913.sol',
81+
},
82+
MultisigWeighted: {
83+
name: 'MultiSignerERC7913Weighted',
84+
path: '@openzeppelin/contracts/utils/cryptography/signers/MultiSignerERC7913Weighted.sol',
85+
},
4986
P256: {
5087
name: 'SignerP256',
5188
path: '@openzeppelin/contracts/utils/cryptography/signers/SignerP256.sol',
@@ -54,13 +91,9 @@ export const signers = {
5491
name: 'SignerRSA',
5592
path: '@openzeppelin/contracts/utils/cryptography/signers/SignerRSA.sol',
5693
},
57-
Multisig: {
58-
name: 'MultiSignerERC7913',
59-
path: '@openzeppelin/contracts/utils/cryptography/signers/MultiSignerERC7913.sol',
60-
},
61-
MultisigWeighted: {
62-
name: 'MultiSignerERC7913Weighted',
63-
path: '@openzeppelin/contracts/utils/cryptography/signers/MultiSignerERC7913Weighted.sol',
94+
WebAuthn: {
95+
name: 'SignerWebAuthn',
96+
path: '@openzeppelin/contracts/utils/cryptography/signers/SignerWebAuthn.sol',
6497
},
6598
};
6699

@@ -70,10 +103,6 @@ export const signerArgs: Record<Exclude<SignerOptions, false | 'EIP7702'>, { nam
70103
{ name: 'qx', type: 'bytes32' },
71104
{ name: 'qy', type: 'bytes32' },
72105
],
73-
RSA: [
74-
{ name: 'e', type: 'bytes memory' },
75-
{ name: 'n', type: 'bytes memory' },
76-
],
77106
Multisig: [
78107
{ name: 'signers', type: 'bytes[] memory' },
79108
{ name: 'threshold', type: 'uint64' },
@@ -83,6 +112,11 @@ export const signerArgs: Record<Exclude<SignerOptions, false | 'EIP7702'>, { nam
83112
{ name: 'weights', type: 'uint64[] memory' },
84113
{ name: 'threshold', type: 'uint64' },
85114
],
115+
RSA: [
116+
{ name: 'e', type: 'bytes memory' },
117+
{ name: 'n', type: 'bytes memory' },
118+
],
119+
WebAuthn: [],
86120
};
87121

88122
export const signerFunctions = defineFunctions({

packages/mcp/src/solidity/schemas.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,11 @@ export const accountSchema = {
127127
.literal(false)
128128
.or(z.literal('ECDSA'))
129129
.or(z.literal('EIP7702'))
130-
.or(z.literal('P256'))
131-
.or(z.literal('RSA'))
132130
.or(z.literal('Multisig'))
133131
.or(z.literal('MultisigWeighted'))
132+
.or(z.literal('P256'))
133+
.or(z.literal('RSA'))
134+
.or(z.literal('WebAuthn'))
134135
.optional()
135136
.describe(solidityAccountDescriptions.signer),
136137
batchedExecution: z.boolean().optional().describe(solidityAccountDescriptions.batchedExecution),

packages/ui/api/ai-assistant/function-definitions/solidity.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ export const solidityAccountAIFunctionDefinition = {
211211
signer: {
212212
anyOf: [
213213
{ type: 'boolean', enum: [false] },
214-
{ type: 'string', enum: ['ECDSA', 'EIP7702', 'P256', 'RSA', 'Multisig', 'MultisigWeighted'] },
214+
{ type: 'string', enum: ['ECDSA', 'EIP7702', 'P256', 'Multisig', 'MultisigWeighted', 'RSA', 'WebAuthn'] },
215215
],
216216
description: solidityAccountDescriptions.signer,
217217
},

0 commit comments

Comments
 (0)