BrightID Honey Faucet

This is an idea for a relatively simple project that would open a lot of interesting possibilities for us, specifically exploring and testing the brightid solution for decentralized sybil resistance. This would be valuable for us as a way to help onboard people, create a broad, fair, and inclusive distribution process for Honey, and create the foundation for integrating more “people-centric” features into the DAO space. As an initial step, I propose we work on a “faucet” which brightid validated users can register for, the faucet can be topped up with honey, and users who participate in the process can then claim distributions from the faucet periodically.

User flow

  1. Users will need to verify an ethereum account using BrightID. An example of this type of account validation can be seen in production at https://ethereum.brightid.org.
  2. After verifying their account they must register with the faucet contract to be eligible to claim in the next period.
  3. During each subsequent period they must claim their distribution and register for the subsequent period. If they fail to claim a distribution they register for, they will forfeit that distribution and will essentially be back at step 2.

Technical Flow

  1. Faucet defines a period as a number of blocks, a currentRegistry as a mapping of accounts, and a nextRegistry as a mapping of accounts.
  2. Users can call claim at any time when they do the following happens:
  3. If this is the first time claim has been called during a period, the currentRegistry is replaced by nextRegistry and nextRegistry is cleared and the distributionAmount for that period is calculated based on the current balance of honey , a rate parameter of the Faucet (that determines the ratio of faucet funds that are distributed in a given distribution), and the total number of users registered for the period.
  4. Checks if the user is registered to receive a distribution this period:
    1. If the user is registered, the faucet releases distributionAmount of honey and then moves the user from the current period registry to the next period registry.
    2. If the user is not registered and not already on the next period registry, they are added.

Some other thoughs

  • We should consider if we can use this faucet as a means to onboard a “brand new users” who may not have a wallet or any xdai.
  • We can potentially use portis and GSN to subsidize transactions via meta transactions with the faucet. If the faucet either also distributes some small amount of xdai, or we provide an option to convert some of the honey to xdai when claiming we can help users get some xdai in order to pay for transactions (enabling them to start interacting with the DAO).
  • If we get the registration/faucet flow figured out, we could consider doing some other proof of concepts, like implementing quadratic conviction voting, quadratic dandelion voting, restricting participation in voting to validated users, creating a “people’s court”, creating moderation policies based on temporary/permanent bans on different types of participation.
3 Likes

I love this @lkngtn .

Do I understand the flow correctly? If you claim in one round, you are registered for the next round–those two actions are coupled for convenience?

Is there any reason someone might want to change addresses between rounds, and not have them linked? (This would usually be for user privacy.)

Within the same round, if someone attempts to claim / register from multiple accounts, they will accumulate a “history” in an iBrightID implemented contract of all the accounts they’ve used with the same BrightID. You can see how the Eidi (IDChain) (working) faucet uses the history. The code is deployed here: https://explorer.idchain.one/address/0x6E39d7540c2ad4C18Eb29501183AFA79156e79aa/contracts
You can see on line 238 the “claim” function, and how it iterates through the history to see if the user has already claimed with one of their other addresses.

    function claim(address payable beneficiary, uint256 amount) public {
        require(brightid.verifications(beneficiary) > 0, "beneficiary is not verified");
        address tmp = beneficiary;
        uint256 sum = 0;
        while (tmp != address(0)) {
            sum = sum.add(claimed[tmp]);
            tmp = brightid.history(tmp);
        }
        require(claimable >= sum.add(amount), "total claimed amount is more than claimable");        
        claimed[beneficiary] = claimed[beneficiary].add(amount);
        beneficiary.transfer(amount);
    }

}
1 Like

Yeah, we are making the assumption since its essentially free honey that if someone is claiming of for a period they almost certainly want to be included also in the subsequent round.

Yeah it seems reasonable to allow someone to change the address they are using, sounds like we could do the registration based on the brightid context not the specific address, so they are registering their id and not their address an can change their address if they want at any point.

I’m a little bit concerned about having to loop through an in-determinant number of addresses though, its maybe less of an issue for the faucet, but could add non-neglible overhead to other interactions. Eg for quadratic voting, each time they vote they would need to be going though this loop right?

Have you guys considered how to handle situations where this list gets long?

1 Like

Yes. In contexts where there are distinct rounds and it’s not important to preserve history between rounds, the history can be cleared safely with each new round.

In contexts where long-term history may be important, every time a user changes their contextid (e.g. an ethereum address) they accumulate baggage that can add to the cost of every action they take on the blockchain. With enough changes, an app could become unusable. I don’t have a good solution for this other than to warn users about how many ids they have every time they add a new one.

Gotcha, so in this case we would have the option of simplifying and just say that if you change your address you have to start over (and miss a distribution period), but we wouldn’t need to loop through addresses we would just make sure when both claiming/registering the address being used is currently validated.

1 Like

Yes, what you’ve just said is the simplest approach. There is probably a way to allow an address change and not miss any distributions–the history would only be checked in the context of a round–but that solution requires more thought on how and when to clear the histories.

Why blocks and not time? Also I think you could get away with just storing the time/block the user last called register/claim and refer to that to determine their eligibility instead of using mappings. We would also need a mapping of periodId -> number of registered users during that period to determine the distribution.

In the code above I think you could make the loop more efficient if you stored the sum for a specific address in the faucet then only loop back until you find an address that has a sum value stored and use that instead of going through the whole history. Would only help if claim() was regularly called though.

We could loop through a few historic addresses but would want to limit it.

1 Like

Yes, that sounds like a good improvement if claim() is called regularly, which I believe is going to be the case for the honey faucet. In the eidi faucet, claim() is only called once or when there’s a change to the lifetime supply.

We created a squad channel for this on the DAO Hack Month server, anyone interested in hacking on this in the next 2 weeks should join there as well https://discordapp.com/channels/577563131585232896/729762932484735137/729763164157378640

1 Like