U-DID - Uncoerced Donations via Information Diffusion
It is a funding system designed to run on Bitcoin Cash or similar chains, without needing protocol changes. Refer to conceptual introduction post.
In Part 1 of this demo, we saw how anyone with a Memo account can easily create a funding intent message and commit to it by anchoring its hash on the BCH blockchain, using an intent-hash message.
In this second part, we follow through with the actual funding, and signal that via a corresponding fulfilment / fulfilment-hash message, on the chain. Showing that the announced funding intent has been fulfilled.
Correcting a past injustice
Before I begin to fulfil the intent (= pay out the intended amount and document it on chain) , I need to come clean about something.
If you tried to validate the JSON intent and hash messages that I submitted in Part 1, you will fail. I wish I could say I did that on purpose, to test if you were all paying intention, but the sad fact is I was lazy and didn't bother to validate my JSON message syntax using a simple tool like https://jsonlint.com/ .
Bad @btcfork! I just assumed I wouldn't make dumb mistakes, forgetting that I always make dumb mistakes. Admittedly I am not a machine (unlike SideShift AI). Fortunately, any human can still read and understand the intent messages very well, so I think the gist wasn't lost. I promise not to be so careless in future! ;)
How exactly did I screw up my JSON? Well, both the intent and the hash message contain a missing comma after certain values, and missing/wrong braces or brackets. In particular, I used curly braces instead of square brackets in the intent where I wanted to list the recipients (which should be an array). Typical errors a human makes when hastily editing JSON using cut&paste without bothering to let the machine revalidate it (or ignoring the editor's invalidity hints :-)
So, is this fatal to my U-DID funding intent? Far from it!
First of all, as I mentioned, probably all humans reading it understood what was meant. In fact, none of them seemed to have bothered to validate either JSON message - nobody bothered to point out the error. Not so unlike me, you are.
Second of all, everything in this demo series is still manual, there are no machines involved yet. Small mistakes are not so serious. I just have to watch out later not to make a decimal point error when sending money to fulfil the request! That could be more painful.
But let me correct the on-chain data for the benefit of future U-DID machine interpretation.
Corrected intent file:
{
"udid-intent": {
"version": 1,
"total_amount": 1.0,
"currency_unit": "BCH",
"recipients": [{
"name": "Bitcoin ABC",
"percentage": 20
},
{
"name": "Bitcoin Unlimited",
"percentage": 20
},
{
"name": "FloweeTheHub",
"percentage": 20
},
{
"name": "BCHD",
"percentage": 20
},
{
"name": "Bitcoin Verde",
"percentage": 20
}
]
}
}
I saved that over the previous stored file and regenerated a new hash so that I can post a corrected intent-hash.
I have republished the corrected intent-hash as a new Memo post, so that at least some machines can understand it too. Note that the message digest value is changed, which means that if a machine locates the corresponding intent message (i.e. the one in THIS post) , it will find valid JSON and all will be good!
Machines should ignore the malformed (invalid) intent hash message and corresponding malformed intent message completely, and carry on with the new, corrected intent data. So they will know about my intent to fund the 5 implementations and can work out how much I plan to donate.
...
Fulfilling the intent
Now that we got that corrected, let's finish this by paying out.
The steps here are simple:
Construct one or more payout transactions that fulfil the intent
Construct a
udid-fulfilment
message that references the transaction(s)Post your fulfilment message / document somewhere where people & machines can locate it
Construct a
udid-fulfilment-hash
that references the fulfilment document and post it on-chain to prove the fulfilment
I hear you asking: Does this have to be so complicated?
I think not. Only if the fulfilment message itself is too long to fit on the chain directly do we need to let machines know where to find it using an intent-hash message.
Perhaps for some small, single-recipient payments, we could all fit in without bothering to construct a separate intent-hash.
We will look at doing that in a future part of the demo series!
For now, we will use the steps above.
Payment
I will be doing a single transaction, paying to multiple receivers as per the posted intent. Try doing that with a bank account!
I'll be using Electron Cash wallet for payment, because it has a nice function to pay multiple recipients (Tools -> Pay to Many , or Ctrl-M).
Of course I need to do some work to dig out the donation addresses for the project that I wanted to fund. Fortunately, that's easy, they all have their donation details posted on their websites, in the form of a Bitcoin Cash address. See the 'References' section for the links I used. Finding the donation addresses on the pages was no problem. Only Bitcoin Verde listed an old-style Bitcoin address (because they have a vanity address starting with '1Verde...'. I had to convert that one, but Electron Cash has a nice built-in converter.
All set!
Now all that remains is to put the addresses and the corresponding easy amounts (0.2 BCH each) into an Electron Cash sending dialog window.
Addresses + amounts are entered one per line, separated by a comma:
Hit that "Send" button and the payment is sent, and a transaction ID of 3cabf982a4ff85393ff2fc9a07f2770ea20388822d5dcd099358431f10d83cf0
is returned.
This txid is what I will need, because I want to reference that in the fulfilment message.
Together with the intent-hash or intent message transaction ID, it will give someone looking at the fulfilment message all the info needed to trace back the intent and check that the payment (a) has been performed and (b) fulfilled the original intent.
Constructing the fulfilment message (more JSON, yay!):
{
"udid-fulfilment": {
"version": 1,
"sender": "btcfork",
"intent": "f3c497006417c43a00362486a1766dc271e9190c11c41f425808ce056dda3951",
"payment_txs": [ "3cabf982a4ff85393ff2fc9a07f2770ea20388822d5dcd099358431f10d83cf0"]
}
}
We don't have to provide a "sender" value, but in this case I chose to include it. It may be useful in some cases where another party is fulfilling an intent on behalf of the originator of the intent. I think machines should not trust the provided value, but rather try to use it as a hint only, and place more focus on who submitted the referenced fulfilment transaction and committed the fulfilment messages onto the chain.
To describe the location of the intent, I simply provided the txid of the intent, or intent-hash, that was placed on-chain. It is the long number corresponding at the end of this Memo link where you can see the associated intent.
https://memo.cash/post/f3c497006417c43a00362486a1766dc271e9190c11c41f425808ce056dda3951
'payment_txs' can be a list of payment transaction IDs, but in this case I made a single payment that covers all recipients in one transaction, so there is only a single txid in that field.
The above JSON seems to be slightly too large (244 bytes) for a Memo message.
Squeezing out all whitespace gets it down to 211 - enough to post the fulfilment on-chain using Memo! Hooray.
Here is the compressed JSON fulfilment doc:
{"udid-fulfilment":{"version":1,"sender":"btcfork","intent":"f3c497006417c43a00362486a1766dc271e9190c11c41f425808ce056dda3951","payment_txs":["3cabf982a4ff85393ff2fc9a07f2770ea20388822d5dcd099358431f10d83cf0"]}}
Now, before I post that on Memo, I will wait for a confirmation on the original payment transaction.
Ideally, I would like the fulfilment message to be included either in the same block, or in a block that follows after my payout transaction, so that machines don't see the fulfilment message referencing a transaction that they potentially have not seen. However, machines would need to be smart enough to even handle that case eventually, since chain re-organizations can always throw off the order of confirmation of transactions that you thought happened in a certain order before. Don't worry about it at this stage, it's no problem.
We just wait for one confirmation on the payout.
Then we post the Memo fulfilment message:
The Memo message above can be found here (it again has an associated txid which is the long number in the URL):
https://memo.cash/post/83c4249b903c02224bc832a273bdc9e106f725e697ea910276f3ca219afdcf5a
Now, you can see where this is going - if the udid-fulfilment
message had been too long to fit on Memo, we would have needed to store it somewhere else, like in this article, on our personal blog, or on our hypothetical foundation site's "Payments Made" page.
And then we would have created a udid-fulfilment-hash
just like we created an intent-hash message before.
The hash messages should always be small enough to be committed directly on chain.
Let's go ahead and create a fulfilment-hash message anyway.
It's going to be practically the same structure as an intent-hash, only difference is that it references a fulfilment document somewhere. In this case, in a previous transaction on the chain. That is really the simplest case, except if we just omit the fulfilment-hash message entirely because the fulfilment itself already fit on chain.
We just have to be very careful about one thing (hopefully I don't screw it up):
We have to get the correct hash corresponding to the precise text that is stored in the Memo post. It is best to check what actually got deposited on the blockchain, so I used a block explorer to confirm exactly what message text was committed by the OP_RETURN performed by Memo. I confirmed it ends on the last curly brace.
I run that message text through the sha256sum utility, making sure it adds no extra characters such as an EOF, and out comes a digest which I can use for the fulfilment-hash.
Getting the hash of the fulfilment:
$ echo -n '{"udid-fulfilment":{"version":1,"sender":"btcfork","intent":"f3c497006417c43a00362486a1766dc271e9190c11c41f425808ce056dda3951","payment_txs":["3cabf982a4ff85393ff2fc9a07f2770ea20388822d5dcd099358431f10d83cf0"]}}' | sha256sum
35020a9374c48810d80ba81bd68b652c260accf037e373432ff94acc8c03966a -
I plug that digest into the fulfilment hash message, shown here in uncompressed JSON (again, too big) but more readable:
{
"udid-fulfilment-hash": {
"version": 1,
"type": "sha256",
"value": "35020a9374c48810d80ba81bd68b652c260accf037e373432ff94acc8c03966a",
"source": {
"txid": "83c4249b903c02224bc832a273bdc9e106f725e697ea910276f3ca219afdcf5a"
}
}
'source' in this demo example is the txid of the Memo post that I made before, where I store the fulfilment document.
I need to compress that down again, and it will fit into a Memo post:
{"udid-fulfilment-hash":{"version":1,"type":"sha256","value":"35020a9374c48810d80ba81bd68b652c260accf037e373432ff94acc8c03966a","source":{"txid":"83c4249b903c02224bc832a273bdc9e106f725e697ea910276f3ca219afdcf5a"}}}
Final step - post the fulfilment-hash on Memo:
And we're done documenting the fulfilment of the first U-DID funding payout!
We went a bit beyond the call of duty in posting the fulfilment-hash when the fulfilment itself already fit on the blockchain so easily.
But I didn't expect the fulfilment message to fit in, and had we done the payout as 5 separate transactions, we would have needed a much longer message and definitely would have needed to refer to the fulfilment doc using a hash.
At least, if we do things over relatively limited Memo transactions.
FreeTrade86, the developer of the Bitcoin Cash application "Member" which is based on an extended variant of the Memo protocol, has told me (via Memo :) that Member supports longer posts called "Memoranda".
It might be very easy to post longish intent or fulfilment documents using Memoranda. As long as a machine can easily extract them and match up the fulfilment memoranda to the intent memoranda, everything will be great!
All in all, it just sounds like a small bit of programming would have to be done to make that matchmaking possible.
In future installments of this demo series, I might have a look at that (using Memoranda or other blockchain file upload/download APIs).
Or, we might try to first set up a basic automatism that listens to the blockchain for new U-DID intents and fulfilments, and displays / analyzes them. That sounds like a bit of work, but it should be doable.
Note about long hashes
In the initial parts of this demo, I used SHA256 hashes for all document digests.
It is possible to save some space by using shorter hashes (e.g. md5sum) but that comes with higher risk of someone producing a collision. Overall, I don't think anyone is going to try to collide hashes for U-DID documents which relate to small funding streams. It would also be noticed as at least the hash messages are posted on chain. An attacker would also need to replace the source document somewhere. It doesn't sound likely that someone would bother. The actual transactions are as always as secure as Bitcoin Cash makes them, so payouts couldn't really be influenced much, only monitoring and controlling systems might be impacted.
Suggestions people have made so far (on Memo, or elsewhere) about U-DID
create a new OP_RETURN based protocol instead of using Memo
That is possibly a good idea, although I don't think I necessarily want to prescribe in what way people store their U-DID intents, fulfilments (& possibly in future: funding requests) on a chain.
The reason people may have suggested to use a separate protocol is because the JSON messages I committed don't look nice in human readable streams.
But:
(a) this is only a demo, I don't expect the JSON format I used here to be followed by everyone.
(b) I don't intend to post U-DID's like that myself, frequently, at least not from @btcfork account. I might create a separate Memo account for funding relateed messages, and no-one would need to follow that - they could mute it. Memo makes it possible to filter out noise you don't like. So generally I wouldn't consider it much of a problem. There are other bots posting on Memo already, with information that frightens some people (like a bunch of numbers :-p ).
Create a site with leaderboards of funding etc.
Yes, I think that would be awesome.
I think sites should listen to many streams of input data to capture U-DID traffic. They might want to listen on Memo. They could listen on Member (an extended version of Memo which allows messages to be concatenated into longer ones). They might listen on a dedicated OP_RETURN protocol, and they might get data feeds from specialized crowd-funding sites.
Please subscribe if you like this content, and consider becoming a sponsor of BTCfork - even tiny amounts are most appreciated.
References
BCH client donation addresses used in this demo:
[1] Bitcoin ABC: bitcoincash:qqeht8vnwag20yv8dvtcrd4ujx09fwxwsqqqw93w88
[2] Bitcoin Unlimited: bitcoincash:pq6snv5fcx2fp6dlzg7s0m9zs8yqh74335tzvvfcmq
[3] BCHD: bitcoincash:qrhea03074073ff3zv9whh0nggxc7k03ssh8jv9mkx
[4] Flowee: bitcoincash:qpgn5ka4jptc98a9ftycvujxx33e79nxuqlz5mvxns
[5] Bitcoin Verde: bitcoincash:qqzkk06w4k3ye05q7fly566tan2chfkerqgku569zg (1VerdeMuXH1ApSZsQDkuHHZrwJaAtXTVn)
Image credits:
FYI: nice JSON editor online https://jsoneditoronline.org/ - auto formatting and shows errors instantly. Also easily shows how long the message is (just select all and click Ctrl/Cmd+A to select all)