/ Discover_Specification.md
Discover_Specification.md
  1  # Discover SNT Ranking
  2  
  3  ## Summary
  4  
  5  In order to fulfill one of our whitepaper promises, we need a mechanism that uses SNT to curate DApps. While this is not the only mechanism we will make available to users to find interesting and relevant DApps, it is one of the most important, both for SNT utility and because economic mechanisms are at the heart of how we buidl sustainable peer-to-peer networks.
  6  
  7  ## Abstract
  8  
  9  We propose using an exponential [bonded curve](https://beta.observablehq.com/@andytudhope/dapp-store-snt-curation-mechanism), which operates only on downvotes, to implement a simple ranking game. It is the most radical market feasible: the more SNT a DApp stakes, the higher it ranks, with one caveat. The more SNT staked, the cheaper it is for the community to move that DApp down the rankings.
 10  
 11  ## Motivation
 12  
 13  Token Curated Registries, and other bonded curve implementations try to incentivise the user with some kind of fungible reward token (often with governance rights/requirements attached to it) in order to decentralise the curation of interesting information. However, this creates mental overhead for users (who must manage multiple tokens, all with different on-chain transactions required) and is unlikely to see high adoption.
 14  
 15  Making the ranking algorithm transparent - and giving users an ability to affect it at a small cost to them should they feel very strongly - is potentially a more effective way to achieve decentralised curation.
 16  
 17  ## User Stories
 18  
 19  An effective economic ranking mechanism, selected with the option `Ranked by SNT` (one of many filters), answers the following user stories from our [swarm doc](https://github.com/status-im/swarms/blob/master/ideas/317-dapps-store.md).
 20  
 21  1. **I want to be confident a DApp is usable / not a scam.**
 22     1. Having an economic mechanism ensures that the DApps which rank highly quite literally are those providing the "most value" to the community. This is because SNT staked to rank is locked out of circulation, meaning each SNT stakeholder's own holding of SNT should increase in value. Coincidentally, the more SNT staked in total in the store, the stronger the assurance that any given DApp which ranks highly is useful and not a scam.
 23  2. **As an SNT stakeholder, I would like to signal using SNT that I find a listing useful.**
 24     1. Achieved by "upvoting" in the UI. Importantly, upvotes do not effect the bonded curve, users simply donate SNT 1-1 directly to the DApp's `balance`.
 25  3. **As an SNT stakeholder, I would like to signal using SNT that I find a listing to be not useful/poor quality/etc.**
 26     1. Achieved, on an increasingly cheap basis the more well-resourced a DApp is, by "downvoting" in the UI. Uses an exponential bonded curve to mint downvotes.
 27  4. **As a DApp developer, I want to be able to propose/vote my DApp for inclusion.**
 28     1. Anybody can submit a DApp for inclusion and "vote" on it by calling `upvote` and adding SNT to its `balance`.
 29  
 30  ## Specification
 31  
 32  #### Constants
 33  
 34  1. `uint total` - total SNT in circulation.
 35  2. `uint ceiling` - most influential parameter for [_shape_ of curves](https://beta.observablehq.com/@andytudhope/dapp-store-snt-curation-mechanism).
 36  3. `uint max` - max SNT that any one DApp can stake.
 37  4. `uint decimals` - the amount of decimal precision to use for the calculating `max`.
 38  5. `uint safeMax` - protect against overflows into infinity in votesMinted.
 39  
 40  #### Data Struct
 41  
 42  1. `address developer` - the developer of the DApp, used to send SNT to when `downvote` or `withdraw` is called.
 43  2. `bytes32 id` - a unique identifier for each DApp, potentially with other metadata associated with it, hence the `bytes32`.
 44  3. `bytes metadata` - the name, url, category and IPFS hash of the DApp so that we can resolve it in the store correctly.
 45  4. `uint balance` - keep track of the total staked on each DApp.
 46  5. `uint rate = 1 - (balance/max)` - used to calculate `available` and `votesMinted`.
 47  6. `uint available = balance * rate` - amount of SNT staked a developer can earn back. NB: this is equivalent to the `cost` of all downvotes.
 48  7. `uint votesMinted = available ** (1/rate)` - total downvotes that are "minted".
 49  8. `uint votesCast` - keep track of the downvotes already cast.
 50  9. `uint effectiveBalance = balance - ((votesCast/(1/rate))*(available/votesMinted))`- the Effective Balance each DApp is actually ranked by in the UI.
 51  
 52  ### Constructor
 53  
 54  1. Sets the address for the SNT contract based on arg passed in.
 55  1. `uint total == 6804870174`
 56  1. `uint ceiling = 292`, as this means the max is close to 2M SNT, and is a local minima for votesMinted.
 57  1. `uint decimals = 1000000` - We're use 1/100th of the total SNT in circulation as our bound, based mostly on Twitter polls...
 58  1. `uint max = (total * ceiling)/decimals`
 59  1. `uint safeMax = 77 * max / 100` - 77% of the absolute max, due to limitations with bancor's power approximations in Solidity.
 60  
 61  #### Methods
 62  
 63  1. **createDapp** external
 64     1. params: `(bytes32 _id, uint _amount)`
 65  
 66  Calls internal method `_createDApp`, passing in `msg.sender`, `_id` and `_amount`.
 67  
 68  2. **upvote** external
 69     1. params:`(bytes32 _id, uint _amount)`
 70  
 71  Calls internal method `_upvote`, passing in `msg.sender`, `_id` and `_amount`.
 72  
 73  3. **downvote** external
 74     1. params: `bytes32 _id, uint _amount`
 75  
 76  Calls `downvoteCost` to check the `_amount`, then calls internal method `_downvote`, passing in `msg.sender`, `_id` and `_amount`.
 77  
 78  4. **withdraw** external
 79     1. params: `(bytes32 _id, uint _amount)`
 80  
 81  Allow developers to reduce thier stake/exit the store provided that `_amount <= available`. Recalculate `balance`, `rate`, `available` and `votesMinted`. If `votesCast > votesMinted`, then set them equal so the maths is future-proof, and recalculate `effectiveBalance`.
 82  
 83  Emit event containing new `effectiveBalance`.
 84  
 85  5. **setMetadata** external
 86     1. params: `(bytes32 _id, bytes calldata _metadata)`
 87  
 88  Checks that the person trying to set/update the metadata is the developer, then updates the metadata associated with the DApp at that `id` so that we can resolve it correctly client side.
 89  
 90  7. **receiveApproval** external
 91     1. params: `(address _from, uint256 _amount, address _token, bytes _data)`
 92  
 93  Included so that users need only sign one transaction when creating a DApp, upvoting or downvoting. Checks that the token (SNT), sender, and data are correct. Decodes the `_data` using `abiDecodeRegister`, checks the amount is correct and figures out which of the three "payable" functions (`createDApp`, `upvote`, and `downvote`) is being called by looking at the signature.
 94  
 95  2. **upvoteEffect** external views
 96     1. params: `(bytes32 _id, uint _amount)`
 97  
 98  Mock add `_amount` to `balance`, calculate `mRate`, `mAvailable`, `mVMinted`, and `mEBalance`.
 99  
100  Returns the difference between `mEBalance` and the actual `effectiveBalance`.
101  
102  3. **downvoteCost** public view
103     1. params: `(bytes32 _id)`
104  
105  Specifying that each downvote must move the DApp down by 1% allows us to calculate the `cost` without integrating anything. Calculate the `votesRequired` to effect the DApp by the specified %.
106  
107  Returns `balanceDownBy`, `votesRequired` and `cost`.
108  
109  4. **\_createDApp** internal
110     1. params: `(address _from, bytes32 _id, uint _amount)`
111  
112  Accepts some nominal amount of tokens (> 0) and creates a new Data struct with the `_id` passed to it, setting the new struct's `balance` and using that to calculate `balance`, `rate`, `available`, `votesMinted` and `effectiveBalance` (which is == `balance` at first).
113  
114  Emit event containing new `effectiveBalance`.
115  
116  4. **\_upvote** internal
117     1. params: `(address _from, bytes32 _id, uint _amount)`
118  
119  Transfer SNT directly to the contract, which means donating directly to the DApp's `balance`, no money to the developer. Though the votes don't use a curve, we still need to recalculate `rate`, `available`, `votesMinted` and `effectiveBalance`.
120  
121  Emit event containing new `effectiveBalance`.
122  
123  4. **\_downvote** internal
124     1. params: `(address _from, bytes32 _id, uint _amount)`
125  
126  Send SNT from user directly to developer in order to downvote. Call `downvoteCost` to get `balance_down_by`, `votes_required` and `cost`.
127  
128  Add `votesRequired` to `votesCast`, recalculate `effectiveBalance`, and subtract `cost` from `available` so that `withdraw` works correctly.
129  
130  Emit event containing new `effectiveBalance`.
131  
132  8. **abiDecodeRegister** private
133     1. params: `(bytes memory _data)`
134  
135  Helps decode the data passed to `receiveApproval` using assembly magic.
136  
137  ## Potential Attacks
138  
139  1. **Sybil resistance?**
140     1. If I create a lot of accounts for one DApp, will that increase it's ranking?
141     2. If I vote for one DApp from lots of different accounts, in small amounts, rather than in 1 big amount from a single account, what effect does it have?
142  
143  Creating many accounts for one DApp is not possible - each DApp is uniquely identified and by its `id` and ranked only by the amount of SNT staked on it. In the same way, there is no quadratic effect in this set up, so staking for a DApp from lots of different accounts in small amounts has no greater/lesser effect on its ranking than staking 1 large amount from a single account.
144  
145  2. **Incentives to stake bad DApps and "force" the community to spend SNT to downvote?**
146  
147  Remember, you never get back more SNT than you stake, so this is also economically sub-optimal. In addition, there will be a free "complaint" feature as part of the "downvote" screen. There is an important difference between "contractual" and "social" (i.e. the Status UI) reality. Status reserves the right to remove from our UI any DApp that actively violates [our principles](https://status.im/contribute/our_principles.html), though anyone else is free to fork the software and implement different social/UI rules for the same contractual reality. This protects even further against any incentive to submit bad/damaging DApps.
148  
149  However, at the beginning of the Store, this is an attack vector: ranking highly requires but a small stake, and this could conceivably result in a successful, cheap hype campaign until we change the UI. The price of freedom is eternal vigilance.
150  
151  3. **Stake a damaging DApp, force some downvotes, and then withdraw my stake?**
152  
153  You can still never earn back quite as much as you initially staked, enforced by the condition in the `withdraw` function: `require(_amount <= available)`.
154  
155  4. **What is left in the store when a DApp withdraws the SNT it staked?**
156  
157  Simply `balance - available`, i.e. some small amount of SNT not available to be withdrawn.
158  
159  ## Rationale
160  
161  This is a simple economic mechanism that
162  
163  1. does not place high mental overheads on users and could conceivably be understood by a wider and non-technical audience and
164  2. does not require a lot of screen real estate (important on mobile). All that is required is a balance for each DApp and up/downvote carrots to it's right or left, a pattern already well understood on sites like Reddit etc.
165  
166  Moreover, having SNT is not required to see (and benefit from) a well-curated list of DApps; only if you want to effect the rankings on that list do you require tokens, which also makes the UX considerably easier for non-technical users.
167  
168  From the perspective of DApp Developers - they must still spend some capital to rank well, just as they currently do with SEO and AdWords etc., but _they stand to earn most of that back_ if the community votes on their product/service, and they can withdraw their stake at any time. The algorithm is entirely transparent and they know where they stand and why at all times.
169  
170  ## Notes
171  
172  The beauty of Ethereum to me, can be summed up simply:
173  
174  `By deploying immutable contracts to a shared, public computational surface - contracts whose data can be read deterministically by anyone with access to the internet - we can encode idealism into the way we run society.`
175  
176  What's more, **what's different this time**, is that the idealism exists independently of the people who encoded it, who inevitably become corrupted, because we are all human.
177  
178  However, there is hope in cryptoeconomics, which is not about egalitarianism, but about designing systems with no central point of control. Decentralisation is the goal; egalitarianism is a great success metric. But not the other way around, because egalitarianism is not something for which we can reasonably optimise.
179  
180  ## Copyright
181  
182  Copyright and related rights for this specification waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).