Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Ledgerjs and Trezor Connect #190

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
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
6 changes: 3 additions & 3 deletions docs/message-signing.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ This example demonstrates how to sign a message. See [CIP-8](https://github.com/
## Requirements

Message signing support:
<!-- TODO update versions -->
* on Ledger, Cardano app version TBD and above
* on Trezor, firmware TBD and above
* on Ledger, Cardano app version 7.1.0 and above
* on Trezor, message signing is not supported yet
<!-- TODO update this when available on Trezor -->

## Sign a message

Expand Down
12 changes: 5 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "cardano-hw-cli",
"version": "1.16.0-rc.1",
"commit": "2706bbbd672f8318dcd2ee95682259f3537590b1",
"version": "1.17.0",
"commit": "5d40c27ee1fc20d2ce79cade0cf3298fa4f8979c",
"description": "Cardano CLI tool for hardware wallets",
"author": "Vacuumlabs",
"homepage": "https://github.com/vacuumlabs/cardano-hw-cli#readme",
Expand Down Expand Up @@ -36,11 +36,11 @@
"pkg": "pkg"
},
"dependencies": {
"@cardano-foundation/ledgerjs-hw-app-cardano": "https://github.com/vacuumlabs/ledgerjs-cardano-shelley/releases/download/v7.1.1/cardano-foundation-ledgerjs-hw-app-cardano-v7.1.1.tgz",
"@cardano-foundation/ledgerjs-hw-app-cardano": "7.1.3",
"@emurgo/cardano-serialization-lib-nodejs": "^8.0.0",
"@ledgerhq/hw-transport": "^6.27.10",
"@ledgerhq/hw-transport-node-hid-noevents": "^6.24.1",
"@trezor/connect": "https://github.com/vacuumlabs/trezor-suite/releases/download/cardano-message-signing-rc2/trezor-connect-message-signing-rc2.tgz",
"@trezor/connect": "9.4.5",
"argparse": "^2.0.1",
"bignumber": "^1.1.0",
"cardano-crypto.js": "^6.1.2",
Expand Down Expand Up @@ -82,8 +82,6 @@
},
"resolutions": {
"//": "This is a workaround for pkg (otherwise, it prints an error when building)",
"node-abi": "^3.24.0",
"@trezor/protobuf": "https://github.com/vacuumlabs/trezor-suite/releases/download/cardano-message-signing-rc2/trezor-protobuf-message-signing-rc2.tgz",
"@trezor/transport": "https://github.com/vacuumlabs/trezor-suite/releases/download/cardano-message-signing-rc2/trezor-transport-message-signing-rc2.tgz"
"node-abi": "^3.24.0"
}
}
2 changes: 2 additions & 0 deletions src/commandExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ const promiseTimeout = <T>(promise: Promise<T>, ms: number): Promise<T> => {
const getCryptoProvider = async (): Promise<CryptoProvider> => {
const ledgerPromise = async () =>
LedgerCryptoProvider(await TransportNodeHid.create())
// if you want to test with speculos, you can use this temporarily:
// LedgerCryptoProvider(await require('@ledgerhq/hw-transport-node-speculos').default.open({apduPort: 9999}))
const trezorPromise = async () => await TrezorCryptoProvider()
const cryptoProviderPromise = Promise.any([ledgerPromise(), trezorPromise()])

Expand Down
243 changes: 117 additions & 126 deletions src/crypto-providers/trezorCryptoProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -359,31 +359,30 @@ export const TrezorCryptoProvider: () => Promise<CryptoProvider> = async () => {
}
}

// TODO uncomment when official Connect build is released
// const prepareDRep = (dRep: TxTypes.DRep): TrezorTypes.CardanoDRep => {
// switch (dRep.type) {
// case TxTypes.DRepType.KEY_HASH:
// return {
// type: TrezorEnums.CardanoDRepType.KEY_HASH,
// keyHash: dRep.keyHash.toString('hex'),
// }
// case TxTypes.DRepType.SCRIPT_HASH:
// return {
// type: TrezorEnums.CardanoDRepType.SCRIPT_HASH,
// scriptHash: dRep.scriptHash.toString('hex'),
// }
// case TxTypes.DRepType.ABSTAIN:
// return {
// type: TrezorEnums.CardanoDRepType.ABSTAIN,
// }
// case TxTypes.DRepType.NO_CONFIDENCE:
// return {
// type: TrezorEnums.CardanoDRepType.NO_CONFIDENCE,
// }
// default:
// throw Error(Errors.Unreachable)
// }
// }
const prepareDRep = (dRep: TxTypes.DRep): TrezorTypes.CardanoDRep => {
switch (dRep.type) {
case TxTypes.DRepType.KEY_HASH:
return {
type: TrezorEnums.CardanoDRepType.KEY_HASH,
keyHash: dRep.keyHash.toString('hex'),
}
case TxTypes.DRepType.SCRIPT_HASH:
return {
type: TrezorEnums.CardanoDRepType.SCRIPT_HASH,
scriptHash: dRep.scriptHash.toString('hex'),
}
case TxTypes.DRepType.ABSTAIN:
return {
type: TrezorEnums.CardanoDRepType.ABSTAIN,
}
case TxTypes.DRepType.NO_CONFIDENCE:
return {
type: TrezorEnums.CardanoDRepType.NO_CONFIDENCE,
}
default:
throw Error(Errors.Unreachable)
}
}

const prepareStakeKeyRegistrationCert = (
cert: TxTypes.StakeRegistrationCertificate,
Expand All @@ -394,16 +393,15 @@ export const TrezorCryptoProvider: () => Promise<CryptoProvider> = async () => {
...prepareCredential(cert.stakeCredential, stakeSigningFiles, signingMode),
})

// TODO uncomment when official Connect build is released
// const prepareStakeKeyRegistrationConwayCert = (
// cert: TxTypes.StakeRegistrationConwayCertificate,
// stakeSigningFiles: HwSigningData[],
// signingMode: SigningMode,
// ): TrezorTypes.CardanoCertificate => ({
// type: TrezorEnums.CardanoCertificateType.STAKE_REGISTRATION_CONWAY,
// ...prepareCredential(cert.stakeCredential, stakeSigningFiles, signingMode),
// deposit: `${cert.deposit}`,
// })
const prepareStakeKeyRegistrationConwayCert = (
cert: TxTypes.StakeRegistrationConwayCertificate,
stakeSigningFiles: HwSigningData[],
signingMode: SigningMode,
): TrezorTypes.CardanoCertificate => ({
type: TrezorEnums.CardanoCertificateType.STAKE_REGISTRATION_CONWAY,
...prepareCredential(cert.stakeCredential, stakeSigningFiles, signingMode),
deposit: `${cert.deposit}`,
})

const prepareStakeKeyDeregistrationCert = (
cert: TxTypes.StakeDeregistrationCertificate,
Expand All @@ -414,16 +412,15 @@ export const TrezorCryptoProvider: () => Promise<CryptoProvider> = async () => {
...prepareCredential(cert.stakeCredential, stakeSigningFiles, signingMode),
})

// TODO uncomment when official Connect build is released
// const prepareStakeKeyDeregistrationConwayCert = (
// cert: TxTypes.StakeDeregistrationConwayCertificate,
// stakeSigningFiles: HwSigningData[],
// signingMode: SigningMode,
// ): TrezorTypes.CardanoCertificate => ({
// type: TrezorEnums.CardanoCertificateType.STAKE_DEREGISTRATION_CONWAY,
// ...prepareCredential(cert.stakeCredential, stakeSigningFiles, signingMode),
// deposit: `${cert.deposit}`,
// })
const prepareStakeKeyDeregistrationConwayCert = (
cert: TxTypes.StakeDeregistrationConwayCertificate,
stakeSigningFiles: HwSigningData[],
signingMode: SigningMode,
): TrezorTypes.CardanoCertificate => ({
type: TrezorEnums.CardanoCertificateType.STAKE_DEREGISTRATION_CONWAY,
...prepareCredential(cert.stakeCredential, stakeSigningFiles, signingMode),
deposit: `${cert.deposit}`,
})

const prepareDelegationCert = (
cert: TxTypes.StakeDelegationCertificate,
Expand All @@ -435,16 +432,15 @@ export const TrezorCryptoProvider: () => Promise<CryptoProvider> = async () => {
pool: cert.poolKeyHash.toString('hex'),
})

// TODO uncomment when official Connect build is released
// const prepareVoteDelegationCert = (
// cert: TxTypes.VoteDelegationCertificate,
// signingFiles: HwSigningData[],
// signingMode: SigningMode,
// ): TrezorTypes.CardanoCertificate => ({
// type: TrezorEnums.CardanoCertificateType.VOTE_DELEGATION,
// ...prepareCredential(cert.stakeCredential, signingFiles, signingMode),
// dRep: prepareDRep(cert.dRep),
// })
const prepareVoteDelegationCert = (
cert: TxTypes.VoteDelegationCertificate,
signingFiles: HwSigningData[],
signingMode: SigningMode,
): TrezorTypes.CardanoCertificate => ({
type: TrezorEnums.CardanoCertificateType.VOTE_DELEGATION,
...prepareCredential(cert.stakeCredential, signingFiles, signingMode),
dRep: prepareDRep(cert.dRep),
})

const preparePoolOwners = (
owners: Buffer[],
Expand Down Expand Up @@ -530,39 +526,36 @@ export const TrezorCryptoProvider: () => Promise<CryptoProvider> = async () => {
stakeSigningFiles,
signingMode,
)
// TODO uncomment when official Connect build is released
// case TxTypes.CertificateType.STAKE_REGISTRATION_CONWAY:
// return prepareStakeKeyRegistrationConwayCert(
// certificate,
// stakeSigningFiles,
// signingMode,
// )
case TxTypes.CertificateType.STAKE_REGISTRATION_CONWAY:
return prepareStakeKeyRegistrationConwayCert(
certificate,
stakeSigningFiles,
signingMode,
)
case TxTypes.CertificateType.STAKE_DEREGISTRATION:
return prepareStakeKeyDeregistrationCert(
certificate,
stakeSigningFiles,
signingMode,
)
// TODO uncomment when official Connect build is released
// case TxTypes.CertificateType.STAKE_DEREGISTRATION_CONWAY:
// return prepareStakeKeyDeregistrationConwayCert(
// certificate,
// stakeSigningFiles,
// signingMode,
// )
case TxTypes.CertificateType.STAKE_DEREGISTRATION_CONWAY:
return prepareStakeKeyDeregistrationConwayCert(
certificate,
stakeSigningFiles,
signingMode,
)
case TxTypes.CertificateType.STAKE_DELEGATION:
return prepareDelegationCert(
certificate,
stakeSigningFiles,
signingMode,
)
// TODO uncomment when official Connect build is released
// case TxTypes.CertificateType.VOTE_DELEGATION:
// return prepareVoteDelegationCert(
// certificate,
// stakeSigningFiles,
// signingMode,
// )
case TxTypes.CertificateType.VOTE_DELEGATION:
return prepareVoteDelegationCert(
certificate,
stakeSigningFiles,
signingMode,
)
case TxTypes.CertificateType.POOL_REGISTRATION:
return prepareStakePoolRegistrationCert(certificate, stakeSigningFiles)

Expand Down Expand Up @@ -801,13 +794,7 @@ export const TrezorCryptoProvider: () => Promise<CryptoProvider> = async () => {

// the tags are either used everywhere or nowhere,
// so we can just look at the inputs
// TODO uncomment when official Connect build is released
// const tagCborSets = tx.body.inputs.hasTag
if (tx.body.inputs.hasTag) {
throw Error(
'Tagged CBOR sets are not supported for Trezor in this release.',
)
}
const tagCborSets = tx.body.inputs.hasTag

const request: TrezorTypes.CardanoSignTransaction = {
signingMode: signingModeToTrezorType(signingMode),
Expand All @@ -831,8 +818,7 @@ export const TrezorCryptoProvider: () => Promise<CryptoProvider> = async () => {
totalCollateral,
referenceInputs,
derivationType: derivationTypeToTrezorType(derivationType),
// TODO uncomment when official Connect build is released
// tagCborSets,
tagCborSets,
}

const response = await TrezorConnect.cardanoSignTransaction(request)
Expand Down Expand Up @@ -1003,6 +989,7 @@ export const TrezorCryptoProvider: () => Promise<CryptoProvider> = async () => {
throw Error(Errors.UnsupportedCryptoProviderCall)
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const prepareAddressFieldData = (
args: ParsedSignMessageArguments,
): [TrezorTypes.CardanoAddressParameters, Network] => {
Expand Down Expand Up @@ -1086,49 +1073,53 @@ export const TrezorCryptoProvider: () => Promise<CryptoProvider> = async () => {
}

const signMessage = async (
// eslint-disable-next-line @typescript-eslint/no-unused-vars,
args: ParsedSignMessageArguments,
// eslint-disable-next-line require-await
): Promise<SignedMessageData> => {
let request: TrezorTypes.CardanoSignMessage = {
signingPath: args.hwSigningFileData.path,
hashPayload: args.hashPayload,
payload: args.messageHex,
preferHexDisplay: args.preferHexDisplay,
derivationType: derivationTypeToTrezorType(args.derivationType),
}
if (args.address !== undefined) {
const [addressFieldData, network] = prepareAddressFieldData(args)
request = {
...request,
addressParameters: addressFieldData,
networkId: network.networkId,
protocolMagic: network.protocolMagic,
}
}

const response = await TrezorConnect.cardanoSignMessage(request)
if (!response.success) {
throw Error(response.payload.error)
}

if (args.address !== undefined) {
const addressCli = bech32.decode(args.address).data as Buffer
const addressFieldHex = response.payload.headers.protected.address
if (addressCli.toString('hex') !== addressFieldHex) {
throw Error(Errors.MessageAddressMismatchError)
}
}
const pubKey = splitXPubKeyCborHex(
args.hwSigningFileData.cborXPubKeyHex,
).pubKey
if (pubKey.toString('hex') !== response.payload.pubKey) {
throw Error(Errors.SigningPubKeyMismatchError)
}

return {
addressFieldHex: response.payload.headers.protected.address as HexString,
signatureHex: response.payload.signature as HexString,
signingPublicKeyHex: response.payload.pubKey as HexString,
}
// TODO uncomment when message signing is merged in Trezor Connect
throw Error(Errors.UnsupportedCryptoProviderCall)
// let request: TrezorTypes.CardanoSignMessage = {
// signingPath: args.hwSigningFileData.path,
// hashPayload: args.hashPayload,
// payload: args.messageHex,
// preferHexDisplay: args.preferHexDisplay,
// derivationType: derivationTypeToTrezorType(args.derivationType),
// }
// if (args.address !== undefined) {
// const [addressFieldData, network] = prepareAddressFieldData(args)
// request = {
// ...request,
// addressParameters: addressFieldData,
// networkId: network.networkId,
// protocolMagic: network.protocolMagic,
// }
// }

// const response = await TrezorConnect.cardanoSignMessage(request)
// if (!response.success) {
// throw Error(response.payload.error)
// }

// if (args.address !== undefined) {
// const addressCli = bech32.decode(args.address).data as Buffer
// const addressFieldHex = response.payload.headers.protected.address
// if (addressCli.toString('hex') !== addressFieldHex) {
// throw Error(Errors.MessageAddressMismatchError)
// }
// }
// const pubKey = splitXPubKeyCborHex(
// args.hwSigningFileData.cborXPubKeyHex,
// ).pubKey
// if (pubKey.toString('hex') !== response.payload.pubKey) {
// throw Error(Errors.SigningPubKeyMismatchError)
// }

// return {
// addressFieldHex: response.payload.headers.protected.address as HexString,
// signatureHex: response.payload.signature as HexString,
// signingPublicKeyHex: response.payload.pubKey as HexString,
// }
}

const nativeScriptToTrezorTypes = (
Expand Down
Loading