From 8268a86018b0322cf1bef7c9ff467f0bff61aa0c Mon Sep 17 00:00:00 2001 From: Alejo Salles Date: Wed, 11 Apr 2018 15:23:36 -0300 Subject: [PATCH] deep stake testing from ZepCore --- test/ZepCore.test.js | 238 +++++++++++++++++++++++++------------ test/helpers/decodeLogs.js | 10 ++ 2 files changed, 169 insertions(+), 79 deletions(-) create mode 100644 test/helpers/decodeLogs.js diff --git a/test/ZepCore.test.js b/test/ZepCore.test.js index 237968e..8c8760a 100644 --- a/test/ZepCore.test.js +++ b/test/ZepCore.test.js @@ -1,17 +1,21 @@ import assertRevert from './helpers/assertRevert'; import Deployer from '../deploy/objects/Deployer'; import RegistryManager from '../deploy/objects/RegistryManager'; +import { beforeEach } from 'mocha'; + +const decodeLogs = require('./helpers/decodeLogs'); const BigNumber = web3.BigNumber; const MockZepCoreV2 = artifacts.require('MockZepCoreV2'); const KernelInstance = artifacts.require('KernelInstance'); +const KernelStakes = artifacts.require('KernelStakes'); const should = require('chai') .use(require('chai-as-promised')) .use(require('chai-bignumber')(BigNumber)) .should(); -contract('ZepCore', ([_, owner, developer, user, anotherDeveloper]) => { +contract('ZepCore', ([_, owner, developer, user, anotherDeveloper, anotherUser]) => { const newVersionCost = 2; const developerFraction = 10; @@ -37,89 +41,165 @@ contract('ZepCore', ([_, owner, developer, user, anotherDeveloper]) => { await this.zepCore.register(this.kernelInstance.address, { from: developer }).should.be.fulfilled; }); - describe('staking for registered instances', async function() { + describe('staking', async function() { const stakeValue = 42; const unstakeValue = 24; const transferValue = 10; - - beforeEach(async function () { - await this.zepToken.transfer(developer, newVersionCost, { from: owner }); - await this.zepToken.transfer(anotherDeveloper, newVersionCost, { from: owner }); - await this.zepToken.approve(this.zepCore.address, newVersionCost, { from: developer }); - await this.zepToken.approve(this.zepCore.address, newVersionCost, { from: anotherDeveloper }); - await this.zepCore.register(this.kernelInstance.address, { from: developer }); - await this.zepCore.register(this.anotherKernelInstance.address, { from: anotherDeveloper }); - - await this.zepToken.transfer(user, stakeValue, { from: owner }); - await this.zepToken.approve(this.zepCore.address, stakeValue, { from: user }); - }); - - it('should accept stakes', async function () { - const effectiveStake = stakeValue - Math.floor(stakeValue/developerFraction); - await this.zepCore.stake(this.kernelInstance.address, stakeValue, 0, { from: user }); - const staked = await this.kernelStakes.totalStakedFor(this.kernelInstance.address); - staked.should.be.bignumber.equal(effectiveStake); - const totalStaked = await this.kernelStakes.totalStaked(); - totalStaked.should.be.bignumber.equal(effectiveStake); + const tooSmallStake = developerFraction - 1; + + describe('registered instances', async function() { + + beforeEach(async function () { + await this.zepToken.transfer(developer, newVersionCost, { from: owner }); + await this.zepToken.transfer(anotherDeveloper, newVersionCost, { from: owner }); + await this.zepToken.approve(this.zepCore.address, newVersionCost, { from: developer }); + await this.zepToken.approve(this.zepCore.address, newVersionCost, { from: anotherDeveloper }); + await this.zepCore.register(this.kernelInstance.address, { from: developer }); + await this.zepCore.register(this.anotherKernelInstance.address, { from: anotherDeveloper }); + + await this.zepToken.transfer(user, stakeValue, { from: owner }); + await this.zepToken.approve(this.zepCore.address, stakeValue, { from: user }); + }); + + describe('stakes', async function () { + beforeEach(async function () { + const { receipt } = await this.zepCore.stake(this.kernelInstance.address, stakeValue, 0, { from: user }); + this.receipt = receipt; + this.totalStakedFor = await this.kernelStakes.totalStakedFor(this.kernelInstance.address); + }) + + it('should accept stakes', async function () { + const effectiveStake = stakeValue - Math.floor(stakeValue/developerFraction); + this.totalStakedFor.should.be.bignumber.equal(effectiveStake); + const totalStaked = await this.kernelStakes.totalStaked(); + totalStaked.should.be.bignumber.equal(effectiveStake); + }); + + it('should emit a Staked event with correct amount', async function () { + this.logs = decodeLogs([this.receipt.logs[1]], KernelStakes, this.kernelStakes.address); + const total = this.logs.find(l => l.event === 'Staked').args.total; + this.totalStakedFor.should.be.bignumber.equal(total); + }); + + it('should reject stakes that result in no payout to dev', async function () { + await assertRevert(this.zepCore.stake(this.kernelInstance.address, tooSmallStake, 0, { from: user })); + }); + }); + + describe('unstakes', function () { + describe('when the staker had some stake', function () { + beforeEach(async function () { + await this.zepCore.stake(this.kernelInstance.address, stakeValue, 0, { from: user }); + }); + + describe('when the requested amount is lower than the staked amount', function () { + const effectiveStake = stakeValue - Math.floor(stakeValue/developerFraction) - unstakeValue; + beforeEach(async function () { + const { receipt } = await this.zepCore.unstake(this.kernelInstance.address, unstakeValue, 0, { from: user }); + this.receipt = receipt; + }) + + it('unstakes the requested amount', async function () { + const staked = await this.kernelStakes.totalStakedFor(this.kernelInstance.address); + staked.should.be.bignumber.equal(effectiveStake); + const totalStaked = await this.kernelStakes.totalStaked(); + totalStaked.should.be.bignumber.equal(effectiveStake); + }); + + it('should emit an Unstaked event with correct amount', async function () { + this.logs = decodeLogs([this.receipt.logs[0]], KernelStakes, this.kernelStakes.address); + const total = this.logs.find(l => l.event === 'Unstaked').args.total; + total.should.be.bignumber.equal(effectiveStake); + }); + }); + + describe('when the requested amount is higher than the staked amount', function () { + it('reverts', async function () { + const tooHighUnstake = stakeValue + 1; + await assertRevert(this.zepCore.unstake(this.kernelInstance.address, tooHighUnstake, 0, { from: user})); + }); + }); + }); + + describe('when the staker had no stake', function () { + it('reverts', async function () { + await assertRevert(this.zepCore.unstake(this.kernelInstance.address, unstakeValue, 0, { from: user })); + }); + }); + }); + + describe('transfers', async function () { + it('should transfer stakes', async function () { + const effectiveStakeFirst = stakeValue - Math.floor(stakeValue/developerFraction) - transferValue; + const effectiveStakeSecond = transferValue - Math.floor(transferValue/developerFraction); + const totalEffectivelyStaked = effectiveStakeFirst + effectiveStakeSecond; + + await this.zepCore.stake(this.kernelInstance.address, stakeValue, 0, { from: user }); + await this.zepCore.transferStake(this.kernelInstance.address, this.anotherKernelInstance.address, transferValue, 0, { from: user }); + + const stakedToFirst = await this.kernelStakes.totalStakedFor(this.kernelInstance.address); + stakedToFirst.should.be.bignumber.equal(effectiveStakeFirst); + + const stakedToSecond = await this.kernelStakes.totalStakedFor(this.anotherKernelInstance.address); + stakedToSecond.should.be.bignumber.equal(effectiveStakeSecond); + + const totalStaked = await this.kernelStakes.totalStaked(); + totalStaked.should.be.bignumber.equal(totalEffectivelyStaked); + }); + }); + + describe('restakes', async function (){ + const anotherStake = 47; + const effectiveStake = stakeValue - Math.floor(stakeValue/developerFraction) + anotherStake - Math.floor(anotherStake/developerFraction); + + beforeEach(async function () { + await this.zepCore.stake(this.kernelInstance.address, stakeValue, 0, { from: user }); + }); + + it('should accept more than one stake to the same instance by the same user', async function() { + await this.zepToken.transfer(user, anotherStake, { from: owner }); + await this.zepToken.approve(this.zepCore.address, anotherStake, { from: user }); + await this.zepCore.stake(this.kernelInstance.address, anotherStake, 0, { from: user }); + + const staked = await this.kernelStakes.totalStakedFor(this.kernelInstance.address); + staked.should.be.bignumber.equal(effectiveStake); + }); + + it('should accept more than one stake to the same instance by different users', async function() { + await this.zepToken.transfer(anotherUser, anotherStake, { from: owner }); + await this.zepToken.approve(this.zepCore.address, anotherStake, { from: anotherUser }); + await this.zepCore.stake(this.kernelInstance.address, anotherStake, 0, { from: anotherUser }); + + const staked = await this.kernelStakes.totalStakedFor(this.kernelInstance.address); + staked.should.be.bignumber.equal(effectiveStake); + }); + }); }); - it('should accept unstakes', async function () { - const effectiveStake = stakeValue - Math.floor(stakeValue/developerFraction) - unstakeValue; - await this.zepCore.stake(this.kernelInstance.address, stakeValue, 0, { from: user }); - await this.zepCore.unstake(this.kernelInstance.address, unstakeValue, 0, { from: user }); - - const staked = await this.kernelStakes.totalStakedFor(this.kernelInstance.address); - staked.should.be.bignumber.equal(effectiveStake); - const totalStaked = await this.kernelStakes.totalStaked(); - totalStaked.should.be.bignumber.equal(effectiveStake); - }); - - it('should transfer stakes', async function () { - const effectiveStakeFirst = stakeValue - Math.floor(stakeValue/developerFraction) - transferValue; - const effectiveStakeSecond = transferValue - Math.floor(transferValue/developerFraction); - const totalEffectivelyStaked = effectiveStakeFirst + effectiveStakeSecond; - - await this.zepCore.stake(this.kernelInstance.address, stakeValue, 0, { from: user }); - await this.zepCore.transferStake(this.kernelInstance.address, this.anotherKernelInstance.address, transferValue, 0, { from: user }); - - const stakedToFirst = await this.kernelStakes.totalStakedFor(this.kernelInstance.address); - stakedToFirst.should.be.bignumber.equal(effectiveStakeFirst); - - const stakedToSecond = await this.kernelStakes.totalStakedFor(this.anotherKernelInstance.address); - stakedToSecond.should.be.bignumber.equal(effectiveStakeSecond); - - const totalStaked = await this.kernelStakes.totalStaked(); - totalStaked.should.be.bignumber.equal(totalEffectivelyStaked); - }); - }); - - describe('staking for unregistered instances', async function() { - const stakeValue = 42; - const unstakeValue = 24; - const transferValue = 10; - - beforeEach(async function () { - await this.zepToken.transfer(developer, newVersionCost, { from: owner }); - await this.zepToken.transfer(anotherDeveloper, newVersionCost, { from: owner }); - await this.zepToken.approve(this.zepCore.address, newVersionCost, { from: developer }); - await this.zepToken.approve(this.zepCore.address, newVersionCost, { from: anotherDeveloper }); - - await this.zepToken.transfer(user, stakeValue, { from: owner }); - await this.zepToken.approve(this.zepCore.address, stakeValue, { from: user }); - }); - - it('should reject stakes', async function () { - await assertRevert(this.zepCore.stake(this.kernelInstance.address, stakeValue, 0, { from: user })); - }); - - it('should reject unstakes', async function () { - await assertRevert(this.zepCore.unstake(this.kernelInstance.address, unstakeValue, 0, { from: user })); - }); - - it('should reject stake transfers', async function () { - await this.zepCore.register(this.kernelInstance.address, { from: developer }); - await this.zepCore.stake(this.kernelInstance.address, stakeValue, 0, { from: user }); - await assertRevert(this.zepCore.transferStake(this.kernelInstance.address, this.anotherKernelInstance.address, transferValue, 0, { from: user })); + describe('unregistered instances', async function() { + beforeEach(async function () { + await this.zepToken.transfer(developer, newVersionCost, { from: owner }); + await this.zepToken.transfer(anotherDeveloper, newVersionCost, { from: owner }); + await this.zepToken.approve(this.zepCore.address, newVersionCost, { from: developer }); + await this.zepToken.approve(this.zepCore.address, newVersionCost, { from: anotherDeveloper }); + + await this.zepToken.transfer(user, stakeValue, { from: owner }); + await this.zepToken.approve(this.zepCore.address, stakeValue, { from: user }); + }); + + it('should reject stakes', async function () { + await assertRevert(this.zepCore.stake(this.kernelInstance.address, stakeValue, 0, { from: user })); + }); + + it('should reject unstakes', async function () { + await assertRevert(this.zepCore.unstake(this.kernelInstance.address, unstakeValue, 0, { from: user })); + }); + + it('should reject stake transfers', async function () { + await this.zepCore.register(this.kernelInstance.address, { from: developer }); + await this.zepCore.stake(this.kernelInstance.address, stakeValue, 0, { from: user }); + await assertRevert(this.zepCore.transferStake(this.kernelInstance.address, this.anotherKernelInstance.address, transferValue, 0, { from: user })); + }); }); }); diff --git a/test/helpers/decodeLogs.js b/test/helpers/decodeLogs.js new file mode 100644 index 0000000..77c5734 --- /dev/null +++ b/test/helpers/decodeLogs.js @@ -0,0 +1,10 @@ +const SolidityEvent = require('web3/lib/web3/event.js'); + +function decodeLogs (logs, contract, address) { + return logs.map(log => { + const event = new SolidityEvent(null, contract.events[log.topics[0]], address); + return event.decode(log); + }); +} + +module.exports = decodeLogs