Skip to content

Commit

Permalink
Refactor: ledger related logic to ledger.ts
Browse files Browse the repository at this point in the history
Goal: Easier integration for upcoming ledger commands
  • Loading branch information
patnir committed Sep 20, 2024
1 parent 4159101 commit 5ee43cf
Show file tree
Hide file tree
Showing 12 changed files with 105 additions and 168 deletions.
6 changes: 3 additions & 3 deletions ironfish-cli/src/commands/wallet/import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { IronfishCommand } from '../../command'
import { RemoteFlags } from '../../flags'
import { checkWalletUnlocked, inputPrompt } from '../../ui'
import { importFile, importPipe, longPrompt } from '../../ui/longPrompt'
import { Ledger } from '../../utils/ledger'
import { initializeLedger } from '../../utils/ledger'

export class ImportCommand extends IronfishCommand {
static description = `import an account`
Expand Down Expand Up @@ -155,9 +155,9 @@ export class ImportCommand extends IronfishCommand {
}

async importLedger(): Promise<string> {
const ledger = await initializeLedger(false, this.logger)

try {
const ledger = new Ledger(this.logger)
await ledger.connect()
const account = await ledger.importAccount()
return encodeAccountImport(account, AccountFormat.Base64Json)
} catch (e) {
Expand Down
13 changes: 2 additions & 11 deletions ironfish-cli/src/commands/wallet/multisig/commitment/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Flags } from '@oclif/core'
import { IronfishCommand } from '../../../../command'
import { RemoteFlags } from '../../../../flags'
import * as ui from '../../../../ui'
import { Ledger } from '../../../../utils/ledger'
import { initializeLedger } from '../../../../utils/ledger'
import { MultisigTransactionJson } from '../../../../utils/multisig'
import { renderUnsignedTransactionDetails } from '../../../../utils/transaction'

Expand Down Expand Up @@ -124,16 +124,7 @@ export class CreateSigningCommitmentCommand extends IronfishCommand {
transactionHash: Buffer,
signers: string[],
): Promise<void> {
const ledger = new Ledger(this.logger)
try {
await ledger.connect(true)
} catch (e) {
if (e instanceof Error) {
this.error(e.message)
} else {
throw e
}
}
const ledger = await initializeLedger(true, this.logger)

const identityResponse = await client.wallet.multisig.getIdentity({ name: participantName })
const identity = identityResponse.content.identity
Expand Down
13 changes: 2 additions & 11 deletions ironfish-cli/src/commands/wallet/multisig/dkg/round1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +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'
import { initializeLedger } from '../../../../utils/ledger'

export class DkgRound1Command extends IronfishCommand {
static description = 'Perform round1 of the DKG protocol for multisig account creation'
Expand Down Expand Up @@ -100,16 +100,7 @@ export class DkgRound1Command extends IronfishCommand {
identities: string[],
minSigners: number,
): Promise<void> {
const ledger = new Ledger(this.logger)
try {
await ledger.connect(true)
} catch (e) {
if (e instanceof Error) {
this.error(e.message)
} else {
throw e
}
}
const ledger = await initializeLedger(true, this.logger)

const identityResponse = await client.wallet.multisig.getIdentity({ name: participantName })
const identity = identityResponse.content.identity
Expand Down
13 changes: 2 additions & 11 deletions ironfish-cli/src/commands/wallet/multisig/dkg/round2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Flags } from '@oclif/core'
import { IronfishCommand } from '../../../../command'
import { RemoteFlags } from '../../../../flags'
import * as ui from '../../../../ui'
import { Ledger } from '../../../../utils/ledger'
import { initializeLedger } from '../../../../utils/ledger'

export class DkgRound2Command extends IronfishCommand {
static description = 'Perform round2 of the DKG protocol for multisig account creation'
Expand Down Expand Up @@ -97,16 +97,7 @@ export class DkgRound2Command extends IronfishCommand {
round1PublicPackages: string[],
round1SecretPackage: string,
): Promise<void> {
const ledger = new Ledger(this.logger)
try {
await ledger.connect(true)
} catch (e) {
if (e instanceof Error) {
this.error(e.message)
} else {
throw e
}
}
const ledger = await initializeLedger(true, this.logger)

// TODO(hughy): determine how to handle multiple identities using index
const { publicPackage, secretPackage } = await ledger.dkgRound2(
Expand Down
64 changes: 7 additions & 57 deletions ironfish-cli/src/commands/wallet/multisig/dkg/round3.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import {
deserializePublicPackage,
deserializeRound2CombinedPublicPackage,
} from '@ironfish/rust-nodejs'
import { AccountFormat, encodeAccountImport, RpcClient } from '@ironfish/sdk'
import { AccountFormat, RpcClient, encodeAccountImport } from '@ironfish/sdk'
import { Flags } from '@oclif/core'
import { IronfishCommand } from '../../../../command'
import { RemoteFlags } from '../../../../flags'
import * as ui from '../../../../ui'
import { Ledger } from '../../../../utils/ledger'
import { initializeLedger } from '../../../../utils/ledger'

export class DkgRound3Command extends IronfishCommand {
static description = 'Perform round3 of the DKG protocol for multisig account creation'
Expand Down Expand Up @@ -143,66 +139,20 @@ export class DkgRound3Command extends IronfishCommand {
round2PublicPackagesStr: string[],
round2SecretPackage: string,
): Promise<void> {
const ledger = new Ledger(this.logger)
try {
await ledger.connect(true)
} catch (e) {
if (e instanceof Error) {
this.error(e.message)
} else {
throw e
}
}
const ledger = await initializeLedger(true, this.logger)

const identityResponse = await client.wallet.multisig.getIdentity({ name: participantName })
const identity = identityResponse.content.identity

// Sort packages by identity
const round1PublicPackages = round1PublicPackagesStr
.map(deserializePublicPackage)
.sort((a, b) => a.identity.localeCompare(b.identity))

// Filter out packages not intended for participant and sort by sender identity
const round2CombinedPublicPackages = round2PublicPackagesStr.map(
deserializeRound2CombinedPublicPackage,
)
const round2PublicPackages = round2CombinedPublicPackages
.flatMap((combined) =>
combined.packages.filter((pkg) => pkg.recipientIdentity === identity),
)
.sort((a, b) => a.senderIdentity.localeCompare(b.senderIdentity))

// Extract raw parts from round1 and round2 public packages
const participants = []
const round1FrostPackages = []
const gskBytes = []
for (const pkg of round1PublicPackages) {
// Exclude participant's own identity and round1 public package
if (pkg.identity !== identity) {
participants.push(pkg.identity)
round1FrostPackages.push(pkg.frostPackage)
}

gskBytes.push(pkg.groupSecretKeyShardEncrypted)
}

const round2FrostPackages = round2PublicPackages.map((pkg) => pkg.frostPackage)

// Perform round3 with Ledger
await ledger.dkgRound3(
const { dkgKeys, publicKeyPackage } = await ledger.dkgRound3(
0,
participants,
round1FrostPackages,
round2FrostPackages,
identity,
round1PublicPackagesStr,
round2PublicPackagesStr,
round2SecretPackage,
gskBytes,
)

// Retrieve all multisig account keys and publicKeyPackage
const dkgKeys = await ledger.dkgRetrieveKeys()

const publicKeyPackage = await ledger.dkgGetPublicPackage()

const accountImport = {
...dkgKeys,
multisigKeys: {
Expand Down
13 changes: 2 additions & 11 deletions ironfish-cli/src/commands/wallet/multisig/ledger/backup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,13 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import { IronfishCommand } from '../../../../command'
import { Ledger } from '../../../../utils/ledger'
import { initializeLedger } from '../../../../utils/ledger'

export class MultisigLedgerBackup extends IronfishCommand {
static description = `show encrypted multisig keys from a Ledger device`

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

const encryptedKeys = await ledger.dkgBackupKeys()

Expand Down
13 changes: 2 additions & 11 deletions ironfish-cli/src/commands/wallet/multisig/ledger/restore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { Flags } from '@oclif/core'
import { IronfishCommand } from '../../../../command'
import * as ui from '../../../../ui'
import { Ledger } from '../../../../utils/ledger'
import { initializeLedger } from '../../../../utils/ledger'

export class MultisigLedgerRestore extends IronfishCommand {
static description = `restore encrypted multisig keys to a Ledger device`
Expand All @@ -26,16 +26,7 @@ export class MultisigLedgerRestore extends IronfishCommand {
)
}

const ledger = new Ledger(this.logger)
try {
await ledger.connect(true)
} catch (e) {
if (e instanceof Error) {
this.error(e.message)
} else {
throw e
}
}
const ledger = await initializeLedger(true, this.logger)

await ledger.dkgRestoreKeys(encryptedKeys)

Expand Down
13 changes: 2 additions & 11 deletions ironfish-cli/src/commands/wallet/multisig/participant/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +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'
import { initializeLedger } from '../../../../utils/ledger'

export class MultisigIdentityCreate extends IronfishCommand {
static description = `Create a multisig participant identity`
Expand Down Expand Up @@ -71,16 +71,7 @@ export class MultisigIdentityCreate extends IronfishCommand {
}

async getIdentityFromLedger(): 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
}
}
const ledger = await initializeLedger(true, this.logger)

// TODO(hughy): support multiple identities using index
return ledger.dkgGetIdentity(0)
Expand Down
13 changes: 2 additions & 11 deletions ironfish-cli/src/commands/wallet/multisig/signature/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Flags } from '@oclif/core'
import { IronfishCommand } from '../../../../command'
import { RemoteFlags } from '../../../../flags'
import * as ui from '../../../../ui'
import { Ledger } from '../../../../utils/ledger'
import { initializeLedger } from '../../../../utils/ledger'
import { MultisigTransactionJson } from '../../../../utils/multisig'
import { renderUnsignedTransactionDetails } from '../../../../utils/transaction'

Expand Down Expand Up @@ -120,16 +120,7 @@ export class CreateSignatureShareCommand extends IronfishCommand {
unsignedTransaction: UnsignedTransaction,
frostSigningPackage: string,
): Promise<void> {
const ledger = new Ledger(this.logger)
try {
await ledger.connect(true)
} catch (e) {
if (e instanceof Error) {
this.error(e.message)
} else {
throw e
}
}
const ledger = await initializeLedger(true, this.logger)

const identityResponse = await client.wallet.multisig.getIdentity({ name: participantName })
const identity = identityResponse.content.identity
Expand Down
13 changes: 2 additions & 11 deletions ironfish-cli/src/commands/wallet/send.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { promptCurrency } from '../../utils/currency'
import { promptExpiration } from '../../utils/expiration'
import { getExplorer } from '../../utils/explorer'
import { selectFee } from '../../utils/fees'
import { Ledger } from '../../utils/ledger'
import { initializeLedger } from '../../utils/ledger'
import { getSpendPostTimeInMs, updateSpendPostTimeInMs } from '../../utils/spendPostTime'
import {
displayTransactionSummary,
Expand Down Expand Up @@ -359,16 +359,7 @@ export class Send extends IronfishCommand {
watch: boolean,
confirm: boolean,
): Promise<void> {
const ledger = new Ledger(this.logger)
try {
await ledger.connect()
} catch (e) {
if (e instanceof Error) {
this.error(e.message)
} else {
throw e
}
}
const ledger = await initializeLedger(false, this.logger)

const publicKey = (await client.wallet.getAccountPublicKey({ account: from })).content
.publicKey
Expand Down
13 changes: 2 additions & 11 deletions ironfish-cli/src/commands/wallet/transactions/sign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Flags } from '@oclif/core'
import { IronfishCommand } from '../../../command'
import { RemoteFlags } from '../../../flags'
import * as ui from '../../../ui'
import { Ledger } from '../../../utils/ledger'
import { initializeLedger } from '../../../utils/ledger'
import { renderTransactionDetails, watchTransaction } from '../../../utils/transaction'

export class TransactionsSignCommand extends IronfishCommand {
Expand Down Expand Up @@ -109,16 +109,7 @@ export class TransactionsSignCommand extends IronfishCommand {
}

private async signWithLedger(client: RpcClient, unsignedTransaction: string) {
const ledger = new Ledger(this.logger)
try {
await ledger.connect()
} catch (e) {
if (e instanceof Error) {
this.error(e.message)
} else {
throw e
}
}
const ledger = await initializeLedger(false, this.logger)

const signature = (await ledger.sign(unsignedTransaction)).toString('hex')

Expand Down
Loading

0 comments on commit 5ee43cf

Please sign in to comment.