├── .nvmrc ├── .prettierignore ├── tsconfig.json ├── src ├── tsconfig.json ├── signMessage │ └── signMessage.ts ├── opCert │ └── opCert.ts ├── util.ts ├── transaction │ ├── txTypes.ts │ ├── transaction.ts │ └── transactionValidation.ts ├── command-parser │ ├── commandParser.ts │ └── argTypes.ts ├── crypto-providers │ └── cryptoProvider.ts ├── index.ts ├── guards.ts ├── constants.ts ├── basicTypes.ts └── errors.ts ├── .gitignore ├── test ├── unit │ ├── commandParser │ │ └── res │ │ │ ├── vote.pub │ │ │ ├── payment.addr │ │ │ ├── tx.hwsfile │ │ │ ├── payment2.hwsfile │ │ │ ├── kes.vkey │ │ │ ├── cip36Vote.vkey │ │ │ ├── cold.counter │ │ │ ├── cold.hwsfile │ │ │ ├── cip36VoteExtended.vkey │ │ │ ├── payment.hwsfile │ │ │ ├── stake.hwsfile │ │ │ ├── cip36Vote.hwsfile │ │ │ ├── tx.raw │ │ │ ├── tx.signed │ │ │ └── nested.script │ ├── transactionValidation │ │ └── cli │ │ │ ├── valid.raw │ │ │ ├── fixable.raw │ │ │ ├── parse-error.raw │ │ │ ├── unfixable.raw │ │ │ └── fixable.signed │ ├── util.ts │ ├── output │ │ ├── keyGenOutput.ts │ │ └── signMessageOutput.ts │ └── cryptoProviders │ │ └── ledger.ts └── integration │ ├── keystone │ ├── cli │ │ ├── scriptFiles │ │ │ ├── invalid_before.script │ │ │ ├── invalid_hereafter.script │ │ │ ├── pubkey.script │ │ │ ├── all.script │ │ │ ├── any.script │ │ │ └── n_of_k.script │ │ ├── keyFiles │ │ │ ├── stake.vkey │ │ │ ├── payment.vkey │ │ │ ├── cold.vkey │ │ │ ├── stake.hwsfile │ │ │ └── payment.hwsfile │ │ ├── opCert │ │ │ ├── kes.vkey │ │ │ └── cold.counter │ │ └── txsFiles │ │ │ ├── simpleTx │ │ │ ├── witness.out │ │ │ ├── tx.raw │ │ │ └── tx.signed │ │ │ ├── simpleConwayEraTx │ │ │ ├── witness.out │ │ │ ├── tx.raw │ │ │ └── tx.signed │ │ │ ├── withPoolRegAndMultiAsset │ │ │ ├── tx.witness │ │ │ └── tx.raw │ │ │ ├── simpleTxWithEmptyScriptWitnesses │ │ │ ├── tx.raw │ │ │ └── tx.signed │ │ │ ├── withMetaData │ │ │ ├── tx.raw │ │ │ └── tx.signed │ │ │ ├── multiAssetTX │ │ │ ├── tx.raw │ │ │ └── tx.signed │ │ │ ├── validityIntervalTx │ │ │ ├── tx.raw │ │ │ └── tx.signed │ │ │ └── multiAssetMultiInputAndOutput │ │ │ ├── tx.raw │ │ │ └── tx.signed │ ├── README.md │ └── node │ │ ├── addresses.ts │ │ ├── opCert.ts │ │ ├── signMessage.ts │ │ ├── conway_era_tx.ts │ │ ├── nativeScripts.ts │ │ └── signingFiles.ts │ ├── ledger │ ├── cli │ │ ├── scriptFiles │ │ │ ├── invalid_before.script │ │ │ ├── invalid_hereafter.script │ │ │ ├── pubkey.script │ │ │ ├── all.script │ │ │ ├── any.script │ │ │ └── n_of_k.script │ │ ├── keyFiles │ │ │ ├── stake.vkey │ │ │ ├── payment.vkey │ │ │ ├── cold.vkey │ │ │ ├── stake.hwsfile │ │ │ ├── payment.hwsfile │ │ │ └── byron_payment.hwsfile │ │ ├── opCert │ │ │ ├── kes.vkey │ │ │ └── cold.counter │ │ └── txsFiles │ │ │ ├── simpleTx │ │ │ ├── witness.out │ │ │ ├── tx.raw │ │ │ └── tx.signed │ │ │ ├── withPoolRegAndMultiAsset │ │ │ ├── tx.witness │ │ │ └── tx.raw │ │ │ ├── simpleTxWithEmptyScriptWitnesses │ │ │ ├── tx.raw │ │ │ └── tx.signed │ │ │ ├── withMetaData │ │ │ ├── tx.raw │ │ │ └── tx.signed │ │ │ ├── multiAssetTX │ │ │ ├── tx.raw │ │ │ └── tx.signed │ │ │ ├── validityIntervalTx │ │ │ ├── tx.raw │ │ │ └── tx.signed │ │ │ └── multiAssetMultiInputAndOutput │ │ │ ├── tx.raw │ │ │ └── tx.signed │ └── node │ │ ├── speculos.ts │ │ ├── addresses.ts │ │ ├── opCert.ts │ │ ├── signMessage.ts │ │ ├── nativeScripts.ts │ │ └── cip36Registration.ts │ └── trezor │ ├── cli │ ├── keyFiles │ │ ├── stake.vkey │ │ ├── payment.vkey │ │ ├── stake.hwsfile │ │ ├── byron_payment.hwsfile │ │ └── payment.hwsfile │ └── txsFiles │ │ ├── testnetTX │ │ ├── witness.out │ │ ├── tx.raw │ │ └── tx.signed │ │ ├── simpleWithMultipleInputsAndOutputs │ │ ├── witness.out │ │ ├── tx.raw │ │ └── tx.signed │ │ ├── validityIntervalStartTx │ │ ├── tx.raw │ │ └── tx.signed │ │ ├── deregTx │ │ ├── tx.raw │ │ └── tx.signed │ │ ├── withdrawalTx │ │ ├── tx.raw │ │ └── tx.signed │ │ ├── withMetaData │ │ ├── tx.raw │ │ └── tx.signed │ │ ├── delegationTx │ │ ├── tx.raw │ │ └── tx.signed │ │ ├── simpleTx │ │ ├── tx.signed │ │ ├── witness.out │ │ └── tx.raw │ │ ├── multiAssetTx │ │ ├── tx.raw │ │ └── tx.signed │ │ └── regAndDelegTx │ │ ├── tx.raw │ │ └── tx.signed │ └── node │ ├── addresses.ts │ ├── signMessage.ts │ ├── signingFiles.ts │ └── cip36Registration.ts ├── .prettierrc.js ├── scripts ├── build-common.sh ├── build-all.sh ├── build-windows.sh ├── build-macos.sh ├── build-linux-x64-tar-gz.sh ├── build-linux-arm64-tar-gz.sh ├── build-linux-deb-package.sh ├── fix-trezor-firmware.js └── autocomplete.sh ├── docs ├── data │ ├── datum-equals-redeemer-v2.plutus │ └── datum-equals-redeemer.plutus ├── public-keys-bulk-export-example.md ├── message-signing.md ├── code-structure.md ├── installation-macos-autocomplete.md ├── spellchecking.md ├── installation.md ├── plutus-babbage-transactions.md ├── delegation-example.md ├── transaction-example.md └── cip36-registration-example.md ├── tsconfig.base.json ├── .circleci └── config.yml ├── .cspell.json ├── .eslintrc.js └── package.json /.nvmrc: -------------------------------------------------------------------------------- 1 | 18.7.0 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .eslintrc.js 2 | README.md 3 | docs 4 | .vscode 5 | .circleci 6 | dist/ 7 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base", 3 | "include": ["./**/*.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.base", 3 | "include": ["./**/*.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist 3 | /build/* 4 | !/build/dependencies 5 | .vscode 6 | .idea 7 | .DS_Store -------------------------------------------------------------------------------- /test/unit/commandParser/res/vote.pub: -------------------------------------------------------------------------------- 1 | ed25519_pk18dqzv5g3mzanc0rq3k2m8g9lsdrp4n3j67fnv4u6ryum82k3czmsundxry -------------------------------------------------------------------------------- /test/integration/keystone/cli/scriptFiles/invalid_before.script: -------------------------------------------------------------------------------- 1 | { 2 | "type": "after", 3 | "slot": 100 4 | } 5 | -------------------------------------------------------------------------------- /test/integration/ledger/cli/scriptFiles/invalid_before.script: -------------------------------------------------------------------------------- 1 | { 2 | "type": "after", 3 | "slot": 100 4 | } 5 | -------------------------------------------------------------------------------- /test/integration/ledger/cli/scriptFiles/invalid_hereafter.script: -------------------------------------------------------------------------------- 1 | { 2 | "type": "before", 3 | "slot": 200 4 | } 5 | -------------------------------------------------------------------------------- /test/integration/keystone/cli/scriptFiles/invalid_hereafter.script: -------------------------------------------------------------------------------- 1 | { 2 | "type": "before", 3 | "slot": 200 4 | } 5 | -------------------------------------------------------------------------------- /test/integration/keystone/README.md: -------------------------------------------------------------------------------- 1 | Support for Keystone is developed and maintained by the Keystone team. https://keyst.one/ 2 | -------------------------------------------------------------------------------- /test/unit/commandParser/res/payment.addr: -------------------------------------------------------------------------------- 1 | addr1qxq0nckg3ekgzuqg7w5p9mvgnd9ym28qh5grlph8xd2z92sj922xhxkn6twlq2wn4q50q352annk3903tj00h45mgfmsl3s9zt -------------------------------------------------------------------------------- /test/integration/ledger/cli/scriptFiles/pubkey.script: -------------------------------------------------------------------------------- 1 | { 2 | "type": "sig", 3 | "keyHash": "14c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f1124" 4 | } 5 | -------------------------------------------------------------------------------- /test/integration/keystone/cli/scriptFiles/pubkey.script: -------------------------------------------------------------------------------- 1 | { 2 | "type": "sig", 3 | "keyHash": "14c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f1124" 4 | } 5 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | bracketSpacing: false, 3 | quoteProps: 'consistent', 4 | semi: false, 5 | singleQuote: true, 6 | trailingComma: 'all', 7 | } 8 | -------------------------------------------------------------------------------- /test/unit/commandParser/res/tx.hwsfile: -------------------------------------------------------------------------------- 1 | { 2 | "type": "placeholder", 3 | "description": "placeholder", 4 | "path": "placeholder", 5 | "cborXPubKeyHex": "placeholder" 6 | } -------------------------------------------------------------------------------- /test/integration/keystone/cli/keyFiles/stake.vkey: -------------------------------------------------------------------------------- 1 | {"type":"StakeVerificationKeyShelley_ed25519","description":"Payment Verification Key","cborHex":"582066610efd336e1137c525937b76511fbcf2a0e6bcf0d340a67bcb39bc870d85e8"} -------------------------------------------------------------------------------- /test/integration/ledger/cli/keyFiles/stake.vkey: -------------------------------------------------------------------------------- 1 | {"type":"StakeVerificationKeyShelley_ed25519","description":"Payment Verification Key","cborHex":"582066610efd336e1137c525937b76511fbcf2a0e6bcf0d340a67bcb39bc870d85e8"} -------------------------------------------------------------------------------- /test/unit/commandParser/res/payment2.hwsfile: -------------------------------------------------------------------------------- 1 | { 2 | "type": "PaymentHWSigningFileShelley_ed25519", 3 | "description": "placeholder", 4 | "path": "1852H/1815H/0H/0/0", 5 | "cborXPubKeyHex": "placeholder" 6 | } -------------------------------------------------------------------------------- /src/signMessage/signMessage.ts: -------------------------------------------------------------------------------- 1 | import {HexString} from '../basicTypes' 2 | 3 | export type SignedMessageData = { 4 | signatureHex: HexString 5 | signingPublicKeyHex: HexString 6 | addressFieldHex: HexString 7 | } 8 | -------------------------------------------------------------------------------- /test/integration/keystone/cli/keyFiles/payment.vkey: -------------------------------------------------------------------------------- 1 | {"type":"PaymentVerificationKeyShelley_ed25519","description":"Payment Verification Key","cborHex":"5820cd2b047d1a803eee059769cffb3dfd0a4b9327e55bc78aa962d9bd4f720db0b2"} -------------------------------------------------------------------------------- /test/integration/ledger/cli/keyFiles/payment.vkey: -------------------------------------------------------------------------------- 1 | {"type":"PaymentVerificationKeyShelley_ed25519","description":"Payment Verification Key","cborHex":"5820cd2b047d1a803eee059769cffb3dfd0a4b9327e55bc78aa962d9bd4f720db0b2"} -------------------------------------------------------------------------------- /scripts/build-common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd ${0%/*} 4 | cd .. 5 | 6 | yarn clean 7 | # --ignore-engines needed because of old node version, can be removed after node update 8 | yarn install --ignore-engines 9 | yarn build-js -------------------------------------------------------------------------------- /test/unit/commandParser/res/kes.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "KesVerificationKey_ed25519_kes_2^6", 3 | "description": "KES Verification Key", 4 | "cborHex": "5820dd90f3ddc4efefeb376dbad809b0f8e35eb5f656a5ceb57afe917f8d99dcd859" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/keystone/cli/opCert/kes.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "KesVerificationKey_ed25519_kes_2^6", 3 | "description": "KES Verification Key", 4 | "cborHex": "5820f70601c4de155e67797e057c07fb768b5590b2241b05ec30235a85b71e2ae858" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/ledger/cli/opCert/kes.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "KesVerificationKey_ed25519_kes_2^6", 3 | "description": "KES Verification Key", 4 | "cborHex": "5820f70601c4de155e67797e057c07fb768b5590b2241b05ec30235a85b71e2ae858" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/trezor/cli/keyFiles/stake.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "StakeVerificationKeyShelley_ed25519", 3 | "description": "Payment Verification Key", 4 | "cborHex": "5820bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e" 5 | } -------------------------------------------------------------------------------- /test/integration/trezor/cli/keyFiles/payment.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "PaymentVerificationKeyShelley_ed25519", 3 | "description": "Payment Verification Key", 4 | "cborHex": "58205d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c1" 5 | } -------------------------------------------------------------------------------- /test/unit/commandParser/res/cip36Vote.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "CIP36VoteVerificationKey_ed25519", 3 | "description": "Hardware CIP36 Vote Verification Key", 4 | "cborHex": "5820aac861247bd24cae705bca1d1c9763f19c19188fb0faf257c50ed69b8157bced" 5 | } -------------------------------------------------------------------------------- /test/integration/ledger/cli/keyFiles/cold.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "StakePoolVerificationKey_ed25519", 3 | "description": "Stake Pool Operator Verification Key", 4 | "cborHex": "58203d7e84dca8b4bc322401a2cc814af7c84d2992a22f99554fe340d7df7910768d" 5 | } 6 | -------------------------------------------------------------------------------- /test/unit/commandParser/res/cold.counter: -------------------------------------------------------------------------------- 1 | { 2 | "type": "NodeOperationalCertificateIssueCounter", 3 | "description": "Next certificate issue number: 2", 4 | "cborHex": "82c2410258203d7e84dca8b4bc322401a2cc814af7c84d2992a22f99554fe340d7df7910768d" 5 | } -------------------------------------------------------------------------------- /test/integration/keystone/cli/keyFiles/cold.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "StakePoolVerificationKey_ed25519", 3 | "description": "Stake Pool Operator Verification Key", 4 | "cborHex": "58203d7e84dca8b4bc322401a2cc814af7c84d2992a22f99554fe340d7df7910768d" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/ledger/cli/scriptFiles/all.script: -------------------------------------------------------------------------------- 1 | { 2 | "type": "all", 3 | "scripts": 4 | [ 5 | { 6 | "type": "sig", 7 | "keyHash": "14c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f1124" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /test/integration/ledger/cli/scriptFiles/any.script: -------------------------------------------------------------------------------- 1 | { 2 | "type": "any", 3 | "scripts": 4 | [ 5 | { 6 | "type": "sig", 7 | "keyHash": "14c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f1124" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /docs/data/datum-equals-redeemer-v2.plutus: -------------------------------------------------------------------------------- 1 | { 2 | "type": "PlutusScriptV2", 3 | "description": "", 4 | "cborHex": "58425840010000332233322222253353004333573466ebc00c00801801440204c98d4c01ccd5ce2481094e6f7420457175616c0000849848800848800480044800480041" 5 | } 6 | -------------------------------------------------------------------------------- /docs/data/datum-equals-redeemer.plutus: -------------------------------------------------------------------------------- 1 | { 2 | "type": "PlutusScriptV1", 3 | "description": "", 4 | "cborHex": "58425840010000332233322222253353004333573466ebc00c00801801440204c98d4c01ccd5ce2481094e6f7420457175616c0000849848800848800480044800480041" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/keystone/cli/opCert/cold.counter: -------------------------------------------------------------------------------- 1 | { 2 | "type": "NodeOperationalCertificateIssueCounter", 3 | "description": "Next certificate issue number: 2", 4 | "cborHex": "82c2410258203d7e84dca8b4bc322401a2cc814af7c84d2992a22f99554fe340d7df7910768d" 5 | } -------------------------------------------------------------------------------- /test/integration/keystone/cli/scriptFiles/all.script: -------------------------------------------------------------------------------- 1 | { 2 | "type": "all", 3 | "scripts": 4 | [ 5 | { 6 | "type": "sig", 7 | "keyHash": "14c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f1124" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /test/integration/keystone/cli/scriptFiles/any.script: -------------------------------------------------------------------------------- 1 | { 2 | "type": "any", 3 | "scripts": 4 | [ 5 | { 6 | "type": "sig", 7 | "keyHash": "14c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f1124" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /test/integration/ledger/cli/opCert/cold.counter: -------------------------------------------------------------------------------- 1 | { 2 | "type": "NodeOperationalCertificateIssueCounter", 3 | "description": "Next certificate issue number: 2", 4 | "cborHex": "82c2410258203d7e84dca8b4bc322401a2cc814af7c84d2992a22f99554fe340d7df7910768d" 5 | } -------------------------------------------------------------------------------- /test/unit/commandParser/res/cold.hwsfile: -------------------------------------------------------------------------------- 1 | {"type":"StakePoolHWSigningFileShelley_ed25519","description":"","path":"1853H/1815H/0H/0H","cborXPubKeyHex":"58403d7e84dca8b4bc322401a2cc814af7c84d2992a22f99554fe340d7df7910768d1e2a47754207da3069f90241fbf3b8742c367e9028e5f3f85ae3660330b4f5b7"} -------------------------------------------------------------------------------- /test/integration/keystone/cli/keyFiles/stake.hwsfile: -------------------------------------------------------------------------------- 1 | {"type":"StakeHWSigningFileShelley_ed25519","description":"","path":"1852H/1815H/0H/2/0","cborXPubKeyHex":"584066610efd336e1137c525937b76511fbcf2a0e6bcf0d340a67bcb39bc870d85e8e977e956d29810dbfbda9c8ea667585982454e401c68578623d4b86bc7eb7b58"} -------------------------------------------------------------------------------- /test/integration/ledger/cli/keyFiles/stake.hwsfile: -------------------------------------------------------------------------------- 1 | {"type":"StakeHWSigningFileShelley_ed25519","description":"","path":"1852H/1815H/0H/2/0","cborXPubKeyHex":"584066610efd336e1137c525937b76511fbcf2a0e6bcf0d340a67bcb39bc870d85e8e977e956d29810dbfbda9c8ea667585982454e401c68578623d4b86bc7eb7b58"} -------------------------------------------------------------------------------- /test/integration/keystone/cli/keyFiles/payment.hwsfile: -------------------------------------------------------------------------------- 1 | {"type":"PaymentHWSigningFileShelley_ed25519","description":"","path":"1852H/1815H/0H/0/0","cborXPubKeyHex":"5840cd2b047d1a803eee059769cffb3dfd0a4b9327e55bc78aa962d9bd4f720db0b2914ba07fb381f23c5c09bce26587bdf359aab7ea8f4192adbf93a38fd893ccea"} -------------------------------------------------------------------------------- /test/integration/ledger/cli/keyFiles/payment.hwsfile: -------------------------------------------------------------------------------- 1 | {"type":"PaymentHWSigningFileShelley_ed25519","description":"","path":"1852H/1815H/0H/0/0","cborXPubKeyHex":"5840cd2b047d1a803eee059769cffb3dfd0a4b9327e55bc78aa962d9bd4f720db0b2914ba07fb381f23c5c09bce26587bdf359aab7ea8f4192adbf93a38fd893ccea"} -------------------------------------------------------------------------------- /test/integration/keystone/cli/scriptFiles/n_of_k.script: -------------------------------------------------------------------------------- 1 | { 2 | "type": "atLeast", 3 | "required": 1, 4 | "scripts": 5 | [ 6 | { 7 | "type": "sig", 8 | "keyHash": "14c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f1124" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /test/integration/ledger/cli/keyFiles/byron_payment.hwsfile: -------------------------------------------------------------------------------- 1 | {"type":"PaymentHWSigningFileShelley_ed25519","description":"","path":"44H/1815H/0H/0/10","cborXPubKeyHex":"584090ca5e64214a03ec975e5097c25b2a49d4ca4988243bc0142b5ada743d80b9d5be68538e05e31dc8fff62a62868c43f229cacbee5c40cbe6493929ad1f0e3cd9"} -------------------------------------------------------------------------------- /test/integration/ledger/cli/scriptFiles/n_of_k.script: -------------------------------------------------------------------------------- 1 | { 2 | "type": "atLeast", 3 | "required": 1, 4 | "scripts": 5 | [ 6 | { 7 | "type": "sig", 8 | "keyHash": "14c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f1124" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /test/integration/ledger/cli/txsFiles/simpleTx/witness.out: -------------------------------------------------------------------------------- 1 | {"type":"TxWitnessByron","description":"","cborHex":"82f7825820cd2b047d1a803eee059769cffb3dfd0a4b9327e55bc78aa962d9bd4f720db0b2584093cbb49246dffb2cb2ca2c18e75039bdb4f80730bb9478045c4b8ef5494145a71bd59a478df4ec0dd22e78c9fc919918f4404115fafb10fa4f218b269d3e220a"} -------------------------------------------------------------------------------- /test/integration/keystone/cli/txsFiles/simpleTx/witness.out: -------------------------------------------------------------------------------- 1 | {"type":"TxWitnessByron","description":"","cborHex":"82f7825820cd2b047d1a803eee059769cffb3dfd0a4b9327e55bc78aa962d9bd4f720db0b2584093cbb49246dffb2cb2ca2c18e75039bdb4f80730bb9478045c4b8ef5494145a71bd59a478df4ec0dd22e78c9fc919918f4404115fafb10fa4f218b269d3e220a"} -------------------------------------------------------------------------------- /test/unit/commandParser/res/cip36VoteExtended.vkey: -------------------------------------------------------------------------------- 1 | { 2 | "type": "CIP36VoteVerificationKey_ed25519", 3 | "description": "Hardware CIP36 Vote Verification Key", 4 | "cborHex": "5840423fa841abf9f7fa8dfa10dacdb6737b27fdb0d9bcd9b95d48cabb53047ab76973dd83b34cb41508cebc007b644129573d3076a82fbba7f7a5192a41047a47ee" 5 | } -------------------------------------------------------------------------------- /test/integration/keystone/cli/txsFiles/simpleConwayEraTx/witness.out: -------------------------------------------------------------------------------- 1 | {"type":"TxWitnessByron","description":"","cborHex":"82f7825820cd2b047d1a803eee059769cffb3dfd0a4b9327e55bc78aa962d9bd4f720db0b2584093cbb49246dffb2cb2ca2c18e75039bdb4f80730bb9478045c4b8ef5494145a71bd59a478df4ec0dd22e78c9fc919918f4404115fafb10fa4f218b269d3e220a"} -------------------------------------------------------------------------------- /test/integration/trezor/cli/txsFiles/testnetTX/witness.out: -------------------------------------------------------------------------------- 1 | { 2 | "type": "TxWitnessShelley", 3 | "description": "", 4 | "cborHex": "82008258203913a8b0e4009fee670ca24735efb7f86d8698bf47f3f144fe1a1a72bba172905840301aa3f378402b4a3f19daa816879b515fa49fc4b0cffcb1574c445b452d46f0011b80da5b9281fcdf400ad4c47a7ff904119b286dad0a8a188c1266a4b68302" 5 | } -------------------------------------------------------------------------------- /test/unit/commandParser/res/payment.hwsfile: -------------------------------------------------------------------------------- 1 | { 2 | "type": "PaymentHWSigningFileShelley_ed25519", 3 | "description": "Hardware wallet extended payment", 4 | "path": "1852H/1815H/0H/0/0", 5 | "cborXPubKeyHex": "58400d94fa4489745249e9cd999c907f2692e0e5c7ac868a960312ed5d480c59f2dc231adc1ee85703f714abe70c6d95f027e76ee947f361cbb72a155ac8cad6d23f" 6 | } -------------------------------------------------------------------------------- /test/unit/commandParser/res/stake.hwsfile: -------------------------------------------------------------------------------- 1 | { 2 | "type": "StakeHWSigningFileShelley_ed25519", 3 | "description": "Stake Hardware Signing File", 4 | "path": "1852H/1815H/0H/2/0", 5 | "cborXPubKeyHex": "584066610efd336e1137c525937b76511fbcf2a0e6bcf0d340a67bcb39bc870d85e8e977e956d29810dbfbda9c8ea667585982454e401c68578623d4b86bc7eb7b58" 6 | } -------------------------------------------------------------------------------- /test/integration/trezor/cli/keyFiles/stake.hwsfile: -------------------------------------------------------------------------------- 1 | { 2 | "type": "StakeHWSigningFileShelley_ed25519", 3 | "description": "Stake Hardware Signing File", 4 | "path": "1852H/1815H/0H/2/0", 5 | "cborXPubKeyHex": "5840bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e413a00f69b7700a96f67c149b7c8eec88afd7f0b9cfb4f86f4c5f1e56296ed90" 6 | } -------------------------------------------------------------------------------- /test/unit/commandParser/res/cip36Vote.hwsfile: -------------------------------------------------------------------------------- 1 | { 2 | "type": "CIP36VoteHWSigningFile_ed25519", 3 | "description": "CIP36 Vote Hardware Signing File", 4 | "path": "1694H/1815H/0H/0/0", 5 | "cborXPubKeyHex": "5840aac861247bd24cae705bca1d1c9763f19c19188fb0faf257c50ed69b8157bcedf23595dd3207b7dde477347fa25d3fd6291c3363df43b54a9cf523d2c7683c10" 6 | } -------------------------------------------------------------------------------- /test/integration/keystone/cli/txsFiles/withPoolRegAndMultiAsset/tx.witness: -------------------------------------------------------------------------------- 1 | { 2 | "type": "TxWitness MaryEra", 3 | "description": "", 4 | "cborHex": "820082582066610efd336e1137c525937b76511fbcf2a0e6bcf0d340a67bcb39bc870d85e85840c04721765227ccf13c595410127070c3b25aa821985f39f1fc15b82db4df05ba2ebc5e7321805c1aac82c8f5704549ac3734c1c80ebe5dfa471809924e1c7207" 5 | } -------------------------------------------------------------------------------- /test/integration/ledger/cli/txsFiles/withPoolRegAndMultiAsset/tx.witness: -------------------------------------------------------------------------------- 1 | { 2 | "type": "TxWitness MaryEra", 3 | "description": "", 4 | "cborHex": "820082582066610efd336e1137c525937b76511fbcf2a0e6bcf0d340a67bcb39bc870d85e85840c04721765227ccf13c595410127070c3b25aa821985f39f1fc15b82db4df05ba2ebc5e7321805c1aac82c8f5704549ac3734c1c80ebe5dfa471809924e1c7207" 5 | } -------------------------------------------------------------------------------- /test/integration/trezor/cli/keyFiles/byron_payment.hwsfile: -------------------------------------------------------------------------------- 1 | { 2 | "type": "PaymentHWSigningFileByron_ed25519", 3 | "description": "Payment Hardware Signing File", 4 | "path": "44H/1815H/0H/0/0", 5 | "cborXPubKeyHex": "5840b90fb812a2268e9569ff1172e8daed1da3dc7e72c7bded7c5bcb7282039f90d5fd8e71c1543de2cdc7f7623130c5f2cceb53549055fa1f5bc88199989e08cce7" 6 | } -------------------------------------------------------------------------------- /test/integration/trezor/cli/keyFiles/payment.hwsfile: -------------------------------------------------------------------------------- 1 | { 2 | "type": "PaymentHWSigningFileShelley_ed25519", 3 | "description": "Payment Hardware Signing File", 4 | "path": "1852H/1815H/0H/0/0", 5 | "cborXPubKeyHex": "58405d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c1f123474e140a2c360b01f0fa66f2f22e2e965a5b07a80358cf75f77abbd66088" 6 | } -------------------------------------------------------------------------------- /test/integration/trezor/cli/txsFiles/simpleWithMultipleInputsAndOutputs/witness.out: -------------------------------------------------------------------------------- 1 | { 2 | "type": "TxWitnessShelley", 3 | "description": "", 4 | "cborHex": "82008258203913a8b0e4009fee670ca24735efb7f86d8698bf47f3f144fe1a1a72bba172905840c93c6205360d09750fcc23e7e8d578411a308e2e9d25853b5d8313ec1ecf97291dd661739eb8b12bb1b90bf34d5035e58cf6602b750da6db07f8baad4cf7140e" 5 | } -------------------------------------------------------------------------------- /test/integration/keystone/cli/txsFiles/simpleConwayEraTx/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx ConwayEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "84a400d9010281825820c9e859524f531fff88cb80bb775d1dc680024628e955b45ca8322d917f64e12600018182581d6052e63f22c5107ed776b70f7b92248b02552fd08f3e747bc7450994411a0108389c021a000281ad031a02ae30b0a0f5f6" 5 | } 6 | 7 | -------------------------------------------------------------------------------- /test/unit/commandParser/res/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx ShelleyEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a40081825820941a33cf9d39bba4102c4eff8bd54efd72cf93e65a023a4475ba48a58fc0de000001818258390114c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c1a002b2b4b021a00029b75031a00a8474ca0f6" 5 | } 6 | -------------------------------------------------------------------------------- /test/unit/transactionValidation/cli/valid.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx MaryEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a40081825820bc8bf52ea894fb8e442fe3eea628be87d0c9a37baef185b70eb00a5c8a849d3b0001818258390180f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b42771a0023583c021a00029b75031a01a3bd8fa0f6" 5 | } 6 | -------------------------------------------------------------------------------- /test/unit/transactionValidation/cli/fixable.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx MaryEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a4009f825820bc8bf52ea894fb8e442fe3eea628be87d0c9a37baef185b70eb00a5c8a849d3b00ff01818258390180f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b42771a0023583c021a00029b75031a01a3bd8fa0f6" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/ledger/cli/txsFiles/simpleTx/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx ShelleyEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a40081825820941a33cf9d39bba4102c4eff8bd54efd72cf93e65a023a4475ba48a58fc0de000001818258390114c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c1a002b2b4b021a00029b75031a00a8474ca0f6" 5 | } 6 | -------------------------------------------------------------------------------- /test/unit/transactionValidation/cli/parse-error.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx MaryEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a4049f825820bc8bf52ea894fb8e442fe3eea628be87d0c9a37baef185b70eb00a5c8a849d3b00ff01818258390180f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b42771a0023583c021a00029b75031a01a3bd8fa0f6" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/keystone/cli/txsFiles/simpleTx/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx ShelleyEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a40081825820941a33cf9d39bba4102c4eff8bd54efd72cf93e65a023a4475ba48a58fc0de000001818258390114c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c1a002b2b4b021a00029b75031a00a8474ca0f6" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/ledger/cli/txsFiles/simpleTxWithEmptyScriptWitnesses/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx MaryEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a300818258202e6d090cf9ea1d422bdb194f9f2c0c8e8f788ff5c17af820b7b8baa447786a9000018182583901724038f8b030597ed190929f13fea3d557138b48c74cafd30d4b6c42876c29f8c45c3fa7d3af0ea45fb2564ace831f70e7d3d5b8c251739a1a002ae090021a0002e630a0f6" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/trezor/cli/txsFiles/testnetTX/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx ShelleyEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a40081825820c8f0d737ca5c647c434fea02759755a404d9915c3bd292bd7443ae9e46f5b7b1000181825839003b04dabe6e473ebffa196a2cee191cba32a25a8dc71f2fa35e74785b5e3b888f476e3634020b43079cf27437aee4432648a7580bc24a7f121b00005af31077b2cf021a00028d31031a0081b320a0f6" 5 | } 6 | -------------------------------------------------------------------------------- /test/unit/transactionValidation/cli/unfixable.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx MaryEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a50081825820bc8bf52ea894fb8e442fe3eea628be87d0c9a37baef185b70eb00a5c8a849d3b0001818258390180f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b42771a0023583c021a00029b75031a01a3bd8f061a01a3bd8fa0f6" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/keystone/cli/txsFiles/simpleTxWithEmptyScriptWitnesses/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx MaryEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a300818258202e6d090cf9ea1d422bdb194f9f2c0c8e8f788ff5c17af820b7b8baa447786a9000018182583901724038f8b030597ed190929f13fea3d557138b48c74cafd30d4b6c42876c29f8c45c3fa7d3af0ea45fb2564ace831f70e7d3d5b8c251739a1a002ae090021a0002e630a0f6" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/trezor/cli/txsFiles/validityIntervalStartTx/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx MaryEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a40081825820371b2d1aa350f3e3ffff8c7dddaa3a218022132d24541cba463292acd51cbbf60101818258390080f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b42771a00493e00021a00030d40081a00868378a0f6" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/trezor/cli/txsFiles/simpleWithMultipleInputsAndOutputs/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx ShelleyEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a4008182582056fad20b5e1786b3e76017b256b56dbe4d677f27da4675f5666b3344add7f330000181825839013fc4aa3daffa8cc5275cd2d095a461c05903bae76aa9a5f7999613c58636aa540280a200e32f45e98013c24218a1a4996504634150dc55381a00211c70021a00029b75031a00c4fab1a0f6" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/trezor/cli/txsFiles/deregTx/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx ShelleyEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a500818258204376ea43c3552cb57197a41428fce00e3c2ec9cff7444e50fe9e3750c279549f0001818258390180f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b42771a0056925e021a0002e06d031a00e37f31048182018200581c122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b4277a0f6" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/trezor/cli/txsFiles/withdrawalTx/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx ShelleyEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a500818258205c38555bbbec0e95cd59cd7df45195e07af73a8dbd08a246bf87a687765d6c590001818258390180f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b42771a003aee4b021a0002eb41031a00e37f3105a1581de1122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b427719d08ca0f6" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/keystone/cli/txsFiles/withMetaData/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx MaryEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a400818258200a0172847d39d5ecb8ed921130415ba01b6c785651b99e9fe969b7837181bf5b0001818258390014c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c1a00e1fb90021a0002e6300758207ad89f0443618428fbf1e9024686a20ee284735a993f9e770896c1a0a8c87014a082a1016763617264616e6f80" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/ledger/cli/txsFiles/withMetaData/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx MaryEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a400818258200a0172847d39d5ecb8ed921130415ba01b6c785651b99e9fe969b7837181bf5b0001818258390014c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c1a00e1fb90021a0002e6300758207ad89f0443618428fbf1e9024686a20ee284735a993f9e770896c1a0a8c87014a082a1016763617264616e6f80" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/trezor/cli/txsFiles/withMetaData/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx ShelleyEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a5008182582008f7b94f631b931ee48bb9c9447f9cc7c366a76ad04b66033cfd3f4ba95740500001818258390080f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b42771a3b97e3d0021a0002e630031a014369d7075820c0523b09bef39412ffd6e9eeb4c4171673821bbe5c06c7e522ecffca8b856eeda0a1016763617264616e6f" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/trezor/cli/txsFiles/delegationTx/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx ShelleyEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a500818258201d7b25ce20ee92aa96b6fba145e8b4a5efdefa7df8fc225477297cf026efadfa0001818258390180f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b42771a00323cdc021a0002e595031a00e37f31048183028200581c122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b4277581c04c60c78417132a195cbb74975346462410f72612952a7c4ade7e438a0f6" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/keystone/cli/txsFiles/simpleTx/tx.signed: -------------------------------------------------------------------------------- 1 | {"type":"TxSignedShelley","description":"","cborHex":"83a40081825820941a33cf9d39bba4102c4eff8bd54efd72cf93e65a023a4475ba48a58fc0de000001818258390114c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c1a002b2b4b021a00029b75031a00a8474ca10081825820cd2b047d1a803eee059769cffb3dfd0a4b9327e55bc78aa962d9bd4f720db0b2584093cbb49246dffb2cb2ca2c18e75039bdb4f80730bb9478045c4b8ef5494145a71bd59a478df4ec0dd22e78c9fc919918f4404115fafb10fa4f218b269d3e220af6"} -------------------------------------------------------------------------------- /test/integration/ledger/cli/txsFiles/simpleTx/tx.signed: -------------------------------------------------------------------------------- 1 | {"type":"TxSignedShelley","description":"","cborHex":"83a40081825820941a33cf9d39bba4102c4eff8bd54efd72cf93e65a023a4475ba48a58fc0de000001818258390114c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c1a002b2b4b021a00029b75031a00a8474ca10081825820cd2b047d1a803eee059769cffb3dfd0a4b9327e55bc78aa962d9bd4f720db0b2584093cbb49246dffb2cb2ca2c18e75039bdb4f80730bb9478045c4b8ef5494145a71bd59a478df4ec0dd22e78c9fc919918f4404115fafb10fa4f218b269d3e220af6"} -------------------------------------------------------------------------------- /test/integration/keystone/cli/txsFiles/simpleConwayEraTx/tx.signed: -------------------------------------------------------------------------------- 1 | {"type":"TxSignedShelley","description":"","cborHex":"83a40081825820941a33cf9d39bba4102c4eff8bd54efd72cf93e65a023a4475ba48a58fc0de000001818258390114c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c1a002b2b4b021a00029b75031a00a8474ca10081825820cd2b047d1a803eee059769cffb3dfd0a4b9327e55bc78aa962d9bd4f720db0b2584093cbb49246dffb2cb2ca2c18e75039bdb4f80730bb9478045c4b8ef5494145a71bd59a478df4ec0dd22e78c9fc919918f4404115fafb10fa4f218b269d3e220af6"} -------------------------------------------------------------------------------- /test/unit/commandParser/res/tx.signed: -------------------------------------------------------------------------------- 1 | { 2 | "type": "TxSignedShelley", 3 | "description": "", 4 | "cborHex": "83a40081825820941a33cf9d39bba4102c4eff8bd54efd72cf93e65a023a4475ba48a58fc0de000001818258390114c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c1a002b2b4b021a00029b75031a00a8474ca10081825820cd2b047d1a803eee059769cffb3dfd0a4b9327e55bc78aa962d9bd4f720db0b2584093cbb49246dffb2cb2ca2c18e75039bdb4f80730bb9478045c4b8ef5494145a71bd59a478df4ec0dd22e78c9fc919918f4404115fafb10fa4f218b269d3e220af6" 5 | } -------------------------------------------------------------------------------- /test/integration/ledger/node/speculos.ts: -------------------------------------------------------------------------------- 1 | const SpeculosTransport = 2 | require('@ledgerhq/hw-transport-node-speculos').default 3 | const TransportNodeHid = 4 | require('@ledgerhq/hw-transport-node-hid-noevents').default 5 | 6 | function shouldUseSpeculos() { 7 | return process.env.LEDGER_TRANSPORT === 'speculos' 8 | } 9 | 10 | async function getTransport() { 11 | return shouldUseSpeculos() 12 | ? await SpeculosTransport.open({apduPort: 9999}) 13 | : await TransportNodeHid.create() 14 | } 15 | 16 | export {shouldUseSpeculos, getTransport} 17 | -------------------------------------------------------------------------------- /test/unit/transactionValidation/cli/fixable.signed: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Tx MaryEra", 3 | "description": "", 4 | "cborHex": "83a4009f825820bc8bf52ea894fb8e442fe3eea628be87d0c9a37baef185b70eb00a5c8a849d3b00ff01818258390180f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b42771a0023583c021a00029b75031a01a3bd8fa100818258205d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c158405bf4d24bca523742d47575af6dd0372dd0ed340e981637135db111cfbba2f598a15e321f4a451911fc387190df96f2ff25726d6a1d5857e41a75d58768c54302f6" 5 | } -------------------------------------------------------------------------------- /test/integration/trezor/cli/txsFiles/simpleTx/tx.signed: -------------------------------------------------------------------------------- 1 | { 2 | "type": "TxSignedShelley", 3 | "description": "", 4 | "cborHex": "83a4008182582066001e24baf17637192d3a91c418cf4ed3c8053e333d0c35bd388deb2fa89c92000181825839013fc4aa3daffa8cc5275cd2d095a461c05903bae76aa9a5f7999613c58636aa540280a200e32f45e98013c24218a1a4996504634150dc55381a002b8a44021a0002b473031a00a2d750a100818258203913a8b0e4009fee670ca24735efb7f86d8698bf47f3f144fe1a1a72bba172905840acd168cc35e98a90297bde0256c95943b37e45b7f571ca871621d4586caa373ec263cf57302ecfc043cd33c251026c49bcf1ce635ac1f2c944be6c6a29f9be09f6" 5 | } -------------------------------------------------------------------------------- /test/integration/trezor/cli/txsFiles/simpleTx/witness.out: -------------------------------------------------------------------------------- 1 | { 2 | "type": "TxSignedShelley", 3 | "description": "", 4 | "cborHex": "83a4008182582066001e24baf17637192d3a91c418cf4ed3c8053e333d0c35bd388deb2fa89c92000181825839013fc4aa3daffa8cc5275cd2d095a461c05903bae76aa9a5f7999613c58636aa540280a200e32f45e98013c24218a1a4996504634150dc55381a002b8a44021a0002b473031a00a2d750a100818258203913a8b0e4009fee670ca24735efb7f86d8698bf47f3f144fe1a1a72bba172905840acd168cc35e98a90297bde0256c95943b37e45b7f571ca871621d4586caa373ec263cf57302ecfc043cd33c251026c49bcf1ce635ac1f2c944be6c6a29f9be09f6" 5 | } -------------------------------------------------------------------------------- /test/integration/keystone/cli/txsFiles/simpleTxWithEmptyScriptWitnesses/tx.signed: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Tx MaryEra", 3 | "description": "", 4 | "cborHex": "83a300818258202e6d090cf9ea1d422bdb194f9f2c0c8e8f788ff5c17af820b7b8baa447786a9000018182583901724038f8b030597ed190929f13fea3d557138b48c74cafd30d4b6c42876c29f8c45c3fa7d3af0ea45fb2564ace831f70e7d3d5b8c251739a1a002ae090021a0002e630a1008182582066e283c52a7f05ca79db5483380597c0bb01abfb5bd8af27d5ed2487875d3b8258404023b019cac0540b4ee3a83d9fbf245173f612de8f26f279c23bac5d3ed9f018c95bd661ab03661da1656678b06ff8151cdda5539a252628afde298a99d26203f6" 5 | } -------------------------------------------------------------------------------- /test/integration/ledger/cli/txsFiles/simpleTxWithEmptyScriptWitnesses/tx.signed: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Tx MaryEra", 3 | "description": "", 4 | "cborHex": "83a300818258202e6d090cf9ea1d422bdb194f9f2c0c8e8f788ff5c17af820b7b8baa447786a9000018182583901724038f8b030597ed190929f13fea3d557138b48c74cafd30d4b6c42876c29f8c45c3fa7d3af0ea45fb2564ace831f70e7d3d5b8c251739a1a002ae090021a0002e630a1008182582066e283c52a7f05ca79db5483380597c0bb01abfb5bd8af27d5ed2487875d3b8258404023b019cac0540b4ee3a83d9fbf245173f612de8f26f279c23bac5d3ed9f018c95bd661ab03661da1656678b06ff8151cdda5539a252628afde298a99d26203f6" 5 | } -------------------------------------------------------------------------------- /test/integration/trezor/cli/txsFiles/testnetTX/tx.signed: -------------------------------------------------------------------------------- 1 | { 2 | "type": "TxSignedShelley", 3 | "description": "", 4 | "cborHex": "83a40081825820c8f0d737ca5c647c434fea02759755a404d9915c3bd292bd7443ae9e46f5b7b1000181825839003b04dabe6e473ebffa196a2cee191cba32a25a8dc71f2fa35e74785b5e3b888f476e3634020b43079cf27437aee4432648a7580bc24a7f121b00005af31077b2cf021a00028d31031a0081b320a100818258203913a8b0e4009fee670ca24735efb7f86d8698bf47f3f144fe1a1a72bba172905840301aa3f378402b4a3f19daa816879b515fa49fc4b0cffcb1574c445b452d46f0011b80da5b9281fcdf400ad4c47a7ff904119b286dad0a8a188c1266a4b68302f6" 5 | } -------------------------------------------------------------------------------- /test/integration/trezor/cli/txsFiles/validityIntervalStartTx/tx.signed: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Tx MaryEra", 3 | "description": "", 4 | "cborHex": "83a40081825820371b2d1aa350f3e3ffff8c7dddaa3a218022132d24541cba463292acd51cbbf60101818258390080f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b42771a00493e00021a00030d40081a00868378a100818258205d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c15840c548f31895c4c79b18eea6b181bf2497d1e00bc19ad059276be46d0999fc4684446cdbb4b958a59f264a7dc5af5a764f0c6abb92b6a72878ffe66c2459e31c01f6" 5 | } -------------------------------------------------------------------------------- /test/integration/keystone/cli/txsFiles/multiAssetTX/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx MaryEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a300818258204592a808e80c8dcd3a5fa3d1ce4d480a97e1c58776190a3f6faad445a77ecc2e0001818258390014c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c821a003b13cfa2581c0b1bda00e69de8d554eeafe22b04541fbb2ff89a61d12049f55ba688a14a6669727374617373657404581c95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39a24a66697273746173736574044b7365636f6e64617373657404021a0002e630a0f6" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/ledger/cli/txsFiles/multiAssetTX/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx MaryEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a300818258204592a808e80c8dcd3a5fa3d1ce4d480a97e1c58776190a3f6faad445a77ecc2e0001818258390014c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c821a003b13cfa2581c0b1bda00e69de8d554eeafe22b04541fbb2ff89a61d12049f55ba688a14a6669727374617373657404581c95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39a24a66697273746173736574044b7365636f6e64617373657404021a0002e630a0f6" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/trezor/cli/txsFiles/multiAssetTx/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx MaryEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a30081825820ac9f9da514965a72270f3dea9f401e509a8e8f8af2716e88a182b399adc233c60101818258390080f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b4277821a00958940a2581c0b1bda00e69de8d554eeafe22b04541fbb2ff89a61d12049f55ba688a14a6669727374617373657401581c95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39a24a66697273746173736574014b7365636f6e64617373657401021a00030d40a0f6" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/trezor/cli/txsFiles/regAndDelegTx/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx ShelleyEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a50081825820b25238a1c60ee9e30dd4ce41af5fa78e2cc4e17346bcc47831a3c98c5945370f0001818258390180f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b42771a00352271021a0002eb6d031a00e37f31048282008200581c122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b427783028200581c122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b4277581c04c60c78417132a195cbb74975346462410f72612952a7c4ade7e438a0f6" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/trezor/cli/txsFiles/simpleWithMultipleInputsAndOutputs/tx.signed: -------------------------------------------------------------------------------- 1 | { 2 | "type": "TxSignedShelley", 3 | "description": "", 4 | "cborHex": "83a4008182582056fad20b5e1786b3e76017b256b56dbe4d677f27da4675f5666b3344add7f330000181825839013fc4aa3daffa8cc5275cd2d095a461c05903bae76aa9a5f7999613c58636aa540280a200e32f45e98013c24218a1a4996504634150dc55381a00211c70021a00029b75031a00c4fab1a100818258203913a8b0e4009fee670ca24735efb7f86d8698bf47f3f144fe1a1a72bba17290584092b5173ff7fceefd69940a20e732cde909067faa54e55e7d542afaa946e41fc9aebb93a2310815bfec98f887b86a78708b22414e8b09edcb52e2105d33000005f6" 5 | } -------------------------------------------------------------------------------- /src/opCert/opCert.ts: -------------------------------------------------------------------------------- 1 | import {CborHex} from '../basicTypes' 2 | import {encodeCbor} from '../util' 3 | 4 | export type KesVKey = Buffer 5 | 6 | export type OpCertIssueCounter = { 7 | counter: bigint 8 | poolColdKey: Buffer 9 | } 10 | 11 | export type SignedOpCertCborHex = CborHex 12 | 13 | export const OpCertSigned = ( 14 | kesVKey: KesVKey, 15 | kesPeriod: bigint, 16 | issueCounter: OpCertIssueCounter, 17 | signature: Buffer, 18 | ): SignedOpCertCborHex => 19 | encodeCbor([ 20 | [kesVKey, issueCounter.counter, kesPeriod, signature], 21 | issueCounter.poolColdKey, 22 | ]).toString('hex') 23 | -------------------------------------------------------------------------------- /test/integration/keystone/cli/txsFiles/validityIntervalTx/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx MaryEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a5008182582014fee2d6da11448c33c63d3f33eaafa33fbb55523a8e7a59f3454d4ff143f5f60001818258390014c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c821a00382d9fa2581c0b1bda00e69de8d554eeafe22b04541fbb2ff89a61d12049f55ba688a14a6669727374617373657404581c95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39a24a66697273746173736574044b7365636f6e64617373657404021a0002e630031a0097fa40081a0089c970a0f6" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/keystone/node/addresses.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | 3 | const addresses = { 4 | mainnet: { 5 | base0: 6 | 'addr1qy2vzmtlgvjrhkq50rngh8d482zj3l20kyrc6kx4ffl3zfqayfawlf9hwv2fzuygt2km5v92kvf8e3s3mk7ynxw77cwqf7zhh2', 7 | reward0: 'stake1uywjy7h05jmhx9y3wzy94td6xz4txynuccgam0zfn800v8qq33z29', 8 | }, 9 | testnet: { 10 | base0: 11 | 'addr_test1qq2vzmtlgvjrhkq50rngh8d482zj3l20kyrc6kx4ffl3zfqayfawlf9hwv2fzuygt2km5v92kvf8e3s3mk7ynxw77cwq2glhm4', 12 | reward0: 'stake_test1uqwjy7h05jmhx9y3wzy94td6xz4txynuccgam0zfn800v8q8mmqwc', 13 | }, 14 | } 15 | 16 | export {addresses} 17 | -------------------------------------------------------------------------------- /test/integration/ledger/cli/txsFiles/validityIntervalTx/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx MaryEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a5008182582014fee2d6da11448c33c63d3f33eaafa33fbb55523a8e7a59f3454d4ff143f5f60001818258390014c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c821a00382d9fa2581c0b1bda00e69de8d554eeafe22b04541fbb2ff89a61d12049f55ba688a14a6669727374617373657404581c95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39a24a66697273746173736574044b7365636f6e64617373657404021a0002e630031a0097fa40081a0089c970a0f6" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/ledger/node/addresses.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | 3 | const addresses = { 4 | mainnet: { 5 | base0: 6 | 'addr1qy2vzmtlgvjrhkq50rngh8d482zj3l20kyrc6kx4ffl3zfqayfawlf9hwv2fzuygt2km5v92kvf8e3s3mk7ynxw77cwqf7zhh2', 7 | reward0: 'stake1uywjy7h05jmhx9y3wzy94td6xz4txynuccgam0zfn800v8qq33z29', 8 | }, 9 | testnet: { 10 | base0: 11 | 'addr_test1qq2vzmtlgvjrhkq50rngh8d482zj3l20kyrc6kx4ffl3zfqayfawlf9hwv2fzuygt2km5v92kvf8e3s3mk7ynxw77cwq2glhm4', 12 | reward0: 'stake_test1uqwjy7h05jmhx9y3wzy94td6xz4txynuccgam0zfn800v8q8mmqwc', 13 | }, 14 | } 15 | 16 | export {addresses} 17 | -------------------------------------------------------------------------------- /test/integration/trezor/node/addresses.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | 3 | const addresses = { 4 | mainnet: { 5 | base0: 6 | 'addr1qxq0nckg3ekgzuqg7w5p9mvgnd9ym28qh5grlph8xd2z92sj922xhxkn6twlq2wn4q50q352annk3903tj00h45mgfmsl3s9zt', 7 | reward0: 'stake1uyfz49rtntfa9h0s98f6s28sg69weemgjhc4e8hm66d5yacalmqha', 8 | }, 9 | testnet: { 10 | base0: 11 | 'addr_test1qzq0nckg3ekgzuqg7w5p9mvgnd9ym28qh5grlph8xd2z92sj922xhxkn6twlq2wn4q50q352annk3903tj00h45mgfmsu8d9w5', 12 | reward0: 'stake_test1uqfz49rtntfa9h0s98f6s28sg69weemgjhc4e8hm66d5yac643znq', 13 | }, 14 | } 15 | 16 | export {addresses} 17 | -------------------------------------------------------------------------------- /test/integration/ledger/cli/txsFiles/withMetaData/tx.signed: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Tx MaryEra", 3 | "description": "", 4 | "cborHex": "83a400818258200a0172847d39d5ecb8ed921130415ba01b6c785651b99e9fe969b7837181bf5b0001818258390014c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c1a00e1fb90021a0002e6300758207ad89f0443618428fbf1e9024686a20ee284735a993f9e770896c1a0a8c87014a10081825820cd2b047d1a803eee059769cffb3dfd0a4b9327e55bc78aa962d9bd4f720db0b258404cadece6fa2e7bb8a52d7d7e3204e0a0540a28bcd072a0a5ab57967f5d95e3f3b4c11450be7c7b161ed7acef21ec0a11ba645ad7383ed09ea2d112a85da86b0082a1016763617264616e6f80" 5 | } -------------------------------------------------------------------------------- /docs/public-keys-bulk-export-example.md: -------------------------------------------------------------------------------- 1 | ## Generate public verification key and hardware wallet signing file - bulk export 2 | ``` 3 | cardano-hw-cli address key-gen \ 4 | --path 1852H/1815H/0H/0/0 \ 5 | --path 1852H/1815H/0H/0/1 \ 6 | --path 1852H/1815H/0H/0/2 \ 7 | --verification-key-file payment0.vkey \ 8 | --verification-key-file payment1.vkey \ 9 | --verification-key-file payment2.vkey \ 10 | --hw-signing-file payment0.hwsfile \ 11 | --hw-signing-file payment1.hwsfile \ 12 | --hw-signing-file payment2.hwsfile 13 | ``` 14 | Should create 6 files: `payment0.vkey`, `payment1.vkey`, `payment2.vkey`, `payment0.hwsfile`, `payment1.hwsfile`, `payment2.hwsfile`. -------------------------------------------------------------------------------- /test/integration/keystone/cli/txsFiles/withMetaData/tx.signed: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Tx MaryEra", 3 | "description": "", 4 | "cborHex": "83a400818258200a0172847d39d5ecb8ed921130415ba01b6c785651b99e9fe969b7837181bf5b0001818258390014c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c1a00e1fb90021a0002e6300758207ad89f0443618428fbf1e9024686a20ee284735a993f9e770896c1a0a8c87014a10081825820cd2b047d1a803eee059769cffb3dfd0a4b9327e55bc78aa962d9bd4f720db0b258404cadece6fa2e7bb8a52d7d7e3204e0a0540a28bcd072a0a5ab57967f5d95e3f3b4c11450be7c7b161ed7acef21ec0a11ba645ad7383ed09ea2d112a85da86b0082a1016763617264616e6f80" 5 | } -------------------------------------------------------------------------------- /test/integration/trezor/cli/txsFiles/withMetaData/tx.signed: -------------------------------------------------------------------------------- 1 | { 2 | "type": "TxSignedShelley", 3 | "description": "", 4 | "cborHex": "83a5008182582008f7b94f631b931ee48bb9c9447f9cc7c366a76ad04b66033cfd3f4ba95740500001818258390080f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b42771a3b97e3d0021a0002e630031a014369d7075820c0523b09bef39412ffd6e9eeb4c4171673821bbe5c06c7e522ecffca8b856eeda100818258205d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c15840ba50f212c23b818a8a128a6a7affa73412463742207096a48450e8d3124517521b88a83fb400886bc770df13d9c04fef4a1db2f632dacfaf2d55dab35d5e060ea1016763617264616e6f" 5 | } -------------------------------------------------------------------------------- /scripts/build-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd ${0%/*} 4 | cd .. 5 | 6 | ./scripts/build-common.sh 7 | ./scripts/build-linux-deb-package.sh 8 | ./scripts/build-linux-x64-tar-gz.sh 9 | ./scripts/build-linux-arm64-tar-gz.sh 10 | ./scripts/build-windows.sh 11 | ./scripts/build-macos.sh 12 | 13 | rm -R build/release 2> /dev/null 14 | mkdir build/release 15 | 16 | find ./build/linux -name '*.deb' -exec cp {} ./build/release \; 17 | find ./build/linux -name '*.tar.gz' -exec cp {} ./build/release \; 18 | find ./build/macos -name '*.tar.gz' -exec cp {} ./build/release \; 19 | find ./build/windows -name '*.zip' -exec cp {} ./build/release \; 20 | cp ./scripts/autocomplete.sh ./build/release/autocomplete.sh 21 | -------------------------------------------------------------------------------- /test/integration/ledger/cli/txsFiles/multiAssetTX/tx.signed: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Tx MaryEra", 3 | "description": "", 4 | "cborHex": "83a300818258204592a808e80c8dcd3a5fa3d1ce4d480a97e1c58776190a3f6faad445a77ecc2e0001818258390014c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c821a003b13cfa2581c0b1bda00e69de8d554eeafe22b04541fbb2ff89a61d12049f55ba688a14a6669727374617373657404581c95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39a24a66697273746173736574044b7365636f6e64617373657404021a0002e630a10081825820cd2b047d1a803eee059769cffb3dfd0a4b9327e55bc78aa962d9bd4f720db0b2584076d30b08a504b2ecf8de05d195868046ef10c368e489b56f5c5613f111cbe617ccc1fc6adaa0bc78a5dbf3f4857e12afcfc2b80bc9b6bb2427745396003db804f6" 5 | } -------------------------------------------------------------------------------- /test/integration/trezor/cli/txsFiles/multiAssetTx/tx.signed: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Tx MaryEra", 3 | "description": "", 4 | "cborHex": "83a30081825820ac9f9da514965a72270f3dea9f401e509a8e8f8af2716e88a182b399adc233c60101818258390080f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b4277821a00958940a2581c0b1bda00e69de8d554eeafe22b04541fbb2ff89a61d12049f55ba688a14a6669727374617373657401581c95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39a24a66697273746173736574014b7365636f6e64617373657401021a00030d40a100818258205d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c15840dfa1fdf3c3e4c2eb4e6afb9ff4ec5cf9b9ee25016787eac9f22ae5963b35c6c3295064d4ef141d2a68e218553c0a3c282d74cf3d796f42f9dc00d178ec604b04f6" 5 | } -------------------------------------------------------------------------------- /test/integration/keystone/cli/txsFiles/multiAssetTX/tx.signed: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Tx MaryEra", 3 | "description": "", 4 | "cborHex": "83a300818258204592a808e80c8dcd3a5fa3d1ce4d480a97e1c58776190a3f6faad445a77ecc2e0001818258390014c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c821a003b13cfa2581c0b1bda00e69de8d554eeafe22b04541fbb2ff89a61d12049f55ba688a14a6669727374617373657404581c95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39a24a66697273746173736574044b7365636f6e64617373657404021a0002e630a10081825820cd2b047d1a803eee059769cffb3dfd0a4b9327e55bc78aa962d9bd4f720db0b2584076d30b08a504b2ecf8de05d195868046ef10c368e489b56f5c5613f111cbe617ccc1fc6adaa0bc78a5dbf3f4857e12afcfc2b80bc9b6bb2427745396003db804f6" 5 | } -------------------------------------------------------------------------------- /test/integration/ledger/cli/txsFiles/validityIntervalTx/tx.signed: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Tx MaryEra", 3 | "description": "", 4 | "cborHex": "83a5008182582014fee2d6da11448c33c63d3f33eaafa33fbb55523a8e7a59f3454d4ff143f5f60001818258390014c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c821a00382d9fa2581c0b1bda00e69de8d554eeafe22b04541fbb2ff89a61d12049f55ba688a14a6669727374617373657404581c95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39a24a66697273746173736574044b7365636f6e64617373657404021a0002e630031a0097fa40081a0089c970a10081825820cd2b047d1a803eee059769cffb3dfd0a4b9327e55bc78aa962d9bd4f720db0b25840cdd429b33a126763872137283ecceed9d64803e8d70ff499f5b51fa96c0f066259f70a124e728006f4eb7b9f911c25591a77ef6a75244ab80cf46ac4d5b53305f6" 5 | } -------------------------------------------------------------------------------- /test/integration/keystone/cli/txsFiles/validityIntervalTx/tx.signed: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Tx MaryEra", 3 | "description": "", 4 | "cborHex": "83a5008182582014fee2d6da11448c33c63d3f33eaafa33fbb55523a8e7a59f3454d4ff143f5f60001818258390014c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c821a00382d9fa2581c0b1bda00e69de8d554eeafe22b04541fbb2ff89a61d12049f55ba688a14a6669727374617373657404581c95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39a24a66697273746173736574044b7365636f6e64617373657404021a0002e630031a0097fa40081a0089c970a10081825820cd2b047d1a803eee059769cffb3dfd0a4b9327e55bc78aa962d9bd4f720db0b25840cdd429b33a126763872137283ecceed9d64803e8d70ff499f5b51fa96c0f066259f70a124e728006f4eb7b9f911c25591a77ef6a75244ab80cf46ac4d5b53305f6" 5 | } -------------------------------------------------------------------------------- /src/util.ts: -------------------------------------------------------------------------------- 1 | import {Encoder} from 'cbor' 2 | 3 | const cbor = require('cbor') 4 | 5 | // we use cardano-hw-interop-lib for transaction decoding & encoding 6 | // these functions should be used only for the other simple stuff (eg. keys, ...) 7 | export const decodeCbor = cbor.decode 8 | 9 | export const encodeCbor = (value: unknown) => { 10 | const enc = new Encoder({collapseBigIntegers: true}) 11 | enc.pushAny(value) 12 | return enc.read() 13 | } 14 | 15 | export const partition = ( 16 | array: T[], 17 | predicate: (t: T) => boolean, 18 | ): [T[], T[]] => [array.filter(predicate), array.filter((t) => !predicate(t))] 19 | 20 | export const invertObject = (obj: { 21 | [key: string]: string 22 | }): {[key: string]: string} => 23 | Object.fromEntries(Object.entries(obj).map(([k, v]) => [v, k])) 24 | -------------------------------------------------------------------------------- /test/integration/ledger/cli/txsFiles/multiAssetMultiInputAndOutput/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx MaryEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a50082825820a2218c7738c374fa68fed428bf28447f550c3c33cb92a5bd06e2b62f3777953900825820ade4616f96066ab24f49dcd4adbcae9ae83750d34e4620a49d737d4a66835d6400018282583900bf63a166d9c10d85e4fd3401de03907e232e7707218c3bfd5a570d7acab53e9efebb49bafb4e74d675c2d682dd8e402f15885fb6d1bc0023821a0095b050a2581c0b1bda00e69de8d554eeafe22b04541fbb2ff89a61d12049f55ba688a14a6669727374617373657404581c95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39a24a66697273746173736574044b7365636f6e646173736574048258390014c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c1a0035476f021a0002e630031a0097fa40081a0089c970a0f6" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/keystone/cli/txsFiles/multiAssetMultiInputAndOutput/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx MaryEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a50082825820a2218c7738c374fa68fed428bf28447f550c3c33cb92a5bd06e2b62f3777953900825820ade4616f96066ab24f49dcd4adbcae9ae83750d34e4620a49d737d4a66835d6400018282583900bf63a166d9c10d85e4fd3401de03907e232e7707218c3bfd5a570d7acab53e9efebb49bafb4e74d675c2d682dd8e402f15885fb6d1bc0023821a0095b050a2581c0b1bda00e69de8d554eeafe22b04541fbb2ff89a61d12049f55ba688a14a6669727374617373657404581c95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39a24a66697273746173736574044b7365636f6e646173736574048258390014c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c1a0035476f021a0002e630031a0097fa40081a0089c970a0f6" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/trezor/cli/txsFiles/deregTx/tx.signed: -------------------------------------------------------------------------------- 1 | { 2 | "type": "TxSignedShelley", 3 | "description": "", 4 | "cborHex": "83a500818258204376ea43c3552cb57197a41428fce00e3c2ec9cff7444e50fe9e3750c279549f0001818258390180f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b42771a0056925e021a0002e06d031a00e37f31048182018200581c122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b4277a10082825820bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e5840efe4b1bbfc0e4ec5aa3b7bb95d61c952bab7f4ab17b99ef197c0b1cb9dafd4b811a1275a56bfac75a1e2e718379487aef49d9f073d132a24ba13491698cef1098258205d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c158400741de2b8807e44f9c8fafc75e8fd44190eddd629d31e5093e2f2c8723bb5df3007ea44d0d242b0ba35b24525782ccbd2e1e7c6bca8b29af744ae88fec635c00f6" 5 | } -------------------------------------------------------------------------------- /test/integration/trezor/cli/txsFiles/withdrawalTx/tx.signed: -------------------------------------------------------------------------------- 1 | { 2 | "type": "TxSignedShelley", 3 | "description": "", 4 | "cborHex": "83a500818258205c38555bbbec0e95cd59cd7df45195e07af73a8dbd08a246bf87a687765d6c590001818258390180f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b42771a003aee4b021a0002eb41031a00e37f3105a1581de1122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b427719d08ca10082825820bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e58400b266bfefe1919673e2aa456b123fdd9bc80ef9f6c948bbc2ad53ca58997ff454a8161d1164e1598255864a27c2ecab3734f9af1a753a24ba0275a72741e130a8258205d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c15840054075f078180eca611201dcf9b6278b2b11389db5a2c841f4e6a5bd62ef6313cfe18c6dd08068878fea764245ed1c63a1e76687899d48849db77c8d9e944e02f6" 5 | } -------------------------------------------------------------------------------- /scripts/build-windows.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This script can be run from linux and executable should be runnable on windows 3 | 4 | cd ${0%/*} 5 | cd .. 6 | 7 | CARDANO_HW_CLI_PACKAGE_VERSION=$(cat package.json | grep version | head -1 | awk -F: '{ print $2 }' | sed 's/[", ]//g') 8 | 9 | # Remove old build 10 | rm -R build/windows 2> /dev/null 11 | 12 | # Prepare directories 13 | mkdir ./build/windows 14 | mkdir ./build/windows/cardano-hw-cli 15 | 16 | # Build executable 17 | yarn pkg ./dist/index.js -o ./build/windows/cardano-hw-cli/cardano-hw-cli -c package.json -t node18-win-x64 --options "no-warnings=ExperimentalWarning" 18 | 19 | # Copy dependencies 20 | cp -R ./build/dependencies/windows/* ./build/windows/cardano-hw-cli/ 21 | 22 | # Archive 23 | cd ./build/windows 24 | zip -r ./cardano-hw-cli-${CARDANO_HW_CLI_PACKAGE_VERSION}_windows-x64.zip ./ 25 | cd ../.. 26 | -------------------------------------------------------------------------------- /test/unit/util.ts: -------------------------------------------------------------------------------- 1 | import assert from 'assert' 2 | import {encodeCbor} from '../../src/util' 3 | 4 | function testCbor(value: unknown, expected: unknown) { 5 | const encoded = encodeCbor(value) 6 | assert.deepStrictEqual(encoded.toString('hex'), expected) 7 | } 8 | 9 | describe('Testing CBOR', () => { 10 | it('Encode into CBOR', () => { 11 | const testCases = [ 12 | [23, '17'], 13 | [23n, '17'], 14 | [24, '1818'], 15 | [24n, '1818'], 16 | [1000, '1903e8'], 17 | [1000n, '1903e8'], 18 | [1000000000000, '1b000000e8d4a51000'], 19 | [1000000000000n, '1b000000e8d4a51000'], 20 | [18446744073709551615n, '1bffffffffffffffff'], 21 | [18446744073709551616n, 'c249010000000000000000'], 22 | ] 23 | 24 | testCases.forEach(([value, expected]) => { 25 | testCbor(value, expected) 26 | }) 27 | }) 28 | }) 29 | -------------------------------------------------------------------------------- /scripts/build-macos.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This script can be run from linux and executable should be runnable on macos 3 | 4 | cd ${0%/*} 5 | cd .. 6 | 7 | CARDANO_HW_CLI_PACKAGE_VERSION=$(cat package.json | grep version | head -1 | awk -F: '{ print $2 }' | sed 's/[", ]//g') 8 | 9 | # Remove old build 10 | rm -R ./build/macos 2> /dev/null 11 | 12 | # Prepare directories 13 | mkdir ./build/macos 2> /dev/null 14 | mkdir ./build/macos/cardano-hw-cli 15 | 16 | # Build executable 17 | yarn pkg ./dist/index.js -o ./build/macos/cardano-hw-cli/cardano-hw-cli -c package.json -t node18-macos --options "no-warnings=ExperimentalWarning" 18 | 19 | # Copy dependencies 20 | cp -R ./build/dependencies/macos/* ./build/macos/cardano-hw-cli/ 21 | 22 | # Archive 23 | cd ./build/macos 24 | tar -czvf ./cardano-hw-cli-${CARDANO_HW_CLI_PACKAGE_VERSION}_mac-x64.tar.gz ./cardano-hw-cli 25 | cd ../.. 26 | -------------------------------------------------------------------------------- /test/integration/trezor/cli/txsFiles/delegationTx/tx.signed: -------------------------------------------------------------------------------- 1 | { 2 | "type": "TxSignedShelley", 3 | "description": "", 4 | "cborHex": "83a500818258201d7b25ce20ee92aa96b6fba145e8b4a5efdefa7df8fc225477297cf026efadfa0001818258390180f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b42771a00323cdc021a0002e595031a00e37f31048183028200581c122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b4277581c04c60c78417132a195cbb74975346462410f72612952a7c4ade7e438a10082825820bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e5840d2addc046794d2ead623e3835b4edc02eba1502771ef145b5634ff63411751a4b63a7580ac9433914cc5e016bbbd23aced51044c479a39cc463cac235ad100038258205d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c158408c09b9f5aaaae2e07389d6101d5ecc4a2c6c33f87adc4ea4ff2a13b8a9128750ff4e67459d23c35aaff94e19d9be9ca8f5bb51245ebcf0d8c85a1ff45a401907f6" 5 | } -------------------------------------------------------------------------------- /scripts/build-linux-x64-tar-gz.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd ${0%/*} 4 | cd .. 5 | 6 | CARDANO_HW_CLI_PACKAGE_VERSION=$(cat package.json | grep version | head -1 | awk -F: '{ print $2 }' | sed 's/[", ]//g') 7 | 8 | # Remove old build 9 | rm -R ./build/linux/archive-x64 2> /dev/null 10 | 11 | # Prepare directories 12 | mkdir ./build/linux 2> /dev/null 13 | mkdir ./build/linux/archive-x64 14 | mkdir ./build/linux/archive-x64/cardano-hw-cli 15 | 16 | # Build executable 17 | yarn pkg ./dist/index.js -o ./build/linux/archive-x64/cardano-hw-cli/cardano-hw-cli -c package.json -t node18-linux-x64 --options "no-warnings=ExperimentalWarning" 18 | 19 | # Copy dependencies 20 | cp -R ./build/dependencies/linux/* ./build/linux/archive-x64/cardano-hw-cli/ 21 | 22 | # Archive 23 | cd ./build/linux/archive-x64 24 | tar -czvf ./cardano-hw-cli-${CARDANO_HW_CLI_PACKAGE_VERSION}_linux-x64.tar.gz ./cardano-hw-cli 25 | cd ../../.. 26 | -------------------------------------------------------------------------------- /scripts/build-linux-arm64-tar-gz.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd ${0%/*} 4 | cd .. 5 | 6 | CARDANO_HW_CLI_PACKAGE_VERSION=$(cat package.json | grep version | head -1 | awk -F: '{ print $2 }' | sed 's/[", ]//g') 7 | 8 | # Remove old build 9 | rm -R ./build/linux/archive-arm64 2> /dev/null 10 | 11 | # Prepare directories 12 | mkdir ./build/linux 2> /dev/null 13 | mkdir ./build/linux/archive-arm64 14 | mkdir ./build/linux/archive-arm64/cardano-hw-cli 15 | 16 | # Build executable 17 | yarn pkg ./dist/index.js -o ./build/linux/archive-arm64/cardano-hw-cli/cardano-hw-cli -c package.json -t node18-linux-arm64 --options "no-warnings=ExperimentalWarning" 18 | 19 | # Copy dependencies 20 | cp -R ./build/dependencies/linux/* ./build/linux/archive-arm64/cardano-hw-cli/ 21 | 22 | # Archive 23 | cd ./build/linux/archive-arm64 24 | tar -czvf ./cardano-hw-cli-${CARDANO_HW_CLI_PACKAGE_VERSION}_linux-arm64.tar.gz ./cardano-hw-cli 25 | cd ../../.. 26 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": false, 4 | "allowSyntheticDefaultImports": true, 5 | "alwaysStrict": true, 6 | "declaration": true, 7 | "declarationMap": true, 8 | "esModuleInterop": true, 9 | "experimentalDecorators": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "inlineSourceMap": true, 12 | "lib": ["es2021"], 13 | "module": "commonjs", 14 | "noImplicitAny": true, 15 | "noImplicitReturns": true, 16 | "noImplicitThis": true, 17 | "noUnusedLocals": false, 18 | "outDir": "dist", 19 | "pretty": true, 20 | "removeComments": false, 21 | "resolveJsonModule": true, 22 | "skipLibCheck": true, 23 | "strict": true, 24 | "strictFunctionTypes": true, 25 | "strictNullChecks": true, 26 | "target": "es2021", 27 | "typeRoots": ["./node_modules/@types", "./types"], 28 | "noErrorTruncation": true, 29 | "baseUrl": "src" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /test/integration/trezor/cli/txsFiles/regAndDelegTx/tx.signed: -------------------------------------------------------------------------------- 1 | { 2 | "type": "TxSignedShelley", 3 | "description": "", 4 | "cborHex": "83a50081825820b25238a1c60ee9e30dd4ce41af5fa78e2cc4e17346bcc47831a3c98c5945370f0001818258390180f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b42771a00352271021a0002eb6d031a00e37f31048282008200581c122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b427783028200581c122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b4277581c04c60c78417132a195cbb74975346462410f72612952a7c4ade7e438a10082825820bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e5840378975f3b728e434471179ed87b8a2041ea478aac2d588ca222a353de3beadae7ecf9c657e62cdb26e9a499dca67fb491386471a119a2b59e17c294ecf7329098258205d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c158406a111389b6bc7b8a8d4e0473f7d8833a4b9d07c28d7c3070e805e2c9ded76140ba77dee65cf4955557bb04e2b58e1c84113f1d20028612cc5fe8fb8b64614e02f6" 5 | } -------------------------------------------------------------------------------- /test/integration/trezor/cli/txsFiles/simpleTx/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx ShelleyEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a500818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7000181825839017cb05fce110fb999f01abb4f62bc455e217d4a51fde909fa9aea545443ac53c046cf6a42095e3c60310fa802771d0672f8fe2d1861138b090102182a030a04818a03581c13381d918ec0283ceeff60f7f4fc21e1540e053ccf8a77307a7a32ad582007821cd344d7fd7e3ae5f2ed863218cb979ff1d59e50c4276bdc479b0d0844501b0000000ba43b74001a1443fd00d81e82031864581de1794d9b3408c9fb67b950a48a0690f070f117e9978f7fc1d120fc58ad82581c122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b4277581c794d9b3408c9fb67b950a48a0690f070f117e9978f7fc1d120fc58ad848400190bb84436e44b9af68400190bb84436e44b9b500178ff2483e3a2330a34c4a5e576c2078301190bb86d616161612e626262622e636f6d82026d616161612e626262632e636f6d82782968747470733a2f2f7777772e76616375756d6c6162732e636f6d2f73616d706c6555726c2e6a736f6e5820cdb714fd722c24aeb10c93dbb0ff03bd4783441cd5ba2a8b6f373390520535bba0f6" 5 | } 6 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | defaults: &defaults 4 | docker: 5 | - image: cimg/node:18.7.0 6 | 7 | commands: 8 | setup: 9 | steps: 10 | - checkout 11 | - run: node --version 12 | - run: sudo apt-get -y update 13 | - run: sudo apt-get -y install libudev-dev libusb-1.0-0-dev 14 | # --ignore-engines needed because of old node version, can be removed after node update 15 | - run: yarn install --ignore-engines 16 | 17 | jobs: 18 | audit: 19 | <<: *defaults 20 | steps: 21 | - setup 22 | - run: yarn audit 23 | 24 | lint: 25 | <<: *defaults 26 | steps: 27 | - setup 28 | - run: yarn prettier:check 29 | - run: yarn spell:check 30 | - run: yarn lint 31 | 32 | build_and_test: 33 | <<: *defaults 34 | steps: 35 | - setup 36 | - run: yarn build-js 37 | - run: yarn test-unit 38 | - run: yarn test-bin 39 | 40 | workflows: 41 | version: 2 42 | all: 43 | jobs: 44 | - audit 45 | - lint 46 | - build_and_test 47 | -------------------------------------------------------------------------------- /test/integration/keystone/cli/txsFiles/withPoolRegAndMultiAsset/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx MaryEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a50082825820a2218c7738c374fa68fed428bf28447f550c3c33cb92a5bd06e2b62f3777953900825820ade4616f96066ab24f49dcd4adbcae9ae83750d34e4620a49d737d4a66835d6400018282583900bf63a166d9c10d85e4fd3401de03907e232e7707218c3bfd5a570d7acab53e9efebb49bafb4e74d675c2d682dd8e402f15885fb6d1bc0023821a0095b050a2581c0b1bda00e69de8d554eeafe22b04541fbb2ff89a61d12049f55ba688a14a6669727374617373657404581c95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39a24a66697273746173736574044b7365636f6e646173736574048258390014c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c1a0035476f021a0002e630031a0097fa4004818a03581c13381d918ec0283ceeff60f7f4fc21e1540e053ccf8a77307a7a32ad582007821cd344d7fd7e3ae5f2ed863218cb979ff1d59e50c4276bdc479b0d0844501b0000000ba43b74001a1443fd00d81e82031864581de1794d9b3408c9fb67b950a48a0690f070f117e9978f7fc1d120fc58ad82581c1d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c581c794d9b3408c9fb67b950a48a0690f070f117e9978f7fc1d120fc58ad80f6a0f6" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/ledger/cli/txsFiles/withPoolRegAndMultiAsset/tx.raw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Unwitnessed Tx MaryEra", 3 | "description": "Ledger Cddl Format", 4 | "cborHex": "83a50082825820a2218c7738c374fa68fed428bf28447f550c3c33cb92a5bd06e2b62f3777953900825820ade4616f96066ab24f49dcd4adbcae9ae83750d34e4620a49d737d4a66835d6400018282583900bf63a166d9c10d85e4fd3401de03907e232e7707218c3bfd5a570d7acab53e9efebb49bafb4e74d675c2d682dd8e402f15885fb6d1bc0023821a0095b050a2581c0b1bda00e69de8d554eeafe22b04541fbb2ff89a61d12049f55ba688a14a6669727374617373657404581c95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39a24a66697273746173736574044b7365636f6e646173736574048258390014c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c1a0035476f021a0002e630031a0097fa4004818a03581c13381d918ec0283ceeff60f7f4fc21e1540e053ccf8a77307a7a32ad582007821cd344d7fd7e3ae5f2ed863218cb979ff1d59e50c4276bdc479b0d0844501b0000000ba43b74001a1443fd00d81e82031864581de1794d9b3408c9fb67b950a48a0690f070f117e9978f7fc1d120fc58ad82581c1d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c581c794d9b3408c9fb67b950a48a0690f070f117e9978f7fc1d120fc58ad80f6a0f6" 5 | } 6 | -------------------------------------------------------------------------------- /test/integration/ledger/cli/txsFiles/multiAssetMultiInputAndOutput/tx.signed: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Tx MaryEra", 3 | "description": "", 4 | "cborHex": "83a50082825820a2218c7738c374fa68fed428bf28447f550c3c33cb92a5bd06e2b62f3777953900825820ade4616f96066ab24f49dcd4adbcae9ae83750d34e4620a49d737d4a66835d6400018282583900bf63a166d9c10d85e4fd3401de03907e232e7707218c3bfd5a570d7acab53e9efebb49bafb4e74d675c2d682dd8e402f15885fb6d1bc0023821a0095b050a2581c0b1bda00e69de8d554eeafe22b04541fbb2ff89a61d12049f55ba688a14a6669727374617373657404581c95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39a24a66697273746173736574044b7365636f6e646173736574048258390014c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c1a0035476f021a0002e630031a0097fa40081a0089c970a10082825820cd2b047d1a803eee059769cffb3dfd0a4b9327e55bc78aa962d9bd4f720db0b2584093067db3757c9f840ca08d42dd3379773e2f279960ccac9c2b109901ff6a3936c6fb6438e43025279ba609ef6c24ef9d653b56db8e80f2ae3c864747c3a6110d825820b3d5f4158f0c391ee2a28a2e285f218f3e895ff6ff59cb9369c64b03b5bab5eb58401055fe293226f9ba6850a6374a12eb84343a7efa678f881b14cc2f9a21a0260614fa1e4b468d88f4a92a5e13fa4ca0cc293f23ac47d1ed7a20005bbba33d0b03f6" 5 | } -------------------------------------------------------------------------------- /test/integration/keystone/cli/txsFiles/multiAssetMultiInputAndOutput/tx.signed: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Tx MaryEra", 3 | "description": "", 4 | "cborHex": "83a50082825820a2218c7738c374fa68fed428bf28447f550c3c33cb92a5bd06e2b62f3777953900825820ade4616f96066ab24f49dcd4adbcae9ae83750d34e4620a49d737d4a66835d6400018282583900bf63a166d9c10d85e4fd3401de03907e232e7707218c3bfd5a570d7acab53e9efebb49bafb4e74d675c2d682dd8e402f15885fb6d1bc0023821a0095b050a2581c0b1bda00e69de8d554eeafe22b04541fbb2ff89a61d12049f55ba688a14a6669727374617373657404581c95a292ffee938be03e9bae5657982a74e9014eb4960108c9e23a5b39a24a66697273746173736574044b7365636f6e646173736574048258390014c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c1a0035476f021a0002e630031a0097fa40081a0089c970a10082825820cd2b047d1a803eee059769cffb3dfd0a4b9327e55bc78aa962d9bd4f720db0b2584093067db3757c9f840ca08d42dd3379773e2f279960ccac9c2b109901ff6a3936c6fb6438e43025279ba609ef6c24ef9d653b56db8e80f2ae3c864747c3a6110d825820b3d5f4158f0c391ee2a28a2e285f218f3e895ff6ff59cb9369c64b03b5bab5eb58401055fe293226f9ba6850a6374a12eb84343a7efa678f881b14cc2f9a21a0260614fa1e4b468d88f4a92a5e13fa4ca0cc293f23ac47d1ed7a20005bbba33d0b03f6" 5 | } -------------------------------------------------------------------------------- /docs/message-signing.md: -------------------------------------------------------------------------------- 1 | # Message signing example 2 | 3 | This example demonstrates how to sign a message. See [CIP-8](https://github.com/cardano-foundation/CIPs/blob/master/CIP-0008/README.md) for more information. 4 | 5 | ## Requirements 6 | 7 | Message signing support: 8 | * on Ledger, Cardano app version 7.1.0 and above 9 | * on Trezor, FW version 2.9.1 and above 10 | 11 | ## Sign a message 12 | 13 | If you want to use an address in the `address` header field, prepare the address file. In this example, we will use the address file `payment.addr` (generated like in the [transaction example guide](./transaction-example.md)). If you leave out the `--address` argument, the signing key hash will be used in the `address` header field instead. 14 | 15 | ``` 16 | cardano-hw-cli message sign \ 17 | --message "hello world" \ 18 | --signing-path-hwsfile payment.hwsfile \ 19 | --address $(cat payment.addr) \ 20 | --address-hwsfile payment.hwsfile \ 21 | --address-hwsfile stake.hwsfile \ 22 | --out-file msg.out 23 | ``` 24 | 25 | You can use `--message` or `--message-hex` to specify the message to sign in ASCII or hex format, respectively. If you add `--prefer-hex`, the message will be shown in hex on HW wallet screen even if it is valid ASCII. 26 | 27 | If you add `--hashed`, the message will be hashed before signing. _Note: This is not supported on Trezor as of now._ 28 | 29 | If successful, the command should save output data to the `msg.out` file. 30 | -------------------------------------------------------------------------------- /test/unit/output/keyGenOutput.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | import assert from 'assert' 3 | import {parseBIP32Path} from '../../../src/command-parser/parsers' 4 | 5 | import { 6 | constructVerificationKeyOutput, 7 | constructHwSigningKeyOutput, 8 | } from '../../../src/fileWriter' 9 | import {XPubKeyHex} from '../../../src/basicTypes' 10 | 11 | describe('Key-gen output', () => { 12 | it('Should generate correct output for CIP36 vote keys', () => { 13 | const pathStr = '1694H/1815H/0H/0/1' 14 | const keyHex = 15 | 'deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef' as XPubKeyHex 16 | const path = parseBIP32Path(pathStr) 17 | const vkey = constructVerificationKeyOutput(keyHex, path) 18 | const expectedVkey = { 19 | type: 'CIP36VoteVerificationKey_ed25519', 20 | description: 'Hardware CIP36 Vote Verification Key', 21 | cborHex: 22 | '5820deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef', 23 | } 24 | assert.deepStrictEqual(vkey, expectedVkey) 25 | 26 | const hwsfile = constructHwSigningKeyOutput(keyHex, path) 27 | const expectedHwsfile = { 28 | type: 'CIP36VoteHWSigningFile_ed25519', 29 | description: 'CIP36 Vote Hardware Signing File', 30 | cborXPubKeyHex: 31 | '5820deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef', 32 | path: pathStr, 33 | } 34 | assert.deepStrictEqual(hwsfile, expectedHwsfile) 35 | }) 36 | }) 37 | -------------------------------------------------------------------------------- /src/transaction/txTypes.ts: -------------------------------------------------------------------------------- 1 | import {BIP32Path, CborHex} from '../basicTypes' 2 | 3 | export const enum TxWitnessKeys { 4 | SHELLEY = 0, 5 | NATIVE_SCRIPTS = 1, 6 | BYRON = 2, 7 | PLUTUS_SCRIPTS = 3, 8 | PLUTUS_DATA = 4, 9 | REDEEMERS = 5, 10 | } 11 | 12 | export type TxWitnessByronData = [ 13 | Buffer, // public key 14 | Buffer, // signature 15 | Buffer, // chain code 16 | Buffer, // address attributes 17 | ] 18 | 19 | export type TxWitnessShelleyData = [ 20 | Buffer, // public key 21 | Buffer, // signature 22 | ] 23 | 24 | export type TxWitnessByron = { 25 | key: TxWitnessKeys.BYRON 26 | data: TxWitnessByronData 27 | path: BIP32Path 28 | } 29 | 30 | export type TxWitnessShelley = { 31 | key: TxWitnessKeys.SHELLEY 32 | data: TxWitnessShelleyData 33 | path: BIP32Path 34 | } 35 | 36 | export type TxWitnesses = { 37 | byronWitnesses: TxWitnessByron[] 38 | shelleyWitnesses: TxWitnessShelley[] 39 | } 40 | 41 | export type TxCborHex = CborHex 42 | 43 | export type TxWitnessCborHex = CborHex 44 | 45 | export type _XPubKey = { 46 | pubKey: Buffer 47 | chainCode: Buffer 48 | } 49 | 50 | export type CIP36RegistrationMetaDataPayloadItem = 51 | | [Buffer, bigint][] 52 | | Buffer 53 | | bigint 54 | export type CIP36RegistrationMetaData = Map< 55 | number, 56 | Map 57 | > 58 | export type CIP36RegistrationMetaDataCborHex = CborHex 59 | 60 | export type CIP36RegistrationAuxiliaryData = [CIP36RegistrationMetaData, []] 61 | -------------------------------------------------------------------------------- /docs/code-structure.md: -------------------------------------------------------------------------------- 1 | # Code structure 2 | 3 | ## 1. Input arguments parsing 4 | 5 | Input arguments are parsed according to [parserConfig.ts](../src/command-parser/parserConfig.ts). 6 | 7 | The first one or two arguments determine what action will be taken (see `CommandType`). 8 | 9 | ## 2. Input files parsing 10 | 11 | Most input data are contained in files that are given by their respective paths in arguments. 12 | 13 | For instance, the transaction that is to be signed is read from the input file and then parsed by `cardano-hw-interop-lib`. 14 | 15 | ## 3. Executing the command 16 | 17 | The given command is then executed by [`CommandExecutor`](../src/commandExecutor.ts) which is responsible for passing the parsed arguments to the relevant cryptoprovider. 18 | 19 | The cryptoprovider translates command arguments into a form suitable for the particular hardware wallet (Ledger or Trezor), including mapping transaction elements into hierarchic derivation (BIP44-like) paths, and passes on the response acquired from the hw wallet. 20 | 21 | ## 4. Processing hw wallet response 22 | 23 | `CommandExecutor` is then responsible for processing the hw wallet response data, typically writing them into the given output files. 24 | 25 | # Tests 26 | 27 | Steps (1) and (2) are tested via unit tests in [commandParser.js](../test/unit/commandParser/commandParser.js). 28 | 29 | Step (3) is covered by [integration tests](../test/integration). 30 | 31 | Step (4) is not covered anywhere (apart from manually running command-line examples): TODO 32 | -------------------------------------------------------------------------------- /test/unit/commandParser/res/nested.script: -------------------------------------------------------------------------------- 1 | { 2 | "type": "all", 3 | "scripts": 4 | [ 5 | { 6 | "type": "sig", 7 | "keyHash": "14c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f1124" 8 | }, 9 | { 10 | "type": "sig", 11 | "keyHash": "c4b9265645fde9536c0795adbcc5291767a0c61fd62448341d7e0386" 12 | }, 13 | { 14 | "type": "any", 15 | "scripts": 16 | [ 17 | { 18 | "type": "sig", 19 | "keyHash": "c4b9265645fde9536c0795adbcc5291767a0c61fd62448341d7e0386" 20 | }, 21 | { 22 | "type": "sig", 23 | "keyHash": "0241f2d196f52a92fbd2183d03b370c30b6960cfdeae364ffabac889" 24 | } 25 | ] 26 | }, 27 | { 28 | "type": "atLeast", 29 | "required": 2, 30 | "scripts": 31 | [ 32 | { 33 | "type": "sig", 34 | "keyHash": "c4b9265645fde9536c0795adbcc5291767a0c61fd62448341d7e0386" 35 | }, 36 | { 37 | "type": "sig", 38 | "keyHash": "0241f2d196f52a92fbd2183d03b370c30b6960cfdeae364ffabac889" 39 | }, 40 | { 41 | "type": "sig", 42 | "keyHash": "cecb1d427c4ae436d28cc0f8ae9bb37501a5b77bcc64cd1693e9ae20" 43 | } 44 | ] 45 | }, 46 | { 47 | "type": "after", 48 | "slot": 100 49 | }, 50 | { 51 | "type": "before", 52 | "slot": 200 53 | } 54 | ] 55 | } 56 | -------------------------------------------------------------------------------- /src/transaction/transaction.ts: -------------------------------------------------------------------------------- 1 | import * as InteropLib from 'cardano-hw-interop-lib' 2 | import {cloneDeep} from 'lodash' 3 | import { 4 | TxWitnessByronData, 5 | TxWitnessShelleyData, 6 | TxWitnessKeys, 7 | } from './txTypes' 8 | import {encodeCbor} from '../util' 9 | 10 | type WitnessSet = Map 11 | 12 | // If witnessSet is empty, the CBOR lib parses it as {}, otherwise it seems to always return a Map. 13 | // Let's convert it to Map in any case, just to make sure. 14 | const _parseWitnessSet = (witnessSet: unknown): WitnessSet => { 15 | const clonedWitnessSet = cloneDeep(witnessSet) 16 | return clonedWitnessSet instanceof Map 17 | ? clonedWitnessSet 18 | : (new Map( 19 | Object.entries(clonedWitnessSet as object), 20 | ) as unknown as WitnessSet) 21 | } 22 | 23 | const TxByronWitnessData = ( 24 | publicKey: Buffer, 25 | signature: Buffer, 26 | chainCode: Buffer, 27 | addressAttributes: object, 28 | ): TxWitnessByronData => [ 29 | publicKey, 30 | signature, 31 | chainCode, 32 | encodeCbor(addressAttributes), 33 | ] 34 | 35 | const TxShelleyWitnessData = ( 36 | publicKey: Buffer, 37 | signature: Buffer, 38 | ): TxWitnessShelleyData => [publicKey, signature] 39 | 40 | export const containsVKeyWitnesses = (tx: InteropLib.Transaction): boolean => { 41 | const witnessSet = _parseWitnessSet(tx.witnessSet) 42 | const shelleyWitnesses = witnessSet.get(TxWitnessKeys.SHELLEY) ?? [] 43 | const byronWitnesses = witnessSet.get(TxWitnessKeys.BYRON) ?? [] 44 | return [...shelleyWitnesses, ...byronWitnesses].length > 0 45 | } 46 | 47 | export {TxByronWitnessData, TxShelleyWitnessData} 48 | -------------------------------------------------------------------------------- /.cspell.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2", 3 | "language": "en", 4 | "ignorePaths": [ 5 | ".cspell.json", 6 | "build", 7 | "node_modules", 8 | "**/*.tgz", 9 | "**/package.json", 10 | "**/tsconfig.json", 11 | ".vscode/**" 12 | ], 13 | "ignoreRegExpList": [ 14 | "0x[A-Z]{7,25}", 15 | "\\S{32,}", 16 | "[A-Za-z0-9+/]+={1,2}", 17 | "deadbe[ea]f", 18 | "'[a-z0-9]{16}'" 19 | ], 20 | "words": [ 21 | "Adalite", 22 | "argparse", 23 | "bech", 24 | "Benc", 25 | "cardano", 26 | "cbor", 27 | "chsh", 28 | "cimg", 29 | "concats", 30 | "COSE", 31 | "cryptoprovider", 32 | "cvote", 33 | "cword", 34 | "czvf", 35 | "Deregisters", 36 | "deregistration", 37 | "dpkg", 38 | "DREP", 39 | "endians", 40 | "fixlen", 41 | "hwsfile", 42 | "insertable", 43 | "jcli", 44 | "jormungandr", 45 | "keystonehq", 46 | "Kojn", 47 | "ledgerhq", 48 | "ledgerjs", 49 | "libudev", 50 | "libusb", 51 | "metavar", 52 | "nargs", 53 | "ngraveio", 54 | "opcert", 55 | "PAYMENTADDRESS", 56 | "PAYMENTPATH", 57 | "pkey", 58 | "policyid", 59 | "precheck", 60 | "PREPROD", 61 | "pubkey", 62 | "pubkeys", 63 | "sgin", 64 | "signdata", 65 | "skey", 66 | "speculos", 67 | "STAKINGPATH", 68 | "subparser", 69 | "subparsers", 70 | "TLDR", 71 | "unfixable", 72 | "uniquify", 73 | "utxo", 74 | "utxos", 75 | "uuidv", 76 | "vacuumlabs", 77 | "vkey", 78 | "vkeys", 79 | "vkeywitnesses", 80 | "VOTINGPURPOSE", 81 | "xpub", 82 | "Xpub", 83 | "zxvf" 84 | ] 85 | } 86 | -------------------------------------------------------------------------------- /docs/installation-macos-autocomplete.md: -------------------------------------------------------------------------------- 1 | # Macos autocomplete installation 2 | On mac you need to update your bash first. Check your version with 3 | 4 | ``` 5 | bash --version 6 | ``` 7 | 8 | If you have version 3.2 from 2007, update to newer version: 9 | 10 | ``` 11 | brew install bash 12 | ``` 13 | 14 | Verify the installation, you should see new version installed: 15 | ``` 16 | $ which -a bash 17 | /usr/local/bin/bash 18 | /bin/bash 19 | ``` 20 | 21 | check version, you should see at least version 5.0: 22 | ``` 23 | $ /usr/local/bin/bash --version 24 | GNU bash, version 5.0.18(1)-release (x86_64-apple-darwin20.2.0) 25 | Copyright (C) 2019 Free Software Foundation, Inc. 26 | License GPLv3+: GNU GPL version 3 or later 27 | 28 | This is free software; you are free to change and redistribute it. 29 | There is NO WARRANTY, to the extent permitted by law. 30 | ``` 31 | 32 | Newly installed bash should be new default, restart terminal and check: 33 | ``` 34 | $ bash --version 35 | GNU bash, version 5.0.18(1)-release (x86_64-apple-darwin20.2.0) 36 | ... 37 | ``` 38 | 39 | Whitelist this shell. Add `/usr/local/bin/bash` to the end of `/etc/shells` file: 40 | ``` 41 | $ sudo vim /etc/shells 42 | ``` 43 | 44 | Change default shell: 45 | ``` 46 | $ chsh -s /usr/local/bin/bash 47 | ``` 48 | 49 | Restart terminal and check version: 50 | ``` 51 | $ echo $BASH_VERSION 52 | 5.0.18(1)-release 53 | ``` 54 | 55 | This change is only for current user, for super user execute: 56 | ``` 57 | $ sudo chsh -s /usr/local/bin/bash 58 | ``` 59 | 60 | Finally append contents of https://github.com/vacuumlabs/cardano-hw-cli/blob/develop/scripts/autocomplete.sh to the `~/.bashrc` and source it in `~/.bash_profile`: 61 | ``` 62 | source .bashrc 63 | ``` -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // copied from https://github.com/vacuumlabs/nufi and adjusted 2 | module.exports = { 3 | extends: [ 4 | 'plugin:@typescript-eslint/recommended', 5 | 'plugin:import/typescript', 6 | 'vacuumlabs', 7 | 'prettier', 8 | ], 9 | env: { 10 | "es6": true, 11 | "node": true, 12 | "mocha": true 13 | }, 14 | rules: { 15 | '@typescript-eslint/no-explicit-any': [ 16 | 'error', 17 | { 18 | ignoreRestArgs: true, 19 | }, 20 | ], 21 | '@typescript-eslint/no-var-requires': 'off', 22 | '@typescript-eslint/explicit-module-boundary-types': 'off', 23 | 24 | // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-use-before-define.md#how-to-use 25 | // note you must disable the base rule as it can report incorrect errors 26 | 'no-use-before-define': 'off', 27 | '@typescript-eslint/no-use-before-define': ['error'], 28 | 'no-unused-vars': 'off', 29 | '@typescript-eslint/no-unused-vars': ['error', {argsIgnorePattern: '^_'}], 30 | // Why detect cycles: https://spin.atomicobject.com/2018/06/25/circular-dependencies-javascript 31 | // TLDR - memory crashes, tangled architecture, unreadable code, undefined imports 32 | 'import/no-cycle': [ 33 | 'error', 34 | ], 35 | 'import/no-extraneous-dependencies': ['error'], 36 | 'spaced-comment': ['error', 'always', {block: {balanced: true}}], 37 | 'quote-props': ['error', 'consistent'], 38 | }, 39 | parser: '@typescript-eslint/parser', 40 | parserOptions: { 41 | ecmaVersion: 2020, 42 | sourceType: 'module', 43 | createDefaultProgram: true, 44 | }, 45 | settings: { 46 | 'import/resolver': { 47 | node: { 48 | extensions: ['.js', '.ts'], 49 | }, 50 | }, 51 | }, 52 | plugins: ['import'], 53 | } 54 | -------------------------------------------------------------------------------- /scripts/build-linux-deb-package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd ${0%/*} 4 | cd .. 5 | 6 | CARDANO_HW_CLI_PACKAGE_VERSION=$(cat package.json | grep version | head -1 | awk -F: '{ print $2 }' | sed 's/[", ]//g') 7 | 8 | PACKAGE='cardano-hw-cli' 9 | VERSION=$CARDANO_HW_CLI_PACKAGE_VERSION'-1' # majorVersion.minorVersion.patchVersion-packageRevision 10 | ARCHITECTURE='amd64' 11 | MAINTAINER='Peter Benc , David Tran Duc ' 12 | DESCRIPTION='Cardano hw cli 13 | Command line tool for ledger/trezor transaction signing' 14 | 15 | # Remove old build 16 | rm -R ./build/linux/deb 2> /dev/null 17 | 18 | # Prepare directories 19 | mkdir ./build/linux 2> /dev/null 20 | mkdir ./build/linux/deb 21 | mkdir ./build/linux/deb/${PACKAGE}_${VERSION} 22 | mkdir ./build/linux/deb/${PACKAGE}_${VERSION}/usr 23 | mkdir ./build/linux/deb/${PACKAGE}_${VERSION}/usr/bin 24 | mkdir ./build/linux/deb/${PACKAGE}_${VERSION}/usr/share 25 | mkdir ./build/linux/deb/${PACKAGE}_${VERSION}/usr/share/cardano-hw-cli 26 | mkdir ./build/linux/deb/${PACKAGE}_${VERSION}/DEBIAN 27 | 28 | # Build executable 29 | yarn pkg ./dist/index.js -o ./build/linux/deb/cardano-hw-cli -c package.json -t node18-linux-x64 --options "no-warnings=ExperimentalWarning" 30 | 31 | # Copy files to package structure 32 | cp -R ./build/dependencies/linux/* ./build/linux/deb/${PACKAGE}_${VERSION}/usr/share/cardano-hw-cli 33 | cp ./build/linux/deb/cardano-hw-cli ./build/linux/deb/${PACKAGE}_${VERSION}/usr/share/cardano-hw-cli 34 | ln -s /usr/share/cardano-hw-cli/cardano-hw-cli ./build/linux/deb/${PACKAGE}_${VERSION}/usr/bin 35 | 36 | # Build package 37 | CONTROL="Package: $PACKAGE 38 | Version: $VERSION 39 | Architecture: $ARCHITECTURE 40 | Maintainer: $MAINTAINER 41 | Description: $DESCRIPTION" 42 | 43 | echo "$CONTROL" >> ./build/linux/deb/${PACKAGE}_${VERSION}/DEBIAN/control 44 | 45 | dpkg-deb --build ./build/linux/deb/${PACKAGE}_${VERSION} 46 | -------------------------------------------------------------------------------- /docs/spellchecking.md: -------------------------------------------------------------------------------- 1 | # Spellchecking 2 | 3 | This file and setup is copied from NuFi. 4 | 5 | We use the "Code Spell Checker" VSCode extension for development, and `cspell` to do checking from scripts. (This extension uses `cspell` under the hood.) 6 | 7 | Both are configured in `.cspell.json`. 8 | 9 | Run `yarn spell:check` to check the whole codebase. (The CI will also run this as part of the lint job.) 10 | 11 | ## Adding unknown words to the dictionary 12 | 13 | The easiest way is to use VSCode's [Quick Fix](https://code.visualstudio.com/docs/getstarted/keybindings) menu. (Quickly accessible using `Ctrl+.`.) Alternately, you can use the `Spelling > Add Words to CSpell Configuration` context menu. 14 | 15 | You can of course manually modify `.cspell.json` as well to add words. See the documentation for the [cspell configuration](http://cspell.org/configuration/) for more advanced features, like ignoring paths, or ignoring words based on a regular expression. 16 | 17 | Finally, sometimes spellchecking some parts of the code is just not practical. Test fixtures are a common example of this, since they tend to use a lot of random constants. In such cases, you should just wrap the relevant parts of the code in `/* cspell:disable */` and `/* cspell:enable */` comments. 18 | 19 | ## Initial setup 20 | 21 | I am documenting the steps for initially settings this up on a new project for completeness, but these steps will probably never be needed in the future: 22 | 23 | - I aggregated all the errors with this command: `yarn cspell lint --words-only --gitignore '**' | sort | uniq -c | sort -nr > /tmp/words.txt` 24 | - Went through the items from the top of the list, and generally handled the words in one of three ways: 25 | - I added words with many occurrences to the dictionary. 26 | - I corrected misspelled words. 27 | - For things that are not words (like base64 or hexadecimal strings), or words that are only one-offs, I added cspell ignore comments to their occurrences. 28 | -------------------------------------------------------------------------------- /docs/installation.md: -------------------------------------------------------------------------------- 1 | # Linux 2 | 3 | ## Option 1: install from `.deb` package: 4 | To install from a `.deb` package, open file from file explorer of your choice or run in command line: 5 | ``` 6 | sudo dpkg --install ./cardano-hw-cli_.deb 7 | ``` 8 | This will create necessary files under `/user/share/cardano-hw-cli/` and create soft link under `/usr/bin/`, so `cardano-hw-cli` command is callable in command line from everywhere. 9 | 10 | If you wish to uninstall `cardano-hw-cli`, run: 11 | ``` 12 | sudo dpkg --remove cardano-hw-cli 13 | ``` 14 | 15 | ## Option 2: decompress `.tar.gz` archive: 16 | if `.deb` package is not working for some reason, you can decompress the `.tar.gz` archive and create a soft link to `cardano-hw-cli` manually: 17 | 18 | decompress: 19 | ``` 20 | tar -zxvf cardano-hw-cli-.tar.gz 21 | ``` 22 | 23 | Create soft link: 24 | ``` 25 | sudo ln -s / /usr/bin 26 | ``` 27 | 28 | or add to PATH. Edit `~/.bashrc`: 29 | ``` 30 | vim ~/.bashrc 31 | ``` 32 | add path to the end of file on new line: 33 | ``` 34 | export PATH= 35 | ``` 36 | 37 | # Mac 38 | decompress the `.tar.gz` archive by double clicking archive in finder or decompress in command line: 39 | ``` 40 | tar -zxvf cardano-hw-cli-.tar.gz 41 | ``` 42 | 43 | Add to PATH: 44 | ``` 45 | sudo vim /etc/paths 46 | ``` 47 | add to the end of file on new line: `` 48 | 49 | # Windows 50 | Unzip `cardano-hw-cli-.zip` and add directory location to your PATH. 51 | 52 | How to add to PATH: https://www.architectryan.com/2018/03/17/add-to-the-path-on-windows-10/ 53 | 54 | # Setup arguments auto-completion 55 | This step is optional. 56 | 57 | ## Linux and windows 58 | Append contents of https://github.com/vacuumlabs/cardano-hw-cli/blob/develop/scripts/autocomplete.sh to the `~/.bashrc` (or source it). 59 | 60 | On windows this works with Git Bash. 61 | 62 | ## Mac 63 | Check https://github.com/vacuumlabs/cardano-hw-cli/blob/develop/docs/installation-macos-autocomplete.md -------------------------------------------------------------------------------- /test/integration/ledger/node/opCert.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | import assert from 'assert' 3 | import {LedgerCryptoProvider} from '../../../../src/crypto-providers/ledgerCryptoProvider' 4 | import {CryptoProvider} from '../../../../src/crypto-providers/cryptoProvider' 5 | 6 | import {signingFiles} from './signingFiles' 7 | import {getTransport} from './speculos' 8 | 9 | const opCerts = { 10 | opcert1: { 11 | kesVKey: Buffer.from( 12 | 'f70601c4de155e67797e057c07fb768b5590b2241b05ec30235a85b71e2ae858', 13 | 'hex', 14 | ), 15 | kesPeriod: 251n, 16 | issueCounter: { 17 | counter: 1, 18 | poolColdKey: Buffer.from( 19 | '3d7e84dca8b4bc322401a2cc814af7c84d2992a22f99554fe340d7df7910768d', 20 | 'hex', 21 | ), 22 | }, 23 | hwSigningFiles: [signingFiles.poolCold0], 24 | signedOpCertCborHex: 25 | '82845820f70601c4de155e67797e057c07fb768b5590b2241b05ec30235a85b71e2ae8580118fb5840b44fcc4505aee4c93a716014ec709d17b28e0c95637384b78d2f8a4cebb92d1e01b54ce952e11771bbeaceda0eaf7a660e5c416f357bdec94e4ce2977997d20458203d7e84dca8b4bc322401a2cc814af7c84d2992a22f99554fe340d7df7910768d', 26 | }, 27 | } 28 | 29 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 30 | async function testOpCertSigning(cryptoProvider: CryptoProvider, opCert: any) { 31 | const signedOpCertCborHex = await cryptoProvider.signOperationalCertificate( 32 | opCert.kesVKey, 33 | opCert.kesPeriod, 34 | opCert.issueCounter, 35 | opCert.hwSigningFiles, 36 | ) 37 | assert.deepStrictEqual(signedOpCertCborHex, opCert.signedOpCertCborHex) 38 | } 39 | 40 | describe('Ledger operational certificate', () => { 41 | let cryptoProvider: CryptoProvider 42 | // eslint-disable-next-line prefer-arrow-callback 43 | before(async function () { 44 | this.timeout(10000) 45 | cryptoProvider = await LedgerCryptoProvider(await getTransport()) 46 | }) 47 | const opCertsToSign = Object.entries(opCerts) 48 | opCertsToSign.forEach(([opCertTestName, opCert]) => 49 | it(`Should sign operational certificate ${opCertTestName}`, async () => 50 | await testOpCertSigning(cryptoProvider, opCert)).timeout(100000), 51 | ) 52 | }) 53 | -------------------------------------------------------------------------------- /test/integration/keystone/node/opCert.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | import assert from 'assert' 3 | import {CryptoProvider} from '../../../../src/crypto-providers/cryptoProvider' 4 | 5 | import {signingFiles} from './signingFiles' 6 | import {KeystoneCryptoProvider} from '../../../../src/crypto-providers/keystoneCryptoProvider' 7 | import {TransportNodeUSB} from '@keystonehq/hw-transport-nodeusb' 8 | 9 | const opCerts = { 10 | opcert1: { 11 | kesVKey: Buffer.from( 12 | 'f70601c4de155e67797e057c07fb768b5590b2241b05ec30235a85b71e2ae858', 13 | 'hex', 14 | ), 15 | kesPeriod: 251n, 16 | issueCounter: { 17 | counter: 1, 18 | poolColdKey: Buffer.from( 19 | '3d7e84dca8b4bc322401a2cc814af7c84d2992a22f99554fe340d7df7910768d', 20 | 'hex', 21 | ), 22 | }, 23 | hwSigningFiles: [signingFiles.poolCold0], 24 | signedOpCertCborHex: 25 | '82845820f70601c4de155e67797e057c07fb768b5590b2241b05ec30235a85b71e2ae8580118fb5840b44fcc4505aee4c93a716014ec709d17b28e0c95637384b78d2f8a4cebb92d1e01b54ce952e11771bbeaceda0eaf7a660e5c416f357bdec94e4ce2977997d20458203d7e84dca8b4bc322401a2cc814af7c84d2992a22f99554fe340d7df7910768d', 26 | }, 27 | } 28 | 29 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 30 | async function testOpCertSigning(cryptoProvider: CryptoProvider, opCert: any) { 31 | const signedOpCertCborHex = await cryptoProvider.signOperationalCertificate( 32 | opCert.kesVKey, 33 | opCert.kesPeriod, 34 | opCert.issueCounter, 35 | opCert.hwSigningFiles, 36 | ) 37 | assert.deepStrictEqual(signedOpCertCborHex, opCert.signedOpCertCborHex) 38 | } 39 | 40 | describe('Keystone operational certificate', () => { 41 | let cryptoProvider: CryptoProvider 42 | // eslint-disable-next-line prefer-arrow-callback 43 | before(async function () { 44 | this.timeout(10000) 45 | cryptoProvider = await KeystoneCryptoProvider( 46 | await TransportNodeUSB.connect({ 47 | timeout: 100000, 48 | }), 49 | ) 50 | }) 51 | const opCertsToSign = Object.entries(opCerts) 52 | opCertsToSign.forEach(([opCertTestName, opCert]) => 53 | it(`Should sign operational certificate ${opCertTestName}`, async () => 54 | await testOpCertSigning(cryptoProvider, opCert)).timeout(100000), 55 | ) 56 | }) 57 | -------------------------------------------------------------------------------- /src/command-parser/commandParser.ts: -------------------------------------------------------------------------------- 1 | import {ArgumentGroup, ArgumentParser, SubParser} from 'argparse' 2 | import {ParsedArguments} from './argTypes' 3 | import {ParserConfig, parserConfig} from './parserConfig' 4 | 5 | const initParser = ( 6 | parser: ArgumentParser | ArgumentGroup, 7 | config: ParserConfig, 8 | ): void => { 9 | const MUTUALLY_EXCLUSIVE_GROUP_KEY = '_mutually-exclusive-group' 10 | const isMutuallyExclusiveGroup = (str: string) => 11 | str.startsWith(MUTUALLY_EXCLUSIVE_GROUP_KEY) 12 | const isOneOfGroupRequired = (str: string) => 13 | str.startsWith(`${MUTUALLY_EXCLUSIVE_GROUP_KEY}-required`) 14 | const isCommand = (str: string) => 15 | !str.startsWith('--') && !isMutuallyExclusiveGroup(str) 16 | const commandType = (parent: string, current: string) => 17 | parent ? `${parent}.${current}` : current 18 | 19 | const subparsers = 'add_subparsers' in parser ? parser.add_subparsers() : null 20 | Object.keys(config).forEach((key) => { 21 | if (isCommand(key)) { 22 | const subparser = (subparsers as SubParser).add_parser(key) 23 | subparser.set_defaults({ 24 | command: commandType(parser.get_default('command'), key), 25 | }) 26 | initParser(subparser, config[key] as ParserConfig) 27 | } else if (isMutuallyExclusiveGroup(key)) { 28 | const group = parser.add_mutually_exclusive_group({ 29 | required: isOneOfGroupRequired(key), 30 | }) 31 | initParser(group, config[key] as ParserConfig) 32 | } else { 33 | parser.add_argument(key, config[key]) 34 | } 35 | }) 36 | } 37 | 38 | const preProcessArgs = (inputArgs: string[]): string[] => { 39 | // First 2 args are node version and script name 40 | const commandArgs = inputArgs.slice(2) 41 | if (commandArgs[0] === 'shelley') { 42 | return commandArgs.slice(1) 43 | } 44 | return commandArgs 45 | } 46 | 47 | export const parse = ( 48 | inputArgs: string[], 49 | ): {parser: ArgumentParser; parsedArgs: ParsedArguments} => { 50 | const parser = new ArgumentParser({ 51 | description: 52 | 'Command line tool for ledger/trezor/keystone transaction signing', 53 | prog: 'cardano-hw-cli', 54 | }) 55 | initParser(parser, parserConfig) 56 | const {...parsedArgs} = parser.parse_args(preProcessArgs(inputArgs)) 57 | return {parser, parsedArgs} 58 | } 59 | -------------------------------------------------------------------------------- /test/integration/trezor/node/signMessage.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | import assert from 'assert' 3 | import {TrezorCryptoProvider} from '../../../../src/crypto-providers/trezorCryptoProvider' 4 | 5 | import {signingFiles} from './signingFiles' 6 | import {CryptoProvider} from '../../../../src/crypto-providers/cryptoProvider' 7 | import { 8 | CommandType, 9 | HwSigningData, 10 | ParsedSignMessageArguments, 11 | } from '../../../../src/command-parser/argTypes' 12 | import {HexString} from '../../../../src/basicTypes' 13 | 14 | type TestData = { 15 | args: ParsedSignMessageArguments 16 | expectedResult: { 17 | signatureHex: string 18 | signingPublicKeyHex: string 19 | addressFieldHex: string 20 | } 21 | } 22 | 23 | const msgTests: {[testName: string]: TestData} = { 24 | msg01: { 25 | args: { 26 | command: CommandType.SIGN_MESSAGE, 27 | messageHex: '68656c6c6f20776f726c64' as HexString, 28 | hwSigningFileData: signingFiles.stake0 as HwSigningData, 29 | hashPayload: false, 30 | preferHexDisplay: false, 31 | outFile: 'msg.out', 32 | }, 33 | expectedResult: { 34 | signatureHex: 35 | 'd284efe58b3bf9e71f5514a6000cfe4f1301a95e0ac20a736ec964ed75e2a38bdc19ef31ef0c7b748d057ba4f67c3ac37040fa1ed8b8ce04a6d66d546b4e8c01', 36 | signingPublicKeyHex: 37 | 'bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e', 38 | addressFieldHex: 39 | '122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b4277', 40 | }, 41 | } 42 | } 43 | 44 | async function testMessageSigning( 45 | cryptoProvider: CryptoProvider, 46 | msgTestData: TestData, 47 | ) { 48 | const {expectedResult, args} = msgTestData 49 | const result = await cryptoProvider.signMessage(args) 50 | assert.deepStrictEqual(result, expectedResult) 51 | } 52 | 53 | describe('Trezor sign message', () => { 54 | let cryptoProvider: CryptoProvider 55 | // eslint-disable-next-line prefer-arrow-callback 56 | before(async function () { 57 | this.timeout(10000) 58 | cryptoProvider = await TrezorCryptoProvider() 59 | }) 60 | const messagesToSign = Object.entries(msgTests) 61 | 62 | messagesToSign.forEach(([testName, testData]) => 63 | it(`Should sign ${testName}`, async () => 64 | await testMessageSigning(cryptoProvider, testData)).timeout(100000), 65 | ) 66 | }) 67 | -------------------------------------------------------------------------------- /src/crypto-providers/cryptoProvider.ts: -------------------------------------------------------------------------------- 1 | import {Transaction} from 'cardano-hw-interop-lib' 2 | import { 3 | KesVKey, 4 | OpCertIssueCounter, 5 | SignedOpCertCborHex, 6 | } from '../opCert/opCert' 7 | import { 8 | TxWitnesses, 9 | CIP36RegistrationMetaDataCborHex, 10 | } from '../transaction/txTypes' 11 | import { 12 | BIP32Path, 13 | XPubKeyHex, 14 | NativeScriptHashKeyHex, 15 | CardanoEra, 16 | DerivationType, 17 | NativeScript, 18 | Network, 19 | CVoteDelegation, 20 | HumanAddress, 21 | } from '../basicTypes' 22 | import { 23 | ParsedShowAddressArguments, 24 | HwSigningData, 25 | ParsedSignMessageArguments, 26 | } from '../command-parser/argTypes' 27 | import {SignedMessageData} from '../signMessage/signMessage' 28 | 29 | export enum SigningMode { 30 | ORDINARY_TRANSACTION, 31 | POOL_REGISTRATION_AS_OWNER, 32 | POOL_REGISTRATION_AS_OPERATOR, 33 | MULTISIG_TRANSACTION, 34 | PLUTUS_TRANSACTION, 35 | } 36 | 37 | export type TxSigningParameters = { 38 | signingMode: SigningMode 39 | tx: Transaction 40 | txBodyHashHex: string 41 | hwSigningFileData: HwSigningData[] 42 | network: Network 43 | era: CardanoEra 44 | derivationType?: DerivationType 45 | } 46 | 47 | export enum NativeScriptDisplayFormat { 48 | BECH32, 49 | POLICY_ID, 50 | } 51 | 52 | export type CryptoProvider = { 53 | getVersion: () => Promise 54 | showAddress: (args: ParsedShowAddressArguments) => Promise 55 | witnessTx: ( 56 | params: TxSigningParameters, 57 | changeOutputFiles: HwSigningData[], 58 | ) => Promise 59 | getXPubKeys: ( 60 | paths: BIP32Path[], 61 | derivationType?: DerivationType, 62 | ) => Promise 63 | signOperationalCertificate: ( 64 | kesVKey: KesVKey, 65 | kesPeriod: bigint, 66 | issueCounter: OpCertIssueCounter, 67 | signingFile: HwSigningData[], 68 | ) => Promise 69 | signCIP36RegistrationMetaData: ( 70 | delegations: CVoteDelegation[], 71 | hwStakeSigningFile: HwSigningData, // describes stake_credential 72 | paymentAddressBech32: HumanAddress, 73 | nonce: bigint, 74 | votingPurpose: bigint, 75 | network: Network, 76 | paymentAddressSigningFiles: HwSigningData[], 77 | derivationType?: DerivationType, 78 | ) => Promise 79 | signMessage: (args: ParsedSignMessageArguments) => Promise 80 | deriveNativeScriptHash: ( 81 | nativeScript: NativeScript, 82 | signingFiles: HwSigningData[], 83 | displayFormat: NativeScriptDisplayFormat, 84 | derivationType?: DerivationType, 85 | ) => Promise 86 | } 87 | -------------------------------------------------------------------------------- /scripts/fix-trezor-firmware.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | // Fix 1: @trezor/connect beta version missing firmware module 5 | const firmwarePath = path.join(__dirname, '../node_modules/@trezor/connect-common/files/firmware'); 6 | const firmwareIndexPath = path.join(firmwarePath, 'index.js'); 7 | 8 | // Only create the firmware fix if the file doesn't exist 9 | if (!fs.existsSync(firmwareIndexPath)) { 10 | const indexContent = `const fs = require('fs'); 11 | const path = require('path'); 12 | 13 | // Build firmwareAssets object by scanning the firmware directory structure 14 | const firmwareAssets = {}; 15 | 16 | const deviceModels = ['t1b1', 't2b1', 't2t1', 't3b1', 't3t1']; 17 | const firmwareTypes = ['universal', 'bitcoinonly']; 18 | 19 | deviceModels.forEach(deviceModel => { 20 | firmwareAssets[deviceModel] = {}; 21 | 22 | firmwareTypes.forEach(firmwareType => { 23 | const firmwareDir = path.join(__dirname, deviceModel, firmwareType); 24 | firmwareAssets[deviceModel][firmwareType] = {}; 25 | 26 | if (fs.existsSync(firmwareDir)) { 27 | const files = fs.readdirSync(firmwareDir); 28 | files.forEach(file => { 29 | if (file.endsWith('.json')) { 30 | const fileName = file.replace('.json', ''); 31 | try { 32 | const filePath = path.join(firmwareDir, file); 33 | const content = JSON.parse(fs.readFileSync(filePath, 'utf8')); 34 | firmwareAssets[deviceModel][firmwareType][fileName] = content; 35 | } catch (e) { 36 | // Skip invalid JSON files 37 | } 38 | } 39 | }); 40 | } 41 | }); 42 | }); 43 | 44 | module.exports = { firmwareAssets };`; 45 | 46 | try { 47 | fs.writeFileSync(firmwareIndexPath, indexContent); 48 | console.log('✓ Fixed @trezor/connect-common firmware module'); 49 | } catch (error) { 50 | console.warn('⚠ Could not create firmware index.js:', error.message); 51 | } 52 | } 53 | 54 | // Fix 2: @trezor/connect beta version trying to import .ts files instead of .js 55 | const methodPath = path.join(__dirname, '../node_modules/@trezor/connect/lib/core/method.js'); 56 | 57 | if (fs.existsSync(methodPath)) { 58 | try { 59 | let methodContent = fs.readFileSync(methodPath, 'utf8'); 60 | 61 | // Replace .ts extension with .js in the dynamic import 62 | const original = `\`../api/\${methodModule}/api/index.ts\``; 63 | const fixed = `\`../api/\${methodModule}/api/index.js\``; 64 | 65 | if (methodContent.includes(original)) { 66 | methodContent = methodContent.replace(original, fixed); 67 | fs.writeFileSync(methodPath, methodContent); 68 | console.log('✓ Fixed @trezor/connect method.js TypeScript import'); 69 | } 70 | } catch (error) { 71 | console.warn('⚠ Could not fix method.js:', error.message); 72 | } 73 | } -------------------------------------------------------------------------------- /docs/plutus-babbage-transactions.md: -------------------------------------------------------------------------------- 1 | # Plutus transactions in Babbage era 2 | Plutus scripts have been supported since the Alonzo era - see Plutus transactions docs for more details. In Babbage era some changes have been made to the way Plutus transactions can be built. For more information see [this post on IOG blog](https://iohk.io/en/blog/posts/2022/07/04/cardano-s-approaching-vasil-upgrade-what-to-expect/) or [the Babbage CDDL spec](https://github.com/input-output-hk/cardano-ledger/blob/master/eras/babbage/test-suite/cddl-files/babbage.cddl). 3 | 4 | ## Script address 5 | In Babbage we need a script address as well. However, to use the new Babbage features we need a Plutus V2 script - you can use [the V2 version of the script used in our Plutus docs](./data/datum-equals-redeemer-v2.plutus). 6 | 7 | ```sh 8 | cardano-cli address build \ 9 | --payment-script-file datum-equals-redeemer-v2.plutus \ 10 | --out-file script.addr \ 11 | --mainnet 12 | ``` 13 | 14 | ### Fund the script address 15 | Send some funds to the script address. The steps are the same as in the [Plutus tutorial](./plutus-transaction.md), the only difference is that we will use an `inline_datum` and a `reference_script`. 16 | 17 | ```sh 18 | cardano-cli transaction build-raw \ 19 | ... 20 | --tx-out $(cat script.addr)+0 \ 21 | --tx-out-inline-datum-value '"chocolate"' \ 22 | --tx-out $(cat payment.addr)+2000000 \ 23 | --tx-out-reference-script-file datum-equals-redeemer-v2.plutus \ 24 | ... 25 | ``` 26 | 27 | ### The steps we need to take before creating the transaction are the same as in the [Plutus tutorial](./plutus-transaction.md) so we won't repeat them here. We do however skip the transaction drafting and fee calculating steps. 28 | 29 | ### Creating the unsigned transaction 30 | ```sh 31 | cardano-cli transaction build-raw \ 32 | --babbage-era \ 33 | --tx-in "1789f11f03143338cfcc0dbf3a93ad8f177e8698fc37ab3ab17c954cf2b28ee8#0" \ 34 | --spending-tx-in-reference "1789f11f03143338cfcc0dbf3a93ad8f177e8698fc37ab3ab17c954cf2b28ee8#1" \ 35 | --spending-plutus-script-v2 \ 36 | --spending-reference-tx-in-inline-datum-present \ 37 | --spending-reference-tx-in-redeemer-value '"chocolate"' \ 38 | --spending-reference-tx-in-execution-units "(2000000, 6000)" \ 39 | --tx-in-collateral "1789f11f03143338cfcc0dbf3a93ad8f177e8698fc37ab3ab17c954cf2b28ee8#1" \ 40 | --tx-out-return-collateral $(cat payment.addr)+23000000 \ 41 | --tx-out "$(cat payment.addr)"+0 \ 42 | --required-signer-hash $(cardano-cli address key-hash --payment-verification-key-file payment.vkey) \ 43 | --fee 4000000 \ 44 | --tx-total-collateral 8000000 \ 45 | --protocol-params-file protocol.json \ 46 | --out-file tx.draft \ 47 | --cddl-format 48 | ``` 49 | Note that your Plutus script may require different execution units. 50 | 51 | ### The steps for submitting the transaction are the same as in the [Plutus tutorial](./plutus-transaction.md) so we won't repeat them here. -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | import {CommandType} from './command-parser/argTypes' 3 | import {parse} from './command-parser/commandParser' 4 | import {parseAppVersion} from './command-parser/parsers' 5 | import {CommandExecutor} from './commandExecutor' 6 | import {Errors, ExitCode} from './errors' 7 | import {transformTx, validateTx} from './transaction/transactionValidation' 8 | 9 | const executeCommand = async (): Promise => { 10 | const {parser, parsedArgs} = parse(process.argv) 11 | if (!Object.values(CommandType).includes(parsedArgs.command)) { 12 | parser.print_help() 13 | return ExitCode.Success 14 | } 15 | 16 | const {version, commit} = parseAppVersion() 17 | 18 | // calls that don't need a cryptoProvider 19 | switch (parsedArgs.command) { 20 | case CommandType.APP_VERSION: 21 | console.log(`Cardano HW CLI Tool version ${version}`) 22 | if (commit) console.log(`Commit hash: ${commit}`) 23 | return ExitCode.Success 24 | case CommandType.VALIDATE_TRANSACTION: 25 | return validateTx(parsedArgs) 26 | case CommandType.TRANSFORM_TRANSACTION: 27 | transformTx(parsedArgs) 28 | return ExitCode.Success 29 | default: 30 | break 31 | } 32 | 33 | const commandExecutor = await CommandExecutor() 34 | switch (parsedArgs.command) { 35 | case CommandType.DEVICE_VERSION: 36 | await commandExecutor.printDeviceVersion() 37 | break 38 | case CommandType.SHOW_ADDRESS: 39 | await commandExecutor.showAddress(parsedArgs) 40 | break 41 | case CommandType.ADDRESS_KEY_GEN: 42 | await commandExecutor.createSigningKeyFile(parsedArgs) 43 | break 44 | case CommandType.VERIFICATION_KEY: 45 | await commandExecutor.createVerificationKeyFile(parsedArgs) 46 | break 47 | case CommandType.DERIVE_NATIVE_SCRIPT_HASH: 48 | await commandExecutor.createTxPolicyId(parsedArgs) 49 | break 50 | case CommandType.WITNESS_TRANSACTION: 51 | await commandExecutor.createTxWitnesses(parsedArgs) 52 | break 53 | case CommandType.NODE_KEY_GEN: 54 | await commandExecutor.createNodeSigningKeyFiles(parsedArgs) 55 | break 56 | case CommandType.SIGN_OPERATIONAL_CERTIFICATE: 57 | await commandExecutor.createSignedOperationalCertificate(parsedArgs) 58 | break 59 | case CommandType.CIP36_REGISTRATION_METADATA: 60 | await commandExecutor.createCIP36RegistrationMetadata(parsedArgs) 61 | break 62 | case CommandType.SIGN_MESSAGE: 63 | await commandExecutor.createSignedMessage(parsedArgs) 64 | break 65 | default: 66 | throw Error(Errors.UndefinedCommandError) 67 | } 68 | 69 | return ExitCode.Success 70 | } 71 | 72 | executeCommand() 73 | .then((exitCode: ExitCode) => process.exit(exitCode)) 74 | .catch((e: Error) => { 75 | console.error('Error:', e.message) 76 | process.exit(ExitCode.Error) 77 | }) 78 | -------------------------------------------------------------------------------- /src/guards.ts: -------------------------------------------------------------------------------- 1 | import {txEnvelopeTypes} from './constants' 2 | import { 3 | BIP32Path, 4 | CborHex, 5 | CardanoEra, 6 | PubKeyHex, 7 | PubKeyCborHex, 8 | ChainCodeHex, 9 | XPubKeyHex, 10 | XPubKeyCborHex, 11 | VotePublicKeyHex, 12 | PUB_KEY_HEX_LENGTH, 13 | VERIFICATION_KEY_CBOR_HEX_LENGTH, 14 | CHAIN_CODE_HEX_LENGTH, 15 | X_PUB_KEY_HEX_LENGTH, 16 | X_PUB_KEY_CBOR_HEX_LENGTH, 17 | VOTE_PUBLIC_KEY_HEX_LENGTH, 18 | DerivationType, 19 | } from './basicTypes' 20 | import {decodeCbor} from './util' 21 | import {TxFileData, HwSigningData} from './command-parser/argTypes' 22 | 23 | export const isEra = (value: unknown): value is CardanoEra => 24 | Object.values(CardanoEra).includes(value as CardanoEra) 25 | 26 | export const isCborHex = (value: unknown): value is CborHex => { 27 | try { 28 | decodeCbor(value) 29 | return true 30 | } catch (e) { 31 | return false 32 | } 33 | } 34 | 35 | const isString = (value: unknown): value is string => 36 | value != null && typeof value === 'string' 37 | 38 | export const isBIP32Path = (value: unknown): value is BIP32Path => 39 | Array.isArray(value) && value.every((element) => Number.isInteger(element)) 40 | 41 | export const isHwSigningData = (value: unknown): value is HwSigningData => 42 | typeof value === 'object' && 43 | value !== null && 44 | 'path' in value && 45 | isBIP32Path(value.path) && 46 | 'cborXPubKeyHex' in value && 47 | isString(value.cborXPubKeyHex) 48 | 49 | export const isTxFileData = (value: unknown): value is TxFileData => 50 | typeof value === 'object' && 51 | value !== null && 52 | 'era' in value && 53 | isEra(value.era) && 54 | 'description' in value && 55 | isString(value.description) && 56 | 'cborHex' in value && 57 | isCborHex(value.cborHex) && 58 | 'envelopeType' in value && 59 | txEnvelopeTypes.includes(value.envelopeType as string) 60 | 61 | export const isArrayOfType = ( 62 | value: unknown, 63 | valueGuard: (item: unknown) => boolean, 64 | ): value is T[] => 65 | Array.isArray(value) && (value as unknown[]).every((item) => valueGuard(item)) 66 | 67 | export const isPubKeyHex = (value: unknown): value is PubKeyHex => 68 | typeof value === 'string' && value.length === PUB_KEY_HEX_LENGTH * 2 69 | 70 | export const isPubKeyCborHex = (value: unknown): value is PubKeyCborHex => 71 | typeof value === 'string' && 72 | value.length === VERIFICATION_KEY_CBOR_HEX_LENGTH * 2 73 | 74 | export const isChainCodeHex = (value: unknown): value is ChainCodeHex => 75 | typeof value === 'string' && value.length === CHAIN_CODE_HEX_LENGTH * 2 76 | 77 | export const isXPubKeyHex = (value: unknown): value is XPubKeyHex => 78 | typeof value === 'string' && value.length === X_PUB_KEY_HEX_LENGTH * 2 79 | 80 | export const isXPubKeyCborHex = (value: unknown): value is XPubKeyCborHex => 81 | typeof value === 'string' && value.length === X_PUB_KEY_CBOR_HEX_LENGTH * 2 82 | 83 | export const isVotePublicKeyHex = (value: unknown): value is VotePublicKeyHex => 84 | typeof value === 'string' && value.length === VOTE_PUBLIC_KEY_HEX_LENGTH * 2 85 | 86 | export const isDerivationType = (value: unknown): value is DerivationType => 87 | typeof value === 'string' && value in DerivationType 88 | -------------------------------------------------------------------------------- /test/integration/ledger/node/signMessage.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | import assert from 'assert' 3 | import {LedgerCryptoProvider} from '../../../../src/crypto-providers/ledgerCryptoProvider' 4 | 5 | import {signingFiles} from './signingFiles' 6 | import {getTransport} from './speculos' 7 | import {CryptoProvider} from '../../../../src/crypto-providers/cryptoProvider' 8 | import { 9 | CommandType, 10 | HwSigningData, 11 | ParsedSignMessageArguments, 12 | } from '../../../../src/command-parser/argTypes' 13 | import {HexString, HumanAddress} from '../../../../src/basicTypes' 14 | 15 | type TestData = { 16 | args: ParsedSignMessageArguments 17 | expectedResult: { 18 | signatureHex: string 19 | signingPublicKeyHex: string 20 | addressFieldHex: string 21 | } 22 | } 23 | 24 | const msgTests: {[testName: string]: TestData} = { 25 | msg01: { 26 | args: { 27 | command: CommandType.SIGN_MESSAGE, 28 | messageHex: '68656c6c6f20776f726c64' as HexString, 29 | hwSigningFileData: signingFiles.stake0 as HwSigningData, 30 | hashPayload: false, 31 | preferHexDisplay: false, 32 | outFile: 'msg.out', 33 | }, 34 | expectedResult: { 35 | signatureHex: 36 | '3142bab939dc3a73329190c55b6aa2dae169ae1e5767b96cf1d2f9c79bc7974ffbaea46c06148b0a5f3240f177cde8437d79706879a3bfbcf74e110504ea3201', 37 | signingPublicKeyHex: 38 | '66610efd336e1137c525937b76511fbcf2a0e6bcf0d340a67bcb39bc870d85e8', 39 | addressFieldHex: 40 | '1d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c', 41 | }, 42 | }, 43 | msg02: { 44 | args: { 45 | command: CommandType.SIGN_MESSAGE, 46 | messageHex: '68656c6c6f20776f726c64' as HexString, 47 | hwSigningFileData: signingFiles.payment0 as HwSigningData, 48 | hashPayload: true, 49 | preferHexDisplay: false, 50 | address: 51 | 'addr_test1qq2vzmtlgvjrhkq50rngh8d482zj3l20kyrc6kx4ffl3zfqayfawlf9hwv2fzuygt2km5v92kvf8e3s3mk7ynxw77cwq2glhm4' as HumanAddress, 52 | addressHwSigningFileData: [ 53 | signingFiles.payment0 as HwSigningData, 54 | signingFiles.stake0 as HwSigningData, 55 | ], 56 | outFile: 'msg.out', 57 | }, 58 | expectedResult: { 59 | signatureHex: 60 | '56ebf5bbea63aafbf1440cd63c5fbcbe3de799de401d48165a366e10f36c17b490c261ea8a00cf464cf7140732369cc4e333eb6714cabe625abddac1cd9dd20b', 61 | signingPublicKeyHex: 62 | 'cd2b047d1a803eee059769cffb3dfd0a4b9327e55bc78aa962d9bd4f720db0b2', 63 | addressFieldHex: 64 | '0014c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c', 65 | }, 66 | }, 67 | } 68 | 69 | async function testMessageSigning( 70 | cryptoProvider: CryptoProvider, 71 | msgTestData: TestData, 72 | ) { 73 | const {expectedResult, args} = msgTestData 74 | const result = await cryptoProvider.signMessage(args) 75 | assert.deepStrictEqual(result, expectedResult) 76 | } 77 | 78 | describe('Ledger sign message', () => { 79 | let cryptoProvider: CryptoProvider 80 | // eslint-disable-next-line prefer-arrow-callback 81 | before(async function () { 82 | this.timeout(10000) 83 | cryptoProvider = await LedgerCryptoProvider(await getTransport()) 84 | }) 85 | const messagesToSign = Object.entries(msgTests) 86 | 87 | messagesToSign.forEach(([testName, testData]) => 88 | it(`Should sign ${testName}`, async () => 89 | await testMessageSigning(cryptoProvider, testData)).timeout(100000), 90 | ) 91 | }) 92 | -------------------------------------------------------------------------------- /src/constants.ts: -------------------------------------------------------------------------------- 1 | import {Network, NetworkIds, ProtocolMagics, CardanoEra} from './basicTypes' 2 | import {invertObject} from './util' 3 | 4 | // taken from https://book.world.dev.cardano.org/environments.html 5 | export const NETWORKS: {[key: string]: Network} = { 6 | MAINNET: { 7 | networkId: NetworkIds.MAINNET, 8 | protocolMagic: ProtocolMagics.MAINNET, 9 | }, 10 | TESTNET_PREVIEW: { 11 | networkId: NetworkIds.TESTNET, 12 | protocolMagic: ProtocolMagics.TESTNET_PREVIEW, 13 | }, 14 | TESTNET_PREPROD: { 15 | networkId: NetworkIds.TESTNET, 16 | protocolMagic: ProtocolMagics.TESTNET_PREPROD, 17 | }, 18 | // we keep these because some test CBORs contain them 19 | TESTNET_LEGACY1: { 20 | networkId: NetworkIds.TESTNET, 21 | protocolMagic: ProtocolMagics.TESTNET_LEGACY1, 22 | }, 23 | TESTNET_LEGACY2: { 24 | networkId: NetworkIds.TESTNET, 25 | protocolMagic: ProtocolMagics.TESTNET_LEGACY2, 26 | }, 27 | } 28 | 29 | export const HARDENED_THRESHOLD = 0x80000000 30 | 31 | // the 'Catalyst' value for voting_purpose in https://cips.cardano.org/cips/cip36/ 32 | export const CIP36_VOTING_PURPOSE_CATALYST = 0n 33 | 34 | export enum PathLabel { 35 | PAYMENT = 'Payment', 36 | STAKE = 'Stake', 37 | DREP = 'DRep', 38 | COMMITTEE_COLD = 'ConstitutionalCommitteeCold', 39 | COMMITTEE_HOT = 'ConstitutionalCommitteeHot', 40 | POOL_COLD = 'StakePool', 41 | CIP36_VOTE = 'CIP36Vote', 42 | } 43 | 44 | // Unwitnessed, Witnessed and Signed types follow the same CDDL format, they are just used 45 | // in different contexts 46 | 47 | export const cardanoEraToUnwitnessedType: {[key in CardanoEra]: string} = { 48 | [CardanoEra.BYRON]: 'Unwitnessed Tx ByronEra', 49 | [CardanoEra.SHELLEY]: 'Unwitnessed Tx ShelleyEra', 50 | [CardanoEra.ALLEGRA]: 'Unwitnessed Tx AllegraEra', 51 | [CardanoEra.MARY]: 'Unwitnessed Tx MaryEra', 52 | [CardanoEra.ALONZO]: 'Unwitnessed Tx AlonzoEra', 53 | [CardanoEra.BABBAGE]: 'Unwitnessed Tx BabbageEra', 54 | [CardanoEra.CONWAY]: 'Unwitnessed Tx ConwayEra', 55 | } 56 | 57 | export const cardanoEraToWitnessedType: {[key in CardanoEra]: string} = { 58 | [CardanoEra.BYRON]: 'Witnessed Tx ByronEra', 59 | [CardanoEra.SHELLEY]: 'Witnessed Tx ShelleyEra', 60 | [CardanoEra.ALLEGRA]: 'Witnessed Tx AllegraEra', 61 | [CardanoEra.MARY]: 'Witnessed Tx MaryEra', 62 | [CardanoEra.ALONZO]: 'Witnessed Tx AlonzoEra', 63 | [CardanoEra.BABBAGE]: 'Witnessed Tx BabbageEra', 64 | [CardanoEra.CONWAY]: 'Witnessed Tx ConwayEra', 65 | } 66 | 67 | export const cardanoEraToSignedType: {[key in CardanoEra]: string} = { 68 | [CardanoEra.BYRON]: 'TxSignedByron', 69 | [CardanoEra.SHELLEY]: 'TxSignedShelley', 70 | [CardanoEra.ALLEGRA]: 'Tx AllegraEra', 71 | [CardanoEra.MARY]: 'Tx MaryEra', 72 | [CardanoEra.ALONZO]: 'Tx AlonzoEra', 73 | [CardanoEra.BABBAGE]: 'Tx BabbageEra', 74 | [CardanoEra.CONWAY]: 'Tx ConwayEra', 75 | } 76 | 77 | export const txTypeToCardanoEra: {[key: string]: string} = { 78 | ...invertObject(cardanoEraToUnwitnessedType), 79 | ...invertObject(cardanoEraToWitnessedType), 80 | ...invertObject(cardanoEraToSignedType), 81 | } 82 | 83 | export const cardanoEraToWitnessType: {[key in CardanoEra]: string} = { 84 | [CardanoEra.BYRON]: 'TxWitnessByron', 85 | [CardanoEra.SHELLEY]: 'TxWitnessShelley', 86 | [CardanoEra.ALLEGRA]: 'TxWitness AllegraEra', 87 | [CardanoEra.MARY]: 'TxWitness MaryEra', 88 | [CardanoEra.ALONZO]: 'TxWitness AlonzoEra', 89 | [CardanoEra.BABBAGE]: 'TxWitness BabbageEra', 90 | [CardanoEra.CONWAY]: 'TxWitness ConwayEra', 91 | } 92 | 93 | export const txEnvelopeTypes: string[] = Object.keys(txTypeToCardanoEra) 94 | -------------------------------------------------------------------------------- /test/integration/keystone/node/signMessage.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | import assert from 'assert' 3 | 4 | import {signingFiles} from './signingFiles' 5 | import {CryptoProvider} from '../../../../src/crypto-providers/cryptoProvider' 6 | import { 7 | CommandType, 8 | HwSigningData, 9 | ParsedSignMessageArguments, 10 | } from '../../../../src/command-parser/argTypes' 11 | import {HexString, HumanAddress} from '../../../../src/basicTypes' 12 | import {KeystoneCryptoProvider} from '../../../../src/crypto-providers/keystoneCryptoProvider' 13 | import {TransportNodeUSB} from '@keystonehq/hw-transport-nodeusb' 14 | 15 | type TestData = { 16 | args: ParsedSignMessageArguments 17 | expectedResult: { 18 | signatureHex: string 19 | signingPublicKeyHex: string 20 | addressFieldHex: string 21 | } 22 | } 23 | 24 | const msgTests: {[testName: string]: TestData} = { 25 | msg01: { 26 | args: { 27 | command: CommandType.SIGN_MESSAGE, 28 | messageHex: '68656c6c6f20776f726c64' as HexString, 29 | hwSigningFileData: signingFiles.stake0 as HwSigningData, 30 | hashPayload: false, 31 | preferHexDisplay: false, 32 | outFile: 'msg.out', 33 | }, 34 | expectedResult: { 35 | signatureHex: 36 | '3142bab939dc3a73329190c55b6aa2dae169ae1e5767b96cf1d2f9c79bc7974ffbaea46c06148b0a5f3240f177cde8437d79706879a3bfbcf74e110504ea3201', 37 | signingPublicKeyHex: 38 | '66610efd336e1137c525937b76511fbcf2a0e6bcf0d340a67bcb39bc870d85e8', 39 | addressFieldHex: 40 | '1d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c', 41 | }, 42 | }, 43 | msg02: { 44 | args: { 45 | command: CommandType.SIGN_MESSAGE, 46 | messageHex: '68656c6c6f20776f726c64' as HexString, 47 | hwSigningFileData: signingFiles.payment0 as HwSigningData, 48 | hashPayload: true, 49 | preferHexDisplay: false, 50 | address: 51 | 'addr_test1qq2vzmtlgvjrhkq50rngh8d482zj3l20kyrc6kx4ffl3zfqayfawlf9hwv2fzuygt2km5v92kvf8e3s3mk7ynxw77cwq2glhm4' as HumanAddress, 52 | addressHwSigningFileData: [ 53 | signingFiles.payment0 as HwSigningData, 54 | signingFiles.stake0 as HwSigningData, 55 | ], 56 | outFile: 'msg.out', 57 | }, 58 | expectedResult: { 59 | signatureHex: 60 | '56ebf5bbea63aafbf1440cd63c5fbcbe3de799de401d48165a366e10f36c17b490c261ea8a00cf464cf7140732369cc4e333eb6714cabe625abddac1cd9dd20b', 61 | signingPublicKeyHex: 62 | 'cd2b047d1a803eee059769cffb3dfd0a4b9327e55bc78aa962d9bd4f720db0b2', 63 | addressFieldHex: 64 | '0014c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c', 65 | }, 66 | }, 67 | } 68 | 69 | async function testMessageSigning( 70 | cryptoProvider: CryptoProvider, 71 | msgTestData: TestData, 72 | ) { 73 | const {expectedResult, args} = msgTestData 74 | const result = await cryptoProvider.signMessage(args) 75 | assert.deepStrictEqual(result, expectedResult) 76 | } 77 | 78 | describe('Keystone sign message', () => { 79 | let cryptoProvider: CryptoProvider 80 | // eslint-disable-next-line prefer-arrow-callback 81 | before(async function () { 82 | this.timeout(10000) 83 | cryptoProvider = await KeystoneCryptoProvider( 84 | await TransportNodeUSB.connect({ 85 | timeout: 100000, 86 | }), 87 | ) 88 | }) 89 | const messagesToSign = Object.entries(msgTests) 90 | 91 | messagesToSign.forEach(([testName, testData]) => 92 | it(`Should sign ${testName}`, async () => 93 | await testMessageSigning(cryptoProvider, testData)).timeout(100000), 94 | ) 95 | }) 96 | -------------------------------------------------------------------------------- /scripts/autocomplete.sh: -------------------------------------------------------------------------------- 1 | _cardano_hw_cli_completions() 2 | { 3 | case $COMP_CWORD in 4 | 1) 5 | COMPREPLY=( $(compgen -W "device version address key transaction node vote" "${COMP_WORDS[1]}") ) 6 | ;; 7 | 2) 8 | if [ "${COMP_WORDS[1]}" = "address" ]; then 9 | COMPREPLY=( $(compgen -W "key-gen show" "${COMP_WORDS[2]}") ) 10 | fi 11 | if [ "${COMP_WORDS[1]}" = "key" ]; then 12 | COMPREPLY=( $(compgen -W "verification-key" "${COMP_WORDS[2]}") ) 13 | fi 14 | if [ "${COMP_WORDS[1]}" = "transaction" ]; then 15 | COMPREPLY=( $(compgen -W "witness policyid validate transform" "${COMP_WORDS[2]}") ) 16 | fi 17 | if [ "${COMP_WORDS[1]}" = "device" ]; then 18 | COMPREPLY=( $(compgen -W "version" "${COMP_WORDS[2]}") ) 19 | fi 20 | if [ "${COMP_WORDS[1]}" = "node" ]; then 21 | COMPREPLY=( $(compgen -W "key-gen issue-op-cert" "${COMP_WORDS[2]}") ) 22 | fi 23 | if [ "${COMP_WORDS[1]}" = "vote" ]; then 24 | COMPREPLY=( $(compgen -W "registration-metadata" "${COMP_WORDS[2]}") ) 25 | fi 26 | ;; 27 | *) 28 | if [ "${COMP_WORDS[1]}" = "address" ] && [ "${COMP_WORDS[2]}" = "key-gen" ]; then 29 | COMPREPLY=( $(compgen -W "--path --hw-signing-file --verification-key-file --derivation-type" -- "${COMP_WORDS[-1]}") ) 30 | fi 31 | if [ "${COMP_WORDS[2]}" = "show" ]; then 32 | COMPREPLY=( $(compgen -W "--payment-path --staking-path --address-file --derivation-type" -- "${COMP_WORDS[-1]}") ) 33 | fi 34 | if [ "${COMP_WORDS[2]}" = "verification-key" ]; then 35 | COMPREPLY=( $(compgen -W "--hw-signing-file --verification-key-file" -- "${COMP_WORDS[-1]}") ) 36 | fi 37 | if [ "${COMP_WORDS[2]}" = "witness" ]; then 38 | COMPREPLY=( $(compgen -W "--mainnet --testnet-magic --hw-signing-file --change-output-key-file --out-file --derivation-type" -- "${COMP_WORDS[-1]}") ) 39 | fi 40 | if [ "${COMP_WORDS[2]}" = "policyid" ]; then 41 | COMPREPLY=( $(compgen -W "--script-file --hw-signing-file --derivation-type" -- "${COMP_WORDS[-1]}") ) 42 | fi 43 | if [ "${COMP_WORDS[2]}" = "validate" ]; then 44 | COMPREPLY=( $(compgen -W "--tx-file" -- "${COMP_WORDS[-1]}") ) 45 | fi 46 | if [ "${COMP_WORDS[2]}" = "transform" ]; then 47 | COMPREPLY=( $(compgen -W "--tx-file --out-file" -- "${COMP_WORDS[-1]}") ) 48 | fi 49 | if [ "${COMP_WORDS[1]}" = "node" ] && [ "${COMP_WORDS[2]}" = "key-gen" ]; then 50 | COMPREPLY=( $(compgen -W "--path --hw-signing-file --cold-verification-key-file --operational-certificate-issue-counter-file" -- "${COMP_WORDS[-1]}") ) 51 | fi 52 | if [ "${COMP_WORDS[2]}" = "issue-op-cert" ]; then 53 | COMPREPLY=( $(compgen -W "--kes-verification-key-file --kes-period --operational-certificate-issue-counter-file --hw-signing-file --out-file" -- "${COMP_WORDS[-1]}") ) 54 | fi 55 | if [ "${COMP_WORDS[2]}" = "registration-metadata" ]; then 56 | COMPREPLY=( $(compgen -W "--mainnet --testnet-magic --vote-public-key --payment-address --stake-signing-key --nonce --voting-purpose --payment-address-signing-key --metadata-cbor-out-file --derivation-type" -- "${COMP_WORDS[-1]}") ) 57 | fi 58 | ;; 59 | esac 60 | } 61 | 62 | complete -F _cardano_hw_cli_completions cardano-hw-cli 63 | -------------------------------------------------------------------------------- /test/integration/keystone/node/conway_era_tx.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | import assert from 'assert' 3 | import {decodeTx} from 'cardano-hw-interop-lib' 4 | import {NETWORKS} from '../../../../src/constants' 5 | import { 6 | determineSigningMode, 7 | getTxBodyHash, 8 | } from '../../../../src/crypto-providers/util' 9 | import {validateWitnessing} from '../../../../src/crypto-providers/witnessingValidation' 10 | import {validateTxBeforeWitnessing} from '../../../../src/transaction/transactionValidation' 11 | 12 | import {signingFiles} from './signingFiles' 13 | import {CardanoEra} from '../../../../src/basicTypes' 14 | import {CryptoProvider} from '../../../../src/crypto-providers/cryptoProvider' 15 | import {TransportNodeUSB} from '@keystonehq/hw-transport-nodeusb' 16 | import {KeystoneCryptoProvider} from '../../../../src/crypto-providers/keystoneCryptoProvider' 17 | 18 | const transactions = { 19 | ordinary_ConwayEraInputAndOutput: { 20 | cborHex: 21 | '84a500d9010282825820d86a9132d14007f86c3bf857a6361679d2eac0ae0b09f20d8ed86c391fef9baa00825820d86a9132d14007f86c3bf857a6361679d2eac0ae0b09f20d8ed86c391fef9baa0101818258390074976c54afaf444f7cd499bd8519aac6592b13b22b9d5817f0da5c5203d205532089ad2f7816892e2ef42849b7b52788e41b3fd43a6e01cf1b0000000bdb93e873021a0002a5f1031a02d3bf4205a1581de003d205532089ad2f7816892e2ef42849b7b52788e41b3fd43a6e01cf1b0000000bdad30ef3a0f5f6', 22 | hwSigningFiles: [signingFiles.payment0], 23 | network: 'MAINNET', 24 | witnesses: { 25 | byronWitnesses: [], 26 | shelleyWitnesses: [ 27 | { 28 | key: 0, 29 | data: [ 30 | Buffer.from( 31 | 'cd2b047d1a803eee059769cffb3dfd0a4b9327e55bc78aa962d9bd4f720db0b2', 32 | 'hex', 33 | ), 34 | Buffer.from( 35 | 'e3e6c81a40f2a3a4ace9a5b3a7dfbac12a9f69115d0800145e163f4ed347dd9367e4e06ae6c4f4899b19c958c88fa4b81b17679b135a45b85f84aa0216ffc408', 36 | 'hex', 37 | ), 38 | ], 39 | path: signingFiles.payment0.path, 40 | }, 41 | ], 42 | }, 43 | }, 44 | } 45 | 46 | async function testTxWitnessing( 47 | cryptoProvider: CryptoProvider, 48 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 49 | transaction: any, 50 | ) { 51 | validateTxBeforeWitnessing(transaction.cborHex) 52 | const txCbor = Buffer.from(transaction.cborHex, 'hex') 53 | const tx = decodeTx(txCbor) 54 | 55 | const signingParameters = { 56 | signingMode: determineSigningMode(tx.body, transaction.hwSigningFiles), 57 | tx, 58 | txBodyHashHex: getTxBodyHash(tx.body), 59 | hwSigningFileData: transaction.hwSigningFiles, 60 | network: NETWORKS[transaction.network], 61 | era: CardanoEra.CONWAY, 62 | } 63 | const changeOutputFiles = transaction.changeOutputFiles || [] 64 | validateWitnessing(signingParameters) 65 | 66 | const witnesses = await cryptoProvider.witnessTx( 67 | signingParameters, 68 | changeOutputFiles, 69 | ) 70 | 71 | // In the current version, Keystone 3 Pro does not support this path. It will be supported in the next version. 72 | assert.deepStrictEqual(witnesses, transaction.witnesses) 73 | } 74 | 75 | describe('Keystone conway era tx witnessing', () => { 76 | let cryptoProvider: CryptoProvider 77 | // eslint-disable-next-line prefer-arrow-callback 78 | before(async function () { 79 | this.timeout(10000) 80 | cryptoProvider = await KeystoneCryptoProvider( 81 | await TransportNodeUSB.connect({ 82 | timeout: 100000, 83 | }), 84 | ) 85 | }) 86 | const txs = Object.entries(transactions) 87 | 88 | txs.forEach(([txType, tx]) => 89 | it(`Should witness byron tx ${txType}`, async () => 90 | await testTxWitnessing(cryptoProvider, tx)).timeout(100000), 91 | ) 92 | }) 93 | -------------------------------------------------------------------------------- /test/unit/output/signMessageOutput.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | import assert from 'assert' 3 | 4 | import {constructSignedMessageOutput} from '../../../src/fileWriter' 5 | import {HexString} from '../../../src/basicTypes' 6 | import {SignedMessageData} from '../../../src/signMessage/signMessage' 7 | 8 | // data verified by M. Lang 9 | describe('Sign message output', () => { 10 | it('Should generate correct output for a hashed message', () => { 11 | const messageHex = 'fa'.repeat(349) as HexString 12 | const hashPayload = true 13 | const signedMsgData = { 14 | signatureHex: 15 | '6fcc42c954ecaa143c8fab436a5cc1d0beb4f46c29c7e554d3593d5c4343b27e83a66b3df011c3197e88032a2e879730c67db71ed0f2d9cd3e9a0978990d3a02', 16 | signingPublicKeyHex: 17 | '7cc18df2fbd3ee1b16b76843b18446679ab95dbcd07b7833b66a9407c0709e37', 18 | addressFieldHex: 19 | 'ba41c59ac6e1a0e4ac304af98db801097d0bf8d2a5b28a54752426a1', 20 | } as SignedMessageData 21 | const output = constructSignedMessageOutput( 22 | messageHex, 23 | hashPayload, 24 | signedMsgData, 25 | ) 26 | const expectedOutput = { 27 | messageHex, 28 | isHashed: hashPayload, 29 | addressHex: 'ba41c59ac6e1a0e4ac304af98db801097d0bf8d2a5b28a54752426a1', 30 | signatureHex: 31 | '6fcc42c954ecaa143c8fab436a5cc1d0beb4f46c29c7e554d3593d5c4343b27e83a66b3df011c3197e88032a2e879730c67db71ed0f2d9cd3e9a0978990d3a02', 32 | publicKeyHex: 33 | '7cc18df2fbd3ee1b16b76843b18446679ab95dbcd07b7833b66a9407c0709e37', 34 | COSE_Sign1_hex: 35 | '845829a201276761646472657373581cba41c59ac6e1a0e4ac304af98db801097d0bf8d2a5b28a54752426a1a166686173686564f5581c47b2016f3ee8e36dbf83585571c7401236f4aee218ed11264dea91fc58406fcc42c954ecaa143c8fab436a5cc1d0beb4f46c29c7e554d3593d5c4343b27e83a66b3df011c3197e88032a2e879730c67db71ed0f2d9cd3e9a0978990d3a02', 36 | COSE_Key_hex: 37 | 'a40101032720062158207cc18df2fbd3ee1b16b76843b18446679ab95dbcd07b7833b66a9407c0709e37', 38 | } 39 | assert.deepStrictEqual(output, expectedOutput) 40 | }) 41 | 42 | it('Should generate correct output for a non-hashed message', () => { 43 | const messageHex = 'deadbeef' as HexString 44 | const hashPayload = false 45 | const signedMsgData = { 46 | signatureHex: 47 | '92586e24a1a43b538720ea3915be0f6536f0894e4ea88713c01f948673865b6d2189a0306bbefc124954e578f8aa1d0f131b1d3e7af7827d1b4488d6fa0f6b07', 48 | signingPublicKeyHex: 49 | '650eb87ddfffe7babd505f2d66c2db28b1c05ac54f9121589107acd6eb20cc2c', 50 | addressFieldHex: 51 | '015a53103829a7382c2ab76111fb69f13e69d616824c62058e44f1a8b31d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c', 52 | } as SignedMessageData 53 | const output = constructSignedMessageOutput( 54 | messageHex, 55 | hashPayload, 56 | signedMsgData, 57 | ) 58 | const expectedOutput = { 59 | messageHex, 60 | isHashed: hashPayload, 61 | addressHex: 62 | '015a53103829a7382c2ab76111fb69f13e69d616824c62058e44f1a8b31d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c', 63 | signatureHex: 64 | '92586e24a1a43b538720ea3915be0f6536f0894e4ea88713c01f948673865b6d2189a0306bbefc124954e578f8aa1d0f131b1d3e7af7827d1b4488d6fa0f6b07', 65 | publicKeyHex: 66 | '650eb87ddfffe7babd505f2d66c2db28b1c05ac54f9121589107acd6eb20cc2c', 67 | COSE_Sign1_hex: 68 | '845846a2012767616464726573735839015a53103829a7382c2ab76111fb69f13e69d616824c62058e44f1a8b31d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61ca166686173686564f444deadbeef584092586e24a1a43b538720ea3915be0f6536f0894e4ea88713c01f948673865b6d2189a0306bbefc124954e578f8aa1d0f131b1d3e7af7827d1b4488d6fa0f6b07', 69 | COSE_Key_hex: 70 | 'a4010103272006215820650eb87ddfffe7babd505f2d66c2db28b1c05ac54f9121589107acd6eb20cc2c', 71 | } 72 | assert.deepStrictEqual(output, expectedOutput) 73 | }) 74 | }) 75 | -------------------------------------------------------------------------------- /test/integration/trezor/node/signingFiles.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | 3 | import {HARDENED_THRESHOLD} from '../../../../src/constants' 4 | import {HwSigningType} from '../../../../src/command-parser/argTypes' 5 | 6 | // mnemonic "all all all all all all all all all all all all" 7 | 8 | const signingFiles = { 9 | payment0: { 10 | type: HwSigningType.Payment, 11 | path: [ 12 | 1852 + HARDENED_THRESHOLD, 13 | 1815 + HARDENED_THRESHOLD, 14 | 0 + HARDENED_THRESHOLD, 15 | 0, 16 | 0, 17 | ], 18 | cborXPubKeyHex: 19 | '58405d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c1f123474e140a2c360b01f0fa66f2f22e2e965a5b07a80358cf75f77abbd66088', 20 | }, 21 | stake0: { 22 | type: HwSigningType.Stake, 23 | path: [ 24 | 1852 + HARDENED_THRESHOLD, 25 | 1815 + HARDENED_THRESHOLD, 26 | 0 + HARDENED_THRESHOLD, 27 | 2, 28 | 0, 29 | ], 30 | cborXPubKeyHex: 31 | '5840bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e413a00f69b7700a96f67c149b7c8eec88afd7f0b9cfb4f86f4c5f1e56296ed90', 32 | }, 33 | byron0: { 34 | type: HwSigningType.Payment, 35 | path: [ 36 | 44 + HARDENED_THRESHOLD, 37 | 1815 + HARDENED_THRESHOLD, 38 | 0 + HARDENED_THRESHOLD, 39 | 0, 40 | 0, 41 | ], 42 | cborXPubKeyHex: 43 | '5840b90fb812a2268e9569ff1172e8daed1da3dc7e72c7bded7c5bcb7282039f90d5fd8e71c1543de2cdc7f7623130c5f2cceb53549055fa1f5bc88199989e08cce7', 44 | }, 45 | mint0: { 46 | type: HwSigningType.Mint, 47 | path: [ 48 | 1855 + HARDENED_THRESHOLD, 49 | 1815 + HARDENED_THRESHOLD, 50 | 0 + HARDENED_THRESHOLD, 51 | ], 52 | cborXPubKeyHex: 53 | '5840b75258e4f61eb7b313d8554c2fe10673cf214ca2d762bfd53ec3b7846e2ee8729ad37dc23fe1cda7b0ac5574c6f16171cdb2bb723496954770a2bf0e08334e8f', 54 | }, 55 | mint1: { 56 | type: HwSigningType.Mint, 57 | path: [ 58 | 1855 + HARDENED_THRESHOLD, 59 | 1815 + HARDENED_THRESHOLD, 60 | 1 + HARDENED_THRESHOLD, 61 | ], 62 | cborXPubKeyHex: 63 | '5840a54627d6d16724032172541d4261e7aa87c06395724f1d18975a21d56650bda9bccfd881a3bb7eefbfb885a80909c30892a9a2151f7530c10c68ec6e7a89b28a', 64 | }, 65 | multisigPayment0: { 66 | type: HwSigningType.MultiSig, 67 | path: [ 68 | 1854 + HARDENED_THRESHOLD, 69 | 1815 + HARDENED_THRESHOLD, 70 | 0 + HARDENED_THRESHOLD, 71 | 0, 72 | 0, 73 | ], 74 | cborXPubKeyHex: 75 | '5840b10be5c0d11ad8292bbe69e220ca0cfbe154610b3041a8e72f9d515c226ab3b165233c4f8300b95eb497ed313f7294500c0a4aa0bd24f2127c4d260861fff4e7', 76 | }, 77 | multisigPayment1: { 78 | type: HwSigningType.MultiSig, 79 | path: [ 80 | 1854 + HARDENED_THRESHOLD, 81 | 1815 + HARDENED_THRESHOLD, 82 | 0 + HARDENED_THRESHOLD, 83 | 0, 84 | 1, 85 | ], 86 | cborXPubKeyHex: 87 | '5840021a000e3be05eb09051983cbf728322149cc5687a79f0a1dbccd25b3a754c59fd1f24d96ba4d4fa344b5121ddfe77b9e8246e2885baa8c766bf35508498e2c5', 88 | }, 89 | multisigStake0: { 90 | type: HwSigningType.MultiSig, 91 | path: [ 92 | 1854 + HARDENED_THRESHOLD, 93 | 1815 + HARDENED_THRESHOLD, 94 | 0 + HARDENED_THRESHOLD, 95 | 2, 96 | 0, 97 | ], 98 | cborXPubKeyHex: 99 | '5840f2ef4ecd21ad28a8d270ca7be7e96c87f60dc821e13c0d0c5870344e9693637cab0d8a3fa4999bc06b0aa9d49bee11fb196dc55d57ff71507f053550c7bdc1e0', 100 | }, 101 | multisigStake1: { 102 | type: HwSigningType.MultiSig, 103 | path: [ 104 | 1854 + HARDENED_THRESHOLD, 105 | 1815 + HARDENED_THRESHOLD, 106 | 0 + HARDENED_THRESHOLD, 107 | 2, 108 | 1, 109 | ], 110 | cborXPubKeyHex: 111 | '58408c9a9345563ec749fbd804bd9b19f048c6686dbc32f4854174c6e4a278fcc0c58690f1fc8289353904711b5aa2d8889265a97a46b14f408b47a69e6fafab176f', 112 | }, 113 | } 114 | 115 | export {signingFiles} 116 | -------------------------------------------------------------------------------- /src/transaction/transactionValidation.ts: -------------------------------------------------------------------------------- 1 | import * as InteropLib from 'cardano-hw-interop-lib' 2 | import {Errors, ExitCode} from '../errors' 3 | import {partition} from '../util' 4 | import { 5 | ParsedTransactionValidateArguments, 6 | ParsedTransactionTransformArguments, 7 | } from '../command-parser/argTypes' 8 | import {constructTxFileOutput, writeOutputData} from '../fileWriter' 9 | import {containsVKeyWitnesses} from './transaction' 10 | import {CborHex} from '../basicTypes' 11 | 12 | const checkValidationErrors = ( 13 | cborHex: CborHex, 14 | validator: (txCbor: Buffer) => InteropLib.ValidationError[], 15 | printErrors: boolean, 16 | printSuccessMessage: boolean, 17 | ): {containsUnfixable: boolean; containsFixable: boolean} => { 18 | const cbor = Buffer.from(cborHex, 'hex') 19 | const validationErrors = validator(cbor) 20 | const [fixableErrors, unfixableErrors] = partition( 21 | validationErrors, 22 | (e) => e.fixable, 23 | ) 24 | const errorGroups = [ 25 | {title: 'unfixable', errors: unfixableErrors}, 26 | {title: 'fixable', errors: fixableErrors}, 27 | ] 28 | errorGroups.forEach(({title, errors}) => { 29 | if (errors.length > 0 && printErrors) { 30 | // eslint-disable-next-line no-console 31 | console.log(`The transaction contains following ${title} errors:`) 32 | // eslint-disable-next-line no-console 33 | errors.forEach((e) => console.log(`- ${e.reason} (${e.position})`)) 34 | } 35 | }) 36 | 37 | if (validationErrors.length === 0 && printSuccessMessage) { 38 | // eslint-disable-next-line no-console 39 | console.log('The transaction CBOR is valid and canonical.') 40 | } 41 | return { 42 | containsUnfixable: unfixableErrors.length > 0, 43 | containsFixable: fixableErrors.length > 0, 44 | } 45 | } 46 | 47 | const validateTxBeforeWitnessing = (txCborHex: CborHex): void => { 48 | const {containsUnfixable, containsFixable} = checkValidationErrors( 49 | txCborHex, 50 | InteropLib.validateTx, 51 | true, 52 | false, 53 | ) 54 | 55 | if (containsUnfixable) { 56 | throw Error(Errors.TxContainsUnfixableErrors) 57 | } 58 | if (containsFixable) { 59 | throw Error(Errors.TxContainsFixableErrors) 60 | } 61 | } 62 | 63 | const validateTx = (args: ParsedTransactionValidateArguments): ExitCode => { 64 | const {containsUnfixable, containsFixable} = checkValidationErrors( 65 | args.txFileData.cborHex, 66 | InteropLib.validateTx, 67 | true, 68 | true, 69 | ) 70 | if (containsUnfixable) return ExitCode.UnfixableValidationErrorsFound 71 | if (containsFixable) return ExitCode.FixableValidationErrorsFound 72 | return ExitCode.Success 73 | } 74 | 75 | const transformTx = (args: ParsedTransactionTransformArguments): void => { 76 | const {containsUnfixable, containsFixable} = checkValidationErrors( 77 | args.txFileData.cborHex, 78 | InteropLib.validateTx, 79 | true, 80 | true, 81 | ) 82 | if (containsUnfixable) { 83 | throw Error(Errors.TxContainsUnfixableErrors) 84 | } 85 | const txCbor = Buffer.from(args.txFileData.cborHex, 'hex') 86 | const transformedTx = InteropLib.transformTx(InteropLib.decodeTx(txCbor)) 87 | if (containsFixable) { 88 | if (containsVKeyWitnesses(transformedTx)) { 89 | throw Error(Errors.CannotTransformSignedTx) 90 | } 91 | // eslint-disable-next-line no-console 92 | console.log('Transformed transaction will be written to the output file.') 93 | } 94 | const encodedTx = InteropLib.encodeTx(transformedTx).toString( 95 | 'hex', 96 | ) as CborHex 97 | const txFileOutput = constructTxFileOutput( 98 | args.txFileData.envelopeType, 99 | args.txFileData.description, 100 | encodedTx, 101 | ) 102 | writeOutputData(args.outFile, txFileOutput) 103 | } 104 | 105 | export { 106 | checkValidationErrors, 107 | validateTxBeforeWitnessing, 108 | validateTx, 109 | transformTx, 110 | } 111 | -------------------------------------------------------------------------------- /src/basicTypes.ts: -------------------------------------------------------------------------------- 1 | export enum CardanoEra { 2 | BYRON = 'Byron', 3 | SHELLEY = 'Shelley', 4 | ALLEGRA = 'Allegra', 5 | MARY = 'Mary', 6 | ALONZO = 'Alonzo', 7 | BABBAGE = 'Babbage', 8 | CONWAY = 'Conway', 9 | } 10 | 11 | export type HexString = string & {__type: 'hex'} 12 | export type FixlenHexString = string & {__type: 'hex'; __length: N} 13 | 14 | export const PUB_KEY_HEX_LENGTH = 32 15 | export type PubKeyHex = FixlenHexString 16 | 17 | export const VERIFICATION_KEY_CBOR_HEX_LENGTH = 34 18 | export type PubKeyCborHex = FixlenHexString< 19 | typeof VERIFICATION_KEY_CBOR_HEX_LENGTH 20 | > 21 | 22 | export const CHAIN_CODE_HEX_LENGTH = 32 23 | export type ChainCodeHex = FixlenHexString 24 | 25 | export const X_PUB_KEY_HEX_LENGTH = 64 26 | export type XPubKeyHex = FixlenHexString 27 | 28 | export const X_PUB_KEY_CBOR_HEX_LENGTH = 66 29 | export type XPubKeyCborHex = FixlenHexString 30 | 31 | export const VOTE_PUBLIC_KEY_HEX_LENGTH = 32 32 | export type VotePublicKeyHex = FixlenHexString< 33 | typeof VOTE_PUBLIC_KEY_HEX_LENGTH 34 | > 35 | 36 | export const NATIVE_SCRIPT_HASH_HEX_LENGTH = 28 37 | export type NativeScriptHashKeyHex = FixlenHexString< 38 | typeof NATIVE_SCRIPT_HASH_HEX_LENGTH 39 | > 40 | 41 | export type Cbor = Buffer & {__type: 'cbor'} 42 | export type CborHex = string & {__type: 'cborHex'} 43 | 44 | export type BIP32Path = number[] & {__type: 'bip32path'} 45 | 46 | export enum NetworkIds { 47 | MAINNET = 1, 48 | TESTNET = 0, 49 | } 50 | 51 | // taken from https://book.world.dev.cardano.org/environments.html 52 | export enum ProtocolMagics { 53 | MAINNET = 764824073, 54 | TESTNET_PREPROD = 1, 55 | TESTNET_PREVIEW = 2, 56 | // we keep these because some test CBORs contain this magic 57 | TESTNET_LEGACY1 = 42, 58 | TESTNET_LEGACY2 = 1097911063, 59 | } 60 | 61 | export type Network = { 62 | networkId: number 63 | protocolMagic: number 64 | } 65 | 66 | // Address type as defined in the Cardano CDDL 67 | export enum AddressType { 68 | BASE_PAYMENT_KEY_STAKE_KEY = 0b0000, 69 | BASE_PAYMENT_SCRIPT_STAKE_KEY = 0b0001, 70 | BASE_PAYMENT_KEY_STAKE_SCRIPT = 0b0010, 71 | BASE_PAYMENT_SCRIPT_STAKE_SCRIPT = 0b0011, 72 | POINTER_KEY = 0b0100, 73 | POINTER_SCRIPT = 0b0101, 74 | ENTERPRISE_KEY = 0b0110, 75 | ENTERPRISE_SCRIPT = 0b0111, 76 | BYRON = 0b1000, 77 | REWARD_KEY = 0b1110, 78 | REWARD_SCRIPT = 0b1111, 79 | } 80 | 81 | // encoded in bech32 82 | export type HumanAddress = string & {__type: 'humanAddress'} 83 | 84 | export enum NativeScriptType { 85 | PUBKEY, 86 | ALL, 87 | ANY, 88 | N_OF_K, 89 | INVALID_BEFORE, 90 | INVALID_HEREAFTER, 91 | } 92 | 93 | export type NativeScript = 94 | | { 95 | type: NativeScriptType.PUBKEY 96 | keyHash: string 97 | } 98 | | { 99 | type: NativeScriptType.ALL | NativeScriptType.ANY 100 | scripts: NativeScript[] 101 | } 102 | | { 103 | type: NativeScriptType.N_OF_K 104 | required: number 105 | scripts: NativeScript[] 106 | } 107 | | { 108 | type: NativeScriptType.INVALID_BEFORE | NativeScriptType.INVALID_HEREAFTER 109 | slot: bigint 110 | } 111 | 112 | export type CVoteDelegation = { 113 | votePublicKey: VotePublicKeyHex 114 | voteWeight: bigint 115 | } 116 | 117 | /* eslint-disable max-len */ 118 | // Currently, this is used only by Trezor. Relevant docs: 119 | // https://github.com/trezor/trezor-suite/blob/1a0125c9e1d738f5750f935f1aed4d17a37e69ba/docs/packages/connect/methods/cardanoSignTransaction.md#params 120 | // https://github.com/trezor/trezor-firmware/blob/4bed278e80d23077676128eba8cb2478fcd31120/core/src/apps/cardano/README.md#seed-derivation-schemes 121 | /* eslint-enable max-len */ 122 | export enum DerivationType { 123 | LEDGER = 'LEDGER', 124 | ICARUS = 'ICARUS', 125 | ICARUS_TREZOR = 'ICARUS_TREZOR', 126 | } 127 | -------------------------------------------------------------------------------- /test/integration/keystone/node/nativeScripts.ts: -------------------------------------------------------------------------------- 1 | import assert from 'assert' 2 | import {NativeScript, NativeScriptType} from '../../../../src/basicTypes' 3 | import { 4 | CryptoProvider, 5 | NativeScriptDisplayFormat, 6 | } from '../../../../src/crypto-providers/cryptoProvider' 7 | import {TransportNodeUSB} from '@keystonehq/hw-transport-nodeusb' 8 | import {KeystoneCryptoProvider} from '../../../../src/crypto-providers/keystoneCryptoProvider' 9 | 10 | interface TestItem { 11 | nativeScript: NativeScript 12 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 13 | hwSigningFiles: any[] 14 | expectedNativeScriptHashHex: string 15 | } 16 | 17 | const nativeScripts: {[key: string]: TestItem} = { 18 | pubkey: { 19 | nativeScript: { 20 | type: NativeScriptType.PUBKEY, 21 | keyHash: '3a55d9f68255dfbefa1efd711f82d005fae1be2e145d616c90cf0fa9', 22 | }, 23 | hwSigningFiles: [], 24 | expectedNativeScriptHashHex: 25 | '855228f5ecececf9c85618007cc3c2e5bdf5e6d41ef8d6fa793fe0eb', 26 | }, 27 | all: { 28 | nativeScript: { 29 | type: NativeScriptType.ALL, 30 | scripts: [ 31 | { 32 | type: NativeScriptType.PUBKEY, 33 | keyHash: '14c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f1124', 34 | }, 35 | ], 36 | }, 37 | hwSigningFiles: [], 38 | expectedNativeScriptHashHex: 39 | 'b442025ae01ccb227ecbfc013d1c17eae7f8d04d366ffff5a091d03f', 40 | }, 41 | any: { 42 | nativeScript: { 43 | type: NativeScriptType.ANY, 44 | scripts: [ 45 | { 46 | type: NativeScriptType.PUBKEY, 47 | keyHash: '14c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f1124', 48 | }, 49 | ], 50 | }, 51 | hwSigningFiles: [], 52 | expectedNativeScriptHashHex: 53 | '74c6eec4851daab6cc93283b06d73c7ce1eccc20f6f9bfdb715a05f3', 54 | }, 55 | nOfK: { 56 | nativeScript: { 57 | type: NativeScriptType.N_OF_K, 58 | required: 1, 59 | scripts: [ 60 | { 61 | type: NativeScriptType.PUBKEY, 62 | keyHash: '14c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f1124', 63 | }, 64 | ], 65 | }, 66 | hwSigningFiles: [], 67 | expectedNativeScriptHashHex: 68 | 'cea740b672a5a359030b0355098407368fb3d4fa1a7f46b4adb8e8f3', 69 | }, 70 | invalidBefore: { 71 | nativeScript: { 72 | type: NativeScriptType.INVALID_BEFORE, 73 | slot: 100n, 74 | }, 75 | hwSigningFiles: [], 76 | expectedNativeScriptHashHex: 77 | '15fa0f97f3fe447a10dfbbd71edae89fb15d2b1b80f805ffaace9a5b', 78 | }, 79 | invalidHereafter: { 80 | nativeScript: { 81 | type: NativeScriptType.INVALID_HEREAFTER, 82 | slot: 200n, 83 | }, 84 | hwSigningFiles: [], 85 | expectedNativeScriptHashHex: 86 | '81a8f494e6cfe6b2407c9f68beda19ac74193548ab7c9aa94fe935f6', 87 | }, 88 | } 89 | 90 | async function testNativeScriptHashDerivation( 91 | cryptoProvider: CryptoProvider, 92 | {nativeScript, hwSigningFiles, expectedNativeScriptHashHex}: TestItem, 93 | ): Promise { 94 | const nativeScriptHashHex = await cryptoProvider.deriveNativeScriptHash( 95 | nativeScript, 96 | hwSigningFiles, 97 | NativeScriptDisplayFormat.POLICY_ID, 98 | ) 99 | assert.deepStrictEqual(nativeScriptHashHex, expectedNativeScriptHashHex) 100 | } 101 | 102 | describe('Keystone native script hash derivation', () => { 103 | let cryptoProvider: CryptoProvider 104 | // eslint-disable-next-line prefer-arrow-callback 105 | before(async function () { 106 | this.timeout(10000) 107 | cryptoProvider = await KeystoneCryptoProvider( 108 | await TransportNodeUSB.connect({ 109 | timeout: 100000, 110 | }), 111 | ) 112 | }) 113 | const nativeScriptsToDerive = Object.entries(nativeScripts) 114 | nativeScriptsToDerive.forEach(([nativeScriptName, nativeScript]) => 115 | it(`Should derive native script hash, script type "${nativeScriptName}"`, async () => 116 | await testNativeScriptHashDerivation( 117 | cryptoProvider, 118 | nativeScript, 119 | )).timeout(100000), 120 | ) 121 | }) 122 | -------------------------------------------------------------------------------- /docs/delegation-example.md: -------------------------------------------------------------------------------- 1 | # Delegation example 2 | 3 | ## Prepare HW wallet 4 | Connect your HW wallet to your computer. 5 | 6 | ## Get protocol parameters 7 | ``` 8 | cardano-cli query protocol-parameters \ 9 | --mainnet \ 10 | --out-file protocol.json 11 | ``` 12 | should create `protocol.json` file. 13 | 14 | ### Verification payment key and hardware wallet signing file 15 | ``` 16 | cardano-hw-cli address key-gen \ 17 | --path 1852H/1815H/0H/0/0 \ 18 | --verification-key-file payment.vkey \ 19 | --hw-signing-file payment.hwsfile 20 | ``` 21 | should create `payment.vkey` and `payment.hwsfile` files. 22 | 23 | ## Verification stake key and hardware wallet signing file 24 | ``` 25 | cardano-hw-cli address key-gen \ 26 | --path 1852H/1815H/0H/2/0 \ 27 | --verification-key-file stake.vkey \ 28 | --hw-signing-file stake.hwsfile 29 | ``` 30 | should create `stake.vkey` and `stake.hwsfile` files. 31 | 32 | ## Payment address 33 | ``` 34 | cardano-cli address build \ 35 | --payment-verification-key-file payment.vkey \ 36 | --stake-verification-key-file stake.vkey \ 37 | --out-file payment.addr \ 38 | --mainnet 39 | ``` 40 | should create `payment.addr` file. 41 | 42 | ## Create delegation certificate 43 | ``` 44 | cardano-cli stake-address delegation-certificate \ 45 | --staking-verification-key-file stake.vkey \ 46 | --stake-pool-verification-key-file cold.vkey \ 47 | --out-file delegation.cert 48 | ``` 49 | should create `delegation.cert` file. 50 | 51 | ## Get the transaction hash and index of the UTXO to spend 52 | ``` 53 | cardano-cli query utxo \ 54 | --address $(cat payment.addr) \ 55 | --mainnet 56 | ``` 57 | example return: 58 | ``` 59 | TxHash TxIx Lovelace 60 | ---------------------------------------------------------------------------------------- 61 | 2a602e9ad218967602b4ca7be48648224e07f34fb0059f164ea3f99dbbfee1cb 0 1983692 62 | ``` 63 | 64 | ## Draft the transaction 65 | ``` 66 | cardano-cli transaction build-raw \ 67 | --tx-in "2a602e9ad218967602b4ca7be48648224e07f34fb0059f164ea3f99dbbfee1cb#0" \ 68 | --tx-out $(cat payment.addr)+0 \ 69 | --ttl 0 \ 70 | --fee 0 \ 71 | --certificate-file delegation.cert \ 72 | --out-file tx.draft \ 73 | --alonzo-era \ 74 | --cddl-format 75 | ``` 76 | should create `tx.draft` file. 77 | 78 | ## Calculate the fee 79 | ``` 80 | cardano-cli transaction calculate-min-fee \ 81 | --tx-body-file tx.draft \ 82 | --tx-in-count 1 \ 83 | --tx-out-count 1 \ 84 | --witness-count 2 \ 85 | --byron-witness-count 0 \ 86 | --mainnet \ 87 | --protocol-params-file protocol.json 88 | ``` 89 | example return: 90 | ``` 91 | 199845 Lovelace 92 | ``` 93 | 94 | ## Determine the TTL for the transaction 95 | ``` 96 | cardano-cli query tip --mainnet 97 | ``` 98 | 99 | ## Build the transaction 100 | ``` 101 | cardano-cli transaction build-raw \ 102 | --tx-in "2a602e9ad218967602b4ca7be48648224e07f34fb0059f164ea3f99dbbfee1cb#0" \ 103 | --tx-out $(cat payment.addr)+1783847 \ 104 | --ttl 13909233 \ 105 | --fee 199845 \ 106 | --certificate-file delegation.cert \ 107 | --out-file tx.raw \ 108 | --alonzo-era \ 109 | --cddl-format 110 | ``` 111 | 112 | ## Transform the transaction 113 | HW wallets expect the transaction CBOR to be in *canonical* format (see CIP-0021). Unfortunately, cardano-cli sometimes produces tx files not compliant with CIP-0021. Use the following command to fix the formatting issues. 114 | ``` 115 | cardano-hw-cli transaction transform \ 116 | --tx-file tx.raw \ 117 | --out-file tx.transformed 118 | ``` 119 | 120 | ## Witness the transaction 121 | ``` 122 | cardano-hw-cli transaction witness \ 123 | --tx-file tx.transformed \ 124 | --hw-signing-file payment.hwsfile \ 125 | --hw-signing-file stake.hwsfile \ 126 | --mainnet \ 127 | --out-file payment.witness \ 128 | --out-file stake.witness 129 | ``` 130 | 131 | ## Assemble the transaction 132 | ``` 133 | cardano-cli transaction assemble \ 134 | --tx-body-file tx.transformed \ 135 | --witness-file payment.witness \ 136 | --witness-file stake.witness \ 137 | --out-file tx.signed 138 | ``` 139 | 140 | ## Submit the transaction 141 | ``` 142 | cardano-cli transaction submit \ 143 | --tx-file tx.signed \ 144 | --mainnet 145 | ``` 146 | 147 | ## Check the balances 148 | ``` 149 | cardano-cli query utxo \ 150 | --address $(cat payment.addr) \ 151 | --mainnet 152 | ``` -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cardano-hw-cli", 3 | "version": "1.19.1", 4 | "commit": "97047f09baf7165a8eda1058980f53b38ff7dcbb", 5 | "description": "Cardano CLI tool for hardware wallets", 6 | "author": "Vacuumlabs", 7 | "homepage": "https://github.com/vacuumlabs/cardano-hw-cli#readme", 8 | "main": "src/index.ts", 9 | "license": "ISC", 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/vacuumlabs/cardano-hw-cli.git" 13 | }, 14 | "bugs": { 15 | "url": "https://github.com/vacuumlabs/cardano-hw-cli/issues" 16 | }, 17 | "scripts": { 18 | "build": "./scripts/build-all.sh", 19 | "build-linux-deb": "./scripts/build-common.sh && ./scripts/build-linux-deb-package.sh", 20 | "build-linux-tar": "./scripts/build-common.sh && ./scripts/build-linux-x64-tar-gz.sh", 21 | "build-linux-tar-arm64": "./scripts/build-common.sh && ./scripts/build-linux-arm64-tar-gz.sh", 22 | "build-windows": "./scripts/build-common.sh && ./scripts/build-windows.sh", 23 | "build-macos": "./scripts/build-common.sh && ./scripts/build-macos.sh", 24 | "build-js": "tsc -p src/tsconfig.json", 25 | "dev": "yarn build-js && node --no-warnings=ExperimentalWarning dist/index.js", 26 | "lint": "eslint src/ test/ --max-warnings=0 --ext .ts,.js", 27 | "prettier:check": "prettier --check .", 28 | "prettier": "prettier --write .", 29 | "spell:check": "yarn cspell lint --gitignore '**' 2>/dev/null", 30 | "test-unit": "mocha -r ts-node/register 'test/unit/**/*.ts'", 31 | "test-bin": "yarn build && ./build/linux/archive-x64/cardano-hw-cli/cardano-hw-cli --help", 32 | "test-integration-ledger": "mocha -r ts-node/register 'test/integration/ledger/node/**/*.ts' --exit", 33 | "test-integration-ledger-speculos": "LEDGER_TRANSPORT=speculos yarn test-integration-ledger", 34 | "test-integration-trezor": "mocha -r ts-node/register 'test/integration/trezor/node/**/*.ts' --exit", 35 | "test-integration-keystone": "mocha -r ts-node/register 'test/integration/keystone/node/**/*.ts' --exit", 36 | "clean": "rm -rf ./dist && rm -rf ./node_modules", 37 | "pkg": "pkg", 38 | "postinstall": "node scripts/fix-trezor-firmware.js" 39 | }, 40 | "dependencies": { 41 | "@cardano-foundation/ledgerjs-hw-app-cardano": "7.1.3", 42 | "@emurgo/cardano-serialization-lib-nodejs": "^13.1.0", 43 | "@keystonehq/bc-ur-registry": "^0.7.1", 44 | "@keystonehq/bc-ur-registry-cardano": "^0.5.0", 45 | "@keystonehq/hw-transport-error": "^0.0.2", 46 | "@keystonehq/hw-transport-nodeusb": "^0.1.1", 47 | "@keystonehq/hw-transport-usb": "^0.1.1", 48 | "@keystonehq/keystone-sdk": "^0.8.1", 49 | "@ledgerhq/hw-transport": "^6.27.10", 50 | "@ledgerhq/hw-transport-node-hid-noevents": "^6.24.1", 51 | "@ngraveio/bc-ur": "^1.1.13", 52 | "@trezor/connect": "^9.6.3", 53 | "argparse": "^2.0.1", 54 | "bech32": "^2.0.0", 55 | "bignumber": "^1.1.0", 56 | "cardano-crypto.js": "^6.1.2", 57 | "cardano-hw-interop-lib": "^3.0.2", 58 | "cbor": "^8.1.0", 59 | "lodash": "^4.17.21", 60 | "rw": "1.3.3", 61 | "uuid": "^10.0.0" 62 | }, 63 | "devDependencies": { 64 | "@ledgerhq/hw-transport-node-speculos": "^6.27.10", 65 | "@types/argparse": "^2.0.10", 66 | "@types/lodash": "^4.17.20", 67 | "@types/mocha": "^10.0.0", 68 | "@types/node": "^18.12.0", 69 | "@types/uuid": "^10.0.0", 70 | "@typescript-eslint/eslint-plugin": "^8.44.0", 71 | "@typescript-eslint/parser": "^8.44.0", 72 | "cspell": "^9.2.1", 73 | "eslint": "^9.35.0", 74 | "eslint-config-prettier": "^8.5.0", 75 | "eslint-config-vacuumlabs": "^8.0.2", 76 | "eslint-plugin-import": "^2.25.4", 77 | "eslint-plugin-mocha": "^10.1.0", 78 | "eslint-plugin-simple-import-sort": "^7.0.0", 79 | "mocha": "^11.7.2", 80 | "pkg": "^5.8.1", 81 | "prettier": "^2.6.2", 82 | "ts-node": "^10.9.1", 83 | "typescript": "^4.9.4" 84 | }, 85 | "pkg": { 86 | "assets": [ 87 | "package.json", 88 | "node_modules/usb/prebuilds/**/*" 89 | ] 90 | }, 91 | "engines": { 92 | "node": "18.7.0", 93 | "npm": ">=6.x", 94 | "yarn": "^1.21.3" 95 | }, 96 | "resolutions": { 97 | "node-abi": "^3.24.0", 98 | "usb": "^2.11.0", 99 | "pbkdf2": "^3.1.3", 100 | "cipher-base": "^1.0.6", 101 | "sha.js": "^2.4.12", 102 | "tar-fs": "^2.1.3" 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /docs/transaction-example.md: -------------------------------------------------------------------------------- 1 | # Transaction example 2 | This example is modified example found in cardano docs, to work with HW wallets: 3 | - https://github.com/input-output-hk/cardano-node/blob/master/doc/stake-pool-operations/keys_and_addresses.md 4 | - https://github.com/input-output-hk/cardano-node/blob/master/doc/stake-pool-operations/simple_transaction.md 5 | 6 | ## Prepare HW wallet 7 | Connect your HW wallet to your computer. 8 | 9 | ## Get protocol parameters 10 | ``` 11 | cardano-cli query protocol-parameters \ 12 | --mainnet \ 13 | --out-file protocol.json 14 | ``` 15 | should create `protocol.json` file. 16 | 17 | ## Verification payment key and hardware wallet signing file 18 | ``` 19 | cardano-hw-cli address key-gen \ 20 | --path 1852H/1815H/0H/0/0 \ 21 | --verification-key-file payment.vkey \ 22 | --hw-signing-file payment.hwsfile 23 | ``` 24 | should create `payment.vkey` and `payment.hwsfile` files. 25 | 26 | ## Verification stake key and hardware wallet signing file 27 | ``` 28 | cardano-hw-cli address key-gen \ 29 | --path 1852H/1815H/0H/2/0 \ 30 | --verification-key-file stake.vkey \ 31 | --hw-signing-file stake.hwsfile 32 | ``` 33 | should create `stake.vkey` and `stake.hwsfile` files. 34 | 35 | ## Payment address 36 | ``` 37 | cardano-cli address build \ 38 | --payment-verification-key-file payment.vkey \ 39 | --stake-verification-key-file stake.vkey \ 40 | --out-file payment.addr \ 41 | --mainnet 42 | ``` 43 | should create `payment.addr` file. 44 | 45 | ## Get the transaction hash and index of the UTXO to spend 46 | ``` 47 | cardano-cli query utxo \ 48 | --address $(cat payment.addr) \ 49 | --mainnet 50 | ``` 51 | example return: 52 | ``` 53 | TxHash TxIx Lovelace 54 | ---------------------------------------------------------------------------------------- 55 | bc8bf52ea894fb8e442fe3eea628be87d0c9a37baef185b70eb00a5c8a849d3b 0 2487217 56 | ``` 57 | 58 | ## Draft the transaction 59 | ``` 60 | cardano-cli transaction build-raw \ 61 | --alonzo-era \ 62 | --tx-in "bc8bf52ea894fb8e442fe3eea628be87d0c9a37baef185b70eb00a5c8a849d3b#0" \ 63 | --tx-out $(cat payment.addr)+0 \ 64 | --ttl 0 \ 65 | --fee 0 \ 66 | --out-file tx.draft \ 67 | --cddl-format 68 | ``` 69 | should create `tx.draft` file. 70 | 71 | ## Calculate the fee 72 | ``` 73 | cardano-cli transaction calculate-min-fee \ 74 | --tx-body-file tx.draft \ 75 | --tx-in-count 1 \ 76 | --tx-out-count 1 \ 77 | --witness-count 1 \ 78 | --byron-witness-count 0 \ 79 | --mainnet \ 80 | --protocol-params-file protocol.json 81 | ``` 82 | example return: 83 | ``` 84 | 170869 Lovelace 85 | ``` 86 | 87 | ## Determine the TTL for the transaction 88 | ``` 89 | cardano-cli query tip --mainnet 90 | ``` 91 | example return: 92 | ``` 93 | { 94 | "era": "Alonzo", 95 | "hash": "c7eab20fb2e03bbd8ac25cba88369a8efe55788a566e6c3d4e1693faca7cf4ba", 96 | "epoch": 189, 97 | "slot": 51672781, 98 | "block": 3356357 99 | } 100 | ``` 101 | 102 | ## Build the transaction 103 | TTL: Add 1000 to `slot` from previous call 104 | ``` 105 | cardano-cli transaction build-raw \ 106 | --alonzo-era \ 107 | --tx-in "bc8bf52ea894fb8e442fe3eea628be87d0c9a37baef185b70eb00a5c8a849d3b#0" \ 108 | --tx-out $(cat payment.addr)+2316348 \ 109 | --ttl 27508111 \ 110 | --fee 170869 \ 111 | --out-file tx.raw \ 112 | --cddl-format 113 | ``` 114 | 115 | ## Transform the transaction 116 | HW wallets expect the transaction CBOR to be in *canonical* format (see CIP-0021). Unfortunately, cardano-cli sometimes produces tx files not compliant with CIP-0021. Use the following command to fix the formatting issues. 117 | ``` 118 | cardano-hw-cli transaction transform \ 119 | --tx-file tx.raw \ 120 | --out-file tx.transformed 121 | ``` 122 | 123 | ## Witness the transaction 124 | ``` 125 | cardano-hw-cli transaction witness \ 126 | --tx-file tx.transformed \ 127 | --hw-signing-file payment.hwsfile \ 128 | --mainnet \ 129 | --out-file payment.witness 130 | ``` 131 | should return `payment.witness` file. 132 | 133 | ## Assemble the transaction 134 | ``` 135 | cardano-cli transaction assemble \ 136 | --tx-body-file tx.transformed \ 137 | --witness-file payment.witness \ 138 | --out-file tx.signed 139 | ``` 140 | 141 | ## Submit the transaction 142 | ``` 143 | cardano-cli transaction submit \ 144 | --tx-file tx.signed \ 145 | --mainnet 146 | ``` 147 | 148 | ## Check the balances 149 | ``` 150 | cardano-cli query utxo \ 151 | --address $(cat payment.addr) \ 152 | --mainnet 153 | ``` -------------------------------------------------------------------------------- /docs/cip36-registration-example.md: -------------------------------------------------------------------------------- 1 | # CIP-36 registration example 2 | 3 | ## Requirements 4 | 5 | CIP-36 support: 6 | * on Ledger, Cardano app version 6.0.2 and above 7 | * on Trezor, firmware 2.5.3 and above 8 | 9 | ## Create CIP36 vote keys 10 | 11 | You may want to keep your vote keys stored on a Ledger Nano hardware device (the key derivation schema is described in [CIP-36](https://cips.cardano.org/cips/cip36/)). Consequently, you will have to sign all voting on the HW device storing the keys. For Trezor, this is not supported. 12 | 13 | It is possible to register and use keys generated in other ways, e.g. as follows: 14 | ``` 15 | wget https://github.com/input-output-hk/jormungandr/releases/download/v0.9.3/jormungandr-0.9.3-x86_64-unknown-linux-gnu-generic.tar.gz 16 | tar -xf jormungandr-0.9.3-x86_64-unknown-linux-gnu-generic.tar.gz 17 | ./jcli key generate --type ed25519extended > catalyst-vote.skey 18 | ./jcli key to-public < catalyst-vote.skey > catalyst-vote.pkey 19 | ``` 20 | 21 | ## Create CIP36 registration metadata 22 | 23 | Generate hardware wallet signing files and verification key files with `cardano-hw-cli`: 24 | ``` 25 | cardano-hw-cli address key-gen \ 26 | --path 1852H/1815H/0H/2/0 \ 27 | --verification-key-file stake.vkey \ 28 | --hw-signing-file stake.hwsfile 29 | 30 | cardano-hw-cli address key-gen \ 31 | --path 1852H/1815H/0H/0/0 \ 32 | --verification-key-file payment.vkey \ 33 | --hw-signing-file payment.hwsfile 34 | ``` 35 | 36 | Get slot number from `cardano-cli`, use slot number as `nonce` in CIP36 registration command: 37 | ``` 38 | cardano-cli query tip --mainnet 39 | ``` 40 | 41 | Get payment address from `cardano-cli`, use it as `payment-address` and `payment-address-signing-key-hwsfile` in CIP36 registration command: 42 | ``` 43 | cardano-cli address build \ 44 | --payment-verification-key-file payment.vkey \ 45 | --stake-verification-key-file stake.vkey \ 46 | --out-file payment.addr \ 47 | --mainnet 48 | ``` 49 | 50 | Create CIP36 registration metadata with `cardano-hw-cli`: 51 | ``` 52 | cardano-hw-cli vote registration-metadata \ 53 | --mainnet \ 54 | --vote-public-key-file catalyst-vote.pkey \ 55 | --payment-address $(cat payment.addr) \ 56 | --stake-signing-key-hwsfile stake.hwsfile \ 57 | --nonce 29747977 \ 58 | --payment-address-signing-key-hwsfile payment.hwsfile \ 59 | --metadata-cbor-out-file cip36_registration.cbor 60 | ``` 61 | (You should add `--voting-purpose` to change the voting purpose to something other than Catalyst.) 62 | 63 | Alternatively, in case you want to split your voting power among several vote keys, the keys and their voting power weights can be specified like this: 64 | ``` 65 | cardano-hw-cli vote registration-metadata \ 66 | --mainnet \ 67 | --vote-public-key-file catalyst-vote1.pkey \ 68 | --vote-weight 1 \ 69 | --vote-public-key-file catalyst-vote2.pkey \ 70 | --vote-weight 10 \ 71 | --payment-address $(cat stake.addr) \ 72 | --stake-signing-key-hwsfile stake.hwsfile \ 73 | --nonce 29747977 \ 74 | --payment-address-signing-key-hwsfile stake.hwsfile \ 75 | --metadata-cbor-out-file cip36_registration.cbor 76 | ``` 77 | 78 | Note: The registration auxiliary data are formatted according to [CIP-36](https://cips.cardano.org/cips/cip36/). 79 | 80 | ## Create and submit transaction 81 | Create raw transaction with `cardano-cli`, if you don't know how to create simple transaction, check https://github.com/vacuumlabs/cardano-hw-cli/blob/develop/docs/transaction-example.md 82 | ``` 83 | cardano-cli transaction build-raw \ 84 | --alonzo-era \ 85 | --tx-in "270eb90adfb4634fb7e7356dab9a36d1d6c6763e03629ead2e64b59f70217c75#0" \ 86 | --tx-out addr1q9nz9shd0wh6uevtnr5j4epyqxtwx6953wegv7pfdttr9hzfn5kc55752ehrcspld7ucc0zt8502efdaac4nlajgagasayc3u9+1810000 \ 87 | --fee 190000 \ 88 | --metadata-cbor-file cip36_registration.cbor \ 89 | --out-file tx.raw \ 90 | --cddl-format 91 | ``` 92 | 93 | HW wallets expect the transaction CBOR to be in *canonical* format (see CIP-0021). Unfortunately, cardano-cli sometimes produces tx files not compliant with CIP-0021. Use the following command to fix the formatting issues. 94 | ``` 95 | cardano-hw-cli transaction transform \ 96 | --tx-file tx.raw \ 97 | --out-file tx.transformed 98 | ``` 99 | 100 | Witness the transaction with `cardano-hw-cli` (we assume that `payment.hwsfile` belongs to the address that controls the transaction inputs): 101 | ``` 102 | cardano-hw-cli transaction witness \ 103 | --tx-file tx.transformed \ 104 | --hw-signing-file payment.hwsfile \ 105 | --mainnet \ 106 | --out-file payment.witness 107 | ``` 108 | 109 | Assemble the transaction with with `cardano-cli`: 110 | ``` 111 | cardano-cli transaction assemble \ 112 | --tx-body-file tx.transformed \ 113 | --witness-file payment.witness \ 114 | --out-file tx.signed 115 | ``` 116 | 117 | Submit transaction to blockchain with with `cardano-cli`: 118 | ``` 119 | cardano-cli transaction submit \ 120 | --tx-file tx.signed \ 121 | --mainnet 122 | ``` 123 | -------------------------------------------------------------------------------- /test/integration/keystone/node/signingFiles.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | 3 | import {HARDENED_THRESHOLD} from '../../../../src/constants' 4 | import {HwSigningType} from '../../../../src/command-parser/argTypes' 5 | 6 | // mnemonic "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" 7 | 8 | const signingFiles = { 9 | payment0: { 10 | type: HwSigningType.Payment, 11 | path: [ 12 | 1852 + HARDENED_THRESHOLD, 13 | 1815 + HARDENED_THRESHOLD, 14 | 0 + HARDENED_THRESHOLD, 15 | 0, 16 | 0, 17 | ], 18 | cborXPubKeyHex: 19 | '5840cd2b047d1a803eee059769cffb3dfd0a4b9327e55bc78aa962d9bd4f720db0b2914ba07fb381f23c5c09bce26587bdf359aab7ea8f4192adbf93a38fd893ccea', 20 | }, 21 | stake0: { 22 | type: HwSigningType.Stake, 23 | path: [ 24 | 1852 + HARDENED_THRESHOLD, 25 | 1815 + HARDENED_THRESHOLD, 26 | 0 + HARDENED_THRESHOLD, 27 | 2, 28 | 0, 29 | ], 30 | cborXPubKeyHex: 31 | '584066610efd336e1137c525937b76511fbcf2a0e6bcf0d340a67bcb39bc870d85e8e977e956d29810dbfbda9c8ea667585982454e401c68578623d4b86bc7eb7b58', 32 | }, 33 | payment1: { 34 | type: HwSigningType.Payment, 35 | path: [ 36 | 1852 + HARDENED_THRESHOLD, 37 | 1815 + HARDENED_THRESHOLD, 38 | 0 + HARDENED_THRESHOLD, 39 | 0, 40 | 1, 41 | ], 42 | cborXPubKeyHex: 43 | '5840b3d5f4158f0c391ee2a28a2e285f218f3e895ff6ff59cb9369c64b03b5bab5eb27e1d1f3a3d0fafc0884e02a2d972e7e5b1be8a385ecc1bc75a977b4073dbd08', 44 | }, 45 | stake1: { 46 | type: HwSigningType.Stake, 47 | path: [ 48 | 1852 + HARDENED_THRESHOLD, 49 | 1815 + HARDENED_THRESHOLD, 50 | 0 + HARDENED_THRESHOLD, 51 | 2, 52 | 1, 53 | ], 54 | cborXPubKeyHex: 55 | '584080d04383c04191af5436d6a25b3d193003884f8c770d2c0db6c54a61bf524075199ff847eb73fea22b46ec74e91ff0588715ce946b7983c85ae4d35477019d4a', 56 | }, 57 | byron10: { 58 | type: HwSigningType.Payment, 59 | path: [ 60 | 44 + HARDENED_THRESHOLD, 61 | 1815 + HARDENED_THRESHOLD, 62 | 0 + HARDENED_THRESHOLD, 63 | 0, 64 | 10, 65 | ], 66 | cborXPubKeyHex: 67 | '584090ca5e64214a03ec975e5097c25b2a49d4ca4988243bc0142b5ada743d80b9d5be68538e05e31dc8fff62a62868c43f229cacbee5c40cbe6493929ad1f0e3cd9', 68 | }, 69 | dRep: { 70 | type: HwSigningType.DRep, 71 | path: [ 72 | 1852 + HARDENED_THRESHOLD, 73 | 1815 + HARDENED_THRESHOLD, 74 | 0 + HARDENED_THRESHOLD, 75 | 3, 76 | 0, 77 | ], 78 | cborXPubKeyHex: 79 | '58407cc18df2fbd3ee1b16b76843b18446679ab95dbcd07b7833b66a9407c0709e3701d881e1c04fed8defa9a3e8bd3cf85bd975f813ff8eb622d20a4375a07d6bc9', 80 | }, 81 | committeeCold: { 82 | type: HwSigningType.CommitteeCold, 83 | path: [ 84 | 1852 + HARDENED_THRESHOLD, 85 | 1815 + HARDENED_THRESHOLD, 86 | 0 + HARDENED_THRESHOLD, 87 | 4, 88 | 0, 89 | ], 90 | cborXPubKeyHex: 91 | '5840bc8c8a37d6ab41339bb073e72ce2e776cefed98d1a6d070ea5fada80dc7d67376f58406a51d33bb35e98884cbadced9bc94f65a752001ad5f4788af07b2ec0fe', 92 | }, 93 | committeeHot: { 94 | type: HwSigningType.CommitteeHot, 95 | path: [ 96 | 1852 + HARDENED_THRESHOLD, 97 | 1815 + HARDENED_THRESHOLD, 98 | 1 + HARDENED_THRESHOLD, 99 | 5, 100 | 0, 101 | ], 102 | cborXPubKeyHex: 103 | '5840624142a80217b95ca2fc5b0c1f8d74e26e5683621c430c7bc7eebca6ee541a5892a8c64cfdf1af08e78c2ba59bef496eb34ddf24bdf0f91404a962415a7a0810', 104 | }, 105 | poolCold0: { 106 | type: HwSigningType.PoolCold, 107 | path: [ 108 | 1853 + HARDENED_THRESHOLD, 109 | 1815 + HARDENED_THRESHOLD, 110 | 0 + HARDENED_THRESHOLD, 111 | 0 + HARDENED_THRESHOLD, 112 | ], 113 | cborXPubKeyHex: 114 | '58403d7e84dca8b4bc322401a2cc814af7c84d2992a22f99554fe340d7df7910768d1e2a47754207da3069f90241fbf3b8742c367e9028e5f3f85ae3660330b4f5b7', 115 | }, 116 | payment0account1: { 117 | type: HwSigningType.Payment, 118 | path: [ 119 | 1852 + HARDENED_THRESHOLD, 120 | 1815 + HARDENED_THRESHOLD, 121 | 1 + HARDENED_THRESHOLD, 122 | 0, 123 | 0, 124 | ], 125 | cborXPubKeyHex: 126 | '584066e283c52a7f05ca79db5483380597c0bb01abfb5bd8af27d5ed2487875d3b82f99653db092154b8299299c8b50c4411d1e18d2e5b0c22b17ce73128bfb92c99', 127 | }, 128 | mint0: { 129 | type: HwSigningType.Mint, 130 | path: [ 131 | 1855 + HARDENED_THRESHOLD, 132 | 1815 + HARDENED_THRESHOLD, 133 | 0 + HARDENED_THRESHOLD, 134 | ], 135 | cborXPubKeyHex: 136 | '5840b9de636bf236e5543377e4b4d6b63613f188fb65b83b8a61c4b68be0c196c3d83545aee9b82476574ff115aa1c7ab688c24b4bca687af4bb79129e4fcea066da', 137 | }, 138 | mint1: { 139 | type: HwSigningType.Mint, 140 | path: [ 141 | 1855 + HARDENED_THRESHOLD, 142 | 1815 + HARDENED_THRESHOLD, 143 | 1 + HARDENED_THRESHOLD, 144 | ], 145 | cborXPubKeyHex: 146 | '5840f87ee3ee2316d92f73dca6112a197340a1eae157574765099dd631132818bc1587110ea86e1a14dec1cb234a179c2b5caba823b4812da2a5c431c695b17982ac', 147 | }, 148 | } 149 | 150 | export {signingFiles} 151 | -------------------------------------------------------------------------------- /src/command-parser/argTypes.ts: -------------------------------------------------------------------------------- 1 | import {KesVKey} from '../opCert/opCert' 2 | import { 3 | HumanAddress, 4 | BIP32Path, 5 | DerivationType, 6 | NativeScript, 7 | Network, 8 | VotePublicKeyHex, 9 | CardanoEra, 10 | CborHex, 11 | XPubKeyCborHex, 12 | HexString, 13 | } from '../basicTypes' 14 | 15 | export enum CommandType { 16 | APP_VERSION = 'version', 17 | DEVICE_VERSION = 'device.version', 18 | SHOW_ADDRESS = 'address.show', 19 | ADDRESS_KEY_GEN = 'address.key-gen', 20 | VERIFICATION_KEY = 'key.verification-key', 21 | WITNESS_TRANSACTION = 'transaction.witness', 22 | VALIDATE_TRANSACTION = 'transaction.validate', 23 | TRANSFORM_TRANSACTION = 'transaction.transform', 24 | DERIVE_NATIVE_SCRIPT_HASH = 'transaction.policyid', 25 | SIGN_OPERATIONAL_CERTIFICATE = 'node.issue-op-cert', 26 | NODE_KEY_GEN = 'node.key-gen', 27 | CIP36_REGISTRATION_METADATA = 'vote.registration-metadata', 28 | SIGN_MESSAGE = 'message.sign', 29 | } 30 | 31 | export enum HwSigningType { 32 | Payment, 33 | Stake, 34 | DRep, 35 | CommitteeCold, 36 | CommitteeHot, 37 | PoolCold, 38 | Mint, 39 | MultiSig, 40 | CIP36Voting, 41 | } 42 | 43 | export type HwSigningData = { 44 | type: HwSigningType 45 | path: BIP32Path 46 | cborXPubKeyHex: XPubKeyCborHex 47 | } 48 | 49 | export type TxFileData = { 50 | envelopeType: string 51 | era: CardanoEra 52 | description: string 53 | cborHex: CborHex 54 | } 55 | 56 | export type ParsedAppVersionArguments = { 57 | command: CommandType.APP_VERSION 58 | } 59 | 60 | export type ParsedDeviceVersionArguments = { 61 | command: CommandType.DEVICE_VERSION 62 | } 63 | 64 | // exactly one of paymentPath vs. paymentScriptHash and stakingPath vs. stakingScriptHash 65 | // should be present (the result of parse() complies with this) 66 | export type ParsedShowAddressArguments = { 67 | command: CommandType.SHOW_ADDRESS 68 | paymentPath: BIP32Path 69 | paymentScriptHash: string 70 | stakingPath: BIP32Path 71 | stakingScriptHash: string 72 | address: HumanAddress 73 | derivationType?: DerivationType 74 | } 75 | 76 | export type ParsedAddressKeyGenArguments = { 77 | command: CommandType.ADDRESS_KEY_GEN 78 | paths: BIP32Path[] 79 | hwSigningFiles: string[] 80 | verificationKeyFiles: string[] 81 | derivationType?: DerivationType 82 | } 83 | 84 | export type ParsedVerificationKeyArguments = { 85 | command: CommandType.VERIFICATION_KEY 86 | hwSigningFileData: HwSigningData 87 | verificationKeyFile: string 88 | } 89 | 90 | export type ParsedTransactionPolicyIdArguments = { 91 | command: CommandType.DERIVE_NATIVE_SCRIPT_HASH 92 | nativeScript: NativeScript 93 | hwSigningFileData: HwSigningData[] 94 | derivationType?: DerivationType 95 | } 96 | 97 | export type ParsedTransactionWitnessArguments = { 98 | command: CommandType.WITNESS_TRANSACTION 99 | network: Network 100 | txFileData: TxFileData 101 | hwSigningFileData: HwSigningData[] 102 | outFiles: string[] 103 | changeOutputKeyFileData: HwSigningData[] 104 | derivationType?: DerivationType 105 | } 106 | 107 | export type ParsedTransactionValidateArguments = { 108 | command: CommandType.VALIDATE_TRANSACTION 109 | txFileData: TxFileData 110 | } 111 | 112 | export type ParsedTransactionTransformArguments = { 113 | command: CommandType.TRANSFORM_TRANSACTION 114 | txFileData: TxFileData 115 | outFile: string 116 | } 117 | 118 | export type ParsedOpCertArguments = { 119 | command: CommandType.SIGN_OPERATIONAL_CERTIFICATE 120 | kesVKey: KesVKey 121 | kesPeriod: bigint 122 | issueCounterFile: string 123 | hwSigningFileData: HwSigningData[] 124 | outFile: string 125 | } 126 | 127 | export type ParsedNodeKeyGenArguments = { 128 | command: CommandType.NODE_KEY_GEN 129 | paths: BIP32Path[] 130 | verificationKeyFiles: string[] 131 | hwSigningFiles: string[] 132 | issueCounterFiles: string[] 133 | } 134 | 135 | export type ParsedCIP36RegistrationMetadataArguments = { 136 | command: CommandType.CIP36_REGISTRATION_METADATA 137 | votePublicKeys: VotePublicKeyHex[] 138 | voteWeights: bigint[] 139 | hwStakeSigningFileData: HwSigningData 140 | paymentAddress: HumanAddress 141 | nonce: bigint 142 | votingPurpose: bigint 143 | network: Network 144 | paymentAddressSigningKeyData: HwSigningData[] 145 | outFile: string 146 | derivationType?: DerivationType 147 | } 148 | 149 | export type ParsedSignMessageArguments = { 150 | command: CommandType.SIGN_MESSAGE 151 | messageHex: HexString 152 | hwSigningFileData: HwSigningData 153 | hashPayload: boolean 154 | preferHexDisplay: boolean 155 | address?: HumanAddress 156 | addressHwSigningFileData?: HwSigningData[] 157 | outFile: string 158 | derivationType?: DerivationType 159 | } 160 | 161 | export type ParsedArguments = 162 | | ParsedAppVersionArguments 163 | | ParsedDeviceVersionArguments 164 | | ParsedShowAddressArguments 165 | | ParsedAddressKeyGenArguments 166 | | ParsedVerificationKeyArguments 167 | | ParsedTransactionPolicyIdArguments 168 | | ParsedTransactionWitnessArguments 169 | | ParsedTransactionValidateArguments 170 | | ParsedTransactionTransformArguments 171 | | ParsedNodeKeyGenArguments 172 | | ParsedOpCertArguments 173 | | ParsedCIP36RegistrationMetadataArguments 174 | | ParsedSignMessageArguments 175 | -------------------------------------------------------------------------------- /test/unit/cryptoProviders/ledger.ts: -------------------------------------------------------------------------------- 1 | import assert from 'assert' 2 | import {HARDENED_THRESHOLD} from '../../../src/constants' 3 | import { 4 | AddressType, 5 | HumanAddress, 6 | NetworkIds, 7 | ProtocolMagics, 8 | } from '../../../src/basicTypes' 9 | import { 10 | classifyPath, 11 | getAddressAttributes, 12 | PathTypes, 13 | } from '../../../src/crypto-providers/util' 14 | 15 | describe('Test util', () => { 16 | describe('Classify path', () => { 17 | it('Byron wallet address path', () => { 18 | const HD = HARDENED_THRESHOLD 19 | 20 | assert.deepStrictEqual( 21 | classifyPath([44 + HD, 1815 + HD, 0 + HD, 0, 0]), 22 | PathTypes.PATH_WALLET_SPENDING_KEY_BYRON, 23 | ) 24 | 25 | assert.deepStrictEqual( 26 | classifyPath([44 + HD, 1815 + HD, 0 + HD, 0]), 27 | PathTypes.PATH_INVALID, 28 | ) 29 | }) 30 | 31 | it('Shelley wallet address path', () => { 32 | const HD = HARDENED_THRESHOLD 33 | 34 | assert.deepStrictEqual( 35 | classifyPath([1852 + HD, 1815 + HD, 0 + HD, 1, 5]), 36 | PathTypes.PATH_WALLET_SPENDING_KEY_SHELLEY, 37 | ) 38 | 39 | assert.deepStrictEqual( 40 | classifyPath([1852 + HD, 1815 + HD, 0 + HD, 6, 0]), 41 | PathTypes.PATH_INVALID, 42 | ) 43 | }) 44 | 45 | it('Staking path', () => { 46 | const HD = HARDENED_THRESHOLD 47 | 48 | assert.deepStrictEqual( 49 | classifyPath([1852 + HD, 1815 + HD, 1 + HD, 2, 0]), 50 | PathTypes.PATH_WALLET_STAKING_KEY, 51 | ) 52 | }) 53 | 54 | it('DRep path', () => { 55 | const HD = HARDENED_THRESHOLD 56 | 57 | assert.deepStrictEqual( 58 | classifyPath([1852 + HD, 1815 + HD, 0 + HD, 3, 0]), 59 | PathTypes.PATH_DREP_KEY, 60 | ) 61 | }) 62 | 63 | it('Constitutional committee cold path', () => { 64 | const HD = HARDENED_THRESHOLD 65 | 66 | assert.deepStrictEqual( 67 | classifyPath([1852 + HD, 1815 + HD, 0 + HD, 4, 0]), 68 | PathTypes.PATH_COMMITTEE_COLD_KEY, 69 | ) 70 | }) 71 | 72 | it('Constitutional committee hot path', () => { 73 | const HD = HARDENED_THRESHOLD 74 | 75 | assert.deepStrictEqual( 76 | classifyPath([1852 + HD, 1815 + HD, 0 + HD, 5, 0]), 77 | PathTypes.PATH_COMMITTEE_HOT_KEY, 78 | ) 79 | }) 80 | }) 81 | 82 | describe('Gets correct address attributes', () => { 83 | it('Byron address', () => { 84 | assert.deepStrictEqual( 85 | getAddressAttributes( 86 | 'Ae2tdPwUPEZELF6oijm8VFmhWpujnNzyG2zCf4RxfhmWqQKHo2drRD5Uhah' as HumanAddress, 87 | ), 88 | { 89 | addressType: AddressType.BYRON, 90 | networkId: NetworkIds.MAINNET, 91 | protocolMagic: ProtocolMagics.MAINNET, 92 | }, 93 | ) 94 | }) 95 | 96 | it('Shelley address (testnet, payment key, staking key)', () => { 97 | assert.deepStrictEqual( 98 | // eslint-disable-next-line max-len 99 | getAddressAttributes( 100 | 'addr_test1qpd9xypc9xnnstp2kas3r7mf7ylxn4sksfxxypvwgnc63vcayfawlf9hwv2fzuygt2km5v92kvf8e3s3mk7ynxw77cwq9nnhk4' as HumanAddress, 101 | ), 102 | { 103 | addressType: AddressType.BASE_PAYMENT_KEY_STAKE_KEY, 104 | networkId: NetworkIds.TESTNET, 105 | protocolMagic: ProtocolMagics.TESTNET_PREVIEW, 106 | }, 107 | ) 108 | }) 109 | 110 | it('Shelley address (mainnet, payment script, staking script)', () => { 111 | assert.deepStrictEqual( 112 | // eslint-disable-next-line max-len 113 | getAddressAttributes( 114 | 'addr1x96vdmkys5w64dkvjv5rkpkh837wrmxvyrm0n07mw9dqtu6jms758dkjge0fvyyuuadtvx47t6wpmz3unnn0lz36755qp6mwvr' as HumanAddress, 115 | ), 116 | { 117 | addressType: AddressType.BASE_PAYMENT_SCRIPT_STAKE_SCRIPT, 118 | networkId: NetworkIds.MAINNET, 119 | protocolMagic: ProtocolMagics.MAINNET, 120 | }, 121 | ) 122 | }) 123 | }) 124 | 125 | it('Classify script payment path', () => { 126 | const HD = HARDENED_THRESHOLD 127 | 128 | assert.deepStrictEqual( 129 | classifyPath([1854 + HD, 1815 + HD, 0 + HD, 0, 5]), 130 | PathTypes.PATH_WALLET_SPENDING_KEY_MULTISIG, 131 | ) 132 | 133 | assert.deepStrictEqual( 134 | classifyPath([1854 + HD, 1815 + HD, 0 + HD, 1, 0]), 135 | PathTypes.PATH_INVALID, 136 | ) 137 | 138 | assert.deepStrictEqual( 139 | classifyPath([1854 + HD, 1815 + HD, 0 + HD, 3, 0]), 140 | PathTypes.PATH_INVALID, 141 | ) 142 | }) 143 | 144 | it('Classify script staking path', () => { 145 | const HD = HARDENED_THRESHOLD 146 | 147 | assert.deepStrictEqual( 148 | classifyPath([1854 + HD, 1815 + HD, 1 + HD, 2, 0]), 149 | PathTypes.PATH_WALLET_STAKING_KEY_MULTISIG, 150 | ) 151 | 152 | assert.deepStrictEqual( 153 | classifyPath([1854 + HD, 1815 + HD, 1 + HD, 2, 1]), 154 | PathTypes.PATH_WALLET_STAKING_KEY_MULTISIG, 155 | ) 156 | }) 157 | 158 | it('Classify mint path', () => { 159 | const HD = HARDENED_THRESHOLD 160 | 161 | assert.deepStrictEqual( 162 | classifyPath([1855 + HD, 1815 + HD, 1 + HD]), 163 | PathTypes.PATH_WALLET_MINTING_KEY, 164 | ) 165 | 166 | assert.deepStrictEqual( 167 | classifyPath([1855 + HD, 1815 + HD, 0 + HD, 0, 0]), 168 | PathTypes.PATH_INVALID, 169 | ) 170 | 171 | assert.deepStrictEqual( 172 | classifyPath([1855 + HD, 1815 + HD, 0 + HD, 2, 0]), 173 | PathTypes.PATH_INVALID, 174 | ) 175 | }) 176 | }) 177 | -------------------------------------------------------------------------------- /test/integration/ledger/node/nativeScripts.ts: -------------------------------------------------------------------------------- 1 | import assert from 'assert' 2 | import {NativeScript, NativeScriptType} from '../../../../src/basicTypes' 3 | import {LedgerCryptoProvider} from '../../../../src/crypto-providers/ledgerCryptoProvider' 4 | import { 5 | CryptoProvider, 6 | NativeScriptDisplayFormat, 7 | } from '../../../../src/crypto-providers/cryptoProvider' 8 | import {signingFiles} from './signingFiles' 9 | import {getTransport} from './speculos' 10 | 11 | interface TestItem { 12 | nativeScript: NativeScript 13 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 14 | hwSigningFiles: any[] 15 | expectedNativeScriptHashHex: string 16 | } 17 | 18 | const nativeScripts: {[key: string]: TestItem} = { 19 | pubkey: { 20 | nativeScript: { 21 | type: NativeScriptType.PUBKEY, 22 | keyHash: '3a55d9f68255dfbefa1efd711f82d005fae1be2e145d616c90cf0fa9', 23 | }, 24 | hwSigningFiles: [], 25 | expectedNativeScriptHashHex: 26 | '855228f5ecececf9c85618007cc3c2e5bdf5e6d41ef8d6fa793fe0eb', 27 | }, 28 | all: { 29 | nativeScript: { 30 | type: NativeScriptType.ALL, 31 | scripts: [ 32 | { 33 | type: NativeScriptType.PUBKEY, 34 | keyHash: '14c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f1124', 35 | }, 36 | ], 37 | }, 38 | hwSigningFiles: [], 39 | expectedNativeScriptHashHex: 40 | 'b442025ae01ccb227ecbfc013d1c17eae7f8d04d366ffff5a091d03f', 41 | }, 42 | any: { 43 | nativeScript: { 44 | type: NativeScriptType.ANY, 45 | scripts: [ 46 | { 47 | type: NativeScriptType.PUBKEY, 48 | keyHash: '14c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f1124', 49 | }, 50 | ], 51 | }, 52 | hwSigningFiles: [], 53 | expectedNativeScriptHashHex: 54 | '74c6eec4851daab6cc93283b06d73c7ce1eccc20f6f9bfdb715a05f3', 55 | }, 56 | nOfK: { 57 | nativeScript: { 58 | type: NativeScriptType.N_OF_K, 59 | required: 1, 60 | scripts: [ 61 | { 62 | type: NativeScriptType.PUBKEY, 63 | keyHash: '14c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f1124', 64 | }, 65 | ], 66 | }, 67 | hwSigningFiles: [], 68 | expectedNativeScriptHashHex: 69 | 'cea740b672a5a359030b0355098407368fb3d4fa1a7f46b4adb8e8f3', 70 | }, 71 | invalidBefore: { 72 | nativeScript: { 73 | type: NativeScriptType.INVALID_BEFORE, 74 | slot: 100n, 75 | }, 76 | hwSigningFiles: [], 77 | expectedNativeScriptHashHex: 78 | '15fa0f97f3fe447a10dfbbd71edae89fb15d2b1b80f805ffaace9a5b', 79 | }, 80 | invalidHereafter: { 81 | nativeScript: { 82 | type: NativeScriptType.INVALID_HEREAFTER, 83 | slot: 200n, 84 | }, 85 | hwSigningFiles: [], 86 | expectedNativeScriptHashHex: 87 | '81a8f494e6cfe6b2407c9f68beda19ac74193548ab7c9aa94fe935f6', 88 | }, 89 | paymentScriptWithSigningFiles: { 90 | nativeScript: { 91 | type: NativeScriptType.ALL, 92 | scripts: [ 93 | { 94 | type: NativeScriptType.PUBKEY, 95 | keyHash: '9205690f6ea4b76742c6bdc5b79fb8a1727260089c71a64c7275320e', 96 | }, 97 | { 98 | type: NativeScriptType.ANY, 99 | scripts: [ 100 | { 101 | type: NativeScriptType.PUBKEY, 102 | keyHash: 103 | '9a70dd7c77e9db9442b560a11446962e9d7c595274c587a62f8a0b61', 104 | }, 105 | { 106 | type: NativeScriptType.PUBKEY, 107 | keyHash: 108 | '3d926054e17d9ed8374d0e1d18c765209dd0c249f954214c45417fea', 109 | }, 110 | ], 111 | }, 112 | ], 113 | }, 114 | hwSigningFiles: [ 115 | signingFiles.multisigPayment0, 116 | signingFiles.multisigPayment1, 117 | signingFiles.multisigPayment2, 118 | ], 119 | expectedNativeScriptHashHex: 120 | '9064dc1a8ce9d07aabd3399b67520ec9f6eb11c82220b9462938c479', 121 | }, 122 | stakingScriptWithSigningFiles: { 123 | nativeScript: { 124 | type: NativeScriptType.ALL, 125 | scripts: [ 126 | { 127 | type: NativeScriptType.N_OF_K, 128 | required: 1, 129 | scripts: [ 130 | { 131 | type: NativeScriptType.PUBKEY, 132 | keyHash: 133 | '4c139dd7e3a600fd1a4855b38cf8f731f39d3051791a5ede1f553d6c', 134 | }, 135 | ], 136 | }, 137 | { 138 | type: NativeScriptType.ANY, 139 | scripts: [ 140 | { 141 | type: NativeScriptType.PUBKEY, 142 | keyHash: 143 | 'f699c6400f85bdca54e44d0cad1f6141ce049a411c0d695fc30c3f73', 144 | }, 145 | { 146 | type: NativeScriptType.INVALID_HEREAFTER, 147 | slot: 200n, 148 | }, 149 | ], 150 | }, 151 | ], 152 | }, 153 | hwSigningFiles: [signingFiles.multisigStake0, signingFiles.multisigStake1], 154 | expectedNativeScriptHashHex: 155 | '54d8e96bb32a441432393d7690ac0132e5669a9ecd95cfc4b8674219', 156 | }, 157 | } 158 | 159 | async function testNativeScriptHashDerivation( 160 | cryptoProvider: CryptoProvider, 161 | {nativeScript, hwSigningFiles, expectedNativeScriptHashHex}: TestItem, 162 | ): Promise { 163 | const nativeScriptHashHex = await cryptoProvider.deriveNativeScriptHash( 164 | nativeScript, 165 | hwSigningFiles, 166 | NativeScriptDisplayFormat.POLICY_ID, 167 | ) 168 | assert.deepStrictEqual(nativeScriptHashHex, expectedNativeScriptHashHex) 169 | } 170 | 171 | describe('Ledger native script hash derivation', () => { 172 | let cryptoProvider: CryptoProvider 173 | // eslint-disable-next-line prefer-arrow-callback 174 | before(async function () { 175 | this.timeout(10000) 176 | cryptoProvider = await LedgerCryptoProvider(await getTransport()) 177 | }) 178 | const nativeScriptsToDerive = Object.entries(nativeScripts) 179 | nativeScriptsToDerive.forEach(([nativeScriptName, nativeScript]) => 180 | it(`Should derive native script hash, script type "${nativeScriptName}"`, async () => 181 | await testNativeScriptHashDerivation( 182 | cryptoProvider, 183 | nativeScript, 184 | )).timeout(100000), 185 | ) 186 | }) 187 | -------------------------------------------------------------------------------- /src/errors.ts: -------------------------------------------------------------------------------- 1 | export enum ExitCode { 2 | Success = 0, 3 | Error = 1, 4 | UnfixableValidationErrorsFound = 2, 5 | FixableValidationErrorsFound = 3, 6 | } 7 | 8 | /* eslint-disable max-len */ 9 | 10 | export const enum Errors { 11 | HwTransportNotFoundError = 'Error occurred while trying to find hw transport, make sure Ledger or Trezor or Keystone is connected to your computer', 12 | InvalidPathError = 'Can not parse path', 13 | InvalidFileTypeError = 'Invalid file type of hw-signing-file', 14 | InvalidHwSigningFileError = 'Invalid file contents of hw-signing-file', 15 | InvalidTxFileError = 'Invalid file contents of tx-file', 16 | InvalidKesVKeyFileError = 'Invalid KES verification key file', 17 | InvalidOpCertIssueCounterFileError = 'Invalid operational certificate issue counter file', 18 | InvalidNodeKeyGenInputsError = 'Invalid node key-gen inputs', 19 | InvalidDerivationTypeError = 'Invalid derivation type', 20 | TxSerializationMismatchError = 'Tx serialization mismatch', 21 | SigningPubKeyMismatchError = 'Signing public key mismatch: likely because an incorrect signing file was used', 22 | MetadataSerializationMismatchError = 'Metadata serialization mismatch', 23 | MissingHwSigningDataAtPathError = 'Can not find hw signing data by path', 24 | MissingHwSigningDataAtXPubKeyError = 'Can not find hw signing data by extended public key', 25 | MissingHwSigningDataAtPoolColdKeyError = 'Can not find hw signing data by pool cold key', 26 | UndefinedCommandError = 'command undefined', 27 | TooManyPaymentFilesWithPoolRegError = 'Unexpected payment hardware signing file with pool registration certificate found', 28 | MissingPaymentSigningFileError = 'Missing payment hardware signing file', 29 | MissingStakeSigningFileError = 'Missing staking signing file', 30 | MissingPoolColdSigningFileError = 'Missing pool cold key signing file', 31 | TooManyPaymentSigningFilesError = 'Too many payment signing files', 32 | TooManyStakeSigningFilesError = 'Too many stake signing files', 33 | TooManyDRepSigningFilesError = 'Too many DRep key signing files', 34 | TooManyCommitteeColdSigningFilesError = 'Too many committee cold key signing files', 35 | TooManyCommitteeHotSigningFilesError = 'Too many committee hot key signing files', 36 | TooManyPoolColdSigningFilesError = 'Too many pool cold key signing files', 37 | TooManyMintSigningFilesError = 'Too many mint signing files', 38 | TooManyMultisigSigningFilesError = 'Too many multisig signing files', 39 | MissingSigningFileForCertificateError = 'Missing signing file for certificate', 40 | OwnerMultipleTimesInTxError = 'Owner multiple times in tx', 41 | UnsupportedRelayTypeError = 'Unsupported relay type', 42 | UnknownCertificateError = 'Unknown certificate', 43 | InvalidAddressError = 'Invalid address', 44 | InvalidAddressParametersProvidedError = 'Invalid address parameters provided', 45 | InvalidKeyGenInputsError = 'Invalid key gen inputs error', 46 | TrezorPassphraseNotInsertableOnDevice = 'Trezor passphrase not insertable on the device', 47 | TrezorXPubKeyCancelled = 'Extended public key export cancelled by user', 48 | UnsupportedCryptoProviderCall = 'The call is not supported by the chosen crypto provider', 49 | Keystone3ProShowAddress = 'Please open Keystone3Pro, go to the receive page, switch to the path you want, and check if your Cardano address corresponds to the correct payment address and staking address.', 50 | Keystone3ProUnsupportedThisCommand = 'This command is currently not supported on Keystone 3 Pro. Support will be added in a future version.', 51 | Keystone3ProUnsupportedThisPath = 'This path is currently not supported on Keystone 3 Pro. Support will be added in a future version.', 52 | Keystone3ProUnsupportedMultisig = 'Multisig paths are currently not supported on Keystone 3 Pro. Support will be added in a future version.', 53 | MissingAuxiliaryDataSupplement = 'Missing auxiliary data supplement in response.', 54 | MissingCIP36RegistrationSignature = 'Missing CIP36 voting signature', 55 | InternalInvalidTypeError = 'Internal invalid type error', 56 | InvalidCVotePublicKey = 'Invalid CIP36 vote public key', 57 | InvalidCVoteWeight = 'Invalid CIP36 vote weight', 58 | InvalidCVoteVotingPurpose = 'Invalid CIP36 voting purpose', 59 | InvalidCVoteDelegations = 'Invalid CIP36 delegations (either a single vote public key or several vote public keys with their weights are expected)', 60 | ByronSigningFilesFoundInCIP36Registration = 'Byron addresses are not allowed for CIP36 registration', 61 | TrezorVersionError = 'Failed to retrieve trezor version', 62 | InvalidCIP36RegistrationAddressType = 'CIP36 registration address type must be either BASE or REWARD', 63 | InvalidTransactionType = 'Invalid transaction type', 64 | InvalidScriptHashHex = 'Invalid script hash hex', 65 | InvalidNativeScriptFile = 'Invalid native script file', 66 | Unreachable = 'Unreachable code reached', 67 | TrezorPoolRegistrationAsOperatorNotSupported = 'Trezor does not support signing pool registration certificate as operator', 68 | TrezorVotingProceduresUnsupported = 'Trezor does not support voting procedures', 69 | TrezorTreasuryUnsupported = 'Trezor does not support treasury item in transaction body', 70 | TrezorDonationUnsupported = 'Trezor does not support donation item in transaction body', 71 | InvalidInputError = 'Invalid input', 72 | InvalidCollateralInputError = 'Invalid collateral input', 73 | TxContainsUnfixableErrors = 'Transaction CBOR contains unfixable errors', 74 | TxContainsFixableErrors = 'Transaction CBOR contains fixable errors, please run "transform" command first', 75 | CannotTransformSignedTx = 'Transaction contains vkey witnesses, transformation would invalidate them', 76 | NetworkIdMismatchError = 'Provided network id differs from network id included in transaction body', 77 | NotEnoughOutFilesError = 'Not enough output files specified', 78 | TestnetProtocolMagicMissing = 'Testnet protocol magic is missing', 79 | InvalidVotingProcedures = 'Invalid voting procedures (might be a number out of range)', 80 | UnsupportedCertificateType = 'Transaction contains a certificate type that is not supported by HW wallets (see CIP-21)', 81 | InvalidMessageError = 'Invalid message to sign, should be ASCII', 82 | InvalidMessageAddressError = 'Cannot derive address parameters in message signing: likely because address signing files are missing', 83 | InvalidMessageAddressTypeError = 'Invalid or unsupported address type in message signing', 84 | InvalidMessageAddressSigningFilesError = 'Missing address signing files in message signing', 85 | MessageAddressMismatchError = 'Message address mismatch: likely because incorrect address signing files were used', 86 | TrezorMessageHashPayloadUnsupported = 'Trezor does not support the `--hashed` option in message signing', 87 | } 88 | -------------------------------------------------------------------------------- /test/integration/trezor/node/cip36Registration.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | import assert from 'assert' 3 | import {TrezorCryptoProvider} from '../../../../src/crypto-providers/trezorCryptoProvider' 4 | 5 | import {NETWORKS} from '../../../../src/constants' 6 | import {signingFiles} from './signingFiles' 7 | import {addresses} from './addresses' 8 | import {CryptoProvider} from '../../../../src/crypto-providers/cryptoProvider' 9 | 10 | const cip36Registrations = { 11 | withTestnetBaseAddress0: { 12 | delegations: [ 13 | { 14 | votePublicKey: 15 | '3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7', 16 | voteWeight: 1, 17 | }, 18 | ], 19 | hwStakeSigningFile: signingFiles.stake0, 20 | paymentAddressBech32: addresses.testnet.base0, 21 | nonce: 165564, 22 | votingPurpose: 0, 23 | network: 'TESTNET_LEGACY1', 24 | auxiliarySigningFiles: [signingFiles.payment0, signingFiles.stake0], 25 | signedCIP36RegistrationMetaDataHex: 26 | 'a219ef64a501818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b701025820bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e0358390080f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b4277041a000286bc050019ef65a1015840d93fbfa58e4bed5c1474a6196ef7c9a87417403a45dcd9a96fc7ac51154e788f6285d1498f8d0e41ee87d8e62ae49f1a070a4677940abebcf3f274bfa60d7001', 27 | }, 28 | withMainnetBaseAddress0: { 29 | delegations: [ 30 | { 31 | votePublicKey: 32 | '3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7', 33 | voteWeight: 1, 34 | }, 35 | ], 36 | hwStakeSigningFile: signingFiles.stake0, 37 | paymentAddressBech32: addresses.mainnet.base0, 38 | nonce: 165564, 39 | votingPurpose: 0, 40 | network: 'MAINNET', 41 | auxiliarySigningFiles: [signingFiles.payment0, signingFiles.stake0], 42 | signedCIP36RegistrationMetaDataHex: 43 | 'a219ef64a501818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b701025820bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e0358390180f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b4277041a000286bc050019ef65a10158400e08dba5d4336c1c7b52cfd95ff2b016ca37cd476756f4217e8d7ecb1c95d09d372d87b8d8da88f701736e6ec15f46d6e55999afa54ecce6adc04da8cf927600', 44 | }, 45 | withTestnetPaymentAddress0: { 46 | delegations: [ 47 | { 48 | votePublicKey: 49 | '3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7', 50 | voteWeight: 1, 51 | }, 52 | ], 53 | hwStakeSigningFile: signingFiles.stake0, 54 | paymentAddressBech32: addresses.testnet.reward0, 55 | nonce: 165564, 56 | votingPurpose: 0, 57 | network: 'TESTNET_LEGACY1', 58 | auxiliarySigningFiles: [signingFiles.stake0], 59 | signedCIP36RegistrationMetaDataHex: 60 | 'a219ef64a501818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b701025820bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e03581de0122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b4277041a000286bc050019ef65a101584077cfc29043677f9061ca4b9b7004d6105e67f9488e9616cd5b5bc9dee5f4ff09db288af602bc3fabd8e259d0a080927f787af23d0e1a698898eaceb65efd6901', 61 | }, 62 | withMultipleDelegations: { 63 | delegations: [ 64 | { 65 | votePublicKey: 66 | '3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7', 67 | voteWeight: 1, 68 | }, 69 | { 70 | votePublicKey: 71 | '1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc', 72 | voteWeight: 2, 73 | }, 74 | ], 75 | hwStakeSigningFile: signingFiles.stake0, 76 | paymentAddressBech32: addresses.mainnet.reward0, 77 | nonce: 165564, 78 | votingPurpose: 0, 79 | network: 'MAINNET', 80 | auxiliarySigningFiles: [signingFiles.stake0], 81 | signedCIP36RegistrationMetaDataHex: 82 | 'a219ef64a501828258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7018258201af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc02025820bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e03581de1122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b4277041a000286bc050019ef65a10158408dcc41c03e7fe9b281f00c9ac2a8418d4fce9c0673f163088f45a014ad30d8740cb60b065ecdb073d44bb0595e519f9e584c6620258f27e20432706999e7a604', 83 | }, 84 | withThirdPartyPaymentAddress: { 85 | delegations: [ 86 | { 87 | votePublicKey: 88 | '3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7', 89 | voteWeight: 2, 90 | }, 91 | ], 92 | hwStakeSigningFile: signingFiles.stake0, 93 | paymentAddressBech32: addresses.mainnet.base0, 94 | nonce: 165564, 95 | votingPurpose: 1, 96 | network: 'MAINNET', 97 | auxiliarySigningFiles: [], 98 | signedCIP36RegistrationMetaDataHex: 99 | 'a219ef64a501818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b702025820bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e0358390180f9e2c88e6c817008f3a812ed889b4a4da8e0bd103f86e7335422aa122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b4277041a000286bc050119ef65a10158404893bdbcf02dd0169de641996db41619cdba64f5d36adb4964ba861139ff5306737e9618a558c4ade41e9118cece138df21cebd56175759de18e20349510f607', 100 | }, 101 | } 102 | 103 | async function testCIP36RegistrationMetaDataSigning( 104 | cryptoProvider: CryptoProvider, 105 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 106 | cip36Registration: any, 107 | ) { 108 | const {signedCIP36RegistrationMetaDataHex, ...args} = cip36Registration 109 | 110 | assert.deepStrictEqual( 111 | await cryptoProvider.signCIP36RegistrationMetaData( 112 | args.delegations, 113 | args.hwStakeSigningFile, 114 | args.paymentAddressBech32, 115 | args.nonce, 116 | args.votingPurpose, 117 | NETWORKS[args.network], 118 | args.auxiliarySigningFiles, 119 | ), 120 | signedCIP36RegistrationMetaDataHex, 121 | ) 122 | } 123 | 124 | describe('Trezor sign CIP36 registration metadata', () => { 125 | let cryptoProvider: CryptoProvider 126 | // eslint-disable-next-line prefer-arrow-callback 127 | before(async function () { 128 | this.timeout(10000) 129 | cryptoProvider = await TrezorCryptoProvider() 130 | }) 131 | const cip36RegistrationsToSign = Object.entries(cip36Registrations) 132 | 133 | cip36RegistrationsToSign.forEach(([testName, cip36Registration]) => 134 | it(`Should sign CIP36 registration ${testName}`, async () => 135 | await testCIP36RegistrationMetaDataSigning( 136 | cryptoProvider, 137 | cip36Registration, 138 | )).timeout(100000), 139 | ) 140 | }).timeout(1000000) 141 | -------------------------------------------------------------------------------- /test/integration/ledger/node/cip36Registration.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | import assert from 'assert' 3 | import {LedgerCryptoProvider} from '../../../../src/crypto-providers/ledgerCryptoProvider' 4 | 5 | import {NETWORKS} from '../../../../src/constants' 6 | import {signingFiles} from './signingFiles' 7 | import {addresses} from './addresses' 8 | import {getTransport} from './speculos' 9 | import {CryptoProvider} from '../../../../src/crypto-providers/cryptoProvider' 10 | 11 | const cip36Registrations = { 12 | withTestnetBaseAddress0: { 13 | delegations: [ 14 | { 15 | votePublicKey: 16 | '3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7', 17 | voteWeight: 2, 18 | }, 19 | ], 20 | hwStakeSigningFile: signingFiles.stake0, 21 | paymentAddressBech32: addresses.testnet.base0, 22 | nonce: 165564, 23 | votingPurpose: 0, 24 | network: 'TESTNET_LEGACY1', 25 | auxiliarySigningFiles: [signingFiles.payment0, signingFiles.stake0], 26 | signedCIP36RegistrationMetaDataHex: 27 | 'a219ef64a501818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b70202582066610efd336e1137c525937b76511fbcf2a0e6bcf0d340a67bcb39bc870d85e80358390014c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c041a000286bc050019ef65a101584031aafad1223d2ac49584e55cf1232221bdb2312b826fef7c901d5802f987a391f4a57b82416de34d60ee13b3a823a61aadec0b0cf09c529efe56922ec3c1ab0c', 28 | }, 29 | withMainnetBaseAddress0: { 30 | delegations: [ 31 | { 32 | votePublicKey: 33 | '3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7', 34 | voteWeight: 2, 35 | }, 36 | ], 37 | hwStakeSigningFile: signingFiles.stake0, 38 | paymentAddressBech32: addresses.mainnet.base0, 39 | nonce: 165564, 40 | votingPurpose: 1, 41 | network: 'MAINNET', 42 | auxiliarySigningFiles: [signingFiles.payment0, signingFiles.stake0], 43 | signedCIP36RegistrationMetaDataHex: 44 | 'a219ef64a501818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b70202582066610efd336e1137c525937b76511fbcf2a0e6bcf0d340a67bcb39bc870d85e80358390114c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c041a000286bc050119ef65a1015840fc76d0ef0e195b8d03a8988f7983c2d881b2fa1098762010d8a61270a779620a4a98361879344f1bc3bda7d33736ae3536d89aec65e4e6adaef15ccc90fa4704', 45 | }, 46 | withTestnetPaymentAddress0: { 47 | delegations: [ 48 | { 49 | votePublicKey: 50 | '3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7', 51 | voteWeight: 1, 52 | }, 53 | ], 54 | hwStakeSigningFile: signingFiles.stake0, 55 | paymentAddressBech32: addresses.testnet.reward0, 56 | nonce: 165564, 57 | votingPurpose: 0, 58 | network: 'TESTNET_LEGACY1', 59 | auxiliarySigningFiles: [signingFiles.stake0], 60 | signedCIP36RegistrationMetaDataHex: 61 | 'a219ef64a501818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b70102582066610efd336e1137c525937b76511fbcf2a0e6bcf0d340a67bcb39bc870d85e803581de01d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c041a000286bc050019ef65a1015840b8d4e3315af77091fc78e1aef92d07121f8d767b65940ad46632d9a835d709aa2f64293beaa077c5c094e43e0bfc479717e6cc54842cdc28cecb2f34ec315507', 62 | }, 63 | withMultipleDelegations: { 64 | delegations: [ 65 | { 66 | votePublicKey: 67 | '3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7', 68 | voteWeight: 1, 69 | }, 70 | { 71 | votePublicKey: 72 | '3eadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef', 73 | voteWeight: 3, 74 | }, 75 | ], 76 | hwStakeSigningFile: signingFiles.stake0, 77 | paymentAddressBech32: addresses.mainnet.reward0, 78 | nonce: 165564, 79 | votingPurpose: 0, 80 | network: 'MAINNET', 81 | auxiliarySigningFiles: [signingFiles.stake0], 82 | signedCIP36RegistrationMetaDataHex: 83 | 'a219ef64a501828258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7018258203eadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef0302582066610efd336e1137c525937b76511fbcf2a0e6bcf0d340a67bcb39bc870d85e803581de11d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c041a000286bc050019ef65a10158401500c4a09b763d5d396933f264d93e51e2aaf85ea41958d3425f1248c72b9d75215857eec227a21a14341efab85ac68882ed246a124398c9f9645b1921cd460c', 84 | }, 85 | withThirdPartyPaymentAddress: { 86 | delegations: [ 87 | { 88 | votePublicKey: 89 | '3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7', 90 | voteWeight: 2, 91 | }, 92 | ], 93 | hwStakeSigningFile: signingFiles.stake0, 94 | paymentAddressBech32: addresses.mainnet.base0, 95 | nonce: 165564, 96 | votingPurpose: 1, 97 | network: 'MAINNET', 98 | auxiliarySigningFiles: [], 99 | signedCIP36RegistrationMetaDataHex: 100 | 'a219ef64a501818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b70202582066610efd336e1137c525937b76511fbcf2a0e6bcf0d340a67bcb39bc870d85e80358390114c16d7f43243bd81478e68b9db53a8528fd4fb1078d58d54a7f11241d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c041a000286bc050119ef65a1015840fc76d0ef0e195b8d03a8988f7983c2d881b2fa1098762010d8a61270a779620a4a98361879344f1bc3bda7d33736ae3536d89aec65e4e6adaef15ccc90fa4704', 101 | }, 102 | } 103 | 104 | async function testCIP36RegistrationMetaDataSigning( 105 | cryptoProvider: CryptoProvider, 106 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 107 | cip36Registration: any, 108 | ) { 109 | const {signedCIP36RegistrationMetaDataHex, ...args} = cip36Registration 110 | 111 | assert.deepStrictEqual( 112 | await cryptoProvider.signCIP36RegistrationMetaData( 113 | args.delegations, 114 | args.hwStakeSigningFile, 115 | args.paymentAddressBech32, 116 | args.nonce, 117 | args.votingPurpose, 118 | NETWORKS[args.network], 119 | args.auxiliarySigningFiles, 120 | ), 121 | signedCIP36RegistrationMetaDataHex, 122 | ) 123 | } 124 | 125 | describe('Ledger sign CIP36 registration metadata', () => { 126 | let cryptoProvider: CryptoProvider 127 | // eslint-disable-next-line prefer-arrow-callback 128 | before(async function () { 129 | this.timeout(10000) 130 | cryptoProvider = await LedgerCryptoProvider(await getTransport()) 131 | }) 132 | const cip36RegistrationsToSign = Object.entries(cip36Registrations) 133 | 134 | cip36RegistrationsToSign.forEach(([testName, cip36Registration]) => 135 | it(`Should sign CIP36 registration ${testName}`, async () => 136 | await testCIP36RegistrationMetaDataSigning( 137 | cryptoProvider, 138 | cip36Registration, 139 | )).timeout(100000), 140 | ) 141 | }) 142 | --------------------------------------------------------------------------------