Closed generalAO closed 1 year ago
No need to use psbtv2, the library can convert from PsbtV0 on the fly.
How do you get the hmac? Was the wallet policy correctly registered beforehand? For testing, I suggest registering and using the wallet policy in the same script. Note that any tiny change in the wallet policy will invalidate the hmac.
So i can use psbt created with bitcoinjs-lib. Right? By default in bitcoinjs-lib version of psbt is 2.
I receive walet policy after i registered it with Ledger.
const [policyId, registeredPolicyHmac] = await app.registerWallet( multisigPolicy, );
Of course wallet policy is the same, but i will try to do it in the same script, just to exclude any differences.
I added registering policy to the same script, but still get the same error
If you can share the psbt encoded in base64, I'll check if anything is missing.
(I don't think bitcoinjs implemented psbtV2, but psbtV0 is fine)
Psbt in Base64. Pls check it, because i can sign it with 2 other (non ledger) keys and successfully broadcast.
cHNidP8BAFICAAAAAXT4O7x9eMNn7ardXHS6FtjY9AXeT7r+71XKP30rg4LvAAAAAAD/////AVIDAAAAAAAAFgAUcrEfm4kwMqMWFRtFfVFhTVvkwhIAAAAAAAEBK+gDAAAAAAAAIgAgvetQm+nFAYsuJvBXI5UYMNPsxjhiSsLPR3u3tsgZUhgBBWlSIQMgbvWSyS19q/KwaqFO49pULo/W6fEbDje10tHXnnggkCEDkrbyTiC5A6k16l0b3zJLHyQfxI5HZ25ONnDRETNE25ohAhcOnDH1MkapKJpJVQMBYCKF3ANvoUh+YCC6hpzmQ3dEU64AAA==
The PSBT is incomplete, it doesn't contain basically anything other than the unsigned transaction.
It is required to have all the information about the keys present in the transaction; in particular, the PSBT_GLOBAL_XPUB and the PSBT_IN_BIP32_DERIVATION are compulsory.
You can find a few complete psbts in this folder, might help as a reference on how they should look like: https://github.com/LedgerHQ/app-bitcoin-new/tree/develop/tests/psbt.
Thx, i will check your psvt. But why i can sign transaction without a ledger? With keys generated by bip39/32 libraries? I thought if i can sign with external keys, then i can sign with Ledger too.
Because hardware wallets perform a number of checks that you can skip if you are blind-signing, but that reduces security. Following the BIP174 standard guarantees that all the fields that signers might need are correctly filled.
Hi, im trying to sign a psbt transaction with Ledger, but got an error:
message: 'Ledger device: Invalid data received (0x6a80)', statusCode: 27264, statusText: 'INCORRECT_DATA'
I have 3 signers. 1 of them with Ledger device, 2 others just with external xpubs. The signing strategy is 2 of 3. I can sign and broadcast psbt with external keys, but when im trying to sign with Ledger, i got an error. What im doing wrong?`import * as bitcoin from 'bitcoinjs-lib'; import { alice, bob, ledger } from './keys'; import { TRANSPORT_TIME_OUT, network } from './constants'; import { derivedPrivateKey, pubkeyFromXpub } from './utils'; import { ECPairFactory } from 'ecpair'; import ecc from '@bitcoinerlab/secp256k1'; import { createLedgerWalletPolicy } from './wallet'; import AppClient, { WalletPolicy } from 'ledger-bitcoin'; import Transport from '@ledgerhq/hw-transport-node-hid';
export async function prepareAndSign2of3Ledger() { const p2ms = bitcoin.payments.p2ms({ m: 2, pubkeys: [ Buffer.from(pubkeyFromXpub(ledger.xpub), 'hex'), Buffer.from(pubkeyFromXpub(alice.xpub), 'hex'), Buffer.from(pubkeyFromXpub(bob.xpub), 'hex'), ], network, });
const p2wsh = bitcoin.payments.p2wsh({ redeem: p2ms, network, });
const inputData = { hash: '***', index: 0, witnessScript: p2wsh.redeem?.output, witnessUtxo: { script: Buffer.from( '0020' + bitcoin.crypto.sha256(p2ms.output!).toString('hex'), 'hex', ), value: 1000, // value in satoshi }, };
const keyPairAlice = ECPair.fromPrivateKey( Buffer.from(derivedPrivateKey(alice.mnemonic) as string, 'hex'), { network: bitcoin.networks.testnet, }, ); const keyPairBob = ECPair.fromPrivateKey( Buffer.from(derivedPrivateKey(bob.mnemonic) as string, 'hex'), { network: bitcoin.networks.testnet, }, );
const psbt = new bitcoin.Psbt({ network }).addInput(inputData).addOutput({ address: '****', value: 850, });
// LEDGER. const walletPolicy = await createLedgerWalletPolicy([ ledger.xpub,
[${alice.pubKeyFingerprintMaster}/49'/1'/0']${alice.xpub}
,[${bob.pubKeyFingerprintMaster}/49'/1'/0']${bob.xpub}
, ]);const transport = await Transport.create( TRANSPORT_TIME_OUT, TRANSPORT_TIME_OUT, ); const app = new AppClient(transport);
const address = await app.getWalletAddress( walletPolicy, Buffer.from(ledger.policyHmac, 'hex'), 0, 0, false, );
const [index, partialSignature] = await app.signPsbt( psbt, walletPolicy, Buffer.from(ledger.policyHmac, 'hex'), );`
`export async function createLedgerWalletPolicy( pubkeys: string[], ): Promise {
const descriptionTemplate = 'wsh(multi(2,@0/,@1/,@2/**))';
const transport = await Transport.create(
TRANSPORT_TIME_OUT,
TRANSPORT_TIME_OUT,
);
const app = new AppClient(transport);
const fpr = await app.getMasterFingerprint();
let ourPubkey; try { ourPubkey = await app.getExtendedPubkey(path, false); } catch (e) { await transport.close(); throw e; }
if (!pubkeys.includes(ourPubkey)) { await transport.close(); throw new Error('pubkey not good'); }
const ourKeyInfo =
[${fpr}/49'/1'/0']${ourPubkey}
; const tempPubKeys: string[] = []; pubkeys.forEach((key) => { if (ourPubkey === key) { tempPubKeys.push(ourKeyInfo); } else { if (key.startsWith('tpub')) { tempPubKeys.push(key); } else { tempPubKeys.push(key); } } });const multisigPolicy = new WalletPolicy( '2 of 3 xpubs', descriptionTemplate, tempPubKeys, );
transport.close(); return multisigPolicy; }`
I tried also use psbtV2
const psbtV2 = new PsbtV2(); psbtV2.deserialize(Buffer.from(psbt.toBase64(), 'base64'));