Source Code
GitHub.com
What is stellar-oc-multisig?
This is a JavaScript library that implement on-chain signature collection.
The Stellar blockchain offers a very innovative implementation of multisignature accounts, as the setup happens on-chain through native support and can be modified by further operations. Very few blockchain offer such a possibility.
However, signature collection is not part of the scheme. I felt like something was missing and an on-chain signature collection mechanism could bring some value and cover some new use cases.
There's an ongoing discussion of whether this is desirable or not, what could be the benefits and drawback of such a solution, and what alternative could actually do better. That's on Galactic Talk. I'm excited that two of the main proposals from this debate are present for this SBC. Both have their own strength and somehow tackle the same core issue in different ways.
What does it bring ?
Stellar-oc-multisig is both a proof-of-concept, a way to push the thinking further and a starting point in making this real. This implementation have the following properties:
- Any account can enable on-chain signature collection.
- The collection can happen each time the account is the source of a transaction:
- It could be because the account have several signer,
- It could be because the transaction have multiple operation sources,
- It could be both.
- Anybody can send signatures for any transaction and a signer can send signatures on the behalf of other signers.
- However, only the legit signatures from legit signers are retrieved.
- Anybody can retrieve the signatures and validate the transaction.
- This is efficient, censorship-resistant, public & decentralized.
How does it works ?
When enabling on-chain signature collection, a dedicated "collection account" is created. This is a standard Stellar account that will receive the signatures. We can send signatures to that account using a multi-operation transaction. The first operation send the minimal amount to it so that the transaction will be part of its payment history. The following operations set an account entry (manageData operation) to the value of a signature. The return memo have to be set to the txHash of signed transaction.
We can then retrieve signatures by filtering the payment history of that dedicated account, looking for a memo that match the transaction for which we want to obtain signatures. When found, we check that the transaction emitters are legit signers, and we scan the manageData operation to retrieve the signatures. Those signatures are checked against the potential signers and are added to the transaction when valid.
The setup of a dedicated account for this task have several benefits. It makes the payment history as small as needed, and we don't put a mess in the master account transaction history. We can simply disable it and forget about it, or we can change it if the history become too big and retrieving too slow. The publicKey of this dedicated account is set into a data entry of the master account called 'config:multisig'.
How to use the library ?
There's two ways to use this library: one is simple, the other is more technic but have its own advantages. I'll only show here the simple way:
Enabling on-chain multi-signature collection
await multisig.enable(keypair)
// => HorizonResponse or null if already enabled
Disabling on-chain signature collection
await multisig.disable(keypair)
// => HorizonResponse or null if already disabled
Check if on-chain signature collection is enabled on an account
await multisig.isEnabled(publicKey)
// => boolean
Getting account signature collection configuration
await multisig.config(publicKey)
// => { multisig: accountId, network: {public|test} } or null if disabled
Sending signatures
await multisig.pushSignatures(transaction, keypair)
// => a boolean that indicates if yes or no signatures have been sent to the blockchain
// This method first check which signatures are new and only send those ones.
Getting signatures
await multisig.pullSignatures(transaction)
// => a boolean that indicates if new signatures have been downloaded and added to the
// transaction object.
You'll get more details in the README.
Is that all ?
Well, no. First of all a few basic checks have to be implemented and a few more tests have to be done.
I'll have to implement a way to make the collection process happens on a different network than the master account. Collecting signatures on testnet have its own advantages: it's free and secure enough in most cases. Other use case will require signature collection on the mainnet. We could also use a dedicated Stellar network. While I was hostile to this idea at first, I understand that signature collection on mainnet comes with a cost and could become a burden as well.
I'd like to implement a method to check if a transaction have enough signatures to be validated or no, so you can implement easily the logic to decide if you should share signatures or send the transaction to validators. This is not as easy as it seems, though.
I'd like to implement a method that strip unneeded signatures. Believe or not, if a transaction have 'too much' legit signatures it won't be accepted by validators. It appears that stripping unneeded signatures could lead to a significant overhead, and should be implemented outside of horizon.
Finally I may end up implementing a way to share the transactions objects themselves.
Use cases
Well to begin with oc-multisig is a cool way to implement multi-signatures wallets. That's free software, quite light and may become a kind of standard way to go. It clearly won't be the only one, but it clearly is something that have no kind of competitive friction associated to it.
Now I'd like to go a bit further about the potential of this tool. Its particular properties allow for some interesting development...
Smart contracts
As I said, once an account enable oc-multisig signature sharing may happen for any transaction in which it is the source account. While other signers needs an access to oc-multisig or a compatible way to share signatures, they don't need to enable it themselves. A service based on smart contracts building may take advantage of this by putting itself as the source of the transactions and immediately share its signature.
Smart contract are typically multi-source transactions that may take days, weeks, month or even years to resolve. Big amounts may be at stake and we surely don't want to loose a signature in a too much zealous spring cleaning. Smart contracts are also supposed to be transparent and auditable, so it may simply looks natural to enable on-chain signature publishing for some of them.
Legal contract
As I said anybody can send signatures to the collecting account. The thing is, it won't be retrieved if it's not a legit signature for a given transaction. But there are cases were it doesn't actually matter. For instance, we could imagine encoding a simple licence into a transaction and requesting users to sign it before accessing a service. You know something like "I'm not a citizen of a country that would pursue you if I buy your token". Ok. Once signed on the blockchain it's signed forever and for every ICOs.
While I like the idea of embedding the licence in the transaction, what is normally done is signing the hash of a text. This is really the same thing as it's still on-chain signature collection and it is just a few lines of code away from oc-multisig.
Cyber-democracy (or: was the previous one an alpha release?)
Here we go! That's kind of logical. We have a system were a transaction or a hash can be signed by an arbitrary amount of people. Signatures stays online forever. It can't be censored or mutated. Data can easily be retrieved and nicely displayed in a modern web page. It's accessible and cheap. Now we don't have any kind of identity protection, but there's a lot of case where it isn't required right? Voting system based on Stellar anyone? I'll be happy hacking a few lines for that matter.
The DAO (or: where did I put those ether?)
The big benefit of on-chain signature collection, as well as the drawback, is that signatures stay forever. Well, let's look for cases where it is actually a good thing. Think for example about a commity that will reward a project with funds after significant progress are made. Each funding step is unlocked by a 60% vote and may happen at any time in the future. We sure want the signatures to be publicly, immutably stored until the day the threshold is met.
What I'm talking about is basically a kind of well-secured DAO. Now we could even scale it over hundreds of participant. An account can have only 20 signers? Right, but we can use pre-authorized transactions as signers. So funds can be locked by 20 pre-authorized transaction, and will be unlocked when those transactions are signed. Each of those transaction can have 20 signers. Which can be other pre-authorized transactions... In a few iteration we'll have more signers than people, dog and cats on this planet ?
Edit: Actually it doesn't works that way. Thank you Dhzam for the correction.
Now that's as much hairy as US elections, where one can win with less votes than the other because of how voters are geographically spread. Same thing here with sub-transactions. However there are cases where it doesn't matter that much. For instance think about a delegated proof-of-stake system. A few big node are accomplishing a task on the behalf of thousands people or more. Each big nodes is staking a big amount of money as a guarantee, and the people would have a way to burn it if it doesn't act honestly. This is a kind of black-or-white case where exact representation doesn't matter so much.
Now I agree that this is a kind of hackery construct. We want something clear and easy, that just works and that doesn't loose a lot of money in programmable smart contract failure. Well thinking about it, we are only a step away of that. It would takes... raising the limit to 65536 signers (216)? or maybe 4294967296 (232)?
Is that all, now? (please...)
Well, yes...
Actually, no. This simple lib have still more hidden potential. I think you would be amazed about it, but that'll be for another day. Right now I'm waiting for some feedback and some further discussion. Please tell me if this light up any idea or whatever. And thank you for reading that. I hope you found it interesting. I've had a good time writing it.
.(°O°). =(G_G)= (v_v)ZzZzz