Support constructing transactions whose output exceeds input (SIGHASH_ANYONECANPAY workflows)#43
Open
151henry151 wants to merge 2 commits into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
createWalletTransactionrefuses to build any transaction whose outputs are worth more than its inputs, throwingInsufficientFundsExceptionbefore construction. That guard is correct for an ordinary spend, but it rules out the family of constructions built onSIGHASH_ANYONECANPAY, where a signer commits an input to a set of outputs and other parties add their own inputs afterwards. Because each signature commits to the outputs but not to the full input set, no one can be cheated and nothing is broadcastable until the inputs collectively cover the outputs. The same primitive underlies assurance contracts and pledges (Lighthouse, Semaphore), atomic swaps (the inscription marketplaces useSINGLE|ANYONECANPAY), and collaborative payments where several parties co-fund one set of outputs. This is the construction requested in #706.The change adds a boolean
anyoneCanPayfield toTransactionParameters. When it's set,createWalletTransactiontakes a dedicated path that spends the wallet's available inputs into the requested outputs without requiring that the inputs cover them. The field defaults to false at every construction site, so existing behaviour is fully preserved and the standard path — both pre-fund checks and the selection loop — is left untouched. The new path keeps an empty-wallet guard, so an anyonecanpay request with nothing to contribute still fails clearly, and it rejects silent payments rather than building toward a placeholder address.I've kept this to transaction construction on purpose and left sighash selection to signing, where it already lives. drongo and Sparrow already sign
ALL|ANYONECANPAYcorrectly, and the transaction view already offers a sighash selector, so the only missing piece was the ability to build the transaction at all. Setting a sighash here would also be premature, since the right variant depends on the use case —ALL|ANYONECANPAYfor pledges,SINGLE|ANYONECANPAYfor swaps — and is really the signer's choice rather than the builder's.Three tests cover the new path: one builds a transaction whose output is twice its single input, one confirms the resulting PSBT signs as
ALL|ANYONECANPAY(sighash0x81), and one confirms that an ordinary request with the flag unset still throws.