No, I don’t think it can be achieved using
SIGHASH_ALL | SIGHASH_ANYONECANPAY. Because there is always an output with a preset value, as you’ve mentioned, any surplus will be treated as the mining fee in this case.
However, I think it’s still achievable under a more complex design. Let’s take a close look at the problem. Since it’s crowdfunding, we can assume that,
- The participants are willing to donate the money, and,
- They want their money back if the crowdfunding fails, i.e., the cap is not reached.
The problem is, if crowdfunding with a cap of 10 BTC is reached, while in the end, it receives a total donation of 11 BTC, how can the fundraiser get the extra 1 BTC as well?
SIGHASH_ALL | SIGHASH_ANYONECANPAY won’t help here, the extra 1 BTC will be treated as the transaction fee. Borrowing some ideas from the lightning network, I think a feasible solution can be achieved using Bitcoin Script. Here’s the draft,
Crowdfunding with a cap of 10 BTC is initiated. If the cap is not reached in 60 days, the money is returned to the participants. Otherwise, all the money goes to the fundraiser.
Stage One - the participant sends money
- The participant generates a secret, called it
payment_secret, and hash it to produce
payment_hash(for instance, using RIPEMD160).
- The participant creates a transaction with an output, its locking script is specified as follows, in which, there are two possible paths to spend it,
- If the
payment_secret is presented, the money goes to the fundraiser.
- Else, if 60 days passed, the money goes to the participant.
# To the fundraiser if payment secret is supplied
OP_HASH160 <RIPEMD160(payment_hash)> OP_EQUALVERIFY
# To the participant after 60 days
<60 days later> OP_CHECKLOCKTIMEVERIFY
where, the fundraiser can spend it using
<fundraiser_sig> <payment_secret> 1, and the participant can spend it using
Stage Two - the fundraiser collects/returns the money
- If the cap is reached, the fundraiser will ask all the participants to reveal the
payment_secret to him/her. The fundraiser will be able to get all the money, even it’s beyond the cap. To spend the outputs, the fundraiser use
<fundraiser_sig> <payment_secret> 1 to unlock them.
- If the cap is not reached, i.e., the 60-day time limit has reached, all the participants can now take their money back, using
<participant_sig> 0 to unlock them.
So the surplus problem is solved, but this approach has many downsides,
- There are too many transactions, especially comparing to the
SIGHASH_ALL | SIGHASH_ANYONECANPAY approach, although it may be optimized.
- The participants need to know how much money has been raised. This requires the fundraiser collecting all the transactions and show them to all the participants, which might require a centralized service, e.g., a website.