/ test / Discover_spec.js
Discover_spec.js
  1  const TestUtils = require("../utils/testUtils");
  2  
  3  const Discover = require('Embark/contracts/Discover');
  4  const SNT = embark.require('Embark/contracts/SNT');
  5  
  6  
  7  config({
  8    deployment: {
  9      accounts: [
 10        {
 11          mnemonic: "foster gesture flock merge beach plate dish view friend leave drink valley shield list enemy",
 12          balance: "5 ether",
 13          numAddresses: "10"
 14        }
 15      ]
 16    },
 17    contracts: {
 18      "MiniMeToken": { "deploy": false },
 19      "MiniMeTokenFactory": {},
 20      "SNT": {
 21        "instanceOf": "MiniMeToken",
 22        "args": [
 23          "$MiniMeTokenFactory",
 24          "0x0000000000000000000000000000000000000000",
 25          0,
 26          "TestMiniMeToken",
 27          18,
 28          "SNT",
 29          true
 30        ]
 31      },
 32      "Discover": {
 33        args: ["$SNT"]
 34      },
 35      "TestBancorFormula": {}
 36    }
 37  }, (_err, web3_accounts) => {
 38    accounts = web3_accounts
 39  });
 40  
 41  contract("Discover", function () {
 42  
 43    this.timeout(0);
 44  
 45    it("should set max and safeMax values correctly", async function () {
 46      let resultMax = await Discover.methods.max().call();
 47      let resultSafeMax = await Discover.methods.safeMax().call();
 48      let expectedMax = 3470483788 * 588 / 1000000;
 49      let expectedSafeMax = expectedMax * 77 / 100 - 1;
 50      assert.strictEqual(parseInt(resultMax, 10), Math.round(expectedMax));
 51      assert.strictEqual(parseInt(resultSafeMax, 10), Math.round(expectedSafeMax));
 52    });
 53  
 54    it("should create a new DApp and initialise it correctly", async function () {
 55      let id = "0x7465737400000000000000000000000000000000000000000000000000000000";
 56      let amount = 10000;
 57      let metadata = "QmSmv5e5DYc2otwWcpUzuqmt389s3HHx651TbxDvKBFFue";
 58  
 59      await SNT.methods.generateTokens(accounts[0], amount).send();
 60      const encodedCall = Discover.methods.createDApp(id, amount, TestUtils.getBytes32FromIpfsHash(metadata)).encodeABI();
 61      await SNT.methods.approveAndCall(Discover.options.address, amount, encodedCall).send({ from: accounts[0] });
 62  
 63      let receipt = await Discover.methods.dapps(0).call();
 64      let developer = accounts[0];
 65  
 66      assert.strictEqual(developer, receipt.developer);
 67      assert.strictEqual(id, receipt.id);
 68      assert.strictEqual(metadata, TestUtils.getIpfsHashFromBytes32(receipt.metadata));
 69  
 70      // Check Discover actually receives the SNT!
 71      let bal_receipt = await SNT.methods.balanceOf(Discover.options.address).call();
 72      assert.strictEqual(amount, parseInt(bal_receipt, 10));
 73  
 74      // Having received the SNT, check that it updates the particular DApp's storage values
 75      assert.strictEqual(amount, parseInt(receipt.balance, 10));
 76  
 77      let max = await Discover.methods.max().call();
 78      let decimals = await Discover.methods.decimals().call();
 79      let rate = Math.round(decimals - (amount * decimals / max));
 80      assert.strictEqual(rate, parseInt(receipt.rate, 10));
 81  
 82      let available = amount * rate;
 83      assert.strictEqual(available, parseInt(receipt.available, 10));
 84  
 85      let votes_minted = Math.round((available / decimals) ** (decimals / rate));
 86      assert.strictEqual(votes_minted, parseInt(receipt.votesMinted, 10));
 87  
 88      assert.strictEqual(0, parseInt(receipt.votesCast, 10));
 89      assert.strictEqual(amount, parseInt(receipt.effectiveBalance, 10));
 90    })
 91  
 92    it("should not create a new DApp with the same ID", async function () {
 93      let id = "0x7465737400000000000000000000000000000000000000000000000000000000";
 94      let amount = 1000;
 95      let metadata = 'QmSmv5e5DYc2otwWcpUzuqmt389s3HHx651TbxDvKBFFue';
 96  
 97      await SNT.methods.generateTokens(accounts[0], amount).send();
 98      const encodedCall = Discover.methods.createDApp(id, amount, TestUtils.getBytes32FromIpfsHash(metadata)).encodeABI();
 99  
100      try {
101        await SNT.methods.approveAndCall(Discover.options.address, amount, encodedCall).send({ from: accounts[0] });
102        assert.fail('should have reverted before');
103      } catch (error) {
104        TestUtils.assertJump(error);
105      }
106    })
107  
108    it("should not create a new DApp when exceeding the ceiling or staking nothing", async function () {
109      let id = "0x7465737400000000000000000000000000000000000000000000000000000000";
110      let metadata = 'QmSmv5e5DYc2otwWcpUzuqmt389s3HHx651TbxDvKBFFue';
111      let initial = await Discover.methods.max().call();
112      let amount = parseInt(initial, 10);
113      let amount0 = 0;
114  
115      await SNT.methods.generateTokens(accounts[0], amount).send();
116  
117      const encodedCall = Discover.methods.createDApp(id, amount, TestUtils.getBytes32FromIpfsHash(metadata)).encodeABI();
118      try {
119        await SNT.methods.approveAndCall(Discover.options.address, amount, encodedCall).send({ from: accounts[0] });
120        assert.fail('should have reverted before');
121      } catch (error) {
122        TestUtils.assertJump(error);
123      }
124  
125      const encodedCall0 = Discover.methods.createDApp(id, amount0, TestUtils.getBytes32FromIpfsHash(metadata)).encodeABI();
126      try {
127        await SNT.methods.approveAndCall(Discover.options.address, amount0, encodedCall0).send({ from: accounts[0] });
128        assert.fail('should have reverted before');
129      } catch (error) {
130        TestUtils.assertJump(error);
131      }
132    })
133  
134    it("should update the metadata correctly", async function () {
135      let id = "0x7465737400000000000000000000000000000000000000000000000000000000";
136      let metadata = "QmSmv5e5DYc2otwWcpUzuqmt389s3HHx651TbxDvKBFFeu";
137      await Discover.methods.setMetadata(id, TestUtils.getBytes32FromIpfsHash(metadata)).send({ from: accounts[0] });
138      let receipt = await Discover.methods.dapps(0).call();
139      assert.strictEqual(TestUtils.getBytes32FromIpfsHash(metadata), receipt.metadata);
140    })
141  
142    it("should not let anyone other than the developer update the metadata", async function () {
143      let id = "0x7465737400000000000000000000000000000000000000000000000000000000";
144      let metadata_actual = "QmSmv5e5DYc2otwWcpUzuqmt389s3HHx651TbxDvKBFFeu";
145      let metadata = "QmSmv5e5DYc2otwWcpUzuqmt389s3HHx651TbxDvKBDDeu";
146      try {
147        await Discover.methods.setMetadata(id, TestUtils.getBytes32FromIpfsHash(metadata)).send({ from: accounts[1] });
148        assert.fail('should have reverted before');
149      } catch (error) {
150        TestUtils.assertJump(error);
151      }
152      let receipt = await Discover.methods.dapps(0).call();
153      assert.strictEqual(TestUtils.getBytes32FromIpfsHash(metadata_actual), receipt.metadata);
154    })
155  
156    it("should handle first upvote correctly", async function () {
157      let id = "0x7465737400000000000000000000000000000000000000000000000000000000";
158      let amount = 100;
159  
160      let initial = await Discover.methods.dapps(0).call();
161      let before = await SNT.methods.balanceOf(Discover.options.address).call();
162      // This is the special case where no downvotes have yet been cast
163      let up_effect = await Discover.methods.upvoteEffect(id, amount).call();
164  
165      await SNT.methods.generateTokens(accounts[0], amount).send();
166      const encodedCall = Discover.methods.upvote(id, amount).encodeABI();
167      await SNT.methods.approveAndCall(Discover.options.address, amount, encodedCall).send({ from: accounts[0] });
168  
169      let receipt = await Discover.methods.dapps(0).call();
170  
171      let developer = accounts[0];
172  
173      assert.strictEqual(developer, receipt.developer);
174      assert.strictEqual(id, receipt.id);
175  
176      // Check Discover  actually receives the SNT!
177      let after = await SNT.methods.balanceOf(Discover.options.address).call();
178      let bal_effect = parseInt(after, 10) - parseInt(before, 10);
179      assert.strictEqual(bal_effect, amount);
180  
181      // Having received the SNT, check that it updates the particular DApp's storage values
182      let upvotedBalance = parseInt(initial.balance, 10) + amount
183      assert.strictEqual(upvotedBalance, parseInt(receipt.balance, 10));
184  
185      let max = await Discover.methods.max().call();
186      let decimals = await Discover.methods.decimals().call();
187      let rate = Math.round(decimals - (upvotedBalance * decimals / max));
188      assert.strictEqual(rate, parseInt(receipt.rate, 10));
189  
190      let available = upvotedBalance * rate;
191      assert.strictEqual(available, parseInt(receipt.available, 10));
192  
193      let votes_minted = Math.round((available / decimals) ** (decimals / rate));
194      assert.strictEqual(votes_minted, parseInt(receipt.votesMinted, 10));
195  
196      // Only true for upvotes made when there are no downvotes
197      assert.strictEqual(0, parseInt(receipt.votesCast, 10));
198  
199      // The effective_balance should match upvoteEffect + initial.effectiveBalance
200      let e_balance = parseInt(up_effect, 10) + parseInt(initial.effectiveBalance, 10);
201      assert.strictEqual(e_balance, parseInt(receipt.effectiveBalance, 10));
202    })
203  
204    it("should not let you upvote without spending SNT", async function () {
205      let id = "0x7465737400000000000000000000000000000000000000000000000000000000";
206      let amount = 0;
207  
208      await SNT.methods.generateTokens(accounts[0], 10000).send();
209      const encodedCall = Discover.methods.upvote(id, amount).encodeABI();
210      try {
211        await SNT.methods.approveAndCall(Discover.options.address, amount, encodedCall).send({ from: accounts[0] });
212        assert.fail('should have reverted before');
213      } catch (error) {
214        TestUtils.assertJump(error);
215      }
216    })
217  
218    it("should not let you upvote by an amount that exceeds the ceiling", async function () {
219      let id = "0x7465737400000000000000000000000000000000000000000000000000000000";
220      let initial = await Discover.methods.max().call();
221      let amount = parseInt(initial, 10);
222  
223      await SNT.methods.generateTokens(accounts[0], amount).send();
224      const encodedCall = Discover.methods.upvote(id, amount).encodeABI();
225      try {
226        await SNT.methods.approveAndCall(Discover.options.address, amount, encodedCall).send({ from: accounts[0] });
227        assert.fail('should have reverted before');
228      } catch (error) {
229        TestUtils.assertJump(error);
230      }
231    })
232  
233    it("should handle first downvote correctly", async function () {
234      let id = "0x7465737400000000000000000000000000000000000000000000000000000000";
235      let cost = await Discover.methods.downvoteCost(id).call()
236      let amount = parseInt(cost.c, 10);
237  
238      let developer = accounts[0];
239      let initial = await Discover.methods.dapps(0).call();
240      let bal_before = await SNT.methods.balanceOf(developer).call();
241  
242      await SNT.methods.generateTokens(accounts[1], amount).send();
243      const encodedCall = Discover.methods.downvote(id, amount).encodeABI();
244      await SNT.methods.approveAndCall(Discover.options.address, amount, encodedCall).send({ from: accounts[1] });
245  
246      let receipt = await Discover.methods.dapps(0).call();
247  
248      assert.strictEqual(developer, receipt.developer);
249      assert.strictEqual(id, receipt.id);
250  
251      // Check the developer actually receives the SNT!
252      let bal_after = await SNT.methods.balanceOf(developer).call();
253      let bal_effect = parseInt(bal_after, 10) - parseInt(bal_before, 10)
254      assert.strictEqual(bal_effect, amount);
255  
256      // Balance, rate, and votes_minted remain unchanged for downvotes
257      assert.strictEqual(initial.balance, receipt.balance);
258      assert.strictEqual(initial.rate, receipt.rate);
259      assert.strictEqual(initial.votesMinted, receipt.votesMinted);
260  
261      let available = parseInt(initial.available, 10) - parseInt(cost.c, 10);
262      assert.strictEqual(available, parseInt(receipt.available, 10));
263  
264      // This is only true for the first downvote
265      assert.strictEqual(parseInt(receipt.votesCast, 10), parseInt(cost.vR, 10));
266  
267      let e_balance = parseInt(initial.effectiveBalance, 10) - parseInt(cost.b, 10);
268      assert.strictEqual(e_balance, parseInt(receipt.effectiveBalance, 10));
269    })
270  
271    it("should handle second downvote correctly", async function () {
272      let id = "0x7465737400000000000000000000000000000000000000000000000000000000";
273      let cost = await Discover.methods.downvoteCost(id).call()
274      let amount = parseInt(cost.c, 10);
275      let developer = accounts[0];
276  
277      let initial = await Discover.methods.dapps(0).call();
278      let bal_before = await SNT.methods.balanceOf(developer).call();
279  
280      await SNT.methods.generateTokens(accounts[1], amount).send();
281      const encodedCall = Discover.methods.downvote(id, amount).encodeABI();
282      await SNT.methods.approveAndCall(Discover.options.address, amount, encodedCall).send({ from: accounts[1] });
283  
284      let receipt = await Discover.methods.dapps(0).call();
285  
286      assert.strictEqual(developer, receipt.developer);
287      assert.strictEqual(id, receipt.id);
288  
289      // Check the developer actually receives the SNT!
290      let bal_after = await SNT.methods.balanceOf(developer).call();
291      let bal_effect = parseInt(bal_after, 10) - parseInt(bal_before, 10)
292      assert.strictEqual(bal_effect, amount);
293  
294      // Balance, rate, and votes_minted remain unchanged for downvotes
295      assert.strictEqual(initial.balance, receipt.balance);
296      assert.strictEqual(initial.rate, receipt.rate);
297      assert.strictEqual(initial.votesMinted, receipt.votesMinted);
298  
299      let available = parseInt(initial.available, 10) - parseInt(cost.c, 10);
300      assert.strictEqual(available, parseInt(receipt.available, 10));
301  
302      let eff_v_cast = parseInt(receipt.votesCast, 10) - parseInt(initial.votesCast, 10);
303      assert.strictEqual(eff_v_cast, parseInt(cost.vR, 10));
304  
305      let e_balance = parseInt(initial.effectiveBalance, 10) - parseInt(cost.b, 10);
306      assert.strictEqual(e_balance, parseInt(receipt.effectiveBalance, 10));
307    })
308  
309    it("should not let you downvote by the wrong amount", async function () {
310      let id = "0x7465737400000000000000000000000000000000000000000000000000000000";
311      let amount_above = 10000;
312      let amount_below = 100;
313  
314      await SNT.methods.generateTokens(accounts[1], amount_above + amount_below).send();
315  
316      const encodedCall = Discover.methods.downvote(id, amount_above).encodeABI();
317      try {
318        await SNT.methods.approveAndCall(Discover.options.address, amount_above, encodedCall).send({ from: accounts[1] });
319        assert.fail('should have reverted before');
320      } catch (error) {
321        TestUtils.assertJump(error);
322      }
323  
324      const encodedCall1 = Discover.methods.downvote(id, amount_below).encodeABI();
325      try {
326        await SNT.methods.approveAndCall(Discover.options.address, amount_below, encodedCall1).send({ from: accounts[1] });
327        assert.fail('should have reverted before');
328      } catch (error) {
329        TestUtils.assertJump(error);
330      }
331    })
332  
333    it("should handle upvotes correctly when votes have been cast", async function () {
334      let id = "0x7465737400000000000000000000000000000000000000000000000000000000";
335      let amount = 500;
336  
337      let initial = await Discover.methods.dapps(0).call();
338      let before = await SNT.methods.balanceOf(Discover.options.address).call();
339      let up_effect = await Discover.methods.upvoteEffect(id, amount).call();
340  
341      await SNT.methods.generateTokens(accounts[0], amount).send();
342      const encodedCall = Discover.methods.upvote(id, amount).encodeABI();
343      await SNT.methods.approveAndCall(Discover.options.address, amount, encodedCall).send({ from: accounts[0] });
344  
345      let receipt = await Discover.methods.dapps(0).call();
346      let developer = accounts[0];
347  
348      assert.strictEqual(developer, receipt.developer);
349      assert.strictEqual(id, receipt.id);
350  
351      // Check Discover actually receives the SNT!
352      let after = await SNT.methods.balanceOf(Discover.options.address).call();
353      let bal_effect = parseInt(after, 10) - parseInt(before, 10);
354      assert.strictEqual(bal_effect, amount);
355  
356      // Having received the SNT, check that it updates the particular DApp's storage values
357      let upvotedBalance = parseInt(initial.balance, 10) + amount
358      assert.strictEqual(upvotedBalance, parseInt(receipt.balance, 10));
359  
360      let max = await Discover.methods.max().call();
361      let decimals = await Discover.methods.decimals().call();
362      let rate = Math.round(decimals - (upvotedBalance * decimals / max));
363      assert.strictEqual(rate, parseInt(receipt.rate, 10));
364  
365      let available = upvotedBalance * rate;
366      assert.strictEqual(available, parseInt(receipt.available, 10));
367  
368      let votes_minted = parseInt(receipt.votesMinted, 10);
369  
370      // Votes have been cast by this stage, so we need to check how many there are
371      // and confirm that `upvote` still calculates the effective_balance correctly
372      let votes_cast = parseInt(receipt.votesCast, 10);
373  
374      let e_balance = Math.round(upvotedBalance - ((votes_cast * rate / decimals) * (available / decimals / votes_minted)));
375      assert.strictEqual(e_balance, parseInt(receipt.effectiveBalance, 10));
376  
377      // The effective_balance should also match upvoteEffect + initial.effectiveBalance
378      let e_balance_2 = parseInt(up_effect, 10) + parseInt(initial.effectiveBalance, 10);
379      assert.strictEqual(e_balance_2, parseInt(receipt.effectiveBalance, 10));
380    })
381  
382    it("should return correct upvoteEffect for use in UI", async function () {
383      let id = "0x7465737400000000000000000000000000000000000000000000000000000000";
384      let amount = 10;
385  
386      let receipt = await Discover.methods.dapps(0).call();
387      let effect = await Discover.methods.upvoteEffect(id, amount).call();
388  
389      // Mock receiving the SNT
390      let mBalance = parseInt(receipt.balance, 10) + amount
391  
392      let max = await Discover.methods.max().call();
393      let decimals = await Discover.methods.decimals().call();
394  
395      let mRate = Math.round(decimals - (mBalance * decimals / max));
396      let mAvailable = mBalance * mRate;
397      let mVMinted = Math.round((mAvailable / decimals) ** (decimals / mRate));
398  
399      // Votes have been cast by this stage, so we need to check how many there are
400      // and confirm that `upvoteEffect` mocks the effect correctly
401      let votes_cast = parseInt(receipt.votesCast, 10);
402      let mEBalance = Math.round(mBalance - ((votes_cast * mRate / decimals) * (mAvailable / decimals / mVMinted)));
403      let effect_calc = mEBalance - receipt.effectiveBalance;
404  
405      // Confirm that what is returned is (mEBalance - d.effective_balance)
406      assert.strictEqual(effect_calc, parseInt(effect, 10));
407    })
408  
409    it("should throw already in upvoteEffect if you exceed the ceiling", async function () {
410      let id = "0x7465737400000000000000000000000000000000000000000000000000000000";
411      let initial = await Discover.methods.max().call();
412      let amount = parseInt(initial, 10);
413      try {
414        await Discover.methods.upvoteEffect(id, amount).call();
415        assert.fail('should have reverted before');
416      } catch (error) {
417        TestUtils.assertJump(error);
418      }
419    })
420  
421    it("should handle withdrawals correctly", async function () {
422      let id = "0x7465737400000000000000000000000000000000000000000000000000000000";
423      let amount = 100;
424  
425      let initial = await Discover.methods.dapps(0).call();
426      let before = await SNT.methods.balanceOf(Discover.options.address).call();
427      let before_dev = await SNT.methods.balanceOf(accounts[0]).call();
428      let receipt_obj = await Discover.methods.withdraw(id, amount).send({ from: accounts[0] });
429      let receipt = receipt_obj.events.Withdraw.returnValues;
430  
431      assert.strictEqual(id, receipt.id);
432  
433      // Check Discover actually sends SNT to the developer
434      let after = await SNT.methods.balanceOf(Discover.options.address).call();
435      let after_dev = await SNT.methods.balanceOf(accounts[0]).call();
436      let difference = parseInt(before, 10) - parseInt(after, 10);
437      let difference_dev = parseInt(after_dev, 10) - parseInt(before_dev, 10);
438  
439      assert.strictEqual(difference, amount)
440      assert.strictEqual(difference_dev, amount)
441  
442      // Recalculate e_balance manually and check it matches what is returned
443      let max = await Discover.methods.max().call();
444      let decimals = await Discover.methods.decimals().call();
445  
446      let balance = parseInt(initial.balance, 10) - amount
447      let rate = Math.round(decimals - (balance * decimals / max));
448      let available = Math.round(balance * rate);
449      let v_minted = Math.round((available / decimals) ** (decimals / rate));
450      let v_cast = parseInt(initial.votesCast, 10);
451      let e_balance = Math.ceil(balance - ((v_cast * rate / decimals) * (available / decimals / v_minted)));
452  
453      let effective_balance = parseInt(receipt.newEffectiveBalance, 10);
454  
455      // We begin to run into precision limitations in the BancorFormula here.
456      // The higher the amount, the less accurate it becomes. Hence Math.ceil() for now.
457      assert.strictEqual(e_balance, effective_balance);
458  
459      // Having withdrawn the SNT, check that it updates the particular DApp's storage values properly
460      let check = await Discover.methods.dapps(0).call();
461  
462      let withdrawnBalance = parseInt(initial.balance, 10) - amount
463      assert.strictEqual(parseInt(check.balance, 10), withdrawnBalance);
464  
465      assert.strictEqual(parseInt(check.rate, 10), rate);
466      assert.strictEqual(parseInt(check.available, 10), available);
467      assert.strictEqual(parseInt(check.votesMinted, 10), v_minted);
468    })
469  
470    it("should not allow withdrawing more than was staked", async function () {
471      let id = "0x7465737400000000000000000000000000000000000000000000000000000000";
472      let amount = 150000;
473      try {
474        await Discover.methods.withdraw(id, amount).send({ from: accounts[0] });
475        assert.fail('should have reverted before');
476      } catch (error) {
477        TestUtils.assertJump(error);
478      }
479    })
480  
481    it("should not allow withdrawing more than was staked minus what has already been received", async function () {
482      let id = "0x7465737400000000000000000000000000000000000000000000000000000000";
483      let receipt = await Discover.methods.dapps(0).call();
484      let amount = parseInt(receipt.available, 10) + 1;
485      try {
486        await Discover.methods.withdraw(id, amount).send({ from: accounts[0] });
487        assert.fail('should have reverted before');
488      } catch (error) {
489        TestUtils.assertJump(error);
490      }
491    })
492  
493    it("should not allow anyone other than the developer to withdraw", async function () {
494      let id = "0x7465737400000000000000000000000000000000000000000000000000000000";
495      let amount = 1000;
496      try {
497        await Discover.methods.withdraw(id, amount).send({ from: accounts[1] });
498      } catch (error) {
499        TestUtils.assertJump(error);
500      }
501    })
502  
503    it("should handle downvotes after withdrawals correctly", async function () {
504      let id = "0x7465737400000000000000000000000000000000000000000000000000000000";
505      let cost = await Discover.methods.downvoteCost(id).call()
506      let amount = parseInt(cost.c, 10);
507      let developer = accounts[0];
508  
509      let initial = await Discover.methods.dapps(0).call();
510      let bal_before = await SNT.methods.balanceOf(developer).call();
511  
512      await SNT.methods.generateTokens(accounts[1], amount).send();
513      const encodedCall = Discover.methods.downvote(id, amount).encodeABI();
514      await SNT.methods.approveAndCall(Discover.options.address, amount, encodedCall).send({ from: accounts[1] });
515  
516      let receipt = await Discover.methods.dapps(0).call();
517  
518      assert.strictEqual(developer, receipt.developer);
519      assert.strictEqual(id, receipt.id);
520  
521      // Check the developer actually receives the SNT!
522      let bal_after = await SNT.methods.balanceOf(developer).call();
523      let bal_effect = parseInt(bal_after, 10) - parseInt(bal_before, 10)
524      assert.strictEqual(bal_effect, amount);
525  
526      // Balance, rate, and votes_minted remain unchanged for downvotes
527      assert.strictEqual(initial.balance, receipt.balance);
528      assert.strictEqual(initial.rate, receipt.rate);
529      assert.strictEqual(initial.votesMinted, receipt.votesMinted);
530  
531      let available = parseInt(initial.available, 10) - parseInt(cost.c, 10);
532      assert.strictEqual(available, parseInt(receipt.available, 10));
533  
534      let eff_v_cast = parseInt(receipt.votesCast, 10) - parseInt(initial.votesCast, 10);
535      assert.strictEqual(eff_v_cast, parseInt(cost.vR, 10));
536  
537      let e_balance = parseInt(initial.effectiveBalance, 10) - parseInt(cost.b, 10);
538      assert.strictEqual(e_balance, parseInt(receipt.effectiveBalance, 10));
539    })
540  
541    it("should handle upvotes after withdrawals correctly", async function () {
542      let id = "0x7465737400000000000000000000000000000000000000000000000000000000";
543      let amount = 100;
544  
545      let initial = await Discover.methods.dapps(0).call();
546      let before = await SNT.methods.balanceOf(Discover.options.address).call();
547      let up_effect = await Discover.methods.upvoteEffect(id, amount).call();
548  
549      await SNT.methods.generateTokens(accounts[0], amount).send();
550      const encodedCall = Discover.methods.upvote(id, amount).encodeABI();
551      await SNT.methods.approveAndCall(Discover.options.address, amount, encodedCall).send({ from: accounts[0] });
552  
553      let receipt = await Discover.methods.dapps(0).call();
554      let developer = accounts[0];
555  
556      assert.strictEqual(developer, receipt.developer);
557      assert.strictEqual(id, receipt.id);
558  
559      // Check Discover  actually receives the SNT!
560      let after = await SNT.methods.balanceOf(Discover.options.address).call();
561      let bal_effect = parseInt(after, 10) - parseInt(before, 10);
562      assert.strictEqual(bal_effect, amount);
563  
564      // Having received the SNT, check that it updates the particular DApp's storage values
565      let upvotedBalance = parseInt(initial.balance, 10) + amount
566      assert.strictEqual(upvotedBalance, parseInt(receipt.balance, 10));
567  
568      let max = await Discover.methods.max().call();
569      let decimals = await Discover.methods.decimals().call();
570      let rate = Math.round(decimals - (upvotedBalance * decimals / max));
571      assert.strictEqual(rate, parseInt(receipt.rate, 10));
572  
573      let available = upvotedBalance * rate;
574      assert.strictEqual(available, parseInt(receipt.available, 10));
575  
576      let votes_minted = parseInt(receipt.votesMinted, 10);
577  
578      // Votes have been cast by this stage, so we need to check how many there are
579      // and confirm that `upvote` still calculates the effective_balance correctly
580      let votes_cast = parseInt(receipt.votesCast, 10);
581  
582      let e_balance = Math.ceil(upvotedBalance - ((votes_cast * rate / decimals) * (available / decimals / votes_minted)));
583      assert.strictEqual(e_balance, parseInt(receipt.effectiveBalance, 10));
584  
585      // The effective_balance should also match upvoteEffect + initial.effectiveBalance
586      let e_balance_2 = parseInt(up_effect, 10) + parseInt(initial.effectiveBalance, 10);
587      assert.strictEqual(e_balance_2, parseInt(receipt.effectiveBalance, 10));
588    })
589  
590    it("should create a DApp without overflowing", async function () {
591      let id = "0x0000000000000000000000000000000000000000000000000000000000000001";
592      let temp = await Discover.methods.safeMax().call();
593      let amount = parseInt(temp, 10);
594      let metadata = "QmSmv5e5DYc2otwWcpUzuqmt389s3HHx651TbxDvKBFFue";
595  
596      await SNT.methods.generateTokens(accounts[0], amount).send();
597      const encodedCall = Discover.methods.createDApp(id, amount, TestUtils.getBytes32FromIpfsHash(metadata)).encodeABI();
598      await SNT.methods.approveAndCall(Discover.options.address, amount, encodedCall).send({ from: accounts[0] });
599  
600      let receipt = await Discover.methods.dapps(1).call();
601      let developer = accounts[0];
602  
603      assert.strictEqual(developer, receipt.developer);
604      assert.strictEqual(id, receipt.id);
605  
606      // Having received the SNT, check that it updates the particular DApp's storage values
607      assert.strictEqual(amount, parseInt(receipt.balance, 10));
608  
609      let max = await Discover.methods.max().call();
610      let decimals = await Discover.methods.decimals().call();
611      let rate = Math.ceil(decimals - (amount * decimals / max));
612      assert.strictEqual(rate, parseInt(receipt.rate, 10));
613  
614      let available = amount * rate;
615      assert.strictEqual(available, parseInt(receipt.available, 10));
616  
617      // It's checking that votesMinted doesn't overflow which we're really interested in here
618      let votes_minted = Math.round((available / decimals) ** (decimals / rate));
619      let returned = parseInt(receipt.votesMinted, 10);
620  
621      // Is going to be less than due to rounding inaccuracies at higher exponents
622      assert.ok(returned <= votes_minted);
623    })
624  
625    // Comment out line 268 in the contract to run this test properly and see 
626    // the BancorFormula fail to find a suitable position in the maxExponentArray
627    it("should prove we have the highest safeMax allowed for by Bancor's power approximation", async function () {
628      let id = "0x0000000000000000000000000000000000000000000000000000000000000002";
629      let max = await Discover.methods.max().call();
630      // Choose a safeMax 1% higher than is currently set
631      let safe = await Discover.methods.safeMax().call();
632      let percent = (safe / max * 100) + 1;
633      let amount = parseInt(max, 10) * percent;
634      let metadata = "QmSmv5e5DYc2otwWcpUzuqmt389s3HHx651TbxDvKBFFue";
635  
636      await SNT.methods.generateTokens(accounts[0], amount).send();
637      const encodedCall = Discover.methods.createDApp(id, amount, TestUtils.getBytes32FromIpfsHash(metadata)).encodeABI();
638  
639      try {
640        await SNT.methods.approveAndCall(Discover.options.address, amount, encodedCall).send({ from: accounts[0] });
641      } catch (error) {
642        TestUtils.assertJump(error);
643      }
644    })
645  });