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