Skip to content

Commit

Permalink
adds ledger flag to participant creation
Browse files Browse the repository at this point in the history
adds dkgGetIDentity method to ledger util module

adds '--ledger' flag to 'wallet:multisig:participant:create' command

uses 'wallet/multisig/importParticipant' RPC to add the participant identity to
the walletDb
  • Loading branch information
hughy committed Sep 18, 2024
1 parent e1eec38 commit 2f6b618
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 12 deletions.
39 changes: 37 additions & 2 deletions ironfish-cli/src/commands/wallet/multisig/participant/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Flags } from '@oclif/core'
import { IronfishCommand } from '../../../../command'
import { RemoteFlags } from '../../../../flags'
import * as ui from '../../../../ui'
import { Ledger } from '../../../../utils/ledger'

export class MultisigIdentityCreate extends IronfishCommand {
static description = `Create a multisig participant identity`
Expand All @@ -16,6 +17,11 @@ export class MultisigIdentityCreate extends IronfishCommand {
char: 'n',
description: 'Name to associate with the identity',
}),
ledger: Flags.boolean({
default: false,
description: 'Perform operation with a ledger device',
hidden: true,
}),
}

async start(): Promise<void> {
Expand All @@ -29,14 +35,27 @@ export class MultisigIdentityCreate extends IronfishCommand {
name = await ui.inputPrompt('Enter a name for the identity', true)
}

let identity
if (flags.ledger) {
identity = await this.createParticipantWithLedger()
}

let response
while (!response) {
try {
response = await client.wallet.multisig.createParticipant({ name })
if (identity) {
response = await client.wallet.multisig.importParticipant({
name,
identity: identity.toString('hex'),
})
} else {
response = await client.wallet.multisig.createParticipant({ name })
}
} catch (e) {
if (
e instanceof RpcRequestError &&
e.code === RPC_ERROR_CODES.DUPLICATE_ACCOUNT_NAME.toString()
(e.code === RPC_ERROR_CODES.DUPLICATE_ACCOUNT_NAME.toString() ||
e.code === RPC_ERROR_CODES.DUPLICATE_IDENTITY_NAME.toString())
) {
this.log()
this.log(e.codeMessage)
Expand All @@ -50,4 +69,20 @@ export class MultisigIdentityCreate extends IronfishCommand {
this.log('Identity:')
this.log(response.content.identity)
}

async createParticipantWithLedger(): Promise<Buffer> {
const ledger = new Ledger(this.logger)
try {
await ledger.connect(true)
} catch (e) {
if (e instanceof Error) {
this.error(e.message)
} else {
throw e
}
}

// TODO(hughy): support multiple identities using index
return ledger.dkgGetIdentity(0)
}
}
36 changes: 26 additions & 10 deletions ironfish-cli/src/utils/ledger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import IronfishApp, {
IronfishKeys,
KeyResponse,
ResponseAddress,
ResponseIdentity,
ResponseProofGenKey,
ResponseSign,
ResponseViewKey,
Expand Down Expand Up @@ -45,26 +46,29 @@ export class Ledger {
}
}

connect = async () => {
connect = async (dkg = false) => {
const transport = await TransportNodeHid.create(3000, 3000)

if (transport.deviceModel) {
this.logger.debug(`${transport.deviceModel.productName} found.`)
}

const app = new IronfishApp(transport, false)
const app = new IronfishApp(transport, dkg)

const appInfo = await this.tryInstruction(app.appInfo())
// TODO: remove this condition if appInfo is available in the DKG app
if (!dkg) {
const appInfo = await this.tryInstruction(app.appInfo())

this.logger.debug(appInfo.appName ?? 'no app name')

if (appInfo.appName !== 'Ironfish') {
this.logger.debug(appInfo.appName ?? 'no app name')
throw new Error('Please open the Iron Fish app on your ledger device.')
}

if (appInfo.appVersion) {
this.logger.debug(`Ironfish App Version: ${appInfo.appVersion}`)
if (appInfo.appName !== 'Ironfish') {
this.logger.debug(appInfo.appName ?? 'no app name')
throw new Error('Please open the Iron Fish app on your ledger device.')
}

if (appInfo.appVersion) {
this.logger.debug(`Ironfish App Version: ${appInfo.appVersion}`)
}
}

this.app = app
Expand Down Expand Up @@ -152,6 +156,18 @@ export class Ledger {

return response.signature
}

dkgGetIdentity = async (index: number): Promise<Buffer> => {
if (!this.app) {
throw new Error('Connect to Ledger first')
}

this.logger.log('Please approve the request on your ledger device.')

const response: ResponseIdentity = await this.tryInstruction(this.app.dkgGetIdentity(index))

return response.identity
}
}

function isResponseAddress(response: KeyResponse): response is ResponseAddress {
Expand Down

0 comments on commit 2f6b618

Please sign in to comment.