Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions packages/wallet/wdk/src/sequence/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { BaseSignatureRequest, SignatureRequest, Wallet } from './types'
import { Transaction, TransactionRequest } from './types/transaction-request'
import { CompleteRedirectArgs, LoginArgs, SignupArgs, StartSignUpWithRedirectArgs, Wallets } from './wallets'
import { Kinds } from './types/signer'
import { WalletSelectionUiHandler } from './types/wallet'

export type ManagerOptions = {
verbose?: boolean
Expand Down Expand Up @@ -302,6 +303,14 @@ export class Manager {
return this.shared.modules.wallets.onWalletsUpdate(cb, trigger)
}

public registerWalletSelector(handler: WalletSelectionUiHandler) {
return this.shared.modules.wallets.registerWalletSelector(handler)
}

public unregisterWalletSelector(handler?: WalletSelectionUiHandler) {
return this.shared.modules.wallets.unregisterWalletSelector(handler)
}

// Signatures

public async listSignatureRequests(): Promise<SignatureRequest[]> {
Expand Down
16 changes: 16 additions & 0 deletions packages/wallet/wdk/src/sequence/types/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,19 @@ export interface Wallet {
loginType: string
useGuard: boolean
}

export type WalletSelectionContext = {
isRedirect: boolean
target?: string
signupKind?: string
}

export type WalletSelectionOptions = {
existingWallets: Address.Address[]
signerAddress: Address.Address
context: WalletSelectionContext
}

export type WalletSelectionResult = 'create' | 'cancel'

export type WalletSelectionUiHandler = (options: WalletSelectionOptions) => Promise<WalletSelectionResult>
58 changes: 49 additions & 9 deletions packages/wallet/wdk/src/sequence/wallets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { OtpHandler } from './handlers/otp'
import { Shared } from './manager'
import { Wallet } from './types'
import { Kinds, WitnessExtraSignerKind } from './types/signer'
import { WalletSelectionUiHandler } from './types/wallet'

export type StartSignUpWithRedirectArgs = {
kind: 'google-pkce' | 'apple-pkce'
Expand All @@ -18,7 +19,6 @@ export type StartSignUpWithRedirectArgs = {
export type CommonSignupArgs = {
noGuard?: boolean
noSessionManager?: boolean
onExistingWallets?: (wallets: Address.Address[]) => Promise<boolean>
}

export type PasskeySignupArgs = CommonSignupArgs & {
Expand All @@ -38,13 +38,14 @@ export type EmailOtpSignupArgs = CommonSignupArgs & {
export type CompleteRedirectArgs = CommonSignupArgs & {
state: string
code: string
onExistingWalletsWithTarget?: (wallets: Address.Address[], target: string) => Promise<boolean>
}

export type AuthCodePkceSignupArgs = CommonSignupArgs & {
kind: 'google-pkce' | 'apple-pkce'
commitment: AuthCommitment
code: string
target: string
isRedirect: boolean
}

export type SignupArgs = PasskeySignupArgs | MnemonicSignupArgs | EmailOtpSignupArgs | AuthCodePkceSignupArgs
Expand Down Expand Up @@ -78,6 +79,10 @@ export function isLoginToPasskeyArgs(args: LoginArgs): args is LoginToPasskeyArg
return 'kind' in args && args.kind === 'passkey'
}

export function isAuthCodePkceArgs(args: SignupArgs): args is AuthCodePkceSignupArgs {
return 'kind' in args && (args.kind === 'google-pkce' || args.kind === 'apple-pkce')
}

function buildCappedTree(members: { address: Address.Address; imageHash?: Hex.Hex }[]): Config.Topology {
const loginMemberWeight = 1n

Expand Down Expand Up @@ -198,6 +203,8 @@ function fromConfig(config: Config.Config): {
}

export class Wallets {
private walletSelectionUiHandler: WalletSelectionUiHandler | null = null

constructor(private readonly shared: Shared) {}

public async exists(wallet: Address.Address): Promise<boolean> {
Expand All @@ -212,6 +219,23 @@ export class Wallets {
return this.shared.databases.manager.list()
}

public registerWalletSelector(handler: WalletSelectionUiHandler) {
if (this.walletSelectionUiHandler) {
throw new Error('wallet-selector-already-registered')
}
this.walletSelectionUiHandler = handler
return () => {
this.unregisterWalletSelector(handler)
}
}

public unregisterWalletSelector(handler?: WalletSelectionUiHandler) {
if (handler && this.walletSelectionUiHandler !== handler) {
throw new Error('wallet-selector-not-registered')
}
this.walletSelectionUiHandler = null
}

public onWalletsUpdate(cb: (wallets: Wallet[]) => void, trigger?: boolean) {
const undo = this.shared.databases.manager.addListener(() => {
this.list().then((wallets) => {
Expand Down Expand Up @@ -318,9 +342,8 @@ export class Wallets {
commitment,
code: args.code,
noGuard: args.noGuard,
onExistingWallets: args.onExistingWalletsWithTarget
? (wallets) => args.onExistingWalletsWithTarget!(wallets, commitment.target)
: args.onExistingWallets,
target: commitment.target,
isRedirect: true,
})
} else {
const handler = this.shared.handlers.get('login-' + commitment.kind) as AuthCodePkceHandler
Expand All @@ -337,14 +360,31 @@ export class Wallets {
const loginSigner = await this.prepareSignUp(args)

// If there is an existing wallet callback, we check if any wallet already exist for this login signer
if (args.onExistingWallets) {
if (this.walletSelectionUiHandler) {
const existingWallets = await State.getWalletsFor(this.shared.sequence.stateProvider, loginSigner.signer)
if (existingWallets.length > 0) {
const result = await args.onExistingWallets(existingWallets.map((w) => w.wallet))
if (result) {
return
const result = await this.walletSelectionUiHandler({
existingWallets: existingWallets.map((w) => w.wallet),
signerAddress: await loginSigner.signer.address,
context: isAuthCodePkceArgs(args)
? {
isRedirect: args.isRedirect,
target: args.target,
}
: {
isRedirect: false,
},
})

switch (result) {
case 'create':
break
case 'cancel':
throw new Error('wallet-selection-cancelled')
}
}
} else {
console.warn('No wallet selector registered, creating a new wallet')
Comment thread
Agusx1211 marked this conversation as resolved.
}

// Create the first session
Expand Down