Skip to content

Commit f0a5171

Browse files
committed
Complete remove recovery methods
1 parent 5202f8d commit f0a5171

File tree

4 files changed

+85
-43
lines changed

4 files changed

+85
-43
lines changed

packages/wallet/wdk/src/sequence/manager.ts

+16
Original file line numberDiff line numberDiff line change
@@ -500,4 +500,20 @@ export class Manager {
500500
public async completeRecoveryPayload(requestId: string) {
501501
return this.shared.modules.recovery.completeRecoveryPayload(requestId)
502502
}
503+
504+
public async addRecoveryMnemonic(wallet: Address.Address, mnemonic: string) {
505+
return this.shared.modules.recovery.addRecoveryMnemonic(wallet, mnemonic)
506+
}
507+
508+
public async addRecoverySigner(wallet: Address.Address, address: Address.Address) {
509+
return this.shared.modules.recovery.addRecoverySigner(wallet, address)
510+
}
511+
512+
public async removeRecoverySigner(wallet: Address.Address, address: Address.Address) {
513+
return this.shared.modules.recovery.removeRecoverySigner(wallet, address)
514+
}
515+
516+
public async completeRecoveryUpdate(requestId: string) {
517+
return this.shared.modules.recovery.completeRecoveryUpdate(requestId)
518+
}
503519
}

packages/wallet/wdk/src/sequence/recovery.ts

+44-9
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { Config, Extensions, GenericTree, Payload } from '@0xsequence/wallet-primitives'
22
import { Shared } from './manager.js'
33
import { Address, Hex, Provider, RpcTransport } from 'ox'
4-
import { RecoverySigner } from './types/signer.js'
4+
import { Kinds, RecoverySigner } from './types/signer.js'
55
import { Envelope } from '@0xsequence/wallet-core'
66
import { QueuedRecoveryPayload } from './types/recovery.js'
77
import { Actions } from './types/index.js'
8+
import { MnemonicHandler } from './handlers/mnemonic.js'
89

910
export class Recovery {
1011
constructor(private readonly shared: Shared) {}
@@ -31,7 +32,12 @@ export class Recovery {
3132
return
3233
}
3334

34-
const genericTree = await this.shared.sequence.stateProvider.getTree(ext)
35+
const sapientSigner = modules[idx]
36+
if (!sapientSigner) {
37+
throw new Error('recovery-module-not-found')
38+
}
39+
40+
const genericTree = await this.shared.sequence.stateProvider.getTree(sapientSigner.imageHash)
3541
if (!genericTree) {
3642
throw new Error('recovery-module-tree-not-found')
3743
}
@@ -129,11 +135,25 @@ export class Recovery {
129135
})
130136
}
131137

