Closed javiervargas closed 1 week ago
Hi, I'd first observe that the 93c410d8
key has the unusual derivation m/45'/1/0
instead of the m/45'/1'/0'
of the other two keys. Is that intended? That's unusual, so it might be a possible mistake.
In any case, the bip32_derivs
of the input are certainly wrong: there you'd expect a path like m/45'/1'/0'/0/<something>
or m/45'/1'/0'/1/<something>
, where the final two derivation steps are the same for all the keys.
Thanks for your answer @bigspider .
First, it's the way that works to achieve recover this address on other open wallets like Caravan, I think it's a ColdCard matter.
About derivation paths, so I should include complete paths like this, right? changed psbt and get same output.
bip32Derivation: [
{
masterFingerprint: Buffer.from('44c11f58', 'hex'),
pubkey: cosigner1Pubkey,
path: "m/45'/1'/0'/0/0",
},
{
masterFingerprint: Buffer.from('ad38d9ea', 'hex'),
pubkey: cosigner2Pubkey,
path: "m/45'/1'/0'/0/0",
},
{
masterFingerprint: Buffer.from('93c410d8', 'hex'),
pubkey: cosigner3Pubkey,
path: "m/45'/1/0/0/0",
}
]
});
psbt.updateGlobal({
globalXpub: [
{
masterFingerprint: Buffer.from('44c11f58', 'hex'),
extendedPubkey: Buffer.from(cosigner1ExtendedPubKey, 'hex'),
path: "m/45'/1'/0'/0/0"
},
{
masterFingerprint: Buffer.from('ad38d9ea', 'hex'),
extendedPubkey: Buffer.from(cosigner2ExtendedPubKey, 'hex'),
path: "m/45'/1'/0'/0/0"
},
{
masterFingerprint: Buffer.from('93c410d8', 'hex'),
extendedPubkey: Buffer.from(cosigner3ExtendedPubKey, 'hex'),
path: "m/45'/1/0/0/0"
}
]
The global_xpubs
should be on the m/45'/1'/0'
path; typically, the global xpubs are at the deepest hardened derivation step, as they are the root xpub from which all the keys used in the wallet are derived.
For Ledger's wallet policies (that are compliant with BIP-388) bip32_paths
should have exactly 2 additional unhardened extra derivation steps, /0/<number>
or /1/<number>
as mentioned above.
Code right now; same result. Is there any way to debug process or capture messages on web console?
Thanks for your help.
bip32Derivation: [
{
masterFingerprint: Buffer.from('44c11f58', 'hex'),
pubkey: cosigner1Pubkey,
path: "m/45'/1'/0'/0/0",
},
{
masterFingerprint: Buffer.from('ad38d9ea', 'hex'),
pubkey: cosigner2Pubkey,
path: "m/45'/1'/0'/0/0",
},
{
masterFingerprint: Buffer.from('93c410d8', 'hex'),
pubkey: cosigner3Pubkey,
path: "m/45'/1/0/0/0",
}
]
});
psbt.updateGlobal({
globalXpub: [
{
masterFingerprint: Buffer.from('44c11f58', 'hex'),
extendedPubkey: Buffer.from(cosigner1ExtendedPubKey, 'hex'),
path: "m/45'/1'/0'"
},
{
masterFingerprint: Buffer.from('ad38d9ea', 'hex'),
extendedPubkey: Buffer.from(cosigner2ExtendedPubKey, 'hex'),
path: "m/45'/1'/0'"
},
{
masterFingerprint: Buffer.from('93c410d8', 'hex'),
extendedPubkey: Buffer.from(cosigner3ExtendedPubKey, 'hex'),
path: "m/45'/1/0"
}
{type: 'transport', id: '434', date: Tue Oct 29 2024 21:44:17 GMT+0100 (Central European Standard Time), message: 'Finalize, clearing busy guard', context: {…}}
index.4d6bcbeb.js:652 {type: 'transport', id: '435', date: Tue Oct 29 2024 21:44:17 GMT+0100 (Central European Standard Time), message: 'Received response from exchange', context: {…}}
index.4d6bcbeb.js:652 {type: 'transport', id: '436', date: Tue Oct 29 2024 21:44:17 GMT+0100 (Central European Standard Time), message: 'Starting an exchange', data: {…}, …}context: {function: 'send'}data: {abortTimeoutMs: undefined}date: Tue Oct 29 2024 21:44:17 GMT+0100 (Central European Standard Time) {}id: "436"message: "Starting an exchange"type: "transport"[[Prototype]]: Object
index.4d6bcbeb.js:652 {type: 'apdu', id: '437', date: Tue Oct 29 2024 21:44:17 GMT+0100 (Central European Standard Time), message: '=> f8010000e3e1e10002000000000101880573fb870032e84…c051b172b139934ea0ae471f4d696006c3a9627b334b43000'}
index.4d6bcbeb.js:652 {type: 'apdu', id: '438', date: Tue Oct 29 2024 21:44:17 GMT+0100 (Central European Standard Time), message: '<= 6a80'}
index.4d6bcbeb.js:652 {type: 'transport', id: '439', date: Tue Oct 29 2024 21:44:17 GMT+0100 (Central European Standard Time), message: 'Finalize, clearing busy guard', context: {…}}
index.4d6bcbeb.js:652 {type: 'transport', id: '440', date: Tue Oct 29 2024 21:44:17 GMT+0100 (Central European Standard Time), message: 'Received response from exchange', context: {…}}
index.4d6bcbeb.js:695 TransportStatusError: Ledger device: Invalid data received (0x6a80)
at TransportWebUSB.<anonymous> (index.4d6bcbeb.js:33475:60)
at Generator.next (<anonymous>)
at fulfilled (index.4d6bcbeb.js:33395:32)`
Not sure about the debug console (I don't use JavaScript), but if you're able to compile the app with DEBUG=1 and run it in speculos, there are a lot of debug statement that will be printed in the shell where speculos is running.
Build instructions are in the main README of the repository.
The most likely failure is still wrong info in the psbt: either wrong derivation paths, or not matching the info in the nonWitnessUtxo.
Trying to launch speculos, Meanwhile, Can you clarify please what's correct way to obtain hmac? According with samples (appClient.test.ts):
{
policy: new WalletPolicy(
"Cold storage",
"wsh(sortedmulti(2,@0/**,@1/**))",
[
"[76223a6e/48'/1'/0'/2']tpubDE7NQymr4AFtewpAsWtnreyq9ghkzQBXpCZjWLFVRAvnbf7vya2eMTvT2fPapNqL8SuVvLQdbUbMfWLVDCZKnsEBqp6UK93QEzL8Ck23AwF",
"[f5acc2fd/48'/1'/0'/2']tpubDFAqEGNyad35aBCKUAXbQGDjdVhNueno5ZZVEn3sQbW5ci457gLR7HyTmHBg93oourBssgUxuWz1jX5uhc1qaqFo9VsybY1J5FuedLfm4dK",
]
),
change: 0,
addrIndex: 0,
expResult: "tb1qmyauyzn08cduzdqweexgna2spwd0rndj55fsrkefry2cpuyt4cpsn2pg28",
walletHmac: Buffer.from("d7c7a60b4ab4a14c1bf8901ba627d72140b2fb907f2b4e35d2e693bce9fbb371", "hex")
}
I'm doing this: I get hmac after register Wallet.
const [policyId, policyHmac] = await app.registerWallet(multisigPolicy);
Later should use all derivation paths? tried different combinations with same result.
const ourPubkey = await app.getExtendedPubkey("m/45'/1'/0'");
const ourKeyInfo = `[${fpr}/45'/1'/0'/0/]${ourPubkey}`;
const otherKeyInfo = "[ad38d9ea/45'/1'/0'/0]tpubDC2QJtarETt4NkxuTuGc6mvtBKgpnwJwPt8paKvQZKWiUESbHyMzgZyLfjzdnENJWNidnqcCmXhKUfShJ7xz1tgLP7jZpkoXpr7SGaTcEt3";
const coldKeyInfo = "[93c410d8/45'/1/0/0]tpubDCz33uKPCZzeN4agYd2vxyyBiJeZJBZKAhW638xyN9C4KxAG4MhiBrDtrq1fRADmt7jqkgym2jUefCuE4UQQgzM6MQLiPfNnpH5H5sGQkjb";
const multisigPolicy = new WalletPolicy(
"Cold storage",
"sh(sortedmulti(2,@0/**,@1/**,@2/**))", // a 2-of-3 multisig policy template
[
otherKeyInfo, // some other bitcoiner
ourKeyInfo, // that's us
coldKeyInfo
]
)
console.log(multisigPolicy);
const [policyId, policyHmac] = await app.registerWallet(multisigPolicy);
console.log(`Policy hmac: ${policyHmac.toString("hex")}. Store it safely (together with the policy).`);
console.log('policy : ', multisigPolicy);
console.log('policyMac: ', policyHmac.toString("hex"));
const hmac = Buffer.from(policyHmac, "hex");
const psbt = "cHNidP8BAFUCAAAAAbbUXGeNYQet/rSpcibXRxpEk0s+qcQ13AIv6TsR7CRxAQAAAAD/////AVgCAAAAAAAAGXapFNPCFDSmzeYKli+eAgd5bQx5dJI+iKwAAAAATwEENYfPAwACfNaAAAAAitcBOSwrKKPETTFTQB2dV2vR7JeW0oWISULd7zff6YwD7CHlhpedfqFMPs/Ynyylrt1MmciorP8y5NheFXQsVBQQRMEfWC0AAIABAACAAAAAgE8BBDWHzwNDTstqgAAAADyYUIjJ0r+BE97TSLMAxAVXqykmzpXn8OjrOZXpGtypAiscEQVdgAYz+aaLNncVAez1gcKaGbwAm9aUjCmBUP3QEK042eotAACAAQAAgAAAAIBPAQQ1h88DgoJ17wAAAACLzmO+hByJ5sRId8P2Yk2ocvvCRfE71oHTxzvR3kFdVQNOPE/+YNwEpZpgurYl3xqaFl7O0iZ6lonO5dkt6egLSBCTxBDYLQAAgAEAAAAAAAAAAAEA4AIAAAAAAQGIBXP7hwAy6E96KP4N/8V/Tfm4vxlR/upITB78hh8fsgAAAAAA/f///wJXHwIAAAAAABepFO9+OkwJ33cbkuScONov2H9WuEnzh6CGAQAAAAAAF6kUFsT5HlQZ3oe3saQ57nNEsrsyEmyHAkcwRAIge7VOHNcQsoLT7uwYuqaaiM4kRhZ8gEEU4cWbDyMbuGoCIBrO5a75aw+y8vhigNmzeKK1Giga1wMrTpFnzNr+XrMRASED3rqKjW60B9oFWHFsBRsXKxOZNOoK5HH01pYAbDqWJ7M0tDAAAQRpUiECI3IHP1F93YV4O5y27ztzqRZ+nLF/jn2cumFBLsJdFDYhAjahpn8UmMFHCIsODyIv7uZwUokqfOo6W5HxwRB9x3mjIQOMWCtjMi9QvCg3MVs+kA4Q8gkf1+NFTR+PrlxfllGrj1OuIgYCKxwRBV2ABjP5pos2dxUB7PWBwpoZvACb1pSMKYFQ/dAYrTjZ6i0AAIABAACAAAAAgAAAAAAAAAAAIgYDTjxP/mDcBKWaYLq2Jd8amhZeztImepaJzuXZLenoC0gYk8QQ2C0AAIABAAAAAAAAAAAAAAAAAAAAIgYD7CHlhpedfqFMPs/Ynyylrt1MmciorP8y5NheFXQsVBQYRMEfWC0AAIABAACAAAAAgAAAAAAAAAAAAAA=");
// const psbt = new PsbtV2();
// psbt.deserialize(psbtBuf);
if (!psbt || !multisigPolicy) {
console.log("Nothing to sign :(");
await transport.close();
return;
}
try{
const result = await app.signPsbt(psbt, multisigPolicy, hmac);
console.log("Returned signatures:");
console.log(result);
await transport.close();
} catch (e) {}
Output:
Error during PSBT signing: TransportStatusError: Ledger device: Invalid data received (0x6a80)
at TransportWebUSB.<anonymous> (index.4d6bcbeb.js:35747:60)
at Generator.next (<anonymous>)
at fulfilled (index.4d6bcbeb.js:35667:32)
Thanks!
The code for registering the wallet policy is correct, except that again the derivation paths are unusual, which might suggest a mistake.
You would expect just 45'/1'/0'
for the derivation paths in the wallet policy, whereas the bip32 paths in the psbt (for each of the inputs, and for the change output, if any) would then have the pattern 45'/1'/0'/<0;1>/*
.
Tried with that option before
const ourPubkey = await app.getExtendedPubkey("m/45'/1'/0'");
console.log(ourPubkey);
const ourKeyInfo = `[${fpr}/45'/1'/0']${ourPubkey}`;
const otherKeyInfo = "[ad38d9ea/45'/1'/0']tpubDC2QJtarETt4NkxuTuGc6mvtBKgpnwJwPt8paKvQZKWiUESbHyMzgZyLfjzdnENJWNidnqcCmXhKUfShJ7xz1tgLP7jZpkoXpr7SGaTcEt3";
const coldKeyInfo = "[93c410d8/45'/1'/0']tpubDCz33uKPCZzeN4agYd2vxyyBiJeZJBZKAhW638xyN9C4KxAG4MhiBrDtrq1fRADmt7jqkgym2jUefCuE4UQQgzM6MQLiPfNnpH5H5sGQkjb";
const multisigPolicy = new WalletPolicy(
"Cold storage",
"sh(sortedmulti(2,@0/**,@1/**,@2/**))", // a 2-of-3 multisig policy template
[
otherKeyInfo, // some other bitcoiner
ourKeyInfo, // that's us
coldKeyInfo
]
)
console.log(multisigPolicy);
With this psbt
const psbt = 'cHNidP8BAFUCAAAAAbbUXGeNYQet/rSpcibXRxpEk0s+qcQ13AIv6TsR7CRxAQAAAAD/////AVgCAAAAAAAAGXapFNPCFDSmzeYKli+eAgd5bQx5dJI+iKwAAAAATwEENYfPAwACfNaAAAAAitcBOSwrKKPETTFTQB2dV2vR7JeW0oWISULd7zff6YwD7CHlhpedfqFMPs/Ynyylrt1MmciorP8y5NheFXQsVBQQRMEfWC0AAIABAACAAAAAgE8BBDWHzwNDTstqgAAAADyYUIjJ0r+BE97TSLMAxAVXqykmzpXn8OjrOZXpGtypAiscEQVdgAYz+aaLNncVAez1gcKaGbwAm9aUjCmBUP3QEK042eotAACAAQAAgAAAAIBPAQQ1h88DgoJ17wAAAACLzmO+hByJ5sRId8P2Yk2ocvvCRfE71oHTxzvR3kFdVQNOPE/+YNwEpZpgurYl3xqaFl7O0iZ6lonO5dkt6egLSBCTxBDYLQAAgAEAAIAAAACAAAEA4AIAAAAAAQGIBXP7hwAy6E96KP4N/8V/Tfm4vxlR/upITB78hh8fsgAAAAAA/f///wJXHwIAAAAAABepFO9+OkwJ33cbkuScONov2H9WuEnzh6CGAQAAAAAAF6kUFsT5HlQZ3oe3saQ57nNEsrsyEmyHAkcwRAIge7VOHNcQsoLT7uwYuqaaiM4kRhZ8gEEU4cWbDyMbuGoCIBrO5a75aw+y8vhigNmzeKK1Giga1wMrTpFnzNr+XrMRASED3rqKjW60B9oFWHFsBRsXKxOZNOoK5HH01pYAbDqWJ7M0tDAAAQRpUiECI3IHP1F93YV4O5y27ztzqRZ+nLF/jn2cumFBLsJdFDYhAjahpn8UmMFHCIsODyIv7uZwUokqfOo6W5HxwRB9x3mjIQOMWCtjMi9QvCg3MVs+kA4Q8gkf1+NFTR+PrlxfllGrj1OuIgYCKxwRBV2ABjP5pos2dxUB7PWBwpoZvACb1pSMKYFQ/dAYrTjZ6i0AAIABAACAAAAAgAAAAAAAAAAAIgYDTjxP/mDcBKWaYLq2Jd8amhZeztImepaJzuXZLenoC0gYk8QQ2C0AAIABAACAAAAAgAAAAAAAAAAAIgYD7CHlhpedfqFMPs/Ynyylrt1MmciorP8y5NheFXQsVBQYRMEfWC0AAIABAACAAAAAgAAAAAAAAAAAAAA=';
You shouldn't have to "try". You should already know what derivation paths were used when producing the utxo you're trying to spend, and fill the psbt with data that you know it's correct.
If you lost track, or if you used non-standard paths, starting over and funding a new output that you know how it's constructed is probably the shortest path.
A safe way to produce valid PSBTs for your tests is to use an existing multisig wallet to spend a transaction (e.g. Electrum / Specter / Sparrow). They all produce wallets and PSBTs that with standard derivation paths, and therefore fully compatible with BIP-388.
You're right, In fact my psbt is working on other wallets, just trying to figure out why this way not.
Just decided come back to old app.
await btc
.signP2SHTransaction()
.then(sig => console.log("\n\nSig hash:", sig))
.catch(err => console.log("\n\nErr:", err));
Thx!
Hi!,
I'm getting this message when trying to sign a psbt. TransportStatusError: Ledger device: Invalid data received (0x6a80)
Comparing with psbt examples noticed my psbt shows:
], "outputs": [ { } ], "fee": 0.00095000 }
I'm adding outputs like this and adding Global
GlobalXpub
Attach my base64 psbt.
PSBT base64:
cHNidP8BAFUCAAAAAbbUXGeNYQet/rSpcibXRxpEk0s+qcQ13AIv6TsR7CRxAAAAAAD/////AYgTAAAAAAAAGXapFNPCFDSmzeYKli+eAgd5bQx5dJI+iKwAAAAATwEENYfPAwACfNaAAAAAitcBOSwrKKPETTFTQB2dV2vR7JeW0oWISULd7zff6YwD7CHlhpedfqFMPs/Ynyylrt1MmciorP8y5NheFXQsVBQQRMEfWC0AAIABAACAAAAAgE8BBDWHzwNDTstqgAAAADyYUIjJ0r+BE97TSLMAxAVXqykmzpXn8OjrOZXpGtypAiscEQVdgAYz+aaLNncVAez1gcKaGbwAm9aUjCmBUP3QEK042eotAACAAQAAgAAAAIBPAQQ1h88DgoJ17wAAAACLzmO+hByJ5sRId8P2Yk2ocvvCRfE71oHTxzvR3kFdVQNOPE/+YNwEpZpgurYl3xqaFl7O0iZ6lonO5dkt6egLSBCTxBDYLQAAgAEAAAAAAAAAAAEA4AIAAAAAAQGIBXP7hwAy6E96KP4N/8V/Tfm4vxlR/upITB78hh8fsgAAAAAA/f///wJXHwIAAAAAABepFO9+OkwJ33cbkuScONov2H9WuEnzh6CGAQAAAAAAF6kUFsT5HlQZ3oe3saQ57nNEsrsyEmyHAkcwRAIge7VOHNcQsoLT7uwYuqaaiM4kRhZ8gEEU4cWbDyMbuGoCIBrO5a75aw+y8vhigNmzeKK1Giga1wMrTpFnzNr+XrMRASED3rqKjW60B9oFWHFsBRsXKxOZNOoK5HH01pYAbDqWJ7M0tDAAAQRpUiECI3IHP1F93YV4O5y27ztzqRZ+nLF/jn2cumFBLsJdFDYhAjahpn8UmMFHCIsODyIv7uZwUokqfOo6W5HxwRB9x3mjIQOMWCtjMi9QvCg3MVs+kA4Q8gkf1+NFTR+PrlxfllGrj1OuIgYCKxwRBV2ABjP5pos2dxUB7PWBwpoZvACb1pSMKYFQ/dAQrTjZ6i0AAIABAACAAAAAgCIGA048T/5g3ASlmmC6tiXfGpoWXs7SJnqWic7l2S3p6AtIEJPEENgtAACAAQAAAAAAAAAiBgPsIeWGl51+oUw+z9ifLKWu3UyZyKis/zLk2F4VdCxUFBBEwR9YLQAAgAEAAIAAAACAAAA=
In console from web browser:Multisig wallet address: 2MuKcpSGWdnXawi1QwuZdLH85x9DTrC9DUc
policyMac: a15d0a482bcce5bad61e7c53e90e7baa963420009d666cd02041d313bfa98236
Fails here:
decodepst
What I'm missing?
Thanks!