laconicd/tests/solidity/suites/staking/test/staking.js

177 lines
8.5 KiB
JavaScript
Raw Normal View History

const { assertRevert } = require('@aragon/contract-helpers-test/assertThrow')
const { bn, assertBn, MAX_UINT64 } = require('@aragon/contract-helpers-test/numbers')
const { deploy } = require('./helpers/deploy')(artifacts)
const { approveAndStake } = require('./helpers/helpers')(artifacts)
const { DEFAULT_STAKE_AMOUNT, EMPTY_DATA } = require('./helpers/constants')
const { STAKING_ERRORS } = require('./helpers/errors')
const StakingMock = artifacts.require('StakingMock')
const StandardTokenMock = artifacts.require('StandardTokenMock');
const BadTokenMock = artifacts.require('BadTokenMock')
const getTokenBalance = async (token, account) => await token.balanceOf(account)
contract('Staking app', ([owner, other]) => {
let staking, token, stakingAddress, tokenAddress
beforeEach(async () => {
const initialAmount = DEFAULT_STAKE_AMOUNT.mul(bn(1000))
const tokenContract = await StandardTokenMock.new(owner, initialAmount)
token = tokenContract
tokenAddress = tokenContract.address
await token.mint(other, DEFAULT_STAKE_AMOUNT)
const stakingContract = await StakingMock.new(tokenAddress)
staking = stakingContract
stakingAddress = stakingContract.address
})
it('has correct initial state', async () => {
assert.equal(await staking.token(), tokenAddress, "Token is wrong")
assert.equal((await staking.totalStaked()).valueOf(), 0, "Initial total staked amount should be zero")
assert.equal(await staking.supportsHistory(), true, "history support should match")
})
it('fails deploying if token is not a contract', async() => {
await assertRevert(StakingMock.new(owner)/*, STAKING_ERRORS.ERROR_TOKEN_NOT_CONTRACT*/)
})
it('stakes', async () => {
const initialOwnerBalance = await getTokenBalance(token, owner)
const initialStakingBalance = await getTokenBalance(token, stakingAddress)
await approveAndStake({ staking, from: owner })
const finalOwnerBalance = await getTokenBalance(token, owner)
const finalStakingBalance = await getTokenBalance(token, stakingAddress)
assertBn(finalOwnerBalance, initialOwnerBalance.sub(bn(DEFAULT_STAKE_AMOUNT)), "owner balance should match")
assertBn(finalStakingBalance, initialStakingBalance.add(bn(DEFAULT_STAKE_AMOUNT)), "Staking app balance should match")
assertBn(await staking.totalStakedFor(owner), bn(DEFAULT_STAKE_AMOUNT), "staked value should match")
// total stake
assertBn(await staking.totalStaked(), bn(DEFAULT_STAKE_AMOUNT), "Total stake should match")
})
it('fails staking 0 amount', async () => {
await token.approve(stakingAddress, 1)
await assertRevert(staking.stake(0, EMPTY_DATA)/*, STAKING_ERRORS.ERROR_AMOUNT_ZERO*/)
})
it('fails staking more than balance', async () => {
const balance = await getTokenBalance(token, owner)
const amount = balance.add(bn(1))
await token.approve(stakingAddress, amount)
await assertRevert(staking.stake(amount, EMPTY_DATA)/*, STAKING_ERRORS.ERROR_TOKEN_DEPOSIT*/)
})
it('stakes for', async () => {
const initialOwnerBalance = await getTokenBalance(token, owner)
const initialOtherBalance = await getTokenBalance(token, other)
const initialStakingBalance = await getTokenBalance(token, stakingAddress)
// allow Staking app to move owner tokens
await token.approve(stakingAddress, DEFAULT_STAKE_AMOUNT)
// stake tokens
await staking.stakeFor(other, DEFAULT_STAKE_AMOUNT, EMPTY_DATA)
const finalOwnerBalance = await getTokenBalance(token, owner)
const finalOtherBalance = await getTokenBalance(token, other)
const finalStakingBalance = await getTokenBalance(token, stakingAddress)
assertBn(finalOwnerBalance, initialOwnerBalance.sub(bn(DEFAULT_STAKE_AMOUNT)), "owner balance should match")
assertBn(finalOtherBalance, initialOtherBalance, "other balance should match")
assertBn(finalStakingBalance, initialStakingBalance.add(bn(DEFAULT_STAKE_AMOUNT)), "Staking app balance should match")
assertBn(await staking.totalStakedFor(owner), bn(0), "staked value for owner should match")
assertBn(await staking.totalStakedFor(other), bn(DEFAULT_STAKE_AMOUNT), "staked value for other should match")
})
it('unstakes', async () => {
const initialOwnerBalance = await getTokenBalance(token, owner)
const initialStakingBalance = await getTokenBalance(token, stakingAddress)
await approveAndStake({ staking, from: owner })
// unstake half of them
await staking.unstake(DEFAULT_STAKE_AMOUNT.div(bn(2)), EMPTY_DATA)
const finalOwnerBalance = await getTokenBalance(token, owner)
const finalStakingBalance = await getTokenBalance(token, stakingAddress)
assertBn(finalOwnerBalance, initialOwnerBalance.sub(bn(DEFAULT_STAKE_AMOUNT.div(bn(2)))), "owner balance should match")
assertBn(finalStakingBalance, initialStakingBalance.add(bn(DEFAULT_STAKE_AMOUNT.div(bn(2)))), "Staking app balance should match")
assertBn(await staking.totalStakedFor(owner), bn(DEFAULT_STAKE_AMOUNT.div(bn(2))), "staked value should match")
})
it('fails unstaking 0 amount', async () => {
await approveAndStake({ staking, from: owner })
await assertRevert(staking.unstake(0, EMPTY_DATA)/*, STAKING_ERRORS.ERROR_AMOUNT_ZERO*/)
})
it('fails unstaking more than staked', async () => {
await approveAndStake({ staking, from: owner })
await assertRevert(staking.unstake(DEFAULT_STAKE_AMOUNT.add(bn(1)), EMPTY_DATA)/*, STAKING_ERRORS.ERROR_NOT_ENOUGH_BALANCE*/)
})
context('History', async () => {
it('supports history', async () => {
assert.equal(await staking.supportsHistory(), true, "It should support History")
})
it('has correct "last staked for"', async () => {
const blockNumber = await staking.getBlockNumberPublic()
const lastStaked = blockNumber.add(bn(5))
await staking.setBlockNumber(lastStaked)
await approveAndStake({ staking, from: owner })
assertBn(await staking.lastStakedFor(owner), lastStaked, "Last staked for should match")
})
it('has correct "total staked for at"', async () => {
const beforeBlockNumber = await staking.getBlockNumberPublic()
const lastStaked = beforeBlockNumber.add(bn(5))
await staking.setBlockNumber(lastStaked)
await approveAndStake({ staking, from: owner })
assertBn(await staking.totalStakedForAt(owner, beforeBlockNumber), bn(0), "Staked for at before staking should match")
assertBn(await staking.totalStakedForAt(owner, lastStaked), bn(DEFAULT_STAKE_AMOUNT), "Staked for after staking should match")
})
it('has correct "total staked at"', async () => {
const beforeBlockNumber = await staking.getBlockNumberPublic()
const lastStaked = beforeBlockNumber.add(bn(5))
await staking.setBlockNumber(lastStaked)
await approveAndStake({ staking, from: owner })
await approveAndStake({ staking, from: other })
assertBn(await staking.totalStakedAt(beforeBlockNumber), bn(0), "Staked for at before should match")
assertBn(await staking.totalStakedAt(lastStaked), bn(DEFAULT_STAKE_AMOUNT.mul(bn(2))), "Staked for at after staking should match")
})
it('fails to call totalStakedForAt with block number greater than max uint64', async () => {
await assertRevert(staking.totalStakedForAt(owner, MAX_UINT64.add(bn(1)))/*, STAKING_ERRORS.ERROR_BLOCKNUMBER_TOO_BIG*/)
})
it('fails to call totalStakedAt with block number greater than max uint64', async () => {
await assertRevert(staking.totalStakedAt(MAX_UINT64.add(bn(1)))/*, STAKING_ERRORS.ERROR_BLOCKNUMBER_TOO_BIG*/)
})
})
context('Bad Token', async () => {
let badStaking, badStakingAddress, badToken, badTokenAddress
beforeEach(async () => {
const initialAmount = DEFAULT_STAKE_AMOUNT.mul(bn(1000))
const tokenContract = await BadTokenMock.new(owner, initialAmount)
badToken = tokenContract
badTokenAddress = tokenContract.address
await badToken.mint(other, DEFAULT_STAKE_AMOUNT)
const stakingContract = await StakingMock.new(badTokenAddress)
badStaking = stakingContract
badStakingAddress = stakingContract.address
})
it('fails unstaking because of bad token', async () => {
// allow Staking app to move owner tokens
await badToken.approve(badStakingAddress, DEFAULT_STAKE_AMOUNT, { from: owner })
// stake tokens
await badStaking.stake(DEFAULT_STAKE_AMOUNT, EMPTY_DATA, { from: owner })
// unstake half of them, fails on token transfer
await assertRevert(badStaking.unstake(DEFAULT_STAKE_AMOUNT.div(bn(2)), EMPTY_DATA)/*, STAKING_ERRORS.ERROR_TOKEN_TRANSFER*/)
})
})
})