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 });