-
Notifications
You must be signed in to change notification settings - Fork 775
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PSBT Cosign WIP #2557
PSBT Cosign WIP #2557
Conversation
@Overtorment I'm thinking of how to test it. Let's create 3 wallets. |
tACK, worked well for me. Some inconsistencies with the current PSBTs and signing flows: |
calculateHowManySignaturesWeHaveFromPsbt(psbt) { | ||
let sigsHave = 0; | ||
for (const inp of psbt.data.inputs) { | ||
if (inp.finalScriptSig || inp.finalScriptWitness || inp.partialSig) sigsHave++; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, this summarizes signatures for all inputs.
theoretically, there could be a tx with 8 inputs, but only 7 are signed. this makes no sense, no one would produce such tx and hope to do smth useful with it, but still.
anyway, for single sig wallets we only care if that method returns something greater than zero or not
(similar to multisig where we care if this method returns something greater than M or not).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think of it this way: you can have 3 offline wallets and want to create one tx to spend all the funds from them. In this case somewhere in the middle of signing process you will have a PBST with 3 inputs and only 2 of them will be signed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how is transactino crafted, adding inputs one by one? its kind of custom transaction. i dont know if theres a software that allows users to craft it.
but could be useful for payjoins and mixes tho
screen/send/psbtSign.js
Outdated
Linking.openURL('https://coinb.in/?verify=' + txHex); | ||
}; | ||
|
||
const exportPSBT = async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure about this. Looks like I can break something
also, needs unit test (at the very least, we can use seed for |
Agree, will do it in another PR |
cosign2.movWhat do you guys think of this one? If everything is ok, I will start working on e2e test |
Is that a send to many (batch) example? |
@ncoelho no |
Example has 2 outputs. One of them is change. But on details page both are shown. I think this is correct behavior. Imagine having 2 wallets and creating one tx using UTXOs from both of them. |
Do you think I should move "Coin control" and "Sign a transaction" to the top of actions list? |
I understand that. But the job of a wallet is to transform outputs in a user/human understandable GUI. I expect to see the balance I'm sending plus the fee, independently of the number of outputs the transaction is generating. And we can't assume the user knows what change is (that's a big assumption). Change should just be/stay in my wallet in a transparent way. This is the logic that happens in all transactions flow. We can improve the verify screen with all information, but the confirmation screen should not show outputs. Balance + address + fee on the confirm screen. User then can verify or send. |
For now I will just try to make as similar as the multisig setup as possible. We do need to "redesign" these screens for consistency later, but let's make them work first. In multisig you have: Here you are adding the sign transaction with both importing and scanning, which should be the correct behaviour. So as 2nd option is fine. Leave coin control in the end for now. |
Can you please elaborate on what exactly you want me to do. I see 2 options:
|
55d8e5f
to
d461305
Compare
I create a PSBT, imported it to the wallet with the seed. And land on a screen to sign the transaction. Am I doing something wrong? I would expect to land on the screen with the transaction signed, ready to copy or broadcast. Screen.Recording.2021-02-08.at.12.40.45.mov |
@ncoelho It can't sign any inputs. Strange. Can't reproduce this. Are you sure psbt was created using zpub from the wallet you are trying to sign tx? |
Sorry my mistake. Imported the wrong psbt file on that video. Worked for me now. |
Transaction signed with the seed, gives QR with HEX. QR is imported to online watch-only to broadcast, doesn't recognize HEX. Something is wrong on the flow right? We are giving HEX and watch-only is expecting PSBT? Screen.Recording.2021-02-08.at.15.25.57.mov |
@ncoelho BlueWallet/screen/send/details.js Line 897 in 52f1bdf
It says this looks like NOT base64, so maybe its transaction's hex we dont support it in this flow May be we should? cc @Overtorment When you generate PSBT there is a "Scan Signed Transaction" button. It works fine. |
2 questions
|
Yes, the text should be changed. |
63b200c
to
9a51cb8
Compare
// TODO make this work | ||
// try { | ||
// psbt.signInputHD(cc, hdRoot); | ||
// } catch (e) { | ||
// // protects agains duplicate cosignings | ||
// if (e.message !== 'Can not add duplicate data to array') throw e; | ||
// } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Overtorment I copy-pasted this from multisig cosign function. This never worked for me in tests. Always throws Need one bip32Derivation masterFingerprint to match the HDSigner fingerprint
error.
Can you please take a look? Maybe I should remove this ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thats because you used fp 00000000
in unit test
signInputHD
tries to match path & fp, and it has proper fp from the seed.
PS. this reminds me. when we have option to display xpub for BIP84/49/44 whatever, we should encode fp & path in json inside qr, not just xpub string. i think we had a ticket for this somewhere...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, would be nice to make signInputHD work, and keep the fallback as well (pls add comments)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, PSBT was specifically invented so developers would not have to pass hex around. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i like how it works in general, tested it on my devices.
but requires some refactoring.
ill probably work on this branch myself.
// TODO make this work | ||
// try { | ||
// psbt.signInputHD(cc, hdRoot); | ||
// } catch (e) { | ||
// // protects agains duplicate cosignings | ||
// if (e.message !== 'Can not add duplicate data to array') throw e; | ||
// } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thats because you used fp 00000000
in unit test
signInputHD
tries to match path & fp, and it has proper fp from the seed.
PS. this reminds me. when we have option to display xpub for BIP84/49/44 whatever, we should encode fp & path in json inside qr, not just xpub string. i think we had a ticket for this somewhere...
tests/e2e/bluewallet.spec.js
Outdated
@@ -831,6 +831,61 @@ describe('BlueWallet UI Tests', () => { | |||
|
|||
process.env.TRAVIS && require('fs').writeFileSync(lockFile, '1'); | |||
}); | |||
|
|||
it('can co-sign psbt with HD wallets', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
time comes when we will have to split e2e specs on several scenarios.
one spec should work with the app where HD_MNEMONIC_BIP84
is already imported. and NOT restart the app (currently app wipes and restarts for each test case).
that should save us lots of time on CI
// but for now, we will construct psbt by hand | ||
|
||
const sequence = HDSegwitBech32Wallet.defaultRBFSequence; | ||
const masterFingerprintBuffer = Buffer.from([0x00, 0x00, 0x00, 0x00]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
incorrect fp
// TODO make this work | ||
// try { | ||
// psbt.signInputHD(cc, hdRoot); | ||
// } catch (e) { | ||
// // protects agains duplicate cosignings | ||
// if (e.message !== 'Can not add duplicate data to array') throw e; | ||
// } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, would be nice to make signInputHD work, and keep the fallback as well (pls add comments)
@@ -119,6 +119,10 @@ export class AbstractWallet { | |||
return false; | |||
} | |||
|
|||
allowCosignPsbt() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
noice
'020000000001035fbc74110c2d6fcf4d1161a59913fbcd2b6ab3c5a9eb4d0dc0859515cbc8654f000000006a473044022041df555e5f6a3769fafdbe23bfe29de84a1341b8fd85ffd279e238309c5df07702207cf1628b35ccacdb7d34e20fd46a3bc8adc0b1bd3b63249a3a4442b5a993d73501210316e84a2556f30a199541633f5dda6787710ccab26771b7084f4c9e1104f47667000000806d93fb792280e26304b370abebd237430ceddb5670877f1d2a98d80924a900ad01000000000000008087c9acd9d5714845343b18abaa26cb83299be2487c22da9c0e270f241b4d9cfe0000000017160014a239b6a0cbc7aadc2e77643de36306a6167fad15000000800110270000000000001976a9144dc6cbf64df9ab106cee812c7501960b93e9217788ac0002483045022100efe66403aba1441041dfdeff1f24b5e89ab5728ae7ceb9edb264eee004d5883c02207bf03cb611c9322086ac75fa97c374e9540c911359ede4f62de3c94c429ea2320121027aaff1bd274812d012464be25dc06587287a4b578678e58c949a133b9fb93c7f0247304402207a99c115f0b372d151caf991bb5af9f880e7d87625eeb4233fefa671489ed8e702200e5675b92e4e22b2fe37f563b2a0e75fb81def5a6efb431c7ca3b654ef63fe5801210202ac3bd159e54dc31e65842ad5f9a10b4eb024e83864a319b27de65ee08b2a3900000000', | ||
); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i like the approach. solid test
// TODO make this work | ||
// try { | ||
// psbt.signInputHD(cc, hdRoot); | ||
// } catch (e) { | ||
// // protects agains duplicate cosignings | ||
// if (e.message !== 'Can not add duplicate data to array') throw e; | ||
// } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
screen/send/details.js
Outdated
}, | ||
() => { | ||
const { fromWallet } = this.state; | ||
this.props.navigation.navigate('PsbtSign', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
screen PsbtSign
is not necessary.
first, you could cosign transaction right on that screen (dont forget to set isLoading) - similar to how its done in importTransactionMultisigScanQr
on the same screen.
and then, if you have a txhex - navigate to send/create
and pass an option that along with multiline input with txhes should also be rendered animated qr (dynamicqrcode, bc-ur encoded). boom! code reuse. flow unification
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Screen unification is a good thing. I just thoungt send/details is already overloaded
Sure, you are welcome! I'm trying to generate a correct fingerprint using: const seed = bip39.mnemonicToSeed(process.env.HD_MNEMONIC);
const root = HDNode.fromSeed(seed);
const child = root.derivePath(path);
const fp = child.fingerprint and use this fingerprint in but |
@limpbrains i simplified it. removed unnecessary screen. drawback is that I had to remove the flow with some inputs being unsigned (class still supports it, so we can bring it back in UI anytime - we just need a use case for it). |
This reverts commit 3bc91f4.
♫ This was a triumph. I'm making a note here: HUGE SUCCESS ♫ [android in browser] https://appetize.io/app/32vde681zvm7yfk2u8hy735xvw |
closes #976
psbt.cosign.mp4
If psbt can be fully-signed, UI shows TX hex-encoded and ready to be broadcasted.
If psbt can be party-signed, UI shows PSBT