GoodDollar Protocol & Gitcoin Bug Bounty - DropsEarn
GoodDollar Protocol & Gitcoin Bug Bounty

GoodDollar Protocol & Gitcoin Bug Bounty

    GoodDollar has recently launched its basic income protocol (you can learn more via our White Paper and Lite Paper published here). This bug bounty challenge serves to stress-test the GoodDollar smart contracts. Successful submissions are at the discretion of the GoodDollar CTO, and will require evidence and documentation of any hack.

    Reward pool
    Expected profit
    $100 - 10,000
    Max participants
    DropsEarn score

  • Activity Type: Bug bounty Hackathon
  • Date: 15 Sep 2020 18:00(UTC+3) - 21 Oct 2020 18:00(UTC+3)
  • Registration: Closed
  • Event status: You can't participate (Event ended)
  • Links: Github GoodDollar Bounty Official Announcement
Go to event page

Detailed Information

GoodDollar is a people-powered framework to generate, finance, and distribute global basic income via the GoodDollar token (“G$ coin”). Its goal is to provide a baseline standard of living and reduce wealth inequality through the creation of a universal basic income (UBI).

GoodDollar -, White Paper - LitePaper -


The Gooddollar Bug Bounty is limited to vulnerabilities affecting the gooddollar smart contracts: DAO Contracts Staking model contracts


The severity of bugs will be assessed under the CVSS Risk Rating.

Critical (9.0–10.0): Up to $10,000 High (7.0–8.9): Up to $5,400 Medium (4.0–6.9): Up to $2,800 Low (0.1–3.9): Up to $1,000

Disclosure Requirements

Any vulnerability or bug discovered must be reported only to the following email:

The bug must not be disclosed publicly or to any other person, entity or email address other than

Please include as much detail about the vulnerability as possible including:

  • Conditions on which reproducing the bug is contingent.
  • Steps needed to reproduce the bug or, preferably, a proof of concept.
  • Implications of the vulnerability being abused.
  • Any bug reporter who reports a previously unreported bug that results in a change to the code or a configuration change and who keeps the vulnerability confidential until it has been resolved by our engineers will be recognized publicly for their contribution, if agreed.


To be eligible for a reward in the Gooddollar Bounty, you must:

  • Discover a previously unreported, non-public vulnerability that would result in a loss of or a lock of any token on Gooddollar (but not on any third party platform interacting with Gooddollar) and that is within the Scope mentioned above.
  • Provide sufficient information to enable our engineers to reproduce and fix the vulnerability.
  • Make a good faith effort to avoid privacy violations, destruction of data, interruption or degradation of Gooddollar.
  • Not submit a vulnerability caused by an underlying issue that is the same as an issue on which a reward has been paid under the bounty program.

Other Terms

All reward decisions, including eligibility for and amounts of the rewards and the manner in which such rewards will be paid, are made at our sole discretion.

Staking Model Contracts Docs


UBI Supporters

People who are staking their crypto to Goodstaking, willing to accept G$ instead of the originally used crypto

GoodStaking Smart Contract

a smart contract who: (a) receives cryptocurrencies from the Stakers and sends it to the third party protocol; (b) issue the GoodStaking record to the Stakers and accept the transactions from the stakers and sends them the principle deposited; (c) receive the Interest out directly from the thrid party protocols and automatically transfer it to the Reserve.

For now - the interest can only be donated to the reserve, and no G$ is minted in returen

Third party protocol

an existing algorithmic autonomous interest bearing protocol developed by third parties where Stakers can deposit cryptocurrencies and earn interest.

Bancor™ Formula

An automatic pricing formula which balances supply and demand for the Smart Token while holding a constant ratio between a Smart Token’s total value (market cap) and its connector token balances (see more here).


users of the GoodDollar wallet who claim daily GoodDollar Token(G$).


decentralized and autonomous entity, eventually owned 100% by the community of GoodDollar users.

  • Controls the Goodreserve

GoodDollar Token (G$)

a digital currency, built initially on ETH blockchain technology and comply with ERC20 standard, with a reserve token attached to it - Initially CDAI.


a smart contract with valuable foreign (not G$) cryptocurrencies in it. Users of the Gooddollar can buy or sell Gooddollar by depositing or withdrawing cryptocurrencies directly into or from the reserve (based on Bancor Formula, see above)

UBI scheme

A smart contract that collects the total minted Gooddollar, and distributed between all claimers that day.

Architecture Diagram

Money flow in the GoodDollar ecosystem

  1. Supporter stake his crypto currency to GoodStaking

    For now - can only be DAI
  2. Goodstaking deposits the crypto currency to a third party DEFI protocol

    At the moment Compound
  3. The third paty issue a staking Token (CDAI)

  4. Goodstaking issues a non transferable record to the staking wallet. (supporter can withdraw at anytime)

  5. FundManager(GoodDao) triggers a daily request to GoodStaking to collect earned interest

  6. Goodstaking sends interest to good reserve

  7. FundManager triggers the Reserve to mint and send the new minted G$ to the FundManager (Interest + UBI)

  8. The interest is Sent back to the GoodStaking - not active at the moment

  9. FundManager send G$ to the UBI scheme smart contract via Fuse token bridge

  10. The G$ in the UBI scheme is divided between all "active" whitelisted users. Each user need to claim his share in the 24 hours window.


