@introspectivelabs/x402-evm 0.1.0-beta.0 → 0.1.0-beta.10
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/dist/cjs/accounts/index.d.ts +150 -0
- package/dist/cjs/accounts/index.js +476 -0
- package/dist/cjs/accounts/index.js.map +1 -0
- package/dist/cjs/exact/client/index.d.ts +39 -3
- package/dist/cjs/exact/client/index.js +430 -70
- package/dist/cjs/exact/client/index.js.map +1 -1
- package/dist/cjs/exact/facilitator/index.js +4 -4
- package/dist/cjs/exact/facilitator/index.js.map +1 -1
- package/dist/cjs/factories/index.d.ts +129 -0
- package/dist/cjs/factories/index.js +193 -0
- package/dist/cjs/factories/index.js.map +1 -0
- package/dist/cjs/index.d.ts +5 -1
- package/dist/cjs/index.js +977 -74
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/networks/index.d.ts +30 -0
- package/dist/cjs/networks/index.js +188 -0
- package/dist/cjs/networks/index.js.map +1 -0
- package/dist/cjs/stamp/index.d.ts +27 -0
- package/dist/cjs/stamp/index.js +78 -0
- package/dist/cjs/stamp/index.js.map +1 -0
- package/dist/cjs/types-lO5B0FRc.d.ts +60 -0
- package/dist/cjs/{userOperation-Dh1zucfd.d.ts → userOperation-bd50ILnY.d.ts} +52 -2
- package/dist/esm/accounts/index.d.mts +150 -0
- package/dist/esm/accounts/index.mjs +19 -0
- package/dist/esm/accounts/index.mjs.map +1 -0
- package/dist/esm/chunk-CGTTWYDC.mjs +150 -0
- package/dist/esm/chunk-CGTTWYDC.mjs.map +1 -0
- package/dist/esm/{chunk-5HWFMQYG.mjs → chunk-DV33VYOK.mjs} +5 -5
- package/dist/esm/{chunk-5HWFMQYG.mjs.map → chunk-DV33VYOK.mjs.map} +1 -1
- package/dist/esm/chunk-U6RQAPAD.mjs +442 -0
- package/dist/esm/chunk-U6RQAPAD.mjs.map +1 -0
- package/dist/esm/chunk-WTGPDVU3.mjs +56 -0
- package/dist/esm/chunk-WTGPDVU3.mjs.map +1 -0
- package/dist/esm/chunk-YSA5EPXF.mjs +16 -0
- package/dist/esm/chunk-YSA5EPXF.mjs.map +1 -0
- package/dist/esm/chunk-ZTFX2VPI.mjs +617 -0
- package/dist/esm/chunk-ZTFX2VPI.mjs.map +1 -0
- package/dist/esm/exact/client/index.d.mts +39 -3
- package/dist/esm/exact/client/index.mjs +13 -1
- package/dist/esm/exact/facilitator/index.mjs +1 -1
- package/dist/esm/factories/index.d.mts +129 -0
- package/dist/esm/factories/index.mjs +157 -0
- package/dist/esm/factories/index.mjs.map +1 -0
- package/dist/esm/index.d.mts +5 -1
- package/dist/esm/index.mjs +56 -2
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/networks/index.d.mts +30 -0
- package/dist/esm/networks/index.mjs +31 -0
- package/dist/esm/networks/index.mjs.map +1 -0
- package/dist/esm/stamp/index.d.mts +27 -0
- package/dist/esm/stamp/index.mjs +7 -0
- package/dist/esm/stamp/index.mjs.map +1 -0
- package/dist/esm/types-lO5B0FRc.d.mts +60 -0
- package/dist/esm/{userOperation-B2UUp3K6.d.mts → userOperation--Sqhz6PA.d.mts} +52 -2
- package/package.json +43 -1
- package/dist/esm/chunk-56L4QUDN.mjs +0 -359
- package/dist/esm/chunk-56L4QUDN.mjs.map +0 -1
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { SmartAccount, WebAuthnAccount } from 'viem/account-abstraction';
|
|
2
|
+
import { b as ToSafeSmartAccountParams, T as ToP256SafeSmartAccountParams } from '../types-lO5B0FRc.js';
|
|
3
|
+
export { P as P256Signer, S as SafeMessageSigner, a as SignerConfig } from '../types-lO5B0FRc.js';
|
|
4
|
+
import { PublicClient, Transport, Chain, Hex } from 'viem';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Creates a Safe SmartAccount with a unified signer configuration.
|
|
8
|
+
*
|
|
9
|
+
* Dispatches to the appropriate implementation based on `signerConfig.type`:
|
|
10
|
+
* - `"p256"`: P256 contract owner (existing `toP256SafeSmartAccount`)
|
|
11
|
+
* - `"webauthn"`: WebAuthn passkey via permissionless native support
|
|
12
|
+
* - `"multi"`: Both P256 and WebAuthn owners on a single Safe
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* // P256 only
|
|
17
|
+
* const account = await toSafeSmartAccount({
|
|
18
|
+
* client,
|
|
19
|
+
* signerConfig: { type: "p256", p256Signer },
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* // WebAuthn only
|
|
23
|
+
* const account = await toSafeSmartAccount({
|
|
24
|
+
* client,
|
|
25
|
+
* signerConfig: { type: "webauthn", webAuthnAccount },
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* // Multi-signer (threshold 1, P256 signs by default)
|
|
29
|
+
* const account = await toSafeSmartAccount({
|
|
30
|
+
* client,
|
|
31
|
+
* signerConfig: {
|
|
32
|
+
* type: "multi",
|
|
33
|
+
* signers: { p256: p256Signer, webAuthn: webAuthnAccount },
|
|
34
|
+
* threshold: 1,
|
|
35
|
+
* },
|
|
36
|
+
* });
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
declare function toSafeSmartAccount(params: ToSafeSmartAccountParams): Promise<SmartAccount>;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Creates a Safe SmartAccount that signs UserOperations with a P256 contract owner.
|
|
43
|
+
*
|
|
44
|
+
* This wraps permissionless's `toSafeSmartAccount` and overrides `signUserOperation`
|
|
45
|
+
* to produce P256 signatures in Safe's contract signature format (v=0). The resulting
|
|
46
|
+
* account is compatible with `SafeAccountSigner` and `ExactEvmSchemeERC4337`.
|
|
47
|
+
*
|
|
48
|
+
* The caller is responsible for:
|
|
49
|
+
* - Deploying the P256Owner contract (or computing its deterministic address)
|
|
50
|
+
* - Providing the `sign()` function (e.g., using `@noble/curves/p256` with `prehash: false`)
|
|
51
|
+
* - Ensuring the P256Owner is an owner of the Safe
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* import { toP256SafeSmartAccount } from '@introspectivelabs/x402-evm';
|
|
56
|
+
* import { p256 } from '@noble/curves/p256';
|
|
57
|
+
*
|
|
58
|
+
* const account = await toP256SafeSmartAccount({
|
|
59
|
+
* client: publicClient,
|
|
60
|
+
* p256Signer: {
|
|
61
|
+
* p256OwnerAddress: '0x349c...',
|
|
62
|
+
* sign: async (hash) => {
|
|
63
|
+
* const sig = p256.sign(hash.slice(2), privateKey, { prehash: false, lowS: true });
|
|
64
|
+
* return {
|
|
65
|
+
* r: `0x${sig.r.toString(16).padStart(64, '0')}`,
|
|
66
|
+
* s: `0x${sig.s.toString(16).padStart(64, '0')}`,
|
|
67
|
+
* };
|
|
68
|
+
* },
|
|
69
|
+
* },
|
|
70
|
+
* safeAddress: '0x...',
|
|
71
|
+
* });
|
|
72
|
+
*
|
|
73
|
+
* const scheme = new ExactEvmSchemeERC4337({ account });
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
declare function toP256SafeSmartAccount(params: ToP256SafeSmartAccountParams): Promise<SmartAccount>;
|
|
77
|
+
|
|
78
|
+
type ToWebAuthnSafeSmartAccountParams = {
|
|
79
|
+
client: PublicClient<Transport, Chain>;
|
|
80
|
+
webAuthnAccount: WebAuthnAccount;
|
|
81
|
+
safeAddress?: Hex;
|
|
82
|
+
entryPoint?: {
|
|
83
|
+
address: Hex;
|
|
84
|
+
version: "0.7";
|
|
85
|
+
};
|
|
86
|
+
safe4337ModuleAddress?: Hex;
|
|
87
|
+
safeWebAuthnSharedSignerAddress?: Hex;
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Creates a Safe SmartAccount that signs UserOperations with a WebAuthn passkey.
|
|
91
|
+
*/
|
|
92
|
+
declare function toWebAuthnSafeSmartAccount(params: ToWebAuthnSafeSmartAccountParams): Promise<SmartAccount>;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Encodes a signature in Safe's contract signature format (v=0).
|
|
96
|
+
*
|
|
97
|
+
* Safe's `checkNSignatures` expects this layout for contract owners:
|
|
98
|
+
*
|
|
99
|
+
* Static part (65 bytes):
|
|
100
|
+
* - r (32 bytes): owner address padded to 32 bytes
|
|
101
|
+
* - s (32 bytes): offset to dynamic data (relative to start of signatures)
|
|
102
|
+
* - v (1 byte): 0x00 (indicates contract signature)
|
|
103
|
+
*
|
|
104
|
+
* Dynamic part (at the offset):
|
|
105
|
+
* - length (32 bytes): length of the signature data
|
|
106
|
+
* - data (variable): the actual signature bytes
|
|
107
|
+
*
|
|
108
|
+
* For a single signer, the static part is 65 bytes, so the dynamic data
|
|
109
|
+
* starts at offset 65.
|
|
110
|
+
*/
|
|
111
|
+
declare function encodeContractSignature(ownerAddress: Hex, signatureData: Hex): Hex;
|
|
112
|
+
|
|
113
|
+
interface SafeOpHashParams {
|
|
114
|
+
sender: Hex;
|
|
115
|
+
nonce: bigint;
|
|
116
|
+
factory?: Hex | null;
|
|
117
|
+
factoryData?: Hex | null;
|
|
118
|
+
callData: Hex;
|
|
119
|
+
verificationGasLimit: bigint;
|
|
120
|
+
callGasLimit: bigint;
|
|
121
|
+
preVerificationGas: bigint;
|
|
122
|
+
maxPriorityFeePerGas: bigint;
|
|
123
|
+
maxFeePerGas: bigint;
|
|
124
|
+
paymaster?: Hex | null;
|
|
125
|
+
paymasterVerificationGasLimit?: bigint | null;
|
|
126
|
+
paymasterPostOpGasLimit?: bigint | null;
|
|
127
|
+
paymasterData?: Hex | null;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Computes the EIP-712 SafeOp hash that Safe4337Module uses for signature verification.
|
|
131
|
+
*
|
|
132
|
+
* The Safe4337Module converts the EntryPoint v0.7 UserOperation into a SafeOp struct,
|
|
133
|
+
* packing initCode and paymasterAndData into their v0.6-style concatenated forms,
|
|
134
|
+
* then hashes the struct using EIP-712.
|
|
135
|
+
*/
|
|
136
|
+
declare function computeSafeOpHash(userOp: SafeOpHashParams, chainId: number, safe4337ModuleAddress?: Hex, entryPointAddress?: Hex): Hex;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Extracts P256 public key coordinates from a WebAuthn credential.
|
|
140
|
+
*
|
|
141
|
+
* Replaces `extractPasskeyData` from `@safe-global/protocol-kit`.
|
|
142
|
+
* Uses only the Web Crypto API (no external dependencies).
|
|
143
|
+
*/
|
|
144
|
+
declare function extractPasskeyCoordinates(credential: PublicKeyCredential): Promise<{
|
|
145
|
+
rawId: string;
|
|
146
|
+
x: Hex;
|
|
147
|
+
y: Hex;
|
|
148
|
+
}>;
|
|
149
|
+
|
|
150
|
+
export { type SafeOpHashParams, ToP256SafeSmartAccountParams, ToSafeSmartAccountParams, type ToWebAuthnSafeSmartAccountParams, computeSafeOpHash, encodeContractSignature, extractPasskeyCoordinates, toP256SafeSmartAccount, toSafeSmartAccount, toWebAuthnSafeSmartAccount };
|
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/accounts/index.ts
|
|
21
|
+
var accounts_exports = {};
|
|
22
|
+
__export(accounts_exports, {
|
|
23
|
+
computeSafeOpHash: () => computeSafeOpHash,
|
|
24
|
+
encodeContractSignature: () => encodeContractSignature,
|
|
25
|
+
extractPasskeyCoordinates: () => extractPasskeyCoordinates,
|
|
26
|
+
toP256SafeSmartAccount: () => toP256SafeSmartAccount,
|
|
27
|
+
toSafeSmartAccount: () => toSafeSmartAccount3,
|
|
28
|
+
toWebAuthnSafeSmartAccount: () => toWebAuthnSafeSmartAccount
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(accounts_exports);
|
|
31
|
+
|
|
32
|
+
// src/accounts/toSafeSmartAccount.ts
|
|
33
|
+
var import_viem4 = require("viem");
|
|
34
|
+
var import_accounts3 = require("permissionless/accounts");
|
|
35
|
+
|
|
36
|
+
// src/accounts/toP256SafeSmartAccount.ts
|
|
37
|
+
var import_viem3 = require("viem");
|
|
38
|
+
var import_accounts = require("permissionless/accounts");
|
|
39
|
+
|
|
40
|
+
// src/accounts/encodeContractSignature.ts
|
|
41
|
+
var import_viem = require("viem");
|
|
42
|
+
function encodeContractSignature(ownerAddress, signatureData) {
|
|
43
|
+
const r = (0, import_viem.pad)(ownerAddress, { size: 32 });
|
|
44
|
+
const dynamicOffset = 65;
|
|
45
|
+
const s = (0, import_viem.pad)((0, import_viem.toHex)(dynamicOffset), { size: 32 });
|
|
46
|
+
const v = "0x00";
|
|
47
|
+
const signatureBytes = (signatureData.length - 2) / 2;
|
|
48
|
+
const length = (0, import_viem.pad)((0, import_viem.toHex)(signatureBytes), { size: 32 });
|
|
49
|
+
return (0, import_viem.concat)([r, s, v, length, signatureData]);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/accounts/computeSafeOpHash.ts
|
|
53
|
+
var import_viem2 = require("viem");
|
|
54
|
+
var SAFE_4337_MODULE_DEFAULT = "0x75cf11467937ce3F2f357CE24ffc3DBF8fD5c226";
|
|
55
|
+
var ENTRYPOINT_V07 = "0x0000000071727De22E5E9d8BAf0edAc6f37da032";
|
|
56
|
+
var SAFE_OP_TYPES = {
|
|
57
|
+
SafeOp: [
|
|
58
|
+
{ type: "address", name: "safe" },
|
|
59
|
+
{ type: "uint256", name: "nonce" },
|
|
60
|
+
{ type: "bytes", name: "initCode" },
|
|
61
|
+
{ type: "bytes", name: "callData" },
|
|
62
|
+
{ type: "uint128", name: "verificationGasLimit" },
|
|
63
|
+
{ type: "uint128", name: "callGasLimit" },
|
|
64
|
+
{ type: "uint256", name: "preVerificationGas" },
|
|
65
|
+
{ type: "uint128", name: "maxPriorityFeePerGas" },
|
|
66
|
+
{ type: "uint128", name: "maxFeePerGas" },
|
|
67
|
+
{ type: "bytes", name: "paymasterAndData" },
|
|
68
|
+
{ type: "uint48", name: "validAfter" },
|
|
69
|
+
{ type: "uint48", name: "validUntil" },
|
|
70
|
+
{ type: "address", name: "entryPoint" }
|
|
71
|
+
]
|
|
72
|
+
};
|
|
73
|
+
function computeSafeOpHash(userOp, chainId, safe4337ModuleAddress = SAFE_4337_MODULE_DEFAULT, entryPointAddress = ENTRYPOINT_V07) {
|
|
74
|
+
const initCode = userOp.factory && (0, import_viem2.isAddress)(userOp.factory) ? (0, import_viem2.concat)([userOp.factory, userOp.factoryData || "0x"]) : "0x";
|
|
75
|
+
let paymasterAndData = "0x";
|
|
76
|
+
if (userOp.paymaster && (0, import_viem2.isAddress)(userOp.paymaster)) {
|
|
77
|
+
paymasterAndData = (0, import_viem2.concat)([
|
|
78
|
+
userOp.paymaster,
|
|
79
|
+
(0, import_viem2.pad)((0, import_viem2.toHex)(userOp.paymasterVerificationGasLimit || 0n), { size: 16 }),
|
|
80
|
+
(0, import_viem2.pad)((0, import_viem2.toHex)(userOp.paymasterPostOpGasLimit || 0n), { size: 16 }),
|
|
81
|
+
userOp.paymasterData || "0x"
|
|
82
|
+
]);
|
|
83
|
+
}
|
|
84
|
+
return (0, import_viem2.hashTypedData)({
|
|
85
|
+
domain: {
|
|
86
|
+
chainId,
|
|
87
|
+
verifyingContract: safe4337ModuleAddress
|
|
88
|
+
},
|
|
89
|
+
types: SAFE_OP_TYPES,
|
|
90
|
+
primaryType: "SafeOp",
|
|
91
|
+
message: {
|
|
92
|
+
safe: userOp.sender,
|
|
93
|
+
nonce: userOp.nonce,
|
|
94
|
+
initCode,
|
|
95
|
+
callData: userOp.callData,
|
|
96
|
+
verificationGasLimit: userOp.verificationGasLimit,
|
|
97
|
+
callGasLimit: userOp.callGasLimit,
|
|
98
|
+
preVerificationGas: userOp.preVerificationGas,
|
|
99
|
+
maxPriorityFeePerGas: userOp.maxPriorityFeePerGas,
|
|
100
|
+
maxFeePerGas: userOp.maxFeePerGas,
|
|
101
|
+
paymasterAndData,
|
|
102
|
+
validAfter: 0,
|
|
103
|
+
validUntil: 0,
|
|
104
|
+
entryPoint: entryPointAddress
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// src/accounts/toP256SafeSmartAccount.ts
|
|
110
|
+
var SAFE_4337_MODULE_DEFAULT2 = "0x75cf11467937ce3F2f357CE24ffc3DBF8fD5c226";
|
|
111
|
+
var ENTRYPOINT_V07_ADDRESS = "0x0000000071727De22E5E9d8BAf0edAc6f37da032";
|
|
112
|
+
function createMockLocalAccount(address) {
|
|
113
|
+
const notImplemented = () => {
|
|
114
|
+
throw new Error("P256 contract owner: use signUserOperation instead");
|
|
115
|
+
};
|
|
116
|
+
return {
|
|
117
|
+
address,
|
|
118
|
+
type: "local",
|
|
119
|
+
source: "custom",
|
|
120
|
+
publicKey: "0x",
|
|
121
|
+
signMessage: notImplemented,
|
|
122
|
+
signTypedData: notImplemented,
|
|
123
|
+
signTransaction: notImplemented,
|
|
124
|
+
sign: notImplemented
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
async function toP256SafeSmartAccount(params) {
|
|
128
|
+
const safe4337ModuleAddress = params.safe4337ModuleAddress ?? SAFE_4337_MODULE_DEFAULT2;
|
|
129
|
+
const entryPointAddress = params.entryPoint?.address ?? ENTRYPOINT_V07_ADDRESS;
|
|
130
|
+
const mockOwner = createMockLocalAccount(params.p256Signer.p256OwnerAddress);
|
|
131
|
+
const baseAccount = await (0, import_accounts.toSafeSmartAccount)({
|
|
132
|
+
client: params.client,
|
|
133
|
+
owners: [mockOwner],
|
|
134
|
+
version: "1.5.0",
|
|
135
|
+
...params.safeAddress ? { address: params.safeAddress } : {},
|
|
136
|
+
entryPoint: {
|
|
137
|
+
address: entryPointAddress,
|
|
138
|
+
version: "0.7"
|
|
139
|
+
},
|
|
140
|
+
safe4337ModuleAddress
|
|
141
|
+
});
|
|
142
|
+
const chainId = await params.client.getChainId();
|
|
143
|
+
return {
|
|
144
|
+
...baseAccount,
|
|
145
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
146
|
+
async signUserOperation(userOp) {
|
|
147
|
+
const op = userOp;
|
|
148
|
+
const hashParams = {
|
|
149
|
+
sender: op.sender,
|
|
150
|
+
nonce: BigInt(op.nonce),
|
|
151
|
+
factory: op.factory ?? null,
|
|
152
|
+
factoryData: op.factoryData ?? null,
|
|
153
|
+
callData: op.callData,
|
|
154
|
+
verificationGasLimit: BigInt(op.verificationGasLimit),
|
|
155
|
+
callGasLimit: BigInt(op.callGasLimit),
|
|
156
|
+
preVerificationGas: BigInt(op.preVerificationGas),
|
|
157
|
+
maxPriorityFeePerGas: BigInt(op.maxPriorityFeePerGas),
|
|
158
|
+
maxFeePerGas: BigInt(op.maxFeePerGas),
|
|
159
|
+
paymaster: op.paymaster ?? null,
|
|
160
|
+
paymasterVerificationGasLimit: op.paymasterVerificationGasLimit ? BigInt(op.paymasterVerificationGasLimit) : null,
|
|
161
|
+
paymasterPostOpGasLimit: op.paymasterPostOpGasLimit ? BigInt(op.paymasterPostOpGasLimit) : null,
|
|
162
|
+
paymasterData: op.paymasterData ?? null
|
|
163
|
+
};
|
|
164
|
+
const safeOpHash = computeSafeOpHash(
|
|
165
|
+
hashParams,
|
|
166
|
+
chainId,
|
|
167
|
+
safe4337ModuleAddress,
|
|
168
|
+
entryPointAddress
|
|
169
|
+
);
|
|
170
|
+
const { r, s } = await params.p256Signer.sign(safeOpHash);
|
|
171
|
+
const rPadded = (0, import_viem3.pad)(r, { size: 32 });
|
|
172
|
+
const sPadded = (0, import_viem3.pad)(s, { size: 32 });
|
|
173
|
+
const p256Signature = (0, import_viem3.concat)([rPadded, sPadded]);
|
|
174
|
+
const contractSig = encodeContractSignature(
|
|
175
|
+
params.p256Signer.p256OwnerAddress,
|
|
176
|
+
p256Signature
|
|
177
|
+
);
|
|
178
|
+
const validAfter = (0, import_viem3.pad)((0, import_viem3.toHex)(0), { size: 6 });
|
|
179
|
+
const validUntil = (0, import_viem3.pad)((0, import_viem3.toHex)(0), { size: 6 });
|
|
180
|
+
return (0, import_viem3.concat)([validAfter, validUntil, contractSig]);
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// src/accounts/toWebAuthnSafeSmartAccount.ts
|
|
186
|
+
var import_accounts2 = require("permissionless/accounts");
|
|
187
|
+
var SAFE_4337_MODULE_DEFAULT3 = "0x75cf11467937ce3F2f357CE24ffc3DBF8fD5c226";
|
|
188
|
+
var ENTRYPOINT_V07_ADDRESS2 = "0x0000000071727De22E5E9d8BAf0edAc6f37da032";
|
|
189
|
+
async function toWebAuthnSafeSmartAccount(params) {
|
|
190
|
+
const safe4337ModuleAddress = params.safe4337ModuleAddress ?? SAFE_4337_MODULE_DEFAULT3;
|
|
191
|
+
const entryPointAddress = params.entryPoint?.address ?? ENTRYPOINT_V07_ADDRESS2;
|
|
192
|
+
const baseAccount = await (0, import_accounts2.toSafeSmartAccount)({
|
|
193
|
+
client: params.client,
|
|
194
|
+
owners: [params.webAuthnAccount],
|
|
195
|
+
version: "1.5.0",
|
|
196
|
+
...params.safeAddress ? { address: params.safeAddress } : {},
|
|
197
|
+
entryPoint: {
|
|
198
|
+
address: entryPointAddress,
|
|
199
|
+
version: "0.7"
|
|
200
|
+
},
|
|
201
|
+
safe4337ModuleAddress,
|
|
202
|
+
...params.safeWebAuthnSharedSignerAddress ? { safeWebAuthnSharedSignerAddress: params.safeWebAuthnSharedSignerAddress } : {}
|
|
203
|
+
});
|
|
204
|
+
return baseAccount;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// src/accounts/toSafeSmartAccount.ts
|
|
208
|
+
var SAFE_4337_MODULE_DEFAULT4 = "0x75cf11467937ce3F2f357CE24ffc3DBF8fD5c226";
|
|
209
|
+
var ENTRYPOINT_V07_ADDRESS3 = "0x0000000071727De22E5E9d8BAf0edAc6f37da032";
|
|
210
|
+
var SAFE_WEBAUTHN_SHARED_SIGNER = "0xfD90FAd33ee8b58f32c00aceEad1358e4AFC23f9";
|
|
211
|
+
async function toSafeSmartAccount3(params) {
|
|
212
|
+
const { signerConfig } = params;
|
|
213
|
+
switch (signerConfig.type) {
|
|
214
|
+
case "p256":
|
|
215
|
+
return toP256SafeSmartAccount({
|
|
216
|
+
client: params.client,
|
|
217
|
+
p256Signer: signerConfig.p256Signer,
|
|
218
|
+
safeAddress: params.safeAddress,
|
|
219
|
+
entryPoint: params.entryPoint,
|
|
220
|
+
safe4337ModuleAddress: params.safe4337ModuleAddress
|
|
221
|
+
});
|
|
222
|
+
case "webauthn":
|
|
223
|
+
return toWebAuthnSafeSmartAccount({
|
|
224
|
+
client: params.client,
|
|
225
|
+
webAuthnAccount: signerConfig.webAuthnAccount,
|
|
226
|
+
safeAddress: params.safeAddress,
|
|
227
|
+
entryPoint: params.entryPoint,
|
|
228
|
+
safe4337ModuleAddress: params.safe4337ModuleAddress,
|
|
229
|
+
safeWebAuthnSharedSignerAddress: signerConfig.safeWebAuthnSharedSignerAddress
|
|
230
|
+
});
|
|
231
|
+
case "multi":
|
|
232
|
+
return buildMultiSignerAccount(params, signerConfig.signers, signerConfig.threshold ?? 1);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
function createMockLocalAccount2(address) {
|
|
236
|
+
const notImplemented = () => {
|
|
237
|
+
throw new Error("Mock owner: use signUserOperation instead");
|
|
238
|
+
};
|
|
239
|
+
return {
|
|
240
|
+
address,
|
|
241
|
+
type: "local",
|
|
242
|
+
source: "custom",
|
|
243
|
+
publicKey: "0x",
|
|
244
|
+
signMessage: notImplemented,
|
|
245
|
+
signTypedData: notImplemented,
|
|
246
|
+
signTransaction: notImplemented,
|
|
247
|
+
sign: notImplemented
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
async function encodeWebAuthnSignature(owner, hash) {
|
|
251
|
+
const { signature: signatureData, webauthn } = await owner.sign({ hash });
|
|
252
|
+
const sigBytes = signatureData.slice(2);
|
|
253
|
+
const r = BigInt("0x" + sigBytes.slice(0, 64));
|
|
254
|
+
const s = BigInt("0x" + sigBytes.slice(64, 128));
|
|
255
|
+
const match = webauthn.clientDataJSON.match(
|
|
256
|
+
/^\{"type":"webauthn.get","challenge":"[A-Za-z0-9\-_]{43}",(.*)\}$/
|
|
257
|
+
);
|
|
258
|
+
const clientDataFields = match ? match[1] : "";
|
|
259
|
+
return (0, import_viem4.encodeAbiParameters)(
|
|
260
|
+
[
|
|
261
|
+
{ name: "authenticatorData", type: "bytes" },
|
|
262
|
+
{ name: "clientDataFields", type: "string" },
|
|
263
|
+
{ name: "signature", type: "uint256[2]" }
|
|
264
|
+
],
|
|
265
|
+
[webauthn.authenticatorData, clientDataFields, [r, s]]
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
async function buildMultiSignerAccount(params, signers, threshold) {
|
|
269
|
+
if (!signers.p256 && !signers.webAuthn) {
|
|
270
|
+
throw new Error("Multi-signer config requires at least one signer");
|
|
271
|
+
}
|
|
272
|
+
if (signers.p256 && !signers.webAuthn) {
|
|
273
|
+
return toP256SafeSmartAccount({
|
|
274
|
+
client: params.client,
|
|
275
|
+
p256Signer: signers.p256,
|
|
276
|
+
safeAddress: params.safeAddress,
|
|
277
|
+
entryPoint: params.entryPoint,
|
|
278
|
+
safe4337ModuleAddress: params.safe4337ModuleAddress
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
if (signers.webAuthn && !signers.p256) {
|
|
282
|
+
const signerConfig = params.signerConfig;
|
|
283
|
+
const sharedSignerAddr = signerConfig.type === "multi" ? signerConfig.safeWebAuthnSharedSignerAddress : void 0;
|
|
284
|
+
return toWebAuthnSafeSmartAccount({
|
|
285
|
+
client: params.client,
|
|
286
|
+
webAuthnAccount: signers.webAuthn,
|
|
287
|
+
safeAddress: params.safeAddress,
|
|
288
|
+
entryPoint: params.entryPoint,
|
|
289
|
+
safe4337ModuleAddress: params.safe4337ModuleAddress,
|
|
290
|
+
safeWebAuthnSharedSignerAddress: sharedSignerAddr
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
const p256Signer = signers.p256;
|
|
294
|
+
const webAuthnAccount = signers.webAuthn;
|
|
295
|
+
const safe4337ModuleAddress = params.safe4337ModuleAddress ?? SAFE_4337_MODULE_DEFAULT4;
|
|
296
|
+
const entryPointAddress = params.entryPoint?.address ?? ENTRYPOINT_V07_ADDRESS3;
|
|
297
|
+
const mockP256Owner = createMockLocalAccount2(p256Signer.p256OwnerAddress);
|
|
298
|
+
const baseAccount = await (0, import_accounts3.toSafeSmartAccount)({
|
|
299
|
+
client: params.client,
|
|
300
|
+
owners: [mockP256Owner, webAuthnAccount],
|
|
301
|
+
version: "1.5.0",
|
|
302
|
+
threshold: BigInt(threshold),
|
|
303
|
+
...params.safeAddress ? { address: params.safeAddress } : {},
|
|
304
|
+
entryPoint: {
|
|
305
|
+
address: entryPointAddress,
|
|
306
|
+
version: "0.7"
|
|
307
|
+
},
|
|
308
|
+
safe4337ModuleAddress
|
|
309
|
+
});
|
|
310
|
+
const chainId = await params.client.getChainId();
|
|
311
|
+
if (threshold >= 2) {
|
|
312
|
+
return buildThreshold2Account(
|
|
313
|
+
baseAccount,
|
|
314
|
+
p256Signer,
|
|
315
|
+
webAuthnAccount,
|
|
316
|
+
chainId,
|
|
317
|
+
safe4337ModuleAddress,
|
|
318
|
+
entryPointAddress
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
return buildThreshold1Account(
|
|
322
|
+
baseAccount,
|
|
323
|
+
p256Signer,
|
|
324
|
+
chainId,
|
|
325
|
+
safe4337ModuleAddress,
|
|
326
|
+
entryPointAddress
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
function buildThreshold1Account(baseAccount, p256Signer, chainId, safe4337ModuleAddress, entryPointAddress) {
|
|
330
|
+
return {
|
|
331
|
+
...baseAccount,
|
|
332
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
333
|
+
async signUserOperation(userOp) {
|
|
334
|
+
const safeOpHash = computeSafeOpHash(
|
|
335
|
+
extractSafeOpHashParams(userOp),
|
|
336
|
+
chainId,
|
|
337
|
+
safe4337ModuleAddress,
|
|
338
|
+
entryPointAddress
|
|
339
|
+
);
|
|
340
|
+
const { r, s } = await p256Signer.sign(safeOpHash);
|
|
341
|
+
const rPadded = (0, import_viem4.pad)(r, { size: 32 });
|
|
342
|
+
const sPadded = (0, import_viem4.pad)(s, { size: 32 });
|
|
343
|
+
const p256Signature = (0, import_viem4.concat)([rPadded, sPadded]);
|
|
344
|
+
const contractSig = encodeContractSignature(
|
|
345
|
+
p256Signer.p256OwnerAddress,
|
|
346
|
+
p256Signature
|
|
347
|
+
);
|
|
348
|
+
const validAfter = (0, import_viem4.pad)((0, import_viem4.toHex)(0), { size: 6 });
|
|
349
|
+
const validUntil = (0, import_viem4.pad)((0, import_viem4.toHex)(0), { size: 6 });
|
|
350
|
+
return (0, import_viem4.concat)([validAfter, validUntil, contractSig]);
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
function buildThreshold2Account(baseAccount, p256Signer, webAuthnAccount, chainId, safe4337ModuleAddress, entryPointAddress) {
|
|
355
|
+
return {
|
|
356
|
+
...baseAccount,
|
|
357
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
358
|
+
async signUserOperation(userOp) {
|
|
359
|
+
const safeOpHash = computeSafeOpHash(
|
|
360
|
+
extractSafeOpHashParams(userOp),
|
|
361
|
+
chainId,
|
|
362
|
+
safe4337ModuleAddress,
|
|
363
|
+
entryPointAddress
|
|
364
|
+
);
|
|
365
|
+
const { r, s } = await p256Signer.sign(safeOpHash);
|
|
366
|
+
const rPadded = (0, import_viem4.pad)(r, { size: 32 });
|
|
367
|
+
const sPadded = (0, import_viem4.pad)(s, { size: 32 });
|
|
368
|
+
const p256SignatureData = (0, import_viem4.concat)([rPadded, sPadded]);
|
|
369
|
+
const webAuthnSignatureData = await encodeWebAuthnSignature(
|
|
370
|
+
webAuthnAccount,
|
|
371
|
+
safeOpHash
|
|
372
|
+
);
|
|
373
|
+
const p256SignerAddress = p256Signer.p256OwnerAddress.toLowerCase();
|
|
374
|
+
const webAuthnSignerAddress = SAFE_WEBAUTHN_SHARED_SIGNER.toLowerCase();
|
|
375
|
+
const signerEntries = [
|
|
376
|
+
{
|
|
377
|
+
address: p256SignerAddress,
|
|
378
|
+
data: p256SignatureData,
|
|
379
|
+
dynamic: true,
|
|
380
|
+
contractOwner: true
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
address: webAuthnSignerAddress,
|
|
384
|
+
data: webAuthnSignatureData,
|
|
385
|
+
dynamic: true,
|
|
386
|
+
contractOwner: false
|
|
387
|
+
}
|
|
388
|
+
].sort((a, b) => a.address < b.address ? -1 : 1);
|
|
389
|
+
const concatenatedSig = concatSafeSignatures(signerEntries);
|
|
390
|
+
const validAfter = (0, import_viem4.pad)((0, import_viem4.toHex)(0), { size: 6 });
|
|
391
|
+
const validUntil = (0, import_viem4.pad)((0, import_viem4.toHex)(0), { size: 6 });
|
|
392
|
+
return (0, import_viem4.concat)([validAfter, validUntil, concatenatedSig]);
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
function concatSafeSignatures(entries) {
|
|
397
|
+
const staticPartSize = 65;
|
|
398
|
+
const totalStaticSize = staticPartSize * entries.length;
|
|
399
|
+
const staticParts = [];
|
|
400
|
+
const dynamicParts = [];
|
|
401
|
+
let dynamicOffset = totalStaticSize;
|
|
402
|
+
for (const entry of entries) {
|
|
403
|
+
if (entry.dynamic) {
|
|
404
|
+
const r = (0, import_viem4.pad)(entry.address, { size: 32 });
|
|
405
|
+
const s = (0, import_viem4.pad)((0, import_viem4.toHex)(dynamicOffset), { size: 32 });
|
|
406
|
+
const v = "0x00";
|
|
407
|
+
staticParts.push((0, import_viem4.concat)([r, s, v]));
|
|
408
|
+
const dataBytes = (entry.data.length - 2) / 2;
|
|
409
|
+
const length = (0, import_viem4.pad)((0, import_viem4.toHex)(dataBytes), { size: 32 });
|
|
410
|
+
dynamicParts.push((0, import_viem4.concat)([length, entry.data]));
|
|
411
|
+
dynamicOffset += 32 + dataBytes;
|
|
412
|
+
} else {
|
|
413
|
+
staticParts.push(entry.data);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
return (0, import_viem4.concat)([...staticParts, ...dynamicParts]);
|
|
417
|
+
}
|
|
418
|
+
function extractSafeOpHashParams(userOp) {
|
|
419
|
+
const op = userOp;
|
|
420
|
+
return {
|
|
421
|
+
sender: op.sender,
|
|
422
|
+
nonce: BigInt(op.nonce),
|
|
423
|
+
factory: op.factory ?? null,
|
|
424
|
+
factoryData: op.factoryData ?? null,
|
|
425
|
+
callData: op.callData,
|
|
426
|
+
verificationGasLimit: BigInt(op.verificationGasLimit),
|
|
427
|
+
callGasLimit: BigInt(op.callGasLimit),
|
|
428
|
+
preVerificationGas: BigInt(op.preVerificationGas),
|
|
429
|
+
maxPriorityFeePerGas: BigInt(op.maxPriorityFeePerGas),
|
|
430
|
+
maxFeePerGas: BigInt(op.maxFeePerGas),
|
|
431
|
+
paymaster: op.paymaster ?? null,
|
|
432
|
+
paymasterVerificationGasLimit: op.paymasterVerificationGasLimit ? BigInt(op.paymasterVerificationGasLimit) : null,
|
|
433
|
+
paymasterPostOpGasLimit: op.paymasterPostOpGasLimit ? BigInt(op.paymasterPostOpGasLimit) : null,
|
|
434
|
+
paymasterData: op.paymasterData ?? null
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// src/accounts/extractPasskeyCoordinates.ts
|
|
439
|
+
function bufferToHex(buffer) {
|
|
440
|
+
return Array.from(new Uint8Array(buffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
441
|
+
}
|
|
442
|
+
function base64urlToHex(base64url) {
|
|
443
|
+
const base64 = base64url.replace(/-/g, "+").replace(/_/g, "/");
|
|
444
|
+
const binary = atob(base64);
|
|
445
|
+
return Array.from(binary, (c) => c.charCodeAt(0).toString(16).padStart(2, "0")).join("");
|
|
446
|
+
}
|
|
447
|
+
async function extractPasskeyCoordinates(credential) {
|
|
448
|
+
const rawId = bufferToHex(credential.rawId);
|
|
449
|
+
const response = credential.response;
|
|
450
|
+
const publicKey = response.getPublicKey();
|
|
451
|
+
if (!publicKey) throw new Error("Failed to extract public key from credential");
|
|
452
|
+
const key = await crypto.subtle.importKey(
|
|
453
|
+
"spki",
|
|
454
|
+
publicKey,
|
|
455
|
+
{ name: "ECDSA", namedCurve: "P-256" },
|
|
456
|
+
true,
|
|
457
|
+
["verify"]
|
|
458
|
+
);
|
|
459
|
+
const jwk = await crypto.subtle.exportKey("jwk", key);
|
|
460
|
+
if (!jwk.x || !jwk.y) throw new Error("Missing coordinates in JWK");
|
|
461
|
+
return {
|
|
462
|
+
rawId,
|
|
463
|
+
x: "0x" + base64urlToHex(jwk.x),
|
|
464
|
+
y: "0x" + base64urlToHex(jwk.y)
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
468
|
+
0 && (module.exports = {
|
|
469
|
+
computeSafeOpHash,
|
|
470
|
+
encodeContractSignature,
|
|
471
|
+
extractPasskeyCoordinates,
|
|
472
|
+
toP256SafeSmartAccount,
|
|
473
|
+
toSafeSmartAccount,
|
|
474
|
+
toWebAuthnSafeSmartAccount
|
|
475
|
+
});
|
|
476
|
+
//# sourceMappingURL=index.js.map
|