@aspect-wallet/sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/LICENSE +21 -0
- package/README.md +708 -0
- package/dist/audit/history.d.ts +44 -0
- package/dist/audit/history.d.ts.map +1 -0
- package/dist/audit/history.js +80 -0
- package/dist/audit/history.js.map +1 -0
- package/dist/auth/email.d.ts +52 -0
- package/dist/auth/email.d.ts.map +1 -0
- package/dist/auth/email.js +66 -0
- package/dist/auth/email.js.map +1 -0
- package/dist/auth/oauth.d.ts +47 -0
- package/dist/auth/oauth.d.ts.map +1 -0
- package/dist/auth/oauth.js +103 -0
- package/dist/auth/oauth.js.map +1 -0
- package/dist/auth/passkey-auth.d.ts +39 -0
- package/dist/auth/passkey-auth.d.ts.map +1 -0
- package/dist/auth/passkey-auth.js +108 -0
- package/dist/auth/passkey-auth.js.map +1 -0
- package/dist/auth/session.d.ts +30 -0
- package/dist/auth/session.d.ts.map +1 -0
- package/dist/auth/session.js +61 -0
- package/dist/auth/session.js.map +1 -0
- package/dist/chain/registry.d.ts +25 -0
- package/dist/chain/registry.d.ts.map +1 -0
- package/dist/chain/registry.js +46 -0
- package/dist/chain/registry.js.map +1 -0
- package/dist/core/client.d.ts +78 -0
- package/dist/core/client.d.ts.map +1 -0
- package/dist/core/client.js +129 -0
- package/dist/core/client.js.map +1 -0
- package/dist/core/config.d.ts +22 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +91 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/errors.d.ts +32 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +95 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +64 -0
- package/dist/index.js.map +1 -0
- package/dist/mfa/guardian.d.ts +27 -0
- package/dist/mfa/guardian.d.ts.map +1 -0
- package/dist/mfa/guardian.js +37 -0
- package/dist/mfa/guardian.js.map +1 -0
- package/dist/mfa/multisig.d.ts +28 -0
- package/dist/mfa/multisig.d.ts.map +1 -0
- package/dist/mfa/multisig.js +40 -0
- package/dist/mfa/multisig.js.map +1 -0
- package/dist/mfa/tiers.d.ts +34 -0
- package/dist/mfa/tiers.d.ts.map +1 -0
- package/dist/mfa/tiers.js +66 -0
- package/dist/mfa/tiers.js.map +1 -0
- package/dist/mfa/timelock.d.ts +32 -0
- package/dist/mfa/timelock.d.ts.map +1 -0
- package/dist/mfa/timelock.js +47 -0
- package/dist/mfa/timelock.js.map +1 -0
- package/dist/recovery/devices.d.ts +31 -0
- package/dist/recovery/devices.d.ts.map +1 -0
- package/dist/recovery/devices.js +33 -0
- package/dist/recovery/devices.js.map +1 -0
- package/dist/recovery/export.d.ts +33 -0
- package/dist/recovery/export.d.ts.map +1 -0
- package/dist/recovery/export.js +44 -0
- package/dist/recovery/export.js.map +1 -0
- package/dist/recovery/rotation.d.ts +26 -0
- package/dist/recovery/rotation.d.ts.map +1 -0
- package/dist/recovery/rotation.js +31 -0
- package/dist/recovery/rotation.js.map +1 -0
- package/dist/recovery/social.d.ts +33 -0
- package/dist/recovery/social.d.ts.map +1 -0
- package/dist/recovery/social.js +36 -0
- package/dist/recovery/social.js.map +1 -0
- package/dist/security/freeze.d.ts +34 -0
- package/dist/security/freeze.d.ts.map +1 -0
- package/dist/security/freeze.js +42 -0
- package/dist/security/freeze.js.map +1 -0
- package/dist/security/revoke.d.ts +27 -0
- package/dist/security/revoke.d.ts.map +1 -0
- package/dist/security/revoke.js +27 -0
- package/dist/security/revoke.js.map +1 -0
- package/dist/security/watchtower.d.ts +34 -0
- package/dist/security/watchtower.d.ts.map +1 -0
- package/dist/security/watchtower.js +38 -0
- package/dist/security/watchtower.js.map +1 -0
- package/dist/session-keys/manager.d.ts +40 -0
- package/dist/session-keys/manager.d.ts.map +1 -0
- package/dist/session-keys/manager.js +65 -0
- package/dist/session-keys/manager.js.map +1 -0
- package/dist/session-keys/permissions.d.ts +44 -0
- package/dist/session-keys/permissions.d.ts.map +1 -0
- package/dist/session-keys/permissions.js +63 -0
- package/dist/session-keys/permissions.js.map +1 -0
- package/dist/session-keys/templates.d.ts +49 -0
- package/dist/session-keys/templates.d.ts.map +1 -0
- package/dist/session-keys/templates.js +65 -0
- package/dist/session-keys/templates.js.map +1 -0
- package/dist/signer/eoa.d.ts +24 -0
- package/dist/signer/eoa.d.ts.map +1 -0
- package/dist/signer/eoa.js +32 -0
- package/dist/signer/eoa.js.map +1 -0
- package/dist/signer/interface.d.ts +60 -0
- package/dist/signer/interface.d.ts.map +1 -0
- package/dist/signer/interface.js +47 -0
- package/dist/signer/interface.js.map +1 -0
- package/dist/signer/multisig.d.ts +38 -0
- package/dist/signer/multisig.d.ts.map +1 -0
- package/dist/signer/multisig.js +56 -0
- package/dist/signer/multisig.js.map +1 -0
- package/dist/signer/passkey.d.ts +35 -0
- package/dist/signer/passkey.d.ts.map +1 -0
- package/dist/signer/passkey.js +112 -0
- package/dist/signer/passkey.js.map +1 -0
- package/dist/signer/session.d.ts +24 -0
- package/dist/signer/session.d.ts.map +1 -0
- package/dist/signer/session.js +32 -0
- package/dist/signer/session.js.map +1 -0
- package/dist/sponsor/paymaster.d.ts +27 -0
- package/dist/sponsor/paymaster.d.ts.map +1 -0
- package/dist/sponsor/paymaster.js +43 -0
- package/dist/sponsor/paymaster.js.map +1 -0
- package/dist/transport/api.d.ts +25 -0
- package/dist/transport/api.d.ts.map +1 -0
- package/dist/transport/api.js +79 -0
- package/dist/transport/api.js.map +1 -0
- package/dist/transport/bundler.d.ts +52 -0
- package/dist/transport/bundler.d.ts.map +1 -0
- package/dist/transport/bundler.js +109 -0
- package/dist/transport/bundler.js.map +1 -0
- package/dist/transport/iframe.d.ts +33 -0
- package/dist/transport/iframe.d.ts.map +1 -0
- package/dist/transport/iframe.js +131 -0
- package/dist/transport/iframe.js.map +1 -0
- package/dist/types.d.ts +366 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/userop/builder.d.ts +75 -0
- package/dist/userop/builder.d.ts.map +1 -0
- package/dist/userop/builder.js +150 -0
- package/dist/userop/builder.js.map +1 -0
- package/dist/userop/encoding.d.ts +44 -0
- package/dist/userop/encoding.d.ts.map +1 -0
- package/dist/userop/encoding.js +99 -0
- package/dist/userop/encoding.js.map +1 -0
- package/dist/userop/gas.d.ts +35 -0
- package/dist/userop/gas.d.ts.map +1 -0
- package/dist/userop/gas.js +53 -0
- package/dist/userop/gas.js.map +1 -0
- package/dist/userop/hash.d.ts +34 -0
- package/dist/userop/hash.d.ts.map +1 -0
- package/dist/userop/hash.js +55 -0
- package/dist/userop/hash.js.map +1 -0
- package/dist/userop/nonce.d.ts +53 -0
- package/dist/userop/nonce.d.ts.map +1 -0
- package/dist/userop/nonce.js +79 -0
- package/dist/userop/nonce.js.map +1 -0
- package/dist/wallet/factory.d.ts +63 -0
- package/dist/wallet/factory.d.ts.map +1 -0
- package/dist/wallet/factory.js +63 -0
- package/dist/wallet/factory.js.map +1 -0
- package/package.json +70 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pre-built session key permission templates.
|
|
3
|
+
* Corresponds to SPEC-013 Section 9.2.
|
|
4
|
+
*/
|
|
5
|
+
import type { Address, SessionKeyPermissions } from '../types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Pre-built permission templates for common session key use cases.
|
|
8
|
+
*/
|
|
9
|
+
export declare class SessionKeyTemplates {
|
|
10
|
+
/**
|
|
11
|
+
* Gaming session: allow specific game contract functions, no ETH transfers, sponsored gas.
|
|
12
|
+
*/
|
|
13
|
+
static gaming(params: {
|
|
14
|
+
gameContract: Address;
|
|
15
|
+
duration: number;
|
|
16
|
+
paymaster?: Address;
|
|
17
|
+
}): SessionKeyPermissions;
|
|
18
|
+
/**
|
|
19
|
+
* DeFi session: allow DEX and lending pool interactions with spend limits.
|
|
20
|
+
*/
|
|
21
|
+
static defi(params: {
|
|
22
|
+
dexRouter: Address;
|
|
23
|
+
lendingPool?: Address;
|
|
24
|
+
spendLimit: bigint;
|
|
25
|
+
duration: number;
|
|
26
|
+
}): SessionKeyPermissions;
|
|
27
|
+
/**
|
|
28
|
+
* Subscription session: allow periodic token transfers to a merchant.
|
|
29
|
+
* ERC-20 transfer selector: 0xa9059cbb
|
|
30
|
+
* ERC-20 approve selector: 0x095ea7b3
|
|
31
|
+
*/
|
|
32
|
+
static subscription(params: {
|
|
33
|
+
token: Address;
|
|
34
|
+
merchant: Address;
|
|
35
|
+
monthlyLimit: bigint;
|
|
36
|
+
duration: number;
|
|
37
|
+
}): SessionKeyPermissions;
|
|
38
|
+
/**
|
|
39
|
+
* NFT minting session: allow minting on a specific contract with no ETH limits.
|
|
40
|
+
*/
|
|
41
|
+
static nftMint(params: {
|
|
42
|
+
nftContract: Address;
|
|
43
|
+
mintSelector: `0x${string}`;
|
|
44
|
+
maxMintCost: bigint;
|
|
45
|
+
duration: number;
|
|
46
|
+
paymaster?: Address;
|
|
47
|
+
}): SessionKeyPermissions;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=templates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/session-keys/templates.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAGlE;;GAEG;AACH,qBAAa,mBAAmB;IAC9B;;OAEG;IACH,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE;QACpB,YAAY,EAAE,OAAO,CAAC;QACtB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,CAAC,EAAE,OAAO,CAAC;KACrB,GAAG,qBAAqB;IAazB;;OAEG;IACH,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE;QAClB,SAAS,EAAE,OAAO,CAAC;QACnB,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;KAClB,GAAG,qBAAqB;IAazB;;;;OAIG;IACH,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE;QAC1B,KAAK,EAAE,OAAO,CAAC;QACf,QAAQ,EAAE,OAAO,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC;KAClB,GAAG,qBAAqB;IAWzB;;OAEG;IACH,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE;QACrB,WAAW,EAAE,OAAO,CAAC;QACrB,YAAY,EAAE,KAAK,MAAM,EAAE,CAAC;QAC5B,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,CAAC,EAAE,OAAO,CAAC;KACrB,GAAG,qBAAqB;CAY1B"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pre-built session key permission templates.
|
|
3
|
+
* Corresponds to SPEC-013 Section 9.2.
|
|
4
|
+
*/
|
|
5
|
+
import { PermissionBuilder } from './permissions.js';
|
|
6
|
+
/**
|
|
7
|
+
* Pre-built permission templates for common session key use cases.
|
|
8
|
+
*/
|
|
9
|
+
export class SessionKeyTemplates {
|
|
10
|
+
/**
|
|
11
|
+
* Gaming session: allow specific game contract functions, no ETH transfers, sponsored gas.
|
|
12
|
+
*/
|
|
13
|
+
static gaming(params) {
|
|
14
|
+
const builder = new PermissionBuilder()
|
|
15
|
+
.allowContractWildcard(params.gameContract)
|
|
16
|
+
.setSpendLimit({ perTx: 0n, cumulative: 0n })
|
|
17
|
+
.setTimeRange({ duration: params.duration });
|
|
18
|
+
if (params.paymaster) {
|
|
19
|
+
builder.requirePaymaster(params.paymaster);
|
|
20
|
+
}
|
|
21
|
+
return builder.build();
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* DeFi session: allow DEX and lending pool interactions with spend limits.
|
|
25
|
+
*/
|
|
26
|
+
static defi(params) {
|
|
27
|
+
const builder = new PermissionBuilder()
|
|
28
|
+
.allowContractWildcard(params.dexRouter)
|
|
29
|
+
.setSpendLimit({ perTx: params.spendLimit, cumulative: params.spendLimit })
|
|
30
|
+
.setTimeRange({ duration: params.duration });
|
|
31
|
+
if (params.lendingPool) {
|
|
32
|
+
builder.allowContractWildcard(params.lendingPool);
|
|
33
|
+
}
|
|
34
|
+
return builder.build();
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Subscription session: allow periodic token transfers to a merchant.
|
|
38
|
+
* ERC-20 transfer selector: 0xa9059cbb
|
|
39
|
+
* ERC-20 approve selector: 0x095ea7b3
|
|
40
|
+
*/
|
|
41
|
+
static subscription(params) {
|
|
42
|
+
return new PermissionBuilder()
|
|
43
|
+
.allowContract(params.token, [
|
|
44
|
+
'0xa9059cbb', // transfer(address,uint256)
|
|
45
|
+
'0x095ea7b3', // approve(address,uint256)
|
|
46
|
+
])
|
|
47
|
+
.setSpendLimit({ perTx: params.monthlyLimit, cumulative: params.monthlyLimit })
|
|
48
|
+
.setTimeRange({ duration: params.duration })
|
|
49
|
+
.build();
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* NFT minting session: allow minting on a specific contract with no ETH limits.
|
|
53
|
+
*/
|
|
54
|
+
static nftMint(params) {
|
|
55
|
+
const builder = new PermissionBuilder()
|
|
56
|
+
.allowContract(params.nftContract, [params.mintSelector])
|
|
57
|
+
.setSpendLimit({ perTx: params.maxMintCost, cumulative: params.maxMintCost })
|
|
58
|
+
.setTimeRange({ duration: params.duration });
|
|
59
|
+
if (params.paymaster) {
|
|
60
|
+
builder.requirePaymaster(params.paymaster);
|
|
61
|
+
}
|
|
62
|
+
return builder.build();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=templates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/session-keys/templates.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD;;GAEG;AACH,MAAM,OAAO,mBAAmB;IAC9B;;OAEG;IACH,MAAM,CAAC,MAAM,CAAC,MAIb;QACC,MAAM,OAAO,GAAG,IAAI,iBAAiB,EAAE;aACpC,qBAAqB,CAAC,MAAM,CAAC,YAAY,CAAC;aAC1C,aAAa,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;aAC5C,YAAY,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QAE/C,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACrB,OAAO,CAAC,gBAAgB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC7C,CAAC;QAED,OAAO,OAAO,CAAC,KAAK,EAAE,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,IAAI,CAAC,MAKX;QACC,MAAM,OAAO,GAAG,IAAI,iBAAiB,EAAE;aACpC,qBAAqB,CAAC,MAAM,CAAC,SAAS,CAAC;aACvC,aAAa,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,UAAU,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC;aAC1E,YAAY,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QAE/C,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;YACvB,OAAO,CAAC,qBAAqB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACpD,CAAC;QAED,OAAO,OAAO,CAAC,KAAK,EAAE,CAAC;IACzB,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,YAAY,CAAC,MAKnB;QACC,OAAO,IAAI,iBAAiB,EAAE;aAC3B,aAAa,CAAC,MAAM,CAAC,KAAK,EAAE;YAC3B,YAAY,EAAE,4BAA4B;YAC1C,YAAY,EAAE,2BAA2B;SAC1C,CAAC;aACD,aAAa,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,YAAY,EAAE,UAAU,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC;aAC9E,YAAY,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;aAC3C,KAAK,EAAE,CAAC;IACb,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,OAAO,CAAC,MAMd;QACC,MAAM,OAAO,GAAG,IAAI,iBAAiB,EAAE;aACpC,aAAa,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;aACxD,aAAa,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,WAAW,EAAE,UAAU,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC;aAC5E,YAAY,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QAE/C,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACrB,OAAO,CAAC,gBAAgB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC7C,CAAC;QAED,OAAO,OAAO,CAAC,KAAK,EAAE,CAAC;IACzB,CAAC;CACF"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EOA (secp256k1 ECDSA) signer implementation.
|
|
3
|
+
* Corresponds to SPEC-013 Section 5.4 -- moduleId=0, 69 bytes.
|
|
4
|
+
*/
|
|
5
|
+
import type { Address, Hex } from '../types.js';
|
|
6
|
+
import { type ISigner } from './interface.js';
|
|
7
|
+
/**
|
|
8
|
+
* Signs UserOperations with a secp256k1 private key (standard EOA).
|
|
9
|
+
* Produces ECDSA signatures: r(32) + s(32) + v(1) = 65 bytes.
|
|
10
|
+
* Prefixed with moduleId(4) = 69 bytes total.
|
|
11
|
+
*/
|
|
12
|
+
export declare class EoaSigner implements ISigner {
|
|
13
|
+
readonly type: "eoa";
|
|
14
|
+
readonly address: Address;
|
|
15
|
+
readonly moduleId: 0;
|
|
16
|
+
private readonly account;
|
|
17
|
+
constructor(privateKey: Hex);
|
|
18
|
+
/**
|
|
19
|
+
* Sign a UserOperation hash with ECDSA.
|
|
20
|
+
* Returns the full prefixed signature: moduleId(4) + ecdsaSig(65) = 69 bytes.
|
|
21
|
+
*/
|
|
22
|
+
sign(userOpHash: Hex): Promise<Hex>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=eoa.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eoa.d.ts","sourceRoot":"","sources":["../../src/signer/eoa.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,KAAK,OAAO,EAAqC,MAAM,gBAAgB,CAAC;AAEjF;;;;GAIG;AACH,qBAAa,SAAU,YAAW,OAAO;IACvC,QAAQ,CAAC,IAAI,EAAG,KAAK,CAAU;IAC/B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,QAAQ,IAA4B;IAE7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;gBAE3B,UAAU,EAAE,GAAG;IAK3B;;;OAGG;IACG,IAAI,CAAC,UAAU,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;CAO1C"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EOA (secp256k1 ECDSA) signer implementation.
|
|
3
|
+
* Corresponds to SPEC-013 Section 5.4 -- moduleId=0, 69 bytes.
|
|
4
|
+
*/
|
|
5
|
+
import { privateKeyToAccount } from 'viem/accounts';
|
|
6
|
+
import { MODULE_IDS, encodeModuleSignature } from './interface.js';
|
|
7
|
+
/**
|
|
8
|
+
* Signs UserOperations with a secp256k1 private key (standard EOA).
|
|
9
|
+
* Produces ECDSA signatures: r(32) + s(32) + v(1) = 65 bytes.
|
|
10
|
+
* Prefixed with moduleId(4) = 69 bytes total.
|
|
11
|
+
*/
|
|
12
|
+
export class EoaSigner {
|
|
13
|
+
type = 'eoa';
|
|
14
|
+
address;
|
|
15
|
+
moduleId = MODULE_IDS.SINGLE_SIGNER;
|
|
16
|
+
account;
|
|
17
|
+
constructor(privateKey) {
|
|
18
|
+
this.account = privateKeyToAccount(privateKey);
|
|
19
|
+
this.address = this.account.address;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Sign a UserOperation hash with ECDSA.
|
|
23
|
+
* Returns the full prefixed signature: moduleId(4) + ecdsaSig(65) = 69 bytes.
|
|
24
|
+
*/
|
|
25
|
+
async sign(userOpHash) {
|
|
26
|
+
const rawSignature = await this.account.signMessage({
|
|
27
|
+
message: { raw: userOpHash },
|
|
28
|
+
});
|
|
29
|
+
return encodeModuleSignature(this.moduleId, rawSignature);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=eoa.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eoa.js","sourceRoot":"","sources":["../../src/signer/eoa.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,EAAgB,UAAU,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAEjF;;;;GAIG;AACH,MAAM,OAAO,SAAS;IACX,IAAI,GAAG,KAAc,CAAC;IACtB,OAAO,CAAU;IACjB,QAAQ,GAAG,UAAU,CAAC,aAAa,CAAC;IAE5B,OAAO,CAAe;IAEvC,YAAY,UAAe;QACzB,IAAI,CAAC,OAAO,GAAG,mBAAmB,CAAC,UAAqB,CAAC,CAAC;QAC1D,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAkB,CAAC;IACjD,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,IAAI,CAAC,UAAe;QACxB,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC;YAClD,OAAO,EAAE,EAAE,GAAG,EAAE,UAAqB,EAAE;SACxC,CAAC,CAAC;QAEH,OAAO,qBAAqB,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAmB,CAAC,CAAC;IACnE,CAAC;CACF"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ISigner abstraction and signature encoding.
|
|
3
|
+
* Corresponds to SPEC-013 Section 5.4.
|
|
4
|
+
*
|
|
5
|
+
* Signature format: abi.encodePacked(uint32(moduleId), moduleSpecificSignature)
|
|
6
|
+
*
|
|
7
|
+
* | Signer | moduleId | Signature Format | Size |
|
|
8
|
+
* |------------------|----------|---------------------------------------------------|------------|
|
|
9
|
+
* | EOA | 0 | moduleId(4) + ecdsaSig(65) | 69 bytes |
|
|
10
|
+
* | Session Key | 1 | moduleId(4) + ecdsaSig(65) | 69 bytes |
|
|
11
|
+
* | Device+Guardian | 2 | moduleId(4) + deviceSig(65) + guardianSig(65) | 134 bytes |
|
|
12
|
+
* | Multi-Sig (2/3) | 3 | moduleId(4) + abi.encode(sig1, sig2) | ~200 bytes |
|
|
13
|
+
* | Passkey (WebAuthn)| 4 | moduleId(4) + abi.encode(authData, clientJSON, r, s) | ~300-500 |
|
|
14
|
+
*/
|
|
15
|
+
import type { Address, Hex } from '../types.js';
|
|
16
|
+
/** Signer type identifiers */
|
|
17
|
+
export type SignerType = 'eoa' | 'passkey' | 'turnkey' | 'session-key' | 'multi-sig';
|
|
18
|
+
/** Module ID constants */
|
|
19
|
+
export declare const MODULE_IDS: {
|
|
20
|
+
readonly SINGLE_SIGNER: 0;
|
|
21
|
+
readonly SESSION_KEY: 1;
|
|
22
|
+
readonly DEVICE_GUARDIAN: 2;
|
|
23
|
+
readonly MULTI_SIG: 3;
|
|
24
|
+
readonly WEBAUTHN: 4;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Universal signer interface.
|
|
28
|
+
* All signer implementations must conform to this interface.
|
|
29
|
+
*/
|
|
30
|
+
export interface ISigner {
|
|
31
|
+
/** Signer type identifier */
|
|
32
|
+
readonly type: SignerType;
|
|
33
|
+
/** Signer's public address */
|
|
34
|
+
readonly address: Address;
|
|
35
|
+
/** On-chain validation module ID */
|
|
36
|
+
readonly moduleId: number;
|
|
37
|
+
/**
|
|
38
|
+
* Sign a UserOperation hash.
|
|
39
|
+
* Returns the raw module-specific signature (without moduleId prefix).
|
|
40
|
+
* Use encodeModuleSignature() to prepend the moduleId.
|
|
41
|
+
*/
|
|
42
|
+
sign(userOpHash: Hex): Promise<Hex>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Encode a signature with the module ID prefix.
|
|
46
|
+
* Format: abi.encodePacked(uint32(moduleId), moduleSpecificSignature)
|
|
47
|
+
*
|
|
48
|
+
* @param moduleId - The validation module ID (0-4)
|
|
49
|
+
* @param signature - The raw module-specific signature
|
|
50
|
+
* @returns The prefixed signature ready for UserOperation.signature
|
|
51
|
+
*/
|
|
52
|
+
export declare function encodeModuleSignature(moduleId: number, signature: Hex): Hex;
|
|
53
|
+
/**
|
|
54
|
+
* Decode a prefixed signature into moduleId and raw signature.
|
|
55
|
+
*/
|
|
56
|
+
export declare function decodeModuleSignature(prefixedSignature: Hex): {
|
|
57
|
+
moduleId: number;
|
|
58
|
+
signature: Hex;
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/signer/interface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAEhD,8BAA8B;AAC9B,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,GAAG,WAAW,CAAC;AAErF,0BAA0B;AAC1B,eAAO,MAAM,UAAU;;;;;;CAMb,CAAC;AAEX;;;GAGG;AACH,MAAM,WAAW,OAAO;IACtB,6BAA6B;IAC7B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAE1B,8BAA8B;IAC9B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAE1B,oCAAoC;IACpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B;;;;OAIG;IACH,IAAI,CAAC,UAAU,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;CACrC;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,GAAG,GAAG,CAM3E;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,iBAAiB,EAAE,GAAG,GAAG;IAC7D,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,GAAG,CAAC;CAChB,CAKA"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ISigner abstraction and signature encoding.
|
|
3
|
+
* Corresponds to SPEC-013 Section 5.4.
|
|
4
|
+
*
|
|
5
|
+
* Signature format: abi.encodePacked(uint32(moduleId), moduleSpecificSignature)
|
|
6
|
+
*
|
|
7
|
+
* | Signer | moduleId | Signature Format | Size |
|
|
8
|
+
* |------------------|----------|---------------------------------------------------|------------|
|
|
9
|
+
* | EOA | 0 | moduleId(4) + ecdsaSig(65) | 69 bytes |
|
|
10
|
+
* | Session Key | 1 | moduleId(4) + ecdsaSig(65) | 69 bytes |
|
|
11
|
+
* | Device+Guardian | 2 | moduleId(4) + deviceSig(65) + guardianSig(65) | 134 bytes |
|
|
12
|
+
* | Multi-Sig (2/3) | 3 | moduleId(4) + abi.encode(sig1, sig2) | ~200 bytes |
|
|
13
|
+
* | Passkey (WebAuthn)| 4 | moduleId(4) + abi.encode(authData, clientJSON, r, s) | ~300-500 |
|
|
14
|
+
*/
|
|
15
|
+
import { concat } from 'viem';
|
|
16
|
+
/** Module ID constants */
|
|
17
|
+
export const MODULE_IDS = {
|
|
18
|
+
SINGLE_SIGNER: 0,
|
|
19
|
+
SESSION_KEY: 1,
|
|
20
|
+
DEVICE_GUARDIAN: 2,
|
|
21
|
+
MULTI_SIG: 3,
|
|
22
|
+
WEBAUTHN: 4,
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Encode a signature with the module ID prefix.
|
|
26
|
+
* Format: abi.encodePacked(uint32(moduleId), moduleSpecificSignature)
|
|
27
|
+
*
|
|
28
|
+
* @param moduleId - The validation module ID (0-4)
|
|
29
|
+
* @param signature - The raw module-specific signature
|
|
30
|
+
* @returns The prefixed signature ready for UserOperation.signature
|
|
31
|
+
*/
|
|
32
|
+
export function encodeModuleSignature(moduleId, signature) {
|
|
33
|
+
// uint32 moduleId = 4 bytes big-endian
|
|
34
|
+
const moduleIdHex = moduleId.toString(16).padStart(8, '0');
|
|
35
|
+
const moduleIdBytes = `0x${moduleIdHex}`;
|
|
36
|
+
return concat([moduleIdBytes, signature]);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Decode a prefixed signature into moduleId and raw signature.
|
|
40
|
+
*/
|
|
41
|
+
export function decodeModuleSignature(prefixedSignature) {
|
|
42
|
+
// First 4 bytes = moduleId
|
|
43
|
+
const moduleId = parseInt(prefixedSignature.slice(2, 10), 16);
|
|
44
|
+
const signature = `0x${prefixedSignature.slice(10)}`;
|
|
45
|
+
return { moduleId, signature };
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=interface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interface.js","sourceRoot":"","sources":["../../src/signer/interface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAgB,MAAM,EAAE,MAAM,MAAM,CAAC;AAM5C,0BAA0B;AAC1B,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,aAAa,EAAE,CAAC;IAChB,WAAW,EAAE,CAAC;IACd,eAAe,EAAE,CAAC;IAClB,SAAS,EAAE,CAAC;IACZ,QAAQ,EAAE,CAAC;CACH,CAAC;AAwBX;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAgB,EAAE,SAAc;IACpE,uCAAuC;IACvC,MAAM,WAAW,GAAG,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC3D,MAAM,aAAa,GAAG,KAAK,WAAW,EAAS,CAAC;IAEhD,OAAO,MAAM,CAAC,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,iBAAsB;IAI1D,2BAA2B;IAC3B,MAAM,QAAQ,GAAG,QAAQ,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAC9D,MAAM,SAAS,GAAG,KAAK,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC,EAAS,CAAC;IAC5D,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-sig signature collector.
|
|
3
|
+
* Corresponds to SPEC-013 Section 5.4 -- moduleId=3, ~200 bytes.
|
|
4
|
+
*
|
|
5
|
+
* Signature format: moduleId(4) + abi.encode(sig1, sig2, ...)
|
|
6
|
+
*/
|
|
7
|
+
import type { Address, Hex } from '../types.js';
|
|
8
|
+
import { type ISigner } from './interface.js';
|
|
9
|
+
/**
|
|
10
|
+
* Collects multiple signatures for K-of-N multi-sig validation.
|
|
11
|
+
* Does not hold private keys -- instead collects raw signatures from other signers.
|
|
12
|
+
*/
|
|
13
|
+
export declare class MultiSigCollector implements ISigner {
|
|
14
|
+
readonly address: Address;
|
|
15
|
+
private readonly threshold;
|
|
16
|
+
readonly type: "multi-sig";
|
|
17
|
+
readonly moduleId: 3;
|
|
18
|
+
private signatures;
|
|
19
|
+
constructor(address: Address, threshold: number);
|
|
20
|
+
/**
|
|
21
|
+
* Add a raw signature from one of the K-of-N signers.
|
|
22
|
+
*/
|
|
23
|
+
addSignature(signature: Hex): void;
|
|
24
|
+
/** Check if enough signatures have been collected */
|
|
25
|
+
get isComplete(): boolean;
|
|
26
|
+
/** Number of signatures collected */
|
|
27
|
+
get count(): number;
|
|
28
|
+
/**
|
|
29
|
+
* Encode all collected signatures.
|
|
30
|
+
* Returns: moduleId(4) + abi.encode(bytes[] signatures)
|
|
31
|
+
*
|
|
32
|
+
* @throws If threshold not met
|
|
33
|
+
*/
|
|
34
|
+
sign(_userOpHash: Hex): Promise<Hex>;
|
|
35
|
+
/** Reset collected signatures */
|
|
36
|
+
reset(): void;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=multisig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multisig.d.ts","sourceRoot":"","sources":["../../src/signer/multisig.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,KAAK,OAAO,EAAqC,MAAM,gBAAgB,CAAC;AAEjF;;;GAGG;AACH,qBAAa,iBAAkB,YAAW,OAAO;IAO7C,QAAQ,CAAC,OAAO,EAAE,OAAO;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAP5B,QAAQ,CAAC,IAAI,EAAG,WAAW,CAAU;IACrC,QAAQ,CAAC,QAAQ,IAAwB;IAEzC,OAAO,CAAC,UAAU,CAAa;gBAGpB,OAAO,EAAE,OAAO,EACR,SAAS,EAAE,MAAM;IAGpC;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,GAAG,GAAG,IAAI;IAIlC,qDAAqD;IACrD,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,qCAAqC;IACrC,IAAI,KAAK,IAAI,MAAM,CAElB;IAED;;;;;OAKG;IACG,IAAI,CAAC,WAAW,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAa1C,iCAAiC;IACjC,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-sig signature collector.
|
|
3
|
+
* Corresponds to SPEC-013 Section 5.4 -- moduleId=3, ~200 bytes.
|
|
4
|
+
*
|
|
5
|
+
* Signature format: moduleId(4) + abi.encode(sig1, sig2, ...)
|
|
6
|
+
*/
|
|
7
|
+
import { encodeAbiParameters, parseAbiParameters } from 'viem';
|
|
8
|
+
import { MODULE_IDS, encodeModuleSignature } from './interface.js';
|
|
9
|
+
/**
|
|
10
|
+
* Collects multiple signatures for K-of-N multi-sig validation.
|
|
11
|
+
* Does not hold private keys -- instead collects raw signatures from other signers.
|
|
12
|
+
*/
|
|
13
|
+
export class MultiSigCollector {
|
|
14
|
+
address;
|
|
15
|
+
threshold;
|
|
16
|
+
type = 'multi-sig';
|
|
17
|
+
moduleId = MODULE_IDS.MULTI_SIG;
|
|
18
|
+
signatures = [];
|
|
19
|
+
constructor(address, threshold) {
|
|
20
|
+
this.address = address;
|
|
21
|
+
this.threshold = threshold;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Add a raw signature from one of the K-of-N signers.
|
|
25
|
+
*/
|
|
26
|
+
addSignature(signature) {
|
|
27
|
+
this.signatures.push(signature);
|
|
28
|
+
}
|
|
29
|
+
/** Check if enough signatures have been collected */
|
|
30
|
+
get isComplete() {
|
|
31
|
+
return this.signatures.length >= this.threshold;
|
|
32
|
+
}
|
|
33
|
+
/** Number of signatures collected */
|
|
34
|
+
get count() {
|
|
35
|
+
return this.signatures.length;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Encode all collected signatures.
|
|
39
|
+
* Returns: moduleId(4) + abi.encode(bytes[] signatures)
|
|
40
|
+
*
|
|
41
|
+
* @throws If threshold not met
|
|
42
|
+
*/
|
|
43
|
+
async sign(_userOpHash) {
|
|
44
|
+
if (!this.isComplete) {
|
|
45
|
+
throw new Error(`Multi-sig threshold not met: ${this.signatures.length}/${this.threshold}`);
|
|
46
|
+
}
|
|
47
|
+
// ABI-encode the array of signatures
|
|
48
|
+
const encoded = encodeAbiParameters(parseAbiParameters('bytes[]'), [this.signatures]);
|
|
49
|
+
return encodeModuleSignature(this.moduleId, encoded);
|
|
50
|
+
}
|
|
51
|
+
/** Reset collected signatures */
|
|
52
|
+
reset() {
|
|
53
|
+
this.signatures = [];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=multisig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multisig.js","sourceRoot":"","sources":["../../src/signer/multisig.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,MAAM,CAAC;AAE/D,OAAO,EAAgB,UAAU,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAEjF;;;GAGG;AACH,MAAM,OAAO,iBAAiB;IAOjB;IACQ;IAPV,IAAI,GAAG,WAAoB,CAAC;IAC5B,QAAQ,GAAG,UAAU,CAAC,SAAS,CAAC;IAEjC,UAAU,GAAU,EAAE,CAAC;IAE/B,YACW,OAAgB,EACR,SAAiB;QADzB,YAAO,GAAP,OAAO,CAAS;QACR,cAAS,GAAT,SAAS,CAAQ;IACjC,CAAC;IAEJ;;OAEG;IACH,YAAY,CAAC,SAAc;QACzB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAClC,CAAC;IAED,qDAAqD;IACrD,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,IAAI,CAAC,SAAS,CAAC;IAClD,CAAC;IAED,qCAAqC;IACrC,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;IAChC,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,IAAI,CAAC,WAAgB;QACzB,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CACb,gCAAgC,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,IAAI,CAAC,SAAS,EAAE,CAC3E,CAAC;QACJ,CAAC;QAED,qCAAqC;QACrC,MAAM,OAAO,GAAG,mBAAmB,CAAC,kBAAkB,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QAEtF,OAAO,qBAAqB,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAc,CAAC,CAAC;IAC9D,CAAC;IAED,iCAAiC;IACjC,KAAK;QACH,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;IACvB,CAAC;CACF"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebAuthn/Passkey P256 signer implementation.
|
|
3
|
+
* Corresponds to SPEC-013 Section 5.4 -- moduleId=4, ~300-500 bytes.
|
|
4
|
+
*
|
|
5
|
+
* Signature format: moduleId(4) + abi.encode(authenticatorData, clientDataJSON, r, s)
|
|
6
|
+
*/
|
|
7
|
+
import type { Address, Hex } from '../types.js';
|
|
8
|
+
import { type ISigner } from './interface.js';
|
|
9
|
+
interface WebAuthnSignResult {
|
|
10
|
+
authenticatorData: Hex;
|
|
11
|
+
clientDataJSON: string;
|
|
12
|
+
r: bigint;
|
|
13
|
+
s: bigint;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Signs UserOperations using WebAuthn/Passkey (P256/secp256r1).
|
|
17
|
+
* Uses the device secure enclave for key storage.
|
|
18
|
+
* On-chain verification via RIP-7212 precompile or daimo-eth/p256-verifier fallback.
|
|
19
|
+
*/
|
|
20
|
+
export declare class PasskeySigner implements ISigner {
|
|
21
|
+
readonly address: Address;
|
|
22
|
+
private readonly credentialId;
|
|
23
|
+
private readonly signFn?;
|
|
24
|
+
readonly type: "passkey";
|
|
25
|
+
readonly moduleId: 4;
|
|
26
|
+
constructor(address: Address, credentialId: string, signFn?: ((challenge: Hex) => Promise<WebAuthnSignResult>) | undefined);
|
|
27
|
+
/**
|
|
28
|
+
* Sign a UserOperation hash with WebAuthn P256.
|
|
29
|
+
* Returns: moduleId(4) + abi.encode(authenticatorData, clientDataJSON, r, s)
|
|
30
|
+
*/
|
|
31
|
+
sign(userOpHash: Hex): Promise<Hex>;
|
|
32
|
+
private webauthnSign;
|
|
33
|
+
}
|
|
34
|
+
export {};
|
|
35
|
+
//# sourceMappingURL=passkey.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"passkey.d.ts","sourceRoot":"","sources":["../../src/signer/passkey.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,KAAK,OAAO,EAAqC,MAAM,gBAAgB,CAAC;AAEjF,UAAU,kBAAkB;IAC1B,iBAAiB,EAAE,GAAG,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED;;;;GAIG;AACH,qBAAa,aAAc,YAAW,OAAO;IAKzC,QAAQ,CAAC,OAAO,EAAE,OAAO;IACzB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IAN1B,QAAQ,CAAC,IAAI,EAAG,SAAS,CAAU;IACnC,QAAQ,CAAC,QAAQ,IAAuB;gBAG7B,OAAO,EAAE,OAAO,EACR,YAAY,EAAE,MAAM,EACpB,MAAM,CAAC,GAAE,CAAC,SAAS,EAAE,GAAG,KAAK,OAAO,CAAC,kBAAkB,CAAC,aAAA;IAG3E;;;OAGG;IACG,IAAI,CAAC,UAAU,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;YAkB3B,YAAY;CA6B3B"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebAuthn/Passkey P256 signer implementation.
|
|
3
|
+
* Corresponds to SPEC-013 Section 5.4 -- moduleId=4, ~300-500 bytes.
|
|
4
|
+
*
|
|
5
|
+
* Signature format: moduleId(4) + abi.encode(authenticatorData, clientDataJSON, r, s)
|
|
6
|
+
*/
|
|
7
|
+
import { encodeAbiParameters, parseAbiParameters } from 'viem';
|
|
8
|
+
import { MODULE_IDS, encodeModuleSignature } from './interface.js';
|
|
9
|
+
/**
|
|
10
|
+
* Signs UserOperations using WebAuthn/Passkey (P256/secp256r1).
|
|
11
|
+
* Uses the device secure enclave for key storage.
|
|
12
|
+
* On-chain verification via RIP-7212 precompile or daimo-eth/p256-verifier fallback.
|
|
13
|
+
*/
|
|
14
|
+
export class PasskeySigner {
|
|
15
|
+
address;
|
|
16
|
+
credentialId;
|
|
17
|
+
signFn;
|
|
18
|
+
type = 'passkey';
|
|
19
|
+
moduleId = MODULE_IDS.WEBAUTHN;
|
|
20
|
+
constructor(address, credentialId, signFn) {
|
|
21
|
+
this.address = address;
|
|
22
|
+
this.credentialId = credentialId;
|
|
23
|
+
this.signFn = signFn;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Sign a UserOperation hash with WebAuthn P256.
|
|
27
|
+
* Returns: moduleId(4) + abi.encode(authenticatorData, clientDataJSON, r, s)
|
|
28
|
+
*/
|
|
29
|
+
async sign(userOpHash) {
|
|
30
|
+
let result;
|
|
31
|
+
if (this.signFn) {
|
|
32
|
+
result = await this.signFn(userOpHash);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
result = await this.webauthnSign(userOpHash);
|
|
36
|
+
}
|
|
37
|
+
// ABI-encode the WebAuthn assertion data
|
|
38
|
+
const moduleSignature = encodeAbiParameters(parseAbiParameters('bytes, string, uint256, uint256'), [result.authenticatorData, result.clientDataJSON, result.r, result.s]);
|
|
39
|
+
return encodeModuleSignature(this.moduleId, moduleSignature);
|
|
40
|
+
}
|
|
41
|
+
async webauthnSign(challenge) {
|
|
42
|
+
if (typeof navigator === 'undefined' || !navigator.credentials) {
|
|
43
|
+
throw new Error('WebAuthn not available in this environment');
|
|
44
|
+
}
|
|
45
|
+
// Convert hex challenge to ArrayBuffer
|
|
46
|
+
const challengeBytes = hexToBytes(challenge).buffer;
|
|
47
|
+
const assertion = (await navigator.credentials.get({
|
|
48
|
+
publicKey: {
|
|
49
|
+
challenge: challengeBytes,
|
|
50
|
+
allowCredentials: [
|
|
51
|
+
{
|
|
52
|
+
type: 'public-key',
|
|
53
|
+
id: base64UrlToBuffer(this.credentialId),
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
userVerification: 'required',
|
|
57
|
+
timeout: 60000,
|
|
58
|
+
},
|
|
59
|
+
}));
|
|
60
|
+
const response = assertion.response;
|
|
61
|
+
const authenticatorData = bytesToHex(new Uint8Array(response.authenticatorData));
|
|
62
|
+
const clientDataJSON = new TextDecoder().decode(response.clientDataJSON);
|
|
63
|
+
const { r, s } = extractP256Signature(new Uint8Array(response.signature));
|
|
64
|
+
return { authenticatorData, clientDataJSON, r, s };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/** Extract r, s from a DER-encoded P256 signature */
|
|
68
|
+
function extractP256Signature(derSig) {
|
|
69
|
+
// DER: 0x30 <len> 0x02 <rlen> <r> 0x02 <slen> <s>
|
|
70
|
+
let offset = 2; // skip 0x30 and total length
|
|
71
|
+
offset += 1; // skip 0x02
|
|
72
|
+
const rLen = derSig[offset];
|
|
73
|
+
offset += 1;
|
|
74
|
+
const rBytes = derSig.slice(offset, offset + rLen);
|
|
75
|
+
offset += rLen;
|
|
76
|
+
offset += 1; // skip 0x02
|
|
77
|
+
const sLen = derSig[offset];
|
|
78
|
+
offset += 1;
|
|
79
|
+
const sBytes = derSig.slice(offset, offset + sLen);
|
|
80
|
+
const r = bytesToBigInt(rBytes);
|
|
81
|
+
const s = bytesToBigInt(sBytes);
|
|
82
|
+
// Normalize s to low-s form (s <= n/2) per P256
|
|
83
|
+
const P256_N = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551n;
|
|
84
|
+
const normalizedS = s > P256_N / 2n ? P256_N - s : s;
|
|
85
|
+
return { r, s: normalizedS };
|
|
86
|
+
}
|
|
87
|
+
function hexToBytes(hex) {
|
|
88
|
+
const bytes = new Uint8Array((hex.length - 2) / 2);
|
|
89
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
90
|
+
bytes[i] = parseInt(hex.slice(2 + i * 2, 4 + i * 2), 16);
|
|
91
|
+
}
|
|
92
|
+
return bytes;
|
|
93
|
+
}
|
|
94
|
+
function bytesToHex(bytes) {
|
|
95
|
+
return `0x${Array.from(bytes)
|
|
96
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
97
|
+
.join('')}`;
|
|
98
|
+
}
|
|
99
|
+
function bytesToBigInt(bytes) {
|
|
100
|
+
return BigInt(bytesToHex(bytes));
|
|
101
|
+
}
|
|
102
|
+
function base64UrlToBuffer(base64url) {
|
|
103
|
+
const base64 = base64url.replace(/-/g, '+').replace(/_/g, '/');
|
|
104
|
+
const padding = '='.repeat((4 - (base64.length % 4)) % 4);
|
|
105
|
+
const binary = atob(base64 + padding);
|
|
106
|
+
const bytes = new Uint8Array(binary.length);
|
|
107
|
+
for (let i = 0; i < binary.length; i++) {
|
|
108
|
+
bytes[i] = binary.charCodeAt(i);
|
|
109
|
+
}
|
|
110
|
+
return bytes.buffer;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=passkey.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"passkey.js","sourceRoot":"","sources":["../../src/signer/passkey.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session key signer implementation.
|
|
3
|
+
* Corresponds to SPEC-013 Section 5.4 -- moduleId=1, 69 bytes.
|
|
4
|
+
*/
|
|
5
|
+
import type { Address, Hex } from '../types.js';
|
|
6
|
+
import { type ISigner } from './interface.js';
|
|
7
|
+
/**
|
|
8
|
+
* Signs UserOperations with a session key (ephemeral ECDSA key).
|
|
9
|
+
* Session keys have scoped permissions enforced on-chain via permission hooks.
|
|
10
|
+
* Signature format is identical to EOA but uses moduleId=1.
|
|
11
|
+
*/
|
|
12
|
+
export declare class SessionKeySigner implements ISigner {
|
|
13
|
+
readonly type: "session-key";
|
|
14
|
+
readonly address: Address;
|
|
15
|
+
readonly moduleId: 1;
|
|
16
|
+
private readonly account;
|
|
17
|
+
constructor(privateKey: Hex);
|
|
18
|
+
/**
|
|
19
|
+
* Sign a UserOperation hash with the session key.
|
|
20
|
+
* Returns: moduleId(4) + ecdsaSig(65) = 69 bytes.
|
|
21
|
+
*/
|
|
22
|
+
sign(userOpHash: Hex): Promise<Hex>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/signer/session.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,KAAK,OAAO,EAAqC,MAAM,gBAAgB,CAAC;AAEjF;;;;GAIG;AACH,qBAAa,gBAAiB,YAAW,OAAO;IAC9C,QAAQ,CAAC,IAAI,EAAG,aAAa,CAAU;IACvC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,QAAQ,IAA0B;IAE3C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;gBAE3B,UAAU,EAAE,GAAG;IAK3B;;;OAGG;IACG,IAAI,CAAC,UAAU,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;CAO1C"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session key signer implementation.
|
|
3
|
+
* Corresponds to SPEC-013 Section 5.4 -- moduleId=1, 69 bytes.
|
|
4
|
+
*/
|
|
5
|
+
import { privateKeyToAccount } from 'viem/accounts';
|
|
6
|
+
import { MODULE_IDS, encodeModuleSignature } from './interface.js';
|
|
7
|
+
/**
|
|
8
|
+
* Signs UserOperations with a session key (ephemeral ECDSA key).
|
|
9
|
+
* Session keys have scoped permissions enforced on-chain via permission hooks.
|
|
10
|
+
* Signature format is identical to EOA but uses moduleId=1.
|
|
11
|
+
*/
|
|
12
|
+
export class SessionKeySigner {
|
|
13
|
+
type = 'session-key';
|
|
14
|
+
address;
|
|
15
|
+
moduleId = MODULE_IDS.SESSION_KEY;
|
|
16
|
+
account;
|
|
17
|
+
constructor(privateKey) {
|
|
18
|
+
this.account = privateKeyToAccount(privateKey);
|
|
19
|
+
this.address = this.account.address;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Sign a UserOperation hash with the session key.
|
|
23
|
+
* Returns: moduleId(4) + ecdsaSig(65) = 69 bytes.
|
|
24
|
+
*/
|
|
25
|
+
async sign(userOpHash) {
|
|
26
|
+
const rawSignature = await this.account.signMessage({
|
|
27
|
+
message: { raw: userOpHash },
|
|
28
|
+
});
|
|
29
|
+
return encodeModuleSignature(this.moduleId, rawSignature);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/signer/session.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,EAAgB,UAAU,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAEjF;;;;GAIG;AACH,MAAM,OAAO,gBAAgB;IAClB,IAAI,GAAG,aAAsB,CAAC;IAC9B,OAAO,CAAU;IACjB,QAAQ,GAAG,UAAU,CAAC,WAAW,CAAC;IAE1B,OAAO,CAAe;IAEvC,YAAY,UAAe;QACzB,IAAI,CAAC,OAAO,GAAG,mBAAmB,CAAC,UAAqB,CAAC,CAAC;QAC1D,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAkB,CAAC;IACjD,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,IAAI,CAAC,UAAe;QACxB,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC;YAClD,OAAO,EAAE,EAAE,GAAG,EAAE,UAAqB,EAAE;SACxC,CAAC,CAAC;QAEH,OAAO,qBAAqB,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAmB,CAAC,CAAC;IACnE,CAAC;CACF"}
|