0

I'm developing a contract that has an admin. That admin has some functions only he can call and I'm calling them from a server. Now my biggest fear is that the server is compromised and someone gets the private-key for said admin.

That's why I thought about putting a function that I can use to reset the admin.

The function looks like so:

    address private constant emergency_admin = 0x...;
    address private admin = 0x...;
      function emergency(address newa, bytes32 h, uint8 v, bytes32 r, bytes32 s,bytes32 h2, uint8 v2, bytes32 r2, bytes32 s2)
          public
        {
          //check if the signed messages match the new addres
          require(h==prefixedHash2(newa));
          require(h2==prefixedHash2(newa));
          //check if admin and emergency_admin signed the messages
          require(ecrecover(h, v, r, s)==admin);
          require(ecrecover(h2, v2, r2, s2)==emergency_admin);
          //set new admin
          admin = newa;
        }
        function prefixedHash2(address message)
          private
          pure
          returns (bytes32)
        {
            bytes32 h = keccak256(message);
            bytes memory prefix = "\x19Ethereum Signed Message:\n32";
            bytes32 prefixedHashe = keccak256(prefix, h);
            return prefixedHashe;
        }

The emergency_admin private-key would obviously not be saved on the server. More like on a piece of paper in a safe.

I'm wondering if this is acceptable or even makes any sense, or if there are way better solutions to this I haven't thought of?

0

This seems like a reasonable approach, but there's no need for the parameters h and h2. I would also consider whether you want the ability to change emergency_admin in case that gets compromised.

Here's a minor rewrite of your code that drops h and h2 and allows changing both admin accounts:

address private admin = 0x...;
address private emergencyAdmin = 0x...;

function emergency(
    address newAdmin,
    address newEmergencyAdmin,
    uint8 v,
    bytes32 r,
    bytes32 s,
    uint8 v2,
    bytes32 r2,
    bytes32 s2
)
    public
{
    bytes32 h = prefixedHash(abi.encodePacked(newAdmin, newEmergencyAdmin));

    require(ecrecover(h, v, r, s) == admin);
    require(ecrecover(h, v2, r2, s2) == emergencyAdmin);

    admin = newAdmin;
    emergencyAdmin = newEmergencyAdmin;
}

function prefixedHash(bytes message) private pure returns (bytes32) {
    bytes32 h = keccak256(message);
    return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", h));
}
  • doesn't "abi.encodePacked" make the call more expensive than passing a parameter? or is more data in the parameters more expensive? in this case it would not matter anyways because i hopefully don't have to call this often. but im just asking because i use similar functions with signed messages that are called a lot more frequently and depending on the cost i would adapt them to your version. – swisswiss Jun 13 '18 at 23:17
  • Well, keccak256 with multiple parameters is deprecated, and passing a single bytes parameter obtained via abi.encodePacked is the replacement. I assume that keccak256(a, b) has the same gas cost as keccak256(abi.encodePacked(a, b)), but I honestly have not checked. – user19510 Jun 13 '18 at 23:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.