A Donation Fund for Parity Wallets

Everybody's up in arms about Parity's proposal to fork the whole blockchain so they get back the money they dropped. Let's say for the sake of argument that we don't fork. What else could we do to help?

An interesting feature of this situation is that the most sophisticated players had the biggest losses, and are most able to recover.

The biggest loss is to Parity's Web3 Foundation. Web3's main project is Polkadot, and Parity said they have enough money left to continue developing it without any great difficulty; if that money is still held as ETH, then the gains since the hack leave them even stronger.

Web3 had planned to use a chunk of the lost funds to fund projects like Swarm and Whisper. Shortly after the hack I checked with the Swarm community; the people I talked with weren't official, but for what it's worth they didn't know about the donations on the way from Web3, and said they had plenty of funding from Ethereum Foundation and Status, had just hired more people, and were full steam ahead. I'm sure the Web3 money would help but Swarm at least seems to be doing fine.

Next in line are the ICOs, which generally hire professionals to write and audit their contracts. These are people who would have known that the Parity multisig had recently been hacked, and could have checked and seen that the latest version of the multisig still had no public audit. These projects may also be able to recover; they have demonstrated some fundraising capability already and, probably in some cases at least, could do it again by expanding their token supply (even if that means replacing their contracts). Their current holders will eat some dilution but may prefer that to the project going broke. (Polkadot could do something like this too, of course, and there are some other interesting ideas at r/FriendsOfParity, like this).

The real victims

The real victims here are the innocent noobs who just downloaded the Parity client and used its built-in features, and ended up losing money when the fancy multisig froze up on them. Can we do anything for them?

I'm thinking this is a lot less money, and maybe we can cover a lot of it with donations. Not that this is anyone's moral obligation or anything, but maybe some people would feel like pitching in.

The people who lost the least are probably the least sophisticated, and the easiest to make whole. So we could make a simple contract that pays them first. Just send ETH to the contract, and it forwards to the victims, starting with the smallest and working its way up.

Normally I would hold the ETH in the contract, and have people withdraw their balances. But in this case, we'll have a whitelist of known recipients. It seems best to skip the withdraw pattern and just immediately transfer the funds instead of holding them.

When building the whitelist, we'll need the owners of these multisigs to tell us what addresses should receive the funds; we can't just pick one of the owners and call it good. We can require the recipients to be either external addresses or known good multisigs, and set up everything off chain.

A large donation might span several small recipients, so we may need to loop a bit. Due to gas limits we can't do much of that. In this code I limit it to five loops and refund whatever's left to the sender.

So with those assumptions in mind, here's a stab at a contract. So far it's barely tested, and not audited at all. At this point it's just a rough idea.

There'd have to be a fair amount of community agreement to actually do this. It'd be unfortunate if, say, several competing donation contracts were in use at the same time, or if one were used and then a hard fork happened after all.

And of course the list of recipients would have to be very carefully reviewed by the community. The list in my sample code is obviously made up.

pragma solidity ^0.4.23;

//poorly tested, not audited, fake addresses
//also assumes recipients are known safe
//i.e. no worries about reentrance or expensive receivers
//(if not the case, need to hold eth and use withdraw pattern)
contract BabySpoon {
    address[] public users = [
        0x123,
        0x345,
        0x456,
        0x678
    ];

    mapping (address => uint) public amounts;

    constructor() public {
        amounts[0x123] = 130249950;
        amounts[0x345] = 229320930;
        amounts[0x456] = 340320330;
        amounts[0x678] = 410320820;
    }

    uint maxIndex = 3; 
    uint public index;

    function min(uint x, uint y) pure private returns (uint) {
        if (x <= y) return x;
        else return y;
    }

    function () public payable {
        uint v = msg.value;
        
        uint currIndex = index;
        uint maxCurrIndex = min(maxIndex, currIndex + 5);
            
        while (currIndex <= maxCurrIndex) {
            address u = users[currIndex];

            if (amounts[u] <= v) {
                v = v - amounts[u];
                u.transfer(amounts[u]); 
                amounts[u] = 0;
            } else {
                amounts[u] = amounts[u] - v;
                u.transfer(v);
                v = 0;
            }

            currIndex += 1;
        }
        index = currIndex;

        if (address(this).balance > 0) {
            msg.sender.transfer(address(this).balance);  
        }
    }
}