Research
Security News
Malicious npm Package Targets Solana Developers and Hijacks Funds
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
hw-app-dfi
Advanced tools
Ledger Hardware Wallet DFI JavaScript bindings. Also supports many altcoins.
DeFiChain API.
transport
TransportscrambleKey
(optional, default "BTC"
)import Dfi from "@ledgerhq/hw-app-dfi";
const dfi = new Dfi(transport)
Get an XPUB with a ledger device
arg
{path: string, xpubVersion: number} derivation parameter* path: a BIP 32 path of the account level. e.g. 84'/0'/0'
Returns Promise<string> XPUB of the account
path
string a BIP 32 path
opts
{verify: boolean?, format: AddressFormat?}?
options
an object with optional these fields:* verify (boolean) will ask user to confirm the address on the device
format ("legacy" | "p2sh" | "bech32" | "bech32m" | "cashaddr") to use different bitcoin address formatter.NB The normal usage is to use:* legacy format with 44' paths
p2sh format with 49' paths
bech32 format with 84' paths
cashaddr in case of Bitcoin Cash
btc.getWalletPublicKey("44'/0'/0'/0/0").then(o => o.bitcoinAddress)
btc.getWalletPublicKey("49'/0'/0'/0/0", { format: "p2sh" }).then(o => o.bitcoinAddress)
Returns Promise<{publicKey: string, bitcoinAddress: string, chainCode: string}>
You can sign a message according to the Bitcoin Signature format and retrieve v, r, s given the message and the BIP 32 path of the account to sign.
btc.signMessageNew_async("44'/60'/0'/0'/0", Buffer.from("test").toString("hex")).then(function(result) {
var v = result['v'] + 27 + 4;
var signature = Buffer.from(v.toString(16) + result['r'] + result['s'], 'hex').toString('base64');
console.log("Signature : " + signature);
}).catch(function(ex) {console.log(ex);});
Returns Promise<{v: number, r: string, s: string}>
To sign a transaction involving standard (P2PKH) inputs, call createTransaction with the following parameters
arg
CreateTransactionArginputs
is an array of [ transaction, output_index, optional redeem script, optional sequence ] where* transaction is the previously computed transaction object for this UTXO
associatedKeysets
is an array of BIP 32 paths pointing to the path to the private key used for each UTXOchangePath
is an optional BIP 32 path pointing to the path to the public key used to compute the change addressoutputScriptHex
is the hexadecimal serialized outputs of the transaction to sign, including leading vararg voutCountlockTime
is the optional lockTime of the transaction to sign, or default (0)sigHashType
is the hash type of the transaction to sign, or default (all)segwit
is an optional boolean indicating wether to use segwit or not. This includes wrapped segwit.initialTimestamp
is an optional timestamp of the function call to use for coins that necessitate timestamps only, (not the one that the tx will include)additionals
list of additionnal options* "bech32" for spending native segwit outputs
expiryHeight
is an optional Buffer for zec overwinter / sapling TxsuseTrustedInputForSegwit
trust inputs for segwit transactions. If app version >= 1.4.0 this should be true.btc.createTransaction({
inputs: [ [tx1, 1] ],
associatedKeysets: ["0'/0/0"],
outputScriptHex: "01905f0100000000001976a91472a5d75c8d2d0565b656a5232703b167d50d5a2b88ac"
}).then(res => ...);
Returns Promise<string> the signed transaction ready to be broadcast
To obtain the signature of multisignature (P2SH) inputs, call signP2SHTransaction_async with the folowing parameters
arg
SignP2SHTransactionArginputs
is an array of [ transaction, output_index, redeem script, optional sequence ] where* transaction is the previously computed transaction object for this UTXO
associatedKeysets
is an array of BIP 32 paths pointing to the path to the private key used for each UTXOoutputScriptHex
is the hexadecimal serialized outputs of the transaction to signlockTime
is the optional lockTime of the transaction to sign, or default (0)sigHashType
is the hash type of the transaction to sign, or default (all)btc.signP2SHTransaction({
inputs: [ [tx, 1, "52210289b4a3ad52a919abd2bdd6920d8a6879b1e788c38aa76f0440a6f32a9f1996d02103a3393b1439d1693b063482c04bd40142db97bdf139eedd1b51ffb7070a37eac321030b9a409a1e476b0d5d17b804fcdb81cf30f9b99c6f3ae1178206e08bc500639853ae"] ],
associatedKeysets: ["0'/0/0"],
outputScriptHex: "01905f0100000000001976a91472a5d75c8d2d0565b656a5232703b167d50d5a2b88ac"
}).then(result => ...);
Returns Promise<Array<string>> the signed transaction ready to be broadcast
For each UTXO included in your transaction, create a transaction object from the raw serialized version of the transaction used in this UTXO.
transactionHex
stringisSegwitSupported
(boolean | null | undefined) (optional, default false
)hasTimestamp
(optional, default false
)hasExtraData
(optional, default false
)additionals
Array<string> (optional, default []
)const tx1 = btc.splitTransaction("01000000014ea60aeac5252c14291d428915bd7ccd1bfc4af009f4d4dc57ae597ed0420b71010000008a47304402201f36a12c240dbf9e566bc04321050b1984cd6eaf6caee8f02bb0bfec08e3354b022012ee2aeadcbbfd1e92959f57c15c1c6debb757b798451b104665aa3010569b49014104090b15bde569386734abf2a2b99f9ca6a50656627e77de663ca7325702769986cf26cc9dd7fdea0af432c8e2becc867c932e1b9dd742f2a108997c2252e2bdebffffffff0281b72e00000000001976a91472a5d75c8d2d0565b656a5232703b167d50d5a2b88aca0860100000000001976a9144533f5fb9b4817f713c48f0bfe96b9f50c476c9b88ac00000000");
Returns Transaction
const tx1 = btc.splitTransaction("01000000014ea60aeac5252c14291d428915bd7ccd1bfc4af009f4d4dc57ae597ed0420b71010000008a47304402201f36a12c240dbf9e566bc04321050b1984cd6eaf6caee8f02bb0bfec08e3354b022012ee2aeadcbbfd1e92959f57c15c1c6debb757b798451b104665aa3010569b49014104090b15bde569386734abf2a2b99f9ca6a50656627e77de663ca7325702769986cf26cc9dd7fdea0af432c8e2becc867c932e1b9dd742f2a108997c2252e2bdebffffffff0281b72e00000000001976a91472a5d75c8d2d0565b656a5232703b167d50d5a2b88aca0860100000000001976a9144533f5fb9b4817f713c48f0bfe96b9f50c476c9b88ac00000000");
const outputScript = btc.serializeTransactionOutputs(tx1).toString('hex');
Returns Buffer
Definition: A "normal path" is a prefix of a standard path where all the hardened steps of the standard path are included. For example, the paths m/44'/1'/17' and m/44'/1'/17'/1 are normal paths, but m/44'/1' is not. m/'199/1'/17'/0/1 is not a normal path either.
There's a compatiblity issue between old and new app: When exporting the key of a non-normal path with verify=false, the new app would return an error, whereas the old app would return the key.
See https://github.com/LedgerHQ/app-bitcoin-new/blob/master/doc/bitcoin.md#get_extended_pubkey
If format bech32m is used, we'll not use old, because it doesn't support it.
When to use new (given the app supports it)
Otherwise use old.
This class implements the same interface as BtcOld (formerly named Btc), but interacts with Bitcoin hardware app version 2+ which uses a totally new APDU protocol. This new protocol is documented at https://github.com/LedgerHQ/app-bitcoin-new/blob/master/doc/bitcoin.md
Since the interface must remain compatible with BtcOld, the methods of this class are quite clunky, because it needs to adapt legacy input data into the PSBT process. In the future, a new interface should be developed that exposes PSBT to the outer world, which would render a much cleaner implementation.
This is a new method that allow users to get an xpub at a standard path. Standard paths are described at https://github.com/LedgerHQ/app-bitcoin-new/blob/master/doc/bitcoin.md#description
This boils down to paths (N=0 for Bitcoin, N=1 for Testnet): M/44'/N'/x'/** M/48'/N'/x'/y'/** M/49'/N'/x'/** M/84'/N'/x'/** M/86'/N'/x'/**
The method was added because of added security in the hardware app v2+. The new hardware app will allow export of any xpub up to and including the deepest hardened key of standard derivation paths, whereas the old app would allow export of any key.
This caused an issue for callers of this class, who only had getWalletPublicKey() to call which means they have to constuct xpub themselves:
Suppose a user of this class wants to create an account xpub on a standard path, M/44'/0'/Z'. The user must get the parent key fingerprint (see BIP32) by requesting the parent key M/44'/0'. The new app won't allow that, because it only allows exporting deepest level hardened path. So the options are to allow requesting M/44'/0' from the app, or to add a new function "getWalletXpub".
We opted for adding a new function, which can greatly simplify client code.
This method returns a public key, a bitcoin address, and and a chaincode for a specific derivation path.
Limitation: If the path is not a leaf node of a standard path, the address will be the empty string "", see this.getWalletAddress() for details.
path
stringopts
{verify: boolean?, format: AddressFormat?}?Returns Promise<{publicKey: string, bitcoinAddress: string, chainCode: string}>
Build and sign a transaction. See Btc.createPaymentTransactionNew for details on how to use this method.
This method will convert the legacy arguments, CreateTransactionArg, into a psbt which is finally signed and finalized, and the extracted fully signed transaction is returned.
Bitcoin API.
import Btc from "@ledgerhq/hw-app-btc";
const btc = new Btc(transport)
path
string a BIP 32 path
opts
{verify: boolean?, format: AddressFormat?}?
options
an object with optional these fields:* verify (boolean) will ask user to confirm the address on the device
format ("legacy" | "p2sh" | "bech32" | "cashaddr") to use different bitcoin address formatter.NB The normal usage is to use:* legacy format with 44' paths
p2sh format with 49' paths
bech32 format with 173' paths
cashaddr in case of Bitcoin Cash
btc.getWalletPublicKey("44'/0'/0'/0/0").then(o => o.bitcoinAddress)
btc.getWalletPublicKey("49'/0'/0'/0/0", { format: "p2sh" }).then(o => o.bitcoinAddress)
Returns Promise<{publicKey: string, bitcoinAddress: string, chainCode: string}>
You can sign a message according to the Bitcoin Signature format and retrieve v, r, s given the message and the BIP 32 path of the account to sign.
btc.signMessageNew_async("44'/60'/0'/0'/0", Buffer.from("test").toString("hex")).then(function(result) {
var v = result['v'] + 27 + 4;
var signature = Buffer.from(v.toString(16) + result['r'] + result['s'], 'hex').toString('base64');
console.log("Signature : " + signature);
}).catch(function(ex) {console.log(ex);});
Returns Promise<{v: number, r: string, s: string}>
To sign a transaction involving standard (P2PKH) inputs, call createTransaction with the following parameters
arg
CreateTransactionArginputs
is an array of [ transaction, output_index, optional redeem script, optional sequence ] where* transaction is the previously computed transaction object for this UTXO
associatedKeysets
is an array of BIP 32 paths pointing to the path to the private key used for each UTXOchangePath
is an optional BIP 32 path pointing to the path to the public key used to compute the change addressoutputScriptHex
is the hexadecimal serialized outputs of the transaction to signlockTime
is the optional lockTime of the transaction to sign, or default (0)sigHashType
is the hash type of the transaction to sign, or default (all)segwit
is an optional boolean indicating wether to use segwit or notinitialTimestamp
is an optional timestamp of the function call to use for coins that necessitate timestamps only, (not the one that the tx will include)additionals
list of additionnal options* "bech32" for spending native segwit outputs
expiryHeight
is an optional Buffer for zec overwinter / sapling TxsuseTrustedInputForSegwit
trust inputs for segwit transactionsbtc.createTransaction({
inputs: [ [tx1, 1] ],
associatedKeysets: ["0'/0/0"],
outputScriptHex: "01905f0100000000001976a91472a5d75c8d2d0565b656a5232703b167d50d5a2b88ac"
}).then(res => ...);
Returns Promise<string> the signed transaction ready to be broadcast
To obtain the signature of multisignature (P2SH) inputs, call signP2SHTransaction_async with the folowing parameters
arg
SignP2SHTransactionArginputs
is an array of [ transaction, output_index, redeem script, optional sequence ] where* transaction is the previously computed transaction object for this UTXO
associatedKeysets
is an array of BIP 32 paths pointing to the path to the private key used for each UTXOoutputScriptHex
is the hexadecimal serialized outputs of the transaction to signlockTime
is the optional lockTime of the transaction to sign, or default (0)sigHashType
is the hash type of the transaction to sign, or default (all)btc.signP2SHTransaction({
inputs: [ [tx, 1, "52210289b4a3ad52a919abd2bdd6920d8a6879b1e788c38aa76f0440a6f32a9f1996d02103a3393b1439d1693b063482c04bd40142db97bdf139eedd1b51ffb7070a37eac321030b9a409a1e476b0d5d17b804fcdb81cf30f9b99c6f3ae1178206e08bc500639853ae"] ],
associatedKeysets: ["0'/0/0"],
outputScriptHex: "01905f0100000000001976a91472a5d75c8d2d0565b656a5232703b167d50d5a2b88ac"
}).then(result => ...);
Returns Promise<Array<string>> the signed transaction ready to be broadcast
Type: {inputs: Array<[Transaction, number, (string | null | undefined), (number | null | undefined)]>, associatedKeysets: Array<string>, changePath: string?, outputScriptHex: string, lockTime: number?, sigHashType: number?, segwit: boolean?, initialTimestamp: number?, additionals: Array<string>, expiryHeight: Buffer?, useTrustedInputForSegwit: boolean?, onDeviceStreaming: function (arg0: {progress: number, total: number, index: number}): void?, onDeviceSignatureRequested: function (): void?, onDeviceSignatureGranted: function (): void?}
inputs
Array<[Transaction, number, (string | null | undefined), (number | null | undefined)]>associatedKeysets
Array<string>changePath
string?outputScriptHex
stringlockTime
number?sigHashType
number?segwit
boolean?initialTimestamp
number?additionals
Array<string>expiryHeight
Buffer?useTrustedInputForSegwit
boolean?onDeviceStreaming
function (arg0: {progress: number, total: number, index: number}): void?onDeviceSignatureRequested
function (): void?onDeviceSignatureGranted
function (): void?address format is one of legacy | p2sh | bech32 | cashaddr
Type: ("legacy"
| "p2sh"
| "bech32"
| "bech32m"
| "cashaddr"
)
Encapsulates differences between account types, for example p2wpkh, p2wpkhWrapped, p2tr.
Generates a scriptPubKey (output script) from a list of public keys. If a p2sh redeemScript or a p2wsh witnessScript is needed it will also be set on the returned SpendingCondition.
The pubkeys are expected to be 33 byte ecdsa compressed pubkeys.
Returns SpendingCondition
Populates the psbt with account type-specific data for an input.
i
number The index of the input map to populateinputTx
(Buffer | undefined) The full transaction containing the spent output. This may
be omitted for taproot.spentOutput
SpentOutput The amount and spending condition of the spent outputpubkeys
Array<Buffer> The 33 byte ecdsa compressed public keys involved in the inputpathElems
Array<Array<number>> The paths corresponding to the pubkeys, in same order.Returns void
Populates the psbt with account type-specific data for an output. This is typically done for change outputs and other outputs that goes to the same account as being spent from.
i
number The index of the output map to populatecond
SpendingCondition The spending condition for this outputpubkeys
Array<Buffer> The 33 byte ecdsa compressed public keys involved in this outputpaths
Array<Array<number>> The paths corresponding to the pubkeys, in same order.Returns void
Returns the descriptor template for this account type. Currently only DefaultDescriptorTemplates are allowed, but that might be changed in the future. See class WalletPolicy for more information on descriptor templates.
Returns DefaultDescriptorTemplate
Extends BaseAccount
Superclass for single signature accounts. This will make sure that the pubkey arrays and path arrays in the method arguments contains exactly one element and calls an abstract method to do the actual work.
Calculates a taproot output key from an internal key. This output key will be used as witness program in a taproot output. The internal key is tweaked according to recommendation in BIP341: https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_ref-22-0
internalPubkey
Buffer A 32 byte x-only taproot internal keyReturns Buffer The output key
This class encapsulates the APDU protocol documented at https://github.com/LedgerHQ/app-bitcoin-new/blob/master/doc/bitcoin.md
transport
TransportThis class will dispatch a client command coming from the hardware device to the appropriate client command implementation. Those client commands typically requests data from a merkle tree or merkelized maps.
A ClientCommandInterpreter is prepared by adding the merkle trees and merkelized maps it should be able to serve to the hardware device. This class doesn't know anything about the semantics of the data it holds, it just serves merkle data. It doesn't even know in what context it is being executed, ie SignPsbt, getWalletAddress, etc.
If the command yelds results to the client, as signPsbt does, the yielded data will be accessible after the command completed by calling getYielded(), which will return the yields in the same order as they came in.
progressCallback
function (): voidExtends PsbtV2
This class merkelizes a PSBTv2, by merkelizing the different maps of the psbt. This is used during the transaction signing process, where the hardware app can request specific parts of the psbt from the client code and be sure that the response data actually belong to the psbt. The reason for this is the limited amount of memory available to the app, so it can't always store the full psbt in memory.
The signing process is documented at https://github.com/LedgerHQ/app-bitcoin-new/blob/master/doc/bitcoin.md#sign_psbt
psbt
PsbtV2This class implements the merkle tree used by Ledger Bitcoin app v2+, which is documented at https://github.com/LedgerHQ/app-bitcoin-new/blob/master/doc/merkle.md
This implements "Merkelized Maps", documented at https://github.com/LedgerHQ/app-bitcoin-new/blob/master/doc/merkle.md#merkleized-maps
A merkelized map consist of two merkle trees, one for the keys of a map and one for the values of the same map, thus the two merkle trees have the same shape. The commitment is the number elements in the map followed by the keys' merkle root followed by the values' merkle root.
keys
Array<Buffer> Sorted list of (unhashed) keysvalues
Array<Buffer> values, in corresponding order as the keys, and of equal lengthThe Bitcon hardware app uses a descriptors-like thing to describe how to construct output scripts from keys. A "Wallet Policy" consists of a "Descriptor Template" and a list of "keys". A key is basically a serialized BIP32 extended public key with some added derivation path information. This is documented at https://github.com/LedgerHQ/app-bitcoin-new/blob/master/doc/wallet.md
descriptorTemplate
DefaultDescriptorTemplatekey
stringThis implements the "Transaction Extractor" role of BIP370 (PSBTv2 https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki#transaction-extractor). However the role is partially documented in BIP174 (PSBTv0 https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#transaction-extractor).
psbt
PsbtV2Returns Buffer
This roughly implements the "input finalizer" role of BIP370 (PSBTv2 https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki). However the role is documented in BIP174 (PSBTv0 https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki).
Verify that all inputs have a signature, and set inputFinalScriptwitness and/or inputFinalScriptSig depending on the type of the spent outputs. Clean fields that aren't useful anymore, partial signatures, redeem script and derivation paths.
psbt
PsbtV2 The psbt with all signatures added as partial sigs, either
through PSBT_IN_PARTIAL_SIG or PSBT_IN_TAP_KEY_SIGReturns void
Deletes fields that are no longer neccesary from the psbt.
Note, the spec doesn't say anything about removing ouput fields like PSBT_OUT_BIP32_DERIVATION_PATH and others, so we keep them without actually knowing why. I think we should remove them too.
Writes a script push operation to buf, which looks different depending on the size of the data. See https://en.bitcoin.it/wiki/Script#Constants
buf
BufferWriter the BufferWriter to write todata
Buffer the Buffer to be pushed.Implements Partially Signed Bitcoin Transaction version 2, BIP370, as documented at https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki and https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki
A psbt is a data structure that can carry all relevant information about a transaction through all stages of the signing process. From constructing an unsigned transaction to extracting the final serialized transaction ready for broadcast.
This implementation is limited to what's needed in ledgerjs to carry out its duties, which means that support for features like multisig or taproot script path spending are not implemented. Specifically, it supports p2pkh, p2wpkhWrappedInP2sh, p2wpkh and p2tr key path spending.
This class is made purposefully dumb, so it's easy to add support for complemantary fields as needed in the future.
$0
Transaction
$0.outputs
const tx1 = btc.splitTransaction("01000000014ea60aeac5252c14291d428915bd7ccd1bfc4af009f4d4dc57ae597ed0420b71010000008a47304402201f36a12c240dbf9e566bc04321050b1984cd6eaf6caee8f02bb0bfec08e3354b022012ee2aeadcbbfd1e92959f57c15c1c6debb757b798451b104665aa3010569b49014104090b15bde569386734abf2a2b99f9ca6a50656627e77de663ca7325702769986cf26cc9dd7fdea0af432c8e2becc867c932e1b9dd742f2a108997c2252e2bdebffffffff0281b72e00000000001976a91472a5d75c8d2d0565b656a5232703b167d50d5a2b88aca0860100000000001976a9144533f5fb9b4817f713c48f0bfe96b9f50c476c9b88ac00000000");
const outputScript = btc.serializeTransactionOutputs(tx1).toString('hex');
Returns Buffer
Type: {inputs: Array<[Transaction, number, (string | null | undefined), (number | null | undefined)]>, associatedKeysets: Array<string>, outputScriptHex: string, lockTime: number?, sigHashType: number?, segwit: boolean?, transactionVersion: number?}
inputs
Array<[Transaction, number, (string | null | undefined), (number | null | undefined)]>associatedKeysets
Array<string>outputScriptHex
stringlockTime
number?sigHashType
number?segwit
boolean?transactionVersion
number?FAQs
Ledger Hardware Wallet DeFiChain Application API
The npm package hw-app-dfi receives a total of 9 weekly downloads. As such, hw-app-dfi popularity was classified as not popular.
We found that hw-app-dfi demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
Security News
Research
Socket researchers have discovered malicious npm packages targeting crypto developers, stealing credentials and wallet data using spyware delivered through typosquats of popular cryptographic libraries.
Security News
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.