132-
async addRecoverySigner(address: Address.Address) {
133-
const { modules } = await this.shared.modules.wallets.getConfigurationParts(address)
138+
async addRecoveryMnemonic(wallet: Address.Address, mnemonic: string) {
139+
const signer = MnemonicHandler.toSigner(mnemonic)
140+
if (!signer) {
141+
throw new Error('invalid-mnemonic')
142+
}
143+
144+
await signer.witness(this.shared.sequence.stateProvider, wallet, {
145+
isForRecovery: true,
146+
signerKind: Kinds.LoginMnemonic,
147+
})
148+
149+
return this.addRecoverySigner(wallet, signer.address)
150+
}
151+
152+
async addRecoverySigner(wallet: Address.Address, address: Address.Address) {
153+
const { modules } = await this.shared.modules.wallets.getConfigurationParts(wallet)
134154
await this.addRecoverySignerToModules(modules, address)
135155
return this.shared.modules.wallets.requestConfigurationUpdate(
136-
address,
156+
wallet,
137157
{
138158
modules,
139159
},
@@ -142,17 +162,26 @@ export class Recovery {
142162
)
143163
}
144164

145-
async removeRecoverySigner(address: Address.Address) {
146-
const { modules } = await this.shared.modules.wallets.getConfigurationParts(address)
165+
async removeRecoverySigner(wallet: Address.Address, address: Address.Address) {
166+
const { modules } = await this.shared.modules.wallets.getConfigurationParts(wallet)
147167
await this.removeRecoverySignerFromModules(modules, address)
148168
return this.shared.modules.wallets.requestConfigurationUpdate(
149-
address,
169+
wallet,
150170
{ modules },
151171
Actions.RemoveRecoverySigner,
152172
'wallet-webapp',
153173
)
154174
}
155175

176+
async completeRecoveryUpdate(requestId: string) {
177+
const request = await this.shared.modules.signatures.get(requestId)
178+
if (request.action !== 'add-recovery-signer' && request.action !== 'remove-recovery-signer') {
179+
throw new Error('invalid-recovery-update-action')
180+
}
181+
182+
return this.shared.modules.wallets.completeConfigurationUpdate(requestId)
183+
}
184+
156185
async getRecoverySigners(address: Address.Address): Promise<RecoverySigner[] | undefined> {
157186
const { raw } = await this.shared.modules.wallets.getConfiguration({ wallet: address })
158187
const recoveryLeaf = raw.modules.find((m) => m.address === this.shared.sequence.extensions.recovery)
@@ -171,11 +200,17 @@ export class Recovery {
171200
throw new Error('recovery-module-tree-incomplete')
172201
}
173202

203+
const kos = await this.shared.modules.signers.resolveKinds(
204+
address,
205+
leaves.map((l) => l.signer),
206+
)
207+
174208
return leaves
175209
.filter((l) => l.signer !== '0x0000000000000000000000000000000000000000')
176210
.map((l) => ({
177211
address: l.signer,
178-
kind: 'recovery',
212+
kind: kos.find((s) => s.address === l.signer)?.kind || 'unknown',
213+
isRecovery: true,
179214
minTimestamp: l.minTimestamp,
180215
requiredDeltaTime: l.requiredDeltaTime,
181216
}))

packages/wallet/wdk/src/sequence/types/signer.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Address, Hex } from 'ox'
33
export const Kinds = {
44
LocalDevice: 'local-device',
55
LoginPasskey: 'login-passkey',
6-
LoginMnemonic: 'login-mnemonic',
6+
LoginMnemonic: 'login-mnemonic', // Todo: do not name it login-mnemonic, just mnemonic
77
LoginEmailOtp: 'login-email-otp',
88
LoginGooglePkce: 'login-google-pkce',
99
LoginApplePkce: 'login-apple-pkce',
@@ -23,7 +23,8 @@ export type SignerWithKind = {
2323
}
2424

2525
export type RecoverySigner = {
26-
kind: 'recovery'
26+
kind: Kind
27+
isRecovery: true
2728
address: Address.Address
2829
minTimestamp: bigint
2930
requiredDeltaTime: bigint

packages/wallet/wdk/src/sequence/wallets.ts

+22-32
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,26 @@ export class Wallets {
543543
return requestId
544544
}
545545

546+
public async completeConfigurationUpdate(requestId: string) {
547+
const request = await this.shared.modules.signatures.get(requestId)
548+
if (!Payload.isConfigUpdate(request.envelope.payload)) {
549+
throw new Error('invalid-request-payload')
550+
}
551+
552+
if (!Envelope.reachedThreshold(request.envelope)) {
553+
throw new Error('insufficient-weight')
554+
}
555+
556+
const wallet = new CoreWallet(request.wallet, {
557+
context: this.shared.sequence.context,
558+
stateProvider: this.shared.sequence.stateProvider,
559+
guest: this.shared.sequence.guest,
560+
})
561+
562+
await wallet.submitUpdate(request.envelope as Envelope.Signed<Payload.ConfigUpdate>)
563+
await this.shared.modules.signatures.complete(requestId)
564+
}
565+
546566
async login(args: LoginArgs): Promise<string | undefined> {
547567
if (isLoginToWalletArgs(args)) {
548568
const prevWallet = await this.exists(args.wallet)
@@ -642,28 +662,12 @@ export class Wallets {
642662
async completeLogin(requestId: string) {
643663
const request = await this.shared.modules.signatures.get(requestId)
644664

645-
const envelope = request.envelope
646-
if (!Payload.isConfigUpdate(envelope.payload)) {
647-
throw new Error('invalid-request-payload')
648-
}
649-
650-
if (!Envelope.reachedThreshold(envelope)) {
651-
throw new Error('insufficient-weight')
652-
}
653-
654665
const walletEntry = await this.shared.databases.manager.get(request.wallet)
655666
if (!walletEntry) {
656667
throw new Error('login-for-wallet-not-found')
657668
}
658669

659-
const wallet = new CoreWallet(request.wallet, {
660-
context: this.shared.sequence.context,
661-
stateProvider: this.shared.sequence.stateProvider,
662-
guest: this.shared.sequence.guest,
663-
})
664-
665-
await wallet.submitUpdate(envelope as Envelope.Signed<Payload.ConfigUpdate>)
666-
await this.shared.modules.signatures.complete(requestId)
670+
await this.completeConfigurationUpdate(requestId)
667671

668672
// Save entry in the manager db
669673
await this.shared.databases.manager.set({
@@ -731,10 +735,6 @@ export class Wallets {
731735

732736
async completeLogout(requestId: string, options?: { skipValidateSave?: boolean }) {
733737
const request = await this.shared.modules.signatures.get(requestId)
734-
if (!Payload.isConfigUpdate(request.envelope.payload)) {
735-
throw new Error('invalid-request-payload')
736-
}
737-
738738
const walletEntry = await this.shared.databases.manager.get(request.wallet)
739739
if (!walletEntry) {
740740
throw new Error('wallet-not-found')
@@ -747,17 +747,7 @@ export class Wallets {
747747
)
748748
}
749749

750-
const wallet = new CoreWallet(request.wallet, {
751-
context: this.shared.sequence.context,
752-
stateProvider: this.shared.sequence.stateProvider,
753-
guest: this.shared.sequence.guest,
754-
})
755-
756-
await wallet.submitUpdate(request.envelope as Envelope.Signed<Payload.ConfigUpdate>, {
757-
validateSave: !options?.skipValidateSave,
758-
})
759-
760-
await this.shared.modules.signatures.complete(requestId)
750+
await this.completeConfigurationUpdate(requestId)
761751
await this.shared.databases.manager.del(request.wallet)
762752
await this.shared.modules.devices.remove(walletEntry.device)
763753
}

0 commit comments

Comments
 (0)