Hey everyone!
TL;DR: There are two ways to make 2FA on smart contracts. One requires everyone running a node who wants 2fa and you control it yourself. The other is a general smart contract for everyone on the same blockchain. Which is best
I’ve had an idea to allow for 2FA on smart contacts and I want to create an EIP for this. Which I’m working on now, but before I submit it, I wanted to have a general discourse about the idea and make sure I’m not blind to some loophole in the security of it.
I’m curious which route is the best route to take for the EIP, a node based system done individually, or a general contract that manages everyone’s data for the entire blockchain.
2FA for Transfers of assets
Route 1: Nodes ran independently. (meaning they have their own login servers that are tied to their own accounts, updating the state of the 2FA code on the smart contract)
UseCase: Lets assume Any Dapp has implemented this standard and their token contracts have been updated with a transferWith2FA() function.
transferWith2FA(address to, uint tokens, uint8 _2FAcode)
Any Dapp will run its own 2FA Node, which consist of the following:
- A login server with traditional user authenication
- A ethereum address that is registered within the 2fa Contract array of registeredAgents (Registered Agents are the only accounts that can update the code and address in the array… Here is the code example)
address registeredAgent = 0x000000000....4259a8;
modifier onlyRegisteredAgent {
require(msg.sender == registeredAgent);
_;
}
So Any Dapp has set up a special address that they use as their agent, that will be the only address that is allowed to update the 2fa code state. This address is connected to a node running on their servers.
Bob wants to transfer Any Dapp tokens, using the new transferWith2FA() function… the function requires the address of the person receiving the tokens, and the amount. But now this functions wants a input field called 2FAcode, bob needs to get this code and generate it.
Any Dapp has set up a website with a user login, once bob has been traditionally logged in, he sees a code that is changing every few seconds on their screen. Just like when you open a google authenticator app on your phone.
The User will press a button that says “Submit Code” or whatever, this triggers an event on Any Dapp’s backend server that will execute a transaction from the registeredAgent address setting the current code that was claimed, and the address of the person logged in. That would look like this function in the smart contract.
function set2FA(address _sender, uint8 _2FAcode)
onlyRegisteredAgent
returns (uint256)
{
codesToAddress[_sender] = _2FAcode;
//this setting the time on the code for that address, to the current time.
addressToDatatoTime[_sender][_2FAcode] = now;
return addressToDatatoTime[_sender][_2FAcode];
}
Now the Bob has his code and can do a normal token transfer, but including this _2FAcode as data.
The transferWith2FA() function would now check the verifyTx function and require that it returns true
function verifyTx(address _sender, uint8 _2FAcode)
returns (bool)
{
//check that timelimit is not expired - can be set via unix timestamp
require(now < (addressToDatatoTime[_sender][_2FAcode] +500));
// needs to verify that the person has the correct 2FA
require(keysToAddress[_sender] == _2FAcode);
return true;
}
Route 2: Centralized as one smart contract across the blockchain (meaning there is one smart contract that everyone has access to, and owners of contracts can add registeredAgents within that overall smart contract that are allowed to only update the 2FAcode for their contract address. )
Usecase:
2FAManager - this is the overall smart contract that everyone on the public network would have access to
Lets assume ZRX wants to implement this standard on their token contracts and they have upgraded to the new contracts for 2FA discussed here. This is how it would work.
ZRX runs their own login servers like before, but now their registeredAgent account needs to be set up with the 2FAManager
In order to set registerAgents on the 2FAManager , they need to call it from the address of the smart contract they are controlling. So, ZRX needs to have an extra function setUpRegisteredAgent() that would call the 2FAManager so that this contract within 2FAManager would be able to run a function that stores the caller’s address (the ZRX contract) and the registered agents address (provided by the setUpRegisteredAgent within ZRX’s contract) to the 2FAManager.
Now that the registeredAgent is set up on the 2FAManager, ZRX can generate their 2fa codes on their web server and have their registeredAgent address connected to their own node on their backend updating the 2fa code for the accounts requesting it.
Anyone would be able to do this for their contracts, some exchanges would be able to do this in order to withdrawal from their hot wallets, who knows.
Problems: The login server goes offline. Solution: A bool flag that is controlled by the owner, turning the ability to transfer without fa on and off depending on if the server is online or offline.
What do you guys think about the overall idea? What are some problems, what needs to be fixed and worked out, before the EIP goes live.
Most importantly, which route is best for the ecosystem? Requiring that each contract who wants to do this, run their own authentication, just like how it is now in the real world? If I want to run a technology company (instagram) I need to handle my own user’s data on my own servers.
Or, should there be ONE general smart contract, that anyone can OPT-in to use 2fa on for their contracts? This means that this one general smart contract would be a single point of failure, which is bad.
Thoughts?