Skip to content
Myra edited this page Jul 31, 2018 · 28 revisions

Introduction

  • A decentralized application running on the Ethereum blockchain, to empower real behavioral change driven by goal setting tied to financial incentivizes.
  • A Pledge contract is a binding agreement you sign with yourself to ensure that you follow through with your intentions, and it does this by utilizing the psychological power of loss aversion and accountability to drive behavior change.
  • By asking users to create a Pledge, dApptastic helps users define their goal (whatever it may be), acknowledge what it’ll take to accomplish it, and leverage the power of putting money on the line to turn that goal into a reality.

Requirements

Tenents

  • An absolute minimum of on-chain computation and data usage
  • A clear UI to notify users of any status changes in background processes.

User Stories

  1. Any user opens up the web app. The user is shown the home page where they can view all ongoing and finished pledges currently on the platform. They can also see stats on total number of pledges, total amount pledged, total users, etc. The user is also show a login button in order to authenticate and create their own pledge.
  2. A user opens up the web app, and successfully authenticates using uPort for the first time. The profile tab shows some account info and an empty avatar. The user is redirected to their dashboard showing their name and location. The previous pledges section is empty, and the current pledges section prompts them to create a new pledge with various input fields - goalType, amount, pledgeLength, etc.
  3. A user successfully creates a pledge. The current pledge section shows details of their ongoing active pledge. The user will only be able to 'checkin' for the current day. Any previous days in relation to the creationDate of the pledge will not be editable after the day has passed. Any future days will also not be editable until the day is the current day. The home page will update to include their pledge in the list, and the stats will be updated to account for the newly created pledge by this user. A user should not be able to create more than one current pledge.
  4. A user wants to close an existing pledge. A user with an active pledge returns to the web app, and successfully authenticates using uPort. The user is redirected to the dashboard and clicks on 'Finish Pledge' on an active pledge. The contract should distribute the amount to the recipient/owner depending on the success % of the pledge, and mark the pledge as inactive. This pledge should then appear under 'Previous Pledges' in the dashboard. At this point, the user can create another active pledge.

Tech Stack

Database - Local blockchain, Ethereum’s Testnet Rinkeby blockchain.
Hosting - IPFS
Frontend - React/Redux/ReduxRouter with Webpack/Babel, Semantic-UI, Avataars
Domain name - tbd
Package Manager - NPM, ethPM
Programing language - Solidity 0.4.24
Frameworks - Trufffle
Development server - Node.js, ganache-cli
Transaction Signing - Metamask
Authentication - uPort

Architecture

Key Design Decisions

Contracts

1. Single contact with structs

2. Factory/Child contracts - [IMPLEMENTED]

  • Considering this question - 'What are the concerns that contracts are dealing with?'
  • Users will have an ability to accept ether to their username; Each pledge will have a certain value tied to it; And keeping it all in one (potentially very complicated) contract seems to create a very nice large honey pot, and is much more difficult to audit.
  • If the users hold their money inside their own single pledge contract, then it would be easier to protect the amount, and provide a much more clear way to audit.
  • Child contracts are more expensive, but given the reasons above, I believe the implementation will be much more secure and auditable.

Storing Users

To keep track of pledges that belong to a single authenticated(by uPort) user.

1. uPort MNID

Originally, I thought this would be a string because I wanted to store the MNID, but as it's a known issue that the EVM doesn't handle string[] well (i.e - can't return string[] from a contract function) - I took the next approach.

2. Metamask address

Usually the address key is a MetaMask address from which the transaction happens. But since many wallet addresses can belong to the same user, this approach didn't make sense in a system where we are using uPort to authenticate.

3. uPort address - [IMPLEMENTED]

I chose the address key here to be the value returned by MNID.decode(). I'm thinking of storing the MNID from uPort as the ‘user address’ key, and not the actual wallet address. A pledge could only be modified if and only if the userNetworkSpecificAddress of the current authenticated user matches the userNetworkSpecificAddress of the creator of that Item.

Storing Checkins

To keep track of what days the user checked in for a given active ongoing pledge.

1. mapping(uint => bool) public checkins saved as storage variable

  • Pros:
    • Takes care of having only unique values by nature
  • Con:
    • Not able to loop over

2. uint8[] only containing the days that the user has checked in. Storage variable.

  • Pros:
    • lower gas costs
  • Cons:
    • Unordered/Unsorted
    • Possible to have duplicates, as prevention of duplicates would mean looping in the contract, which is not cost-effective.

3. bool[PLEDGE_DAYS_LENGTH]. Storage variable. [IMPLEMENTED]

  • Pros:
    • array is a restricted and known length, so we can still loop over without gas costs being too high
  • Cons:
    • tbd

Cost Analysis

Tests

Resources