@0xsequence/wallet-wdk 3.0.0-beta.9 → 3.0.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/.turbo/turbo-build.log +2 -2
- package/.turbo/turbo-lint.log +4 -0
- package/.turbo/turbo-typecheck.log +4 -0
- package/CHANGELOG.md +170 -0
- package/dist/dbs/auth-commitments.d.ts.map +1 -1
- package/dist/dbs/auth-keys.d.ts +3 -1
- package/dist/dbs/auth-keys.d.ts.map +1 -1
- package/dist/dbs/auth-keys.js +16 -4
- package/dist/dbs/messages.d.ts.map +1 -1
- package/dist/dbs/passkey-credentials.d.ts.map +1 -1
- package/dist/dbs/recovery.d.ts.map +1 -1
- package/dist/dbs/signatures.d.ts.map +1 -1
- package/dist/dbs/transactions.d.ts.map +1 -1
- package/dist/dbs/wallets.d.ts.map +1 -1
- package/dist/env.d.ts +22 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +30 -0
- package/dist/identity/signer.d.ts +5 -4
- package/dist/identity/signer.d.ts.map +1 -1
- package/dist/identity/signer.js +11 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/sequence/cron.d.ts +3 -0
- package/dist/sequence/cron.d.ts.map +1 -1
- package/dist/sequence/cron.js +72 -39
- package/dist/sequence/handlers/authcode-pkce.d.ts +2 -1
- package/dist/sequence/handlers/authcode-pkce.d.ts.map +1 -1
- package/dist/sequence/handlers/authcode-pkce.js +4 -4
- package/dist/sequence/handlers/authcode.d.ts +4 -1
- package/dist/sequence/handlers/authcode.d.ts.map +1 -1
- package/dist/sequence/handlers/authcode.js +23 -6
- package/dist/sequence/handlers/devices.d.ts +1 -1
- package/dist/sequence/handlers/devices.d.ts.map +1 -1
- package/dist/sequence/handlers/devices.js +1 -1
- package/dist/sequence/handlers/guard.d.ts +1 -1
- package/dist/sequence/handlers/guard.d.ts.map +1 -1
- package/dist/sequence/handlers/guard.js +22 -19
- package/dist/sequence/handlers/identity.d.ts +3 -1
- package/dist/sequence/handlers/identity.d.ts.map +1 -1
- package/dist/sequence/handlers/identity.js +14 -7
- package/dist/sequence/handlers/mnemonic.d.ts.map +1 -1
- package/dist/sequence/handlers/mnemonic.js +21 -18
- package/dist/sequence/handlers/otp.d.ts +2 -1
- package/dist/sequence/handlers/otp.d.ts.map +1 -1
- package/dist/sequence/handlers/otp.js +4 -3
- package/dist/sequence/handlers/passkeys.d.ts +6 -4
- package/dist/sequence/handlers/passkeys.d.ts.map +1 -1
- package/dist/sequence/handlers/passkeys.js +8 -5
- package/dist/sequence/handlers/recovery.js +1 -1
- package/dist/sequence/index.d.ts +2 -0
- package/dist/sequence/index.d.ts.map +1 -1
- package/dist/sequence/index.js +1 -0
- package/dist/sequence/manager.d.ts +67 -55
- package/dist/sequence/manager.d.ts.map +1 -1
- package/dist/sequence/manager.js +77 -17
- package/dist/sequence/messages.js +1 -1
- package/dist/sequence/passkeys-provider.d.ts +24 -0
- package/dist/sequence/passkeys-provider.d.ts.map +1 -0
- package/dist/sequence/passkeys-provider.js +15 -0
- package/dist/sequence/recovery.d.ts +2 -0
- package/dist/sequence/recovery.d.ts.map +1 -1
- package/dist/sequence/recovery.js +100 -34
- package/dist/sequence/signers.d.ts.map +1 -1
- package/dist/sequence/signers.js +3 -1
- package/dist/sequence/transactions.d.ts.map +1 -1
- package/dist/sequence/transactions.js +5 -2
- package/dist/sequence/wallets.d.ts +2 -1
- package/dist/sequence/wallets.d.ts.map +1 -1
- package/dist/sequence/wallets.js +32 -22
- package/eslint.config.js +12 -0
- package/package.json +16 -14
- package/src/dbs/auth-commitments.ts +1 -1
- package/src/dbs/auth-keys.ts +20 -6
- package/src/dbs/messages.ts +1 -1
- package/src/dbs/passkey-credentials.ts +1 -1
- package/src/dbs/recovery.ts +1 -1
- package/src/dbs/signatures.ts +1 -1
- package/src/dbs/transactions.ts +1 -1
- package/src/dbs/wallets.ts +1 -1
- package/src/env.ts +58 -0
- package/src/identity/signer.ts +13 -7
- package/src/index.ts +1 -0
- package/src/sequence/cron.ts +75 -42
- package/src/sequence/handlers/authcode-pkce.ts +6 -4
- package/src/sequence/handlers/authcode.ts +26 -5
- package/src/sequence/handlers/devices.ts +1 -1
- package/src/sequence/handlers/guard.ts +6 -4
- package/src/sequence/handlers/identity.ts +18 -8
- package/src/sequence/handlers/mnemonic.ts +5 -3
- package/src/sequence/handlers/otp.ts +5 -3
- package/src/sequence/handlers/passkeys.ts +13 -13
- package/src/sequence/handlers/recovery.ts +1 -1
- package/src/sequence/index.ts +2 -0
- package/src/sequence/manager.ts +168 -14
- package/src/sequence/messages.ts +1 -1
- package/src/sequence/passkeys-provider.ts +55 -0
- package/src/sequence/recovery.ts +165 -56
- package/src/sequence/signers.ts +3 -1
- package/src/sequence/transactions.ts +6 -2
- package/src/sequence/wallets.ts +39 -25
- package/test/authcode-pkce.test.ts +2 -3
- package/test/authcode.test.ts +6 -8
- package/test/constants.ts +4 -2
- package/test/guard.test.ts +5 -5
- package/test/identity-signer.test.ts +1 -1
- package/test/otp.test.ts +1 -1
- package/test/passkeys.test.ts +1 -1
- package/test/recovery.test.ts +3 -3
- package/test/sessions.test.ts +1 -1
- package/test/{test-ssr-safety.mjs → test-ssr-safety.js} +143 -137
- package/test/transactions.test.ts +3 -3
- package/test/wallets.test.ts +5 -5
package/src/sequence/manager.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { createAttestationVerifyingFetch } from '@0xsequence/tee-verifier'
|
|
|
5
5
|
import { Config, Constants, Context, Extensions, Network } from '@0xsequence/wallet-primitives'
|
|
6
6
|
import { Address } from 'ox'
|
|
7
7
|
import * as Db from '../dbs/index.js'
|
|
8
|
+
import { resolveWdkEnv, type WdkEnv } from '../env.js'
|
|
8
9
|
import { Cron } from './cron.js'
|
|
9
10
|
import { Devices } from './devices.js'
|
|
10
11
|
import { Guards, GuardRole } from './guards.js'
|
|
@@ -31,6 +32,7 @@ import { GuardHandler, PromptCodeHandler } from './handlers/guard.js'
|
|
|
31
32
|
import { PasskeyCredential } from '../dbs/index.js'
|
|
32
33
|
import { PromptMnemonicHandler } from './handlers/mnemonic.js'
|
|
33
34
|
import { PromptOtpHandler } from './handlers/otp.js'
|
|
35
|
+
import { defaultPasskeyProvider, type PasskeyProvider } from './passkeys-provider.js'
|
|
34
36
|
|
|
35
37
|
export type ManagerOptions = {
|
|
36
38
|
verbose?: boolean
|
|
@@ -52,6 +54,9 @@ export type ManagerOptions = {
|
|
|
52
54
|
|
|
53
55
|
dbPruningInterval?: number
|
|
54
56
|
|
|
57
|
+
env?: WdkEnv
|
|
58
|
+
passkeyProvider?: PasskeyProvider
|
|
59
|
+
|
|
55
60
|
stateProvider?: State.Provider
|
|
56
61
|
networks?: Network.Network[]
|
|
57
62
|
relayers?: Relayer.Relayer[] | (() => Relayer.Relayer[])
|
|
@@ -70,7 +75,7 @@ export type ManagerOptions = {
|
|
|
70
75
|
|
|
71
76
|
identity?: {
|
|
72
77
|
url?: string
|
|
73
|
-
fetch?: typeof
|
|
78
|
+
fetch?: typeof fetch
|
|
74
79
|
verifyAttestation?: boolean
|
|
75
80
|
expectedPcr0?: string[]
|
|
76
81
|
scope?: string
|
|
@@ -95,6 +100,72 @@ export type ManagerOptions = {
|
|
|
95
100
|
}
|
|
96
101
|
}
|
|
97
102
|
|
|
103
|
+
export type ResolvedIdentityOptions = {
|
|
104
|
+
url: string
|
|
105
|
+
fetch?: typeof fetch
|
|
106
|
+
verifyAttestation: boolean
|
|
107
|
+
expectedPcr0?: string[]
|
|
108
|
+
scope?: string
|
|
109
|
+
email: {
|
|
110
|
+
enabled: boolean
|
|
111
|
+
}
|
|
112
|
+
google: {
|
|
113
|
+
enabled: boolean
|
|
114
|
+
clientId: string
|
|
115
|
+
}
|
|
116
|
+
apple: {
|
|
117
|
+
enabled: boolean
|
|
118
|
+
clientId: string
|
|
119
|
+
}
|
|
120
|
+
customProviders?: {
|
|
121
|
+
kind: `custom-${string}`
|
|
122
|
+
authMethod: 'id-token' | 'authcode' | 'authcode-pkce'
|
|
123
|
+
issuer: string
|
|
124
|
+
oauthUrl: string
|
|
125
|
+
clientId: string
|
|
126
|
+
}[]
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export type ResolvedManagerOptions = {
|
|
130
|
+
verbose: boolean
|
|
131
|
+
|
|
132
|
+
extensions: Extensions.Extensions
|
|
133
|
+
context: Context.Context
|
|
134
|
+
context4337: Context.Context
|
|
135
|
+
guest: Address.Address
|
|
136
|
+
|
|
137
|
+
encryptedPksDb: CoreSigners.Pk.Encrypted.EncryptedPksDb
|
|
138
|
+
managerDb: Db.Wallets
|
|
139
|
+
transactionsDb: Db.Transactions
|
|
140
|
+
signaturesDb: Db.Signatures
|
|
141
|
+
messagesDb: Db.Messages
|
|
142
|
+
authCommitmentsDb: Db.AuthCommitments
|
|
143
|
+
authKeysDb: Db.AuthKeys
|
|
144
|
+
recoveryDb: Db.Recovery
|
|
145
|
+
passkeyCredentialsDb: Db.PasskeyCredentials
|
|
146
|
+
|
|
147
|
+
dbPruningInterval: number
|
|
148
|
+
|
|
149
|
+
env: WdkEnv
|
|
150
|
+
passkeyProvider: PasskeyProvider
|
|
151
|
+
|
|
152
|
+
stateProvider: State.Provider
|
|
153
|
+
networks: Network.Network[]
|
|
154
|
+
relayers: Relayer.Relayer[] | (() => Relayer.Relayer[])
|
|
155
|
+
bundlers: Bundler.Bundler[]
|
|
156
|
+
guardUrl: string
|
|
157
|
+
guardAddresses: Record<GuardRole, Address.Address>
|
|
158
|
+
|
|
159
|
+
nonWitnessableSigners: Address.Address[]
|
|
160
|
+
|
|
161
|
+
defaultGuardTopology: Config.Topology
|
|
162
|
+
defaultRecoverySettings: RecoverySettings
|
|
163
|
+
|
|
164
|
+
multiInjectedProviderDiscovery: boolean
|
|
165
|
+
|
|
166
|
+
identity: ResolvedIdentityOptions
|
|
167
|
+
}
|
|
168
|
+
|
|
98
169
|
export const ManagerOptionsDefaults = {
|
|
99
170
|
verbose: false,
|
|
100
171
|
|
|
@@ -115,7 +186,9 @@ export const ManagerOptionsDefaults = {
|
|
|
115
186
|
|
|
116
187
|
dbPruningInterval: 1000 * 60 * 60 * 24, // 24 hours
|
|
117
188
|
|
|
118
|
-
|
|
189
|
+
passkeyProvider: defaultPasskeyProvider,
|
|
190
|
+
|
|
191
|
+
stateProvider: typeof fetch !== 'undefined' ? new State.Sequence.Provider(undefined, fetch) : undefined,
|
|
119
192
|
networks: Network.ALL,
|
|
120
193
|
relayers: () => {
|
|
121
194
|
if (typeof window !== 'undefined') {
|
|
@@ -160,6 +233,7 @@ export const ManagerOptionsDefaults = {
|
|
|
160
233
|
defaultRecoverySettings: {
|
|
161
234
|
requiredDeltaTime: 2592000n, // 30 days (in seconds)
|
|
162
235
|
minTimestamp: 0n,
|
|
236
|
+
includeTestnets: false,
|
|
163
237
|
},
|
|
164
238
|
|
|
165
239
|
multiInjectedProviderDiscovery: true,
|
|
@@ -186,13 +260,45 @@ export const CreateWalletOptionsDefaults = {
|
|
|
186
260
|
useGuard: false,
|
|
187
261
|
}
|
|
188
262
|
|
|
189
|
-
export function applyManagerOptionsDefaults(options?: ManagerOptions) {
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
263
|
+
export function applyManagerOptionsDefaults(options?: ManagerOptions): ResolvedManagerOptions {
|
|
264
|
+
const env = resolveWdkEnv(options?.env)
|
|
265
|
+
|
|
266
|
+
const identity: ResolvedIdentityOptions = {
|
|
267
|
+
...ManagerOptionsDefaults.identity,
|
|
268
|
+
...options?.identity,
|
|
269
|
+
email: { ...ManagerOptionsDefaults.identity.email, ...options?.identity?.email },
|
|
270
|
+
google: { ...ManagerOptionsDefaults.identity.google, ...options?.identity?.google },
|
|
271
|
+
apple: { ...ManagerOptionsDefaults.identity.apple, ...options?.identity?.apple },
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (!identity.fetch && env.fetch) {
|
|
275
|
+
identity.fetch = env.fetch
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
let encryptedPksDb = options?.encryptedPksDb ?? ManagerOptionsDefaults.encryptedPksDb
|
|
279
|
+
if (!options?.encryptedPksDb && options?.env) {
|
|
280
|
+
encryptedPksDb = new CoreSigners.Pk.Encrypted.EncryptedPksDb(undefined, undefined, env)
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
let authKeysDb = options?.authKeysDb ?? ManagerOptionsDefaults.authKeysDb
|
|
284
|
+
if (!options?.authKeysDb && options?.env) {
|
|
285
|
+
authKeysDb = new Db.AuthKeys(undefined, env)
|
|
194
286
|
}
|
|
195
287
|
|
|
288
|
+
let stateProvider = options?.stateProvider ?? ManagerOptionsDefaults.stateProvider
|
|
289
|
+
if (!options?.stateProvider && options?.env?.fetch) {
|
|
290
|
+
stateProvider = new State.Sequence.Provider(undefined, options.env.fetch)
|
|
291
|
+
} else if (!stateProvider && env.fetch) {
|
|
292
|
+
stateProvider = new State.Sequence.Provider(undefined, env.fetch)
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (!stateProvider) {
|
|
296
|
+
throw new Error('stateProvider is required. Provide ManagerOptions.stateProvider or env.fetch')
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const extensions = options?.extensions ?? ManagerOptionsDefaults.extensions
|
|
300
|
+
const defaultGuardTopology = options?.defaultGuardTopology ?? ManagerOptionsDefaults.defaultGuardTopology
|
|
301
|
+
|
|
196
302
|
// Merge and normalize non-witnessable signers.
|
|
197
303
|
// We always include the sessions extension address for the active extensions set.
|
|
198
304
|
const nonWitnessable = new Set<string>()
|
|
@@ -202,12 +308,12 @@ export function applyManagerOptionsDefaults(options?: ManagerOptions) {
|
|
|
202
308
|
for (const address of options?.nonWitnessableSigners ?? []) {
|
|
203
309
|
nonWitnessable.add(address.toLowerCase())
|
|
204
310
|
}
|
|
205
|
-
nonWitnessable.add(
|
|
311
|
+
nonWitnessable.add(extensions.sessions.toLowerCase())
|
|
206
312
|
|
|
207
313
|
// Include static signer leaves from the guard topology (e.g. recovery guard signer),
|
|
208
314
|
// but ignore the placeholder address that is later replaced per-role.
|
|
209
|
-
if (
|
|
210
|
-
const guardTopologySigners = Config.getSigners(
|
|
315
|
+
if (defaultGuardTopology) {
|
|
316
|
+
const guardTopologySigners = Config.getSigners(defaultGuardTopology)
|
|
211
317
|
for (const signer of guardTopologySigners.signers) {
|
|
212
318
|
if (Address.isEqual(signer, Constants.PlaceholderAddress)) {
|
|
213
319
|
continue
|
|
@@ -219,14 +325,52 @@ export function applyManagerOptionsDefaults(options?: ManagerOptions) {
|
|
|
219
325
|
}
|
|
220
326
|
}
|
|
221
327
|
|
|
222
|
-
|
|
328
|
+
return {
|
|
329
|
+
verbose: options?.verbose ?? ManagerOptionsDefaults.verbose,
|
|
223
330
|
|
|
224
|
-
|
|
331
|
+
extensions,
|
|
332
|
+
context: options?.context ?? ManagerOptionsDefaults.context,
|
|
333
|
+
context4337: options?.context4337 ?? ManagerOptionsDefaults.context4337,
|
|
334
|
+
guest: options?.guest ?? ManagerOptionsDefaults.guest,
|
|
335
|
+
|
|
336
|
+
encryptedPksDb,
|
|
337
|
+
managerDb: options?.managerDb ?? ManagerOptionsDefaults.managerDb,
|
|
338
|
+
transactionsDb: options?.transactionsDb ?? ManagerOptionsDefaults.transactionsDb,
|
|
339
|
+
signaturesDb: options?.signaturesDb ?? ManagerOptionsDefaults.signaturesDb,
|
|
340
|
+
messagesDb: options?.messagesDb ?? ManagerOptionsDefaults.messagesDb,
|
|
341
|
+
authCommitmentsDb: options?.authCommitmentsDb ?? ManagerOptionsDefaults.authCommitmentsDb,
|
|
342
|
+
recoveryDb: options?.recoveryDb ?? ManagerOptionsDefaults.recoveryDb,
|
|
343
|
+
authKeysDb,
|
|
344
|
+
passkeyCredentialsDb: options?.passkeyCredentialsDb ?? ManagerOptionsDefaults.passkeyCredentialsDb,
|
|
345
|
+
|
|
346
|
+
dbPruningInterval: options?.dbPruningInterval ?? ManagerOptionsDefaults.dbPruningInterval,
|
|
347
|
+
|
|
348
|
+
env,
|
|
349
|
+
passkeyProvider: options?.passkeyProvider ?? ManagerOptionsDefaults.passkeyProvider,
|
|
350
|
+
|
|
351
|
+
stateProvider,
|
|
352
|
+
networks: options?.networks ?? ManagerOptionsDefaults.networks,
|
|
353
|
+
relayers: options?.relayers ?? ManagerOptionsDefaults.relayers,
|
|
354
|
+
bundlers: options?.bundlers ?? ManagerOptionsDefaults.bundlers,
|
|
355
|
+
guardUrl: options?.guardUrl ?? ManagerOptionsDefaults.guardUrl,
|
|
356
|
+
guardAddresses: options?.guardAddresses ?? ManagerOptionsDefaults.guardAddresses,
|
|
357
|
+
|
|
358
|
+
nonWitnessableSigners: Array.from(nonWitnessable) as Address.Address[],
|
|
359
|
+
|
|
360
|
+
defaultGuardTopology,
|
|
361
|
+
defaultRecoverySettings: options?.defaultRecoverySettings ?? ManagerOptionsDefaults.defaultRecoverySettings,
|
|
362
|
+
|
|
363
|
+
multiInjectedProviderDiscovery:
|
|
364
|
+
options?.multiInjectedProviderDiscovery ?? ManagerOptionsDefaults.multiInjectedProviderDiscovery,
|
|
365
|
+
|
|
366
|
+
identity,
|
|
367
|
+
}
|
|
225
368
|
}
|
|
226
369
|
|
|
227
370
|
export type RecoverySettings = {
|
|
228
371
|
requiredDeltaTime: bigint
|
|
229
372
|
minTimestamp: bigint
|
|
373
|
+
includeTestnets?: boolean
|
|
230
374
|
}
|
|
231
375
|
|
|
232
376
|
export type Databases = {
|
|
@@ -283,6 +427,8 @@ export type Shared = {
|
|
|
283
427
|
|
|
284
428
|
readonly sequence: Sequence
|
|
285
429
|
readonly databases: Databases
|
|
430
|
+
readonly env: WdkEnv
|
|
431
|
+
readonly passkeyProvider: PasskeyProvider
|
|
286
432
|
|
|
287
433
|
readonly handlers: Map<string, Handler>
|
|
288
434
|
|
|
@@ -415,7 +561,7 @@ export class Manager {
|
|
|
415
561
|
const ops = applyManagerOptionsDefaults(options)
|
|
416
562
|
|
|
417
563
|
// Build relayers list
|
|
418
|
-
|
|
564
|
+
const relayers: Relayer.Relayer[] = []
|
|
419
565
|
|
|
420
566
|
// Add EIP-6963 relayers if enabled
|
|
421
567
|
if (ops.multiInjectedProviderDiscovery) {
|
|
@@ -469,6 +615,9 @@ export class Manager {
|
|
|
469
615
|
pruningInterval: ops.dbPruningInterval,
|
|
470
616
|
},
|
|
471
617
|
|
|
618
|
+
env: ops.env,
|
|
619
|
+
passkeyProvider: ops.passkeyProvider,
|
|
620
|
+
|
|
472
621
|
modules: {} as any,
|
|
473
622
|
handlers: new Map(),
|
|
474
623
|
}
|
|
@@ -501,6 +650,7 @@ export class Manager {
|
|
|
501
650
|
modules.signatures,
|
|
502
651
|
shared.sequence.extensions,
|
|
503
652
|
shared.sequence.stateProvider,
|
|
653
|
+
shared.passkeyProvider,
|
|
504
654
|
)
|
|
505
655
|
shared.handlers.set(Kinds.LoginPasskey, this.passkeysHandler)
|
|
506
656
|
|
|
@@ -523,7 +673,7 @@ export class Manager {
|
|
|
523
673
|
const identityInstrument = new IdentityInstrument(ops.identity.url, ops.identity.scope, verifyingFetch)
|
|
524
674
|
|
|
525
675
|
if (ops.identity.email?.enabled) {
|
|
526
|
-
this.otpHandler = new OtpHandler(identityInstrument, modules.signatures, shared.databases.authKeys)
|
|
676
|
+
this.otpHandler = new OtpHandler(identityInstrument, modules.signatures, shared.databases.authKeys, shared.env)
|
|
527
677
|
shared.handlers.set(Kinds.LoginEmailOtp, this.otpHandler)
|
|
528
678
|
}
|
|
529
679
|
if (ops.identity.google?.enabled) {
|
|
@@ -538,6 +688,7 @@ export class Manager {
|
|
|
538
688
|
modules.signatures,
|
|
539
689
|
shared.databases.authCommitments,
|
|
540
690
|
shared.databases.authKeys,
|
|
691
|
+
shared.env,
|
|
541
692
|
),
|
|
542
693
|
)
|
|
543
694
|
}
|
|
@@ -553,6 +704,7 @@ export class Manager {
|
|
|
553
704
|
modules.signatures,
|
|
554
705
|
shared.databases.authCommitments,
|
|
555
706
|
shared.databases.authKeys,
|
|
707
|
+
shared.env,
|
|
556
708
|
),
|
|
557
709
|
)
|
|
558
710
|
}
|
|
@@ -573,6 +725,7 @@ export class Manager {
|
|
|
573
725
|
modules.signatures,
|
|
574
726
|
shared.databases.authCommitments,
|
|
575
727
|
shared.databases.authKeys,
|
|
728
|
+
shared.env,
|
|
576
729
|
),
|
|
577
730
|
)
|
|
578
731
|
break
|
|
@@ -588,6 +741,7 @@ export class Manager {
|
|
|
588
741
|
modules.signatures,
|
|
589
742
|
shared.databases.authCommitments,
|
|
590
743
|
shared.databases.authKeys,
|
|
744
|
+
shared.env,
|
|
591
745
|
),
|
|
592
746
|
)
|
|
593
747
|
break
|
package/src/sequence/messages.ts
CHANGED
|
@@ -242,7 +242,7 @@ export class Messages implements MessagesInterface {
|
|
|
242
242
|
const message = await this.getByMessageOrSignatureId(messageOrSignatureId)
|
|
243
243
|
await this.shared.databases.signatures.del(message.signatureId)
|
|
244
244
|
await this.shared.databases.messages.del(message.id)
|
|
245
|
-
} catch
|
|
245
|
+
} catch {
|
|
246
246
|
// Ignore
|
|
247
247
|
}
|
|
248
248
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Signers, State } from '@0xsequence/wallet-core'
|
|
2
|
+
import type { Extensions } from '@0xsequence/wallet-primitives'
|
|
3
|
+
import type { Address, Hex } from 'ox'
|
|
4
|
+
|
|
5
|
+
export type PasskeySigner = Signers.SapientSigner &
|
|
6
|
+
Signers.Witnessable & {
|
|
7
|
+
credentialId: string
|
|
8
|
+
publicKey: Extensions.Passkeys.PublicKey
|
|
9
|
+
imageHash: Hex.Hex
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type PasskeyProvider = {
|
|
13
|
+
create: (
|
|
14
|
+
extensions: Pick<Extensions.Extensions, 'passkeys'>,
|
|
15
|
+
options?: Signers.Passkey.CreatePasskeyOptions,
|
|
16
|
+
) => Promise<PasskeySigner>
|
|
17
|
+
find: (
|
|
18
|
+
stateReader: State.Reader,
|
|
19
|
+
extensions: Pick<Extensions.Extensions, 'passkeys'>,
|
|
20
|
+
options?: Signers.Passkey.FindPasskeyOptions,
|
|
21
|
+
) => Promise<PasskeySigner | undefined>
|
|
22
|
+
loadFromWitness: (
|
|
23
|
+
stateReader: State.Reader,
|
|
24
|
+
extensions: Pick<Extensions.Extensions, 'passkeys'>,
|
|
25
|
+
wallet: Address.Address,
|
|
26
|
+
imageHash: Hex.Hex,
|
|
27
|
+
options?: Signers.Passkey.FindPasskeyOptions,
|
|
28
|
+
) => Promise<PasskeySigner | undefined>
|
|
29
|
+
fromCredential: (args: {
|
|
30
|
+
credentialId: string
|
|
31
|
+
publicKey: Extensions.Passkeys.PublicKey
|
|
32
|
+
extensions: Pick<Extensions.Extensions, 'passkeys'>
|
|
33
|
+
embedMetadata?: boolean
|
|
34
|
+
metadata?: Extensions.Passkeys.PasskeyMetadata
|
|
35
|
+
webauthn?: Signers.Passkey.WebAuthnLike
|
|
36
|
+
}) => PasskeySigner
|
|
37
|
+
isSigner?: (signer: unknown) => signer is PasskeySigner
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const defaultPasskeyProvider: PasskeyProvider = {
|
|
41
|
+
create: (extensions, options) => Signers.Passkey.Passkey.create(extensions, options),
|
|
42
|
+
find: (stateReader, extensions, options) => Signers.Passkey.Passkey.find(stateReader, extensions, options),
|
|
43
|
+
loadFromWitness: (stateReader, extensions, wallet, imageHash, options) =>
|
|
44
|
+
Signers.Passkey.Passkey.loadFromWitness(stateReader, extensions, wallet, imageHash, options),
|
|
45
|
+
fromCredential: ({ credentialId, publicKey, extensions, embedMetadata, metadata, webauthn }) =>
|
|
46
|
+
new Signers.Passkey.Passkey({
|
|
47
|
+
credentialId,
|
|
48
|
+
publicKey,
|
|
49
|
+
extensions,
|
|
50
|
+
embedMetadata,
|
|
51
|
+
metadata,
|
|
52
|
+
webauthn,
|
|
53
|
+
}),
|
|
54
|
+
isSigner: (signer: unknown): signer is PasskeySigner => signer instanceof Signers.Passkey.Passkey,
|
|
55
|
+
}
|
package/src/sequence/recovery.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { Envelope } from '@0xsequence/wallet-core'
|
|
2
2
|
import { Config, Constants, Extensions, GenericTree, Payload } from '@0xsequence/wallet-primitives'
|
|
3
|
-
import { Address, Hex, Provider, RpcTransport } from 'ox'
|
|
3
|
+
import { Abi, AbiFunction, Address, Hex, Provider, RpcTransport } from 'ox'
|
|
4
4
|
import { MnemonicHandler } from './handlers/mnemonic.js'
|
|
5
5
|
import { Shared } from './manager.js'
|
|
6
6
|
import { Actions, Module } from './types/index.js'
|
|
7
7
|
import { QueuedRecoveryPayload } from './types/recovery.js'
|
|
8
8
|
import { Kinds, RecoverySigner } from './types/signer.js'
|
|
9
9
|
|
|
10
|
+
const AGGREGATE3 = Abi.from([
|
|
11
|
+
'function aggregate3((address target, bool allowFailure, bytes callData)[] calls) external payable returns ((bool success, bytes returnData)[])',
|
|
12
|
+
])[0]!
|
|
13
|
+
|
|
10
14
|
export interface RecoveryInterface {
|
|
11
15
|
/**
|
|
12
16
|
* Retrieves the list of configured recovery signers for a given wallet.
|
|
@@ -284,7 +288,7 @@ export class Recovery implements RecoveryInterface {
|
|
|
284
288
|
}
|
|
285
289
|
|
|
286
290
|
await this.updateRecoveryModule(modules, (leaves) => {
|
|
287
|
-
const next = leaves.filter((l) => l.signer
|
|
291
|
+
const next = leaves.filter((l) => !Address.isEqual(l.signer, address))
|
|
288
292
|
if (next.length === 0) {
|
|
289
293
|
return [
|
|
290
294
|
{
|
|
@@ -514,9 +518,16 @@ export class Recovery implements RecoveryInterface {
|
|
|
514
518
|
async fetchQueuedPayloads(wallet: Address.Address, chainId?: number): Promise<QueuedRecoveryPayload[]> {
|
|
515
519
|
// Create providers for each network
|
|
516
520
|
const providers = this.shared.sequence.networks
|
|
517
|
-
.filter((network) =>
|
|
521
|
+
.filter((network) =>
|
|
522
|
+
chainId
|
|
523
|
+
? network.chainId === chainId
|
|
524
|
+
: !this.shared.sequence.defaultRecoverySettings.includeTestnets
|
|
525
|
+
? network.type !== 'testnet'
|
|
526
|
+
: true,
|
|
527
|
+
)
|
|
518
528
|
.map((network) => ({
|
|
519
529
|
chainId: network.chainId,
|
|
530
|
+
multicall3Address: network.contracts?.multicall3,
|
|
520
531
|
provider: Provider.from(RpcTransport.fromHttp(network.rpcUrl)),
|
|
521
532
|
}))
|
|
522
533
|
|
|
@@ -526,69 +537,167 @@ export class Recovery implements RecoveryInterface {
|
|
|
526
537
|
return []
|
|
527
538
|
}
|
|
528
539
|
|
|
540
|
+
const recoveryExtension = this.shared.sequence.extensions.recovery
|
|
529
541
|
const payloads: QueuedRecoveryPayload[] = []
|
|
530
542
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
// If ready, we need to check if it was executed already
|
|
560
|
-
// for this, we check if the wallet nonce for the given space
|
|
561
|
-
// is greater than the nonce in the payload
|
|
562
|
-
if (timestamp < Date.now() / 1000 && payload && Payload.isCalls(payload.payload)) {
|
|
563
|
-
const nonce = await this.shared.modules.wallets.getNonce(chainId, wallet, payload.payload.space)
|
|
564
|
-
if (nonce > i) {
|
|
565
|
-
continue
|
|
543
|
+
await Promise.all(
|
|
544
|
+
providers.map(async ({ chainId, provider, multicall3Address }) => {
|
|
545
|
+
try {
|
|
546
|
+
let totalPayloadsBySigner: bigint[]
|
|
547
|
+
|
|
548
|
+
if (multicall3Address) {
|
|
549
|
+
try {
|
|
550
|
+
// Batch all totalQueuedPayloads calls for every signer into a single Multicall3 request.
|
|
551
|
+
// This reduces N signer calls per network down to 1 call per network.
|
|
552
|
+
totalPayloadsBySigner = await this.fetchTotalQueuedPayloadsBatched(
|
|
553
|
+
provider,
|
|
554
|
+
recoveryExtension,
|
|
555
|
+
wallet,
|
|
556
|
+
signers,
|
|
557
|
+
multicall3Address,
|
|
558
|
+
)
|
|
559
|
+
} catch (err) {
|
|
560
|
+
console.error(
|
|
561
|
+
`Recovery.fetchQueuedPayloads multicall3 failed for chainId ${chainId}, retrying with individual calls:`,
|
|
562
|
+
err,
|
|
563
|
+
)
|
|
564
|
+
totalPayloadsBySigner = await this.fetchTotalQueuedPayloadsFallback(
|
|
565
|
+
provider,
|
|
566
|
+
recoveryExtension,
|
|
567
|
+
wallet,
|
|
568
|
+
signers,
|
|
569
|
+
)
|
|
566
570
|
}
|
|
571
|
+
} else {
|
|
572
|
+
totalPayloadsBySigner = await this.fetchTotalQueuedPayloadsFallback(
|
|
573
|
+
provider,
|
|
574
|
+
recoveryExtension,
|
|
575
|
+
wallet,
|
|
576
|
+
signers,
|
|
577
|
+
)
|
|
567
578
|
}
|
|
568
579
|
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
580
|
+
for (let s = 0; s < signers.length; s++) {
|
|
581
|
+
const signer = signers[s]!
|
|
582
|
+
const totalPayloads = totalPayloadsBySigner[s]!
|
|
583
|
+
if (totalPayloads === 0n) continue
|
|
584
|
+
|
|
585
|
+
// Only make individual calls for the rare case where payloads actually exist
|
|
586
|
+
for (let i = 0n; i < totalPayloads; i++) {
|
|
587
|
+
const payloadHash = await Extensions.Recovery.queuedPayloadHashOf(
|
|
588
|
+
provider,
|
|
589
|
+
recoveryExtension,
|
|
590
|
+
wallet,
|
|
591
|
+
signer.address,
|
|
592
|
+
i,
|
|
593
|
+
)
|
|
594
|
+
|
|
595
|
+
const timestamp = await Extensions.Recovery.timestampForQueuedPayload(
|
|
596
|
+
provider,
|
|
597
|
+
recoveryExtension,
|
|
598
|
+
wallet,
|
|
599
|
+
signer.address,
|
|
600
|
+
payloadHash,
|
|
601
|
+
)
|
|
602
|
+
|
|
603
|
+
const payload = await this.shared.sequence.stateProvider.getPayload(payloadHash)
|
|
604
|
+
|
|
605
|
+
// If ready, we need to check if it was executed already
|
|
606
|
+
// for this, we check if the wallet nonce for the given space
|
|
607
|
+
// is greater than the nonce in the payload
|
|
608
|
+
if (timestamp < Date.now() / 1000 && payload && Payload.isCalls(payload.payload)) {
|
|
609
|
+
const nonce = await this.shared.modules.wallets.getNonce(chainId, wallet, payload.payload.space)
|
|
610
|
+
if (nonce > i) {
|
|
611
|
+
continue
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// The id is the index + signer address + chainId + wallet address
|
|
616
|
+
const id = `${i}-${signer.address}-${chainId}-${wallet}`
|
|
617
|
+
|
|
618
|
+
const payloadEntry: QueuedRecoveryPayload = {
|
|
619
|
+
id,
|
|
620
|
+
index: i,
|
|
621
|
+
recoveryModule: recoveryExtension,
|
|
622
|
+
wallet: wallet,
|
|
623
|
+
signer: signer.address,
|
|
624
|
+
chainId,
|
|
625
|
+
startTimestamp: timestamp,
|
|
626
|
+
endTimestamp: timestamp + signer.requiredDeltaTime,
|
|
627
|
+
payloadHash,
|
|
628
|
+
payload: payload?.payload,
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
payloads.push(payloadEntry)
|
|
632
|
+
}
|
|
584
633
|
}
|
|
585
|
-
|
|
586
|
-
|
|
634
|
+
} catch (err) {
|
|
635
|
+
console.error(`Recovery.fetchQueuedPayloads error for chainId ${chainId}:`, err)
|
|
587
636
|
}
|
|
637
|
+
}),
|
|
638
|
+
)
|
|
639
|
+
|
|
640
|
+
return payloads
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
private async fetchTotalQueuedPayloadsBatched(
|
|
644
|
+
provider: Provider.Provider,
|
|
645
|
+
recoveryExtension: Address.Address,
|
|
646
|
+
wallet: Address.Address,
|
|
647
|
+
signers: RecoverySigner[],
|
|
648
|
+
multicall3Address: Address.Address,
|
|
649
|
+
): Promise<bigint[]> {
|
|
650
|
+
const calls = signers.map((signer) => ({
|
|
651
|
+
target: recoveryExtension,
|
|
652
|
+
allowFailure: true,
|
|
653
|
+
callData: AbiFunction.encodeData(Extensions.Recovery.TOTAL_QUEUED_PAYLOADS, [wallet, signer.address]),
|
|
654
|
+
}))
|
|
655
|
+
|
|
656
|
+
const response = await provider.request({
|
|
657
|
+
method: 'eth_call',
|
|
658
|
+
params: [
|
|
659
|
+
{
|
|
660
|
+
to: multicall3Address,
|
|
661
|
+
data: AbiFunction.encodeData(AGGREGATE3, [calls]),
|
|
662
|
+
},
|
|
663
|
+
'latest',
|
|
664
|
+
],
|
|
665
|
+
})
|
|
666
|
+
|
|
667
|
+
const results = AbiFunction.decodeResult(AGGREGATE3, response) as readonly {
|
|
668
|
+
success: boolean
|
|
669
|
+
returnData: Hex.Hex
|
|
670
|
+
}[]
|
|
671
|
+
|
|
672
|
+
return results.map((result) => {
|
|
673
|
+
if (!result.success || result.returnData === '0x') {
|
|
674
|
+
return 0n
|
|
588
675
|
}
|
|
676
|
+
return Hex.toBigInt(result.returnData)
|
|
677
|
+
})
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
private fetchTotalQueuedPayloadsFallback = async (
|
|
681
|
+
provider: Provider.Provider,
|
|
682
|
+
recoveryExtension: Address.Address,
|
|
683
|
+
wallet: Address.Address,
|
|
684
|
+
signers: RecoverySigner[],
|
|
685
|
+
): Promise<bigint[]> => {
|
|
686
|
+
const result: bigint[] = signers.map(() => 0n)
|
|
687
|
+
|
|
688
|
+
// Fallback to individual calls if the multicall3 call fails
|
|
689
|
+
for (let s = 0; s < signers.length; s++) {
|
|
690
|
+
const signer = signers[s]!
|
|
691
|
+
const totalPayloads = await Extensions.Recovery.totalQueuedPayloads(
|
|
692
|
+
provider,
|
|
693
|
+
recoveryExtension,
|
|
694
|
+
wallet,
|
|
695
|
+
signer.address,
|
|
696
|
+
)
|
|
697
|
+
result[s] = totalPayloads
|
|
589
698
|
}
|
|
590
699
|
|
|
591
|
-
return
|
|
700
|
+
return result
|
|
592
701
|
}
|
|
593
702
|
|
|
594
703
|
async encodeRecoverySignature(imageHash: Hex.Hex, signer: Address.Address) {
|
package/src/sequence/signers.ts
CHANGED
|
@@ -347,7 +347,11 @@ export class Transactions implements TransactionsInterface {
|
|
|
347
347
|
return []
|
|
348
348
|
}
|
|
349
349
|
|
|
350
|
-
|
|
350
|
+
// Determine the to address for the built transaction
|
|
351
|
+
const walletStatus = await wallet.getStatus(provider)
|
|
352
|
+
const to = walletStatus.isDeployed ? wallet.address : wallet.guest
|
|
353
|
+
|
|
354
|
+
const feeOptions = await relayer.feeOptions(tx.wallet, tx.envelope.chainId, to, tx.envelope.payload.calls)
|
|
351
355
|
|
|
352
356
|
if (feeOptions.options.length === 0) {
|
|
353
357
|
const { name, icon } = relayer instanceof Relayer.EIP6963.EIP6963Relayer ? relayer.info : {}
|
|
@@ -492,7 +496,7 @@ export class Transactions implements TransactionsInterface {
|
|
|
492
496
|
let tx: Transaction | undefined
|
|
493
497
|
try {
|
|
494
498
|
tx = await this.get(transactionOrSignatureId)
|
|
495
|
-
} catch
|
|
499
|
+
} catch {
|
|
496
500
|
// If not found, it might be a signature ID
|
|
497
501
|
const signature = await this.shared.modules.signatures.get(transactionOrSignatureId)
|
|
498
502
|
if (!signature) {
|