Nice job xeroc! But I do have some criticism.
The way I see it there are two ways to do multisig on Graphene.
The first is to use proposed transactions the way you have done here. You have a secured account whose funds are protected by multisig, and you have a reference account that can create transactions using only the private key stored locally in the user's wallet. The secured account's active authority requires signatures from both the reference account and the 2FA provider. The reference account is needed to create and submit the proposed transaction to the blockchain.
This method has some advantages:
- The signaling to the 2FA provider is done through the blockchain which (maybe?) simplifies the interaction between user and 2FA provider.
- The user can hold funds securely in the secured account but can also hold some funds in the reference account that can be spent without the extra overhead of 2FA. The funds in the reference account are at risk of being stolen if the user's wallet is compromised, but if the user only keeps small amounts in the reference account for temporary convenience, this may not be a big issue.
But it also has disadvantages:
- There is additional blockchain bloat required for each transaction. And though these would likely be rate-limited free transactions, there is still some cost to the overhead for example through the opportunity cost of using the bandwidth allocation for other free transactions. And the 2FA provider needs to broadcast a proposal approval transaction to the blockchain. How will they pay for this overhead (say through the opportunity cost of holding enough BTS so they have sufficient bandwidth available to serve their customers)? They might have a policy of only approving transactions that pay them a small fee. Or they might just slightly increase their monthly subscription fee that they expect users to pay them for their service. Either way, a profitable business acting as the 2FA provider will somehow pass on this overhead cost to the user.
- It requires the user to setup two different accounts. Perhaps users don't care about the flexibility of having an account that they can spend some funds without 2FA required. In that case, dealing with two accounts just adds extra cognitive burden to the user.
- If the reference account runs out of funds to pay fees, it is no longer possible to even propose a transaction to move funds from the secured account to the reference account despite the fact that the user has plenty of funds in the secured account to pay the fees. I ran into this problem myself when using the testnet. Check out the transaction history for arhag1 and arhag2 to get a sense of the problem I ran into. I needed to create a new account i-messed-up to just get free money from the faucet to transfer to arhag2 so that arhag2 could pay the fee for a proposed transaction.
The second way to do 2FA is for the user's client to pass the partially signed transaction to the 2FA provider and have the provider sign it (after verifying authority using 2FA) and broadcast the fully signed transaction. This method avoids the overhead of proposed transactions and allows the user to use just their one account. Graphene's proposed transactions are incredibly useful when you have more than one signing parties that are regular users and not services provided by a business. But in the typical setup for 2FA, you have one regular user and one business. The signaling and communication protocol to carry out multisig in this case is simple enough that Graphene proposed transactions are not necessary.
I would love to see 2FA providers allowing both options to be available for users. But I think the second approach is the simpler one that users should be pushed towards by default.
So now for some problems I had with the current implementation of 2FA using proposed transactions. It was hard to follow your guide. I'm pretty sure I didn't end up following the exact procedure you meant for us to follow due to vagueness of the guide. It would be better if you went through an example using actual account names rather than "secured account" and "reference account". I also ended up having both accounts in one wallet for convenience. I am not sure if that is what you intended. I created a proposed transaction that was payed for by my arhag2 reference account to send 300,000 TEST from my arhag1 secure account to arhag2. After creating this proposed transaction, nothing happened. I went to my arhag1 account in the wallet and discovered that the proposed transaction had not been approved by either secured-by-peermit or arhag2. I don't see why the client doesn't automatically approve using the reference account when I create the proposed transaction using the refernce account. I was forced to create yet another transaction to approve the proposed transaction using arhag2. This entire UX needs to be streamlined so that some of these implementation details are abstracted away.
Anyway, I wasn't able to actually get it to work because the proposed transaction I created is still waiting to be approved by seecured-by-peermit, but I haven't received any email at all. Nevermind, it worked. I turns out the email went to my spam folder.
The other thing I would like to see is for the 2FA authentication to be optionally done using
TOTP. It is much easier for me to read a 6 digit one-time code off my smartphone and type it into the BitShares wallet than it is to deal with emailed links for every single transaction. This can be an authentication mechanism for lower stakes transactions. The 2FA provider can provide limits on how much funds can be transfered in some time window using authentication by TOTP alone. For higher stakes transactions, email links + TOTP could be used so that the user can get feedback from the provider about what transaction they are approving (in case their desktop computer is compromised for example).
Edit: BTW, I think we need the following additions/utilities. The GUI wallet should have a mechanism of creating and perhaps partially signing but not broadcasting a transaction which can be saved to a file. It should also have a mechanism to read a (perhaps partially) signed transaction from a file, presenting the transaction to the user, adding any extra signatures it can and then broadcasting it to the network. We then need a nice offline utility to: 1) generate new public key/private key pairs; 2) deterministically generate private keys from a brain key + passphrase and import them into a temporary wallet session; and, 3) read a transactions from a file, presenting it to the user, adding any signatures it can, and then saving the signed transaction to a file. This way, the offline utility can sign transactions that change the secure account's owner and active permissions without ever exposing the owner keys of the secure account to an internet connected computer.