GoodDollar protocol is deployed both on Ethereum mainnet and on Fuse as a sidechain. Some contracts like the Reserve are only on mainnet and some contracts like the UBIScheme are only on the sidechain. The DAO and Token are deployed on both networks.

Core Contracts

Contract                 Mainnet        Fuse Source code
GoodDollar ERC20              Contract link       Contract link          GoodDollar.sol
Identity Contract link Contract link Identity.sol
GoodStaking Contract link   SimpleDAIStaking.sol
GoodReserve Contract link   GoodReserveCDAI.sol
GoodFundManager Contract link   GoodFundManager.sol
GoodMarketMaker Contract link   GoodMarketMaker.sol
ContributionCalculation Contract link   ContributionCalculation.sol
UBIScheme   Contract link UBIScheme.sol
FirstClaimPool   Contract link FirstClaimPool.sol
AdminWallet   Contract link FirstClaimPool.sol
OneTimePayments   Contract link OneTimePayments.sol

GoodDollar ERC20

The GoodDollar token follows the erc20 standard and also supports erc677.


The identity contract controls which addresses are whitelisted to "Claim" UBI.

Face Verification

Currently the GoodDollar Foundation is whitelisting users based on user prooving he signed up with a live and unique face. Since the user facial details are anonymized in order to allow the user to create a new account in case he is unable to recover his wallet, facial details are deleted after authenticationPeriod and users are required to perform face verification again every authenticationPeriod days.

Social Profile

Each address is linked to the user public profile as created in the wallet. The DID is the node id in the public p2p GunDB database. Mappings from wallet address to DID are held in addrTODID

 * @dev Returns true if given address has been added to whitelist
 * @param account the address to check
 * @return a bool indicating weather the address is present in whitelist
function isWhitelisted(address account) public view returns (bool)

 * @dev Function that gives the date the given user was added
 * @param account The address to check
 * @return The date the address was added
function lastAuthenticated(address account) public view returns (uint256)

/* the number of days an authentication is valid for*/
uint256 public authenticationPeriod

mapping(address => string) public addrToDID;


UBI Supporters can stake crypto which is then invested in DEFI protocols. The FundManager has permissions to collect gained interest from this contract.

 * @dev Allows a staker to deposit DAI tokens. Notice that `approve` is
 * needed to be executed before the execution of this method.
 * Can be executed only when the contract is not paused.
 * @param _amount The amount of DAI to stake
function stakeDAI(uint256 _amount) public whenNotPaused

 * @dev Withdraws the sender staked DAI.
function withdrawStake() public


The reserve mints G$ based on interest transfered from the FundManager, only the FundManager can trigger minting. The reserve also acts as the GoodDollar liquidity pool and AMM (Automatic Market Maker) and exposes methods to buy and sell G$s.

 * @dev Converts `buyWith` tokens to GD tokens and updates the bonding curve 
 * `buy` occurs only if the GD return is above the given minimum. It is possible
 * to buy only with cDAI and when the contract is set to active. 
 * MUST `approve` prior this action to allow this contract to accomplish the
 * conversion.
 * @param _buyWith The tokens that should be converted to GD tokens
 * @param _tokenAmount The amount of `buyWith` tokens that should be converted to 
GD tokens
 * @param _minReturn The minimum allowed return in GD tokens
 * @return (gdReturn) How much GD tokens were transferred
function buy(ERC20 _buyWith,uint256 _tokenAmount,uint256 _minReturn) public 
 onlyCDai(_buyWith) returns (uint256)

 * @dev Converts GD tokens to `sellTo` tokens and update the bonding curve params.
 * `sell` occurs only if the token return is above the given minimum. Notice that
 * there is a contribution amount from the given GD that remains in the reserve.
 * It is only possible to sell to cDAI and only when the contract is set to
 * active. MUST make call to G$ `approve` prior to this action to allow this
 * contract to accomplish the conversion.
 * @param _sellTo The tokens that will be received after the conversion
 * @param _gdAmount The amount of GD tokens that should be converted to `_sellTo` 
 * @param _minReturn The minimum allowed `sellTo` tokens return
 * @return (tokenReturn) How much `sellTo` tokens were transferred

function sell(
    ERC20 _sellTo,
    uint256 _gdAmount,
    uint256 _minReturn
) public requireActive onlyCDai(_sellTo) returns (uint256)

 * @dev Current price of GD in `token`. currently only cDAI is supported.
 * @param _token The desired reserve token to have
 * @return price of GD
function currentPrice(ERC20 _token) public view returns (uint256)


Has permissions to collect interest from the GoodStaking contract and permissions to tell GoodReserve to mint. Anyone can trigger the collection and minting process

 * @dev Collects UBI interest in cDai from a given staking contract and 
 * that interest to the reserve contract. Then transfers the gd
 * received from the reserve contract back to the staking contract and to the
 * bridge, which locks the funds and then same amount of G$ tokens are minted 
to the
 * ubiRecipient address on the sidechain
 * @param _staking Contract that implements `collectUBIInterest` and transfer 
cDai to
 * a given address. The given address should be the same whitelisted `reserve`
 * address in the current contract, in case that the given staking contract 
 * the funds to another contract, zero GD tokens will be minted by the reserve 
 * Emits `FundsTransferred` event in case which interest has been passed to the 
function transferInterest(StakingContract _staking)


Holds all the G$s that were transfered via bridge from the FundManager. The pool of G$s is divided daily by the amount of current active users. Each active user can then "claim" his quota. If a user fails to claim his quota it becomes part of the next day UBI pool.

 * @dev Checks the amount which the sender address is eligible to claim for,
 * regardless if they have been whitelisted or not.
 * @return The amount of GD tokens the address can claim.
function checkEntitlement() public view requireActive returns (uint256)

 * @dev Function for claiming UBI. Requires contract to be active and claimer 
to be whitelisted.
 * Calls distributionFormula, calculats the amount the caller can claim, and 
transfers the amount
 * to the caller. Emits the address of caller and amount claimed.
 * @return A bool indicating if UBI was claimed
function claim() public requireActive onlyWhitelisted returns (bool)

 * @dev In order to update users from active to inactive, we give out incentive 
to people
 * to update the status of inactive users, this action is called "Fishing". 
Anyone can
 * send a tx to the contract to mark inactive users. The "fisherman" receives 
a reward
 * equal to the daily UBI (ie instead of the “fished” user). User that “last 
claimed” > 14
 * can be "fished" and made inactive (reduces active users count by one). 
 * contract to be active.
 * @param _account to fish
 * @return A bool indicating if UBI was fished
function fish(address _account) public requireActive returns (bool)

 * @dev executes `fish` with multiple addresses. emits the number of users 
from the given
 * array who actually been tried being fished.
 * @param _accounts to fish
 * @return A bool indicating if all the UBIs were fished
function fishMulti(address[] memory _accounts)


Payments on the GoodDollar wallet are done via payment links. G$s are held in escrow and the recipient can retrieve the funds if he has the key. While the money is in escrow the sender can choose to cancel the payment and retrieve the funds. Based on Celo's payments contract

* @dev ERC677 on token transfer function. When transferAndCall is called on 
this contract,
 * this function is called, depositing the payment amount under the hash 
of the given bytes.
 * Reverts if hash is already in use. Can only be called by token contract.
 * @param sender the address of the sender
 * @param value the amount to deposit
 * @param data The given paymentId which should be a fresh public key

to deposit a payment to a one time payment address call:
GoodDollar.transferAndCall(value,data) this will trigger OneTimePayments 

/* @dev Withdrawal function.
 * allows the sender that proves ownership of paymentId to withdraw
 * @param paymentId the address of the public key that the
 *   rightful receiver of the payment knows the private key to
 * @param signature the signature of a the message containing the msg.sender 
address signed
 *   with the private key.
function withdraw(address paymentId, bytes memory signature) public 

/* @dev Cancel function
 * allows only creator of payment to cancel
 * @param paymentId The paymentId of the payment to cancelæ
function cancel(address paymentId) public


Helper contract for the GoodReserve.


Helper contract for calculating the exit contribution (ie when selling G$ back to the reserve)


Helper contract for UBIScheme. Manually funded by the Foundation to give 1G$ for "inactive" users when they claim. Since a new user (inactive) becomes active and eligible to claim UBI only in the next UBI epoch. So for new users not go empty handed on their first claim we give out a 1G$.


Helper contract for our backend servers to whitelist users and to fill their Fuse network gas.

Token Bridge Contracts

Bridge contracts were developed by Fuse

Contract Mainnet Fuse Source Code
ForeignBridge (mainnet -> fuse)        Etherscan link     l
HomeBridge (fuse -> mainnet)   Etherscan link         HomeBridgeErcToErc.sol

DAO Contracts

DAO contracts were developed by DAOStack

Contract Mainnet Fuse Source Code
Controller Etherscan link        Etherscan link       Controller.sol
Avatar Etherscan link Etherscan link Avatar.sol
Reputation Etherscan link Etherscan link Reputation.sol                  
SchemeRegistrar       Etherscan link Etherscan link SchemeRegistrar.sol
AbsoluteVote Etherscan link Etherscan link AbsoluteVote.sol
UpgradeScheme Etherscan link Etherscan link UpgradeScheme.sol