Skip to content

Commit

Permalink
signhub: InteractiveSigner
Browse files Browse the repository at this point in the history
  • Loading branch information
attente committed Oct 18, 2023
1 parent 36fd605 commit 5476d47
Showing 1 changed file with 109 additions and 0 deletions.
109 changes: 109 additions & 0 deletions packages/signhub/src/signers/interactive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { BytesLike } from 'ethers'
import { Status, isSignerStatusPending } from '../orchestrator'
import { SapientSigner } from './signer'

export class InteractiveSigner implements SapientSigner {
private readonly requests: Map<string, Request> = new Map()

constructor(
private readonly signer: SapientSigner,
private readonly dependencies: string[]
) {}

async prompt(id: string) {
const request = this.requests.get(id)

if (request === undefined) {
return
}

this.signer.requestSignature(id, request.message, request.metadata, {
onSignature(signature) {
request.callbacks.onSignature(signature)
request.resolve()
},
onRejection(_error) {},
onStatus(_situation) {}
})
}

getAddress(): Promise<string> {
return this.signer.getAddress()
}

requestSignature(
id: string,
message: BytesLike,
metadata: object,
callbacks: {
onSignature: (signature: BytesLike) => void
onRejection: (error: string) => void
onStatus: (situation: string) => void
}
): Promise<boolean> {
return new Promise(resolve => {
const request = {
message,
metadata,
callbacks,
autoPrompts: 0,
resolve: () => resolve(true)
}

this.requests.set(id, request)

// prompt immediately if we're not waiting for other signers
if (this.dependencies.length === 0) {
request.autoPrompts++
this.prompt(id)
}
})
}

notifyStatusChange(id: string, status: Status, metadata: object): void {
const request = this.requests.get(id)

if (request === undefined) {
return
}

request.metadata = metadata

if (status.ended) {
this.requests.delete(id)
return
}

if (request.autoPrompts > 0) {
return
}

const isPending = (dependency: string) => {
const signerStatus = status.signers[dependency]
return signerStatus !== undefined && isSignerStatusPending(signerStatus)
}

if (this.dependencies.some(isPending)) {
return
}

request.autoPrompts++
this.prompt(id)
}

suffix(): BytesLike {
return this.signer.suffix()
}
}

type Request = {
message: BytesLike
metadata: object
callbacks: {
onSignature: (signature: BytesLike) => void
onRejection: (error: string) => void
onStatus: (situation: string) => void
}
autoPrompts: number
resolve: () => void
}

0 comments on commit 5476d47

Please sign in to comment.