laconicd/tests-solidity/suites/staking/test/locking/locking.js
Brett Sun c9639c3860
tests: add solidity test suites (#487)
* tests: add solidity test suite

* tests: remove require strings

* Update tests-solidity/init-test-node.sh

* Update tests-solidity/init-test-node.sh

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
2020-09-01 17:16:28 -04:00

396 lines
18 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const { assertRevert } = require('@aragon/contract-helpers-test/assertThrow')
const { bn, bigExp, assertBn, MAX_UINT64 } = require('@aragon/contract-helpers-test/numbers')
const { deploy } = require('../helpers/deploy')(artifacts)
const { approveAndStake, approveStakeAndLock } = require('../helpers/helpers')(artifacts)
const { DEFAULT_STAKE_AMOUNT, DEFAULT_LOCK_AMOUNT, EMPTY_DATA, ZERO_ADDRESS } = require('../helpers/constants')
const { STAKING_ERRORS } = require('../helpers/errors')
contract('Staking app, Locking', ([owner, user1, user2]) => {
let staking, lockManager
beforeEach(async () => {
const deployment = await deploy(owner)
staking = deployment.staking
lockManager = deployment.lockManager
})
it('allows new manager and locks amount', async () => {
await approveStakeAndLock({ staking, manager: user1, from: owner })
// check lock values
const { _amount, _allowance } = await staking.getLock(owner, user1)
assertBn(_amount, DEFAULT_LOCK_AMOUNT, "locked amount should match")
assertBn(_allowance, DEFAULT_LOCK_AMOUNT, "locked allowance should match")
assertBn(await staking.unlockedBalanceOf(owner), DEFAULT_STAKE_AMOUNT.sub(DEFAULT_LOCK_AMOUNT), "Unlocked balance should match")
const { staked, locked } = await staking.getBalancesOf(owner)
assertBn(staked, DEFAULT_STAKE_AMOUNT, "Staked balance should match")
assertBn(locked, DEFAULT_LOCK_AMOUNT, "Locked balance should match")
})
it('fails locking 0 tokens', async () => {
await approveAndStake({ staking, from: owner })
await assertRevert(staking.allowManagerAndLock(0, user1, 1, EMPTY_DATA), STAKING_ERRORS.ERROR_AMOUNT_ZERO)
})
it('fails locking without enough allowance', async () => {
await approveAndStake({ staking, from: owner })
await assertRevert(staking.allowManagerAndLock(2, user1, 1, EMPTY_DATA), STAKING_ERRORS.ERROR_NOT_ENOUGH_ALLOWANCE)
})
it('fails locking more tokens than staked', async () => {
await approveAndStake({ staking, from: owner })
await assertRevert(staking.allowManagerAndLock(DEFAULT_STAKE_AMOUNT.add(bn(1)), user1, DEFAULT_STAKE_AMOUNT.add(bn(1)), EMPTY_DATA), STAKING_ERRORS.ERROR_NOT_ENOUGH_BALANCE)
})
it('fails locking if already locked', async () => {
await approveStakeAndLock({ staking, manager: user1, from: owner })
await approveAndStake({ staking, from: owner })
await assertRevert(staking.allowManagerAndLock(DEFAULT_STAKE_AMOUNT, user1, DEFAULT_STAKE_AMOUNT, "0x02"), STAKING_ERRORS.ERROR_LOCK_ALREADY_EXISTS)
})
it('fails unstaking locked tokens', async () => {
await approveStakeAndLock({ staking, manager: user1, from: owner })
await assertRevert(staking.unstake(DEFAULT_STAKE_AMOUNT, EMPTY_DATA), STAKING_ERRORS.ERROR_NOT_ENOUGH_BALANCE)
})
it('creates a new allowance', async () => {
await staking.allowManager(user1, DEFAULT_LOCK_AMOUNT, EMPTY_DATA)
const { _allowance } = await staking.getLock(owner, user1)
assertBn(_allowance, DEFAULT_LOCK_AMOUNT, "allowed amount should match")
})
it('creates a new allowance and then lock manager locks', async () => {
await approveAndStake({ staking, from: owner })
await staking.allowManager(user1, DEFAULT_LOCK_AMOUNT, EMPTY_DATA)
await staking.lock(owner, user1, DEFAULT_LOCK_AMOUNT, { from: user1 })
// check lock values
const { _amount, _allowance } = await staking.getLock(owner, user1)
assertBn(_amount, DEFAULT_LOCK_AMOUNT, "locked amount should match")
assertBn(_allowance, DEFAULT_LOCK_AMOUNT, "locked allowance should match")
assertBn(await staking.unlockedBalanceOf(owner), DEFAULT_STAKE_AMOUNT.sub(DEFAULT_LOCK_AMOUNT), "Unlocked balance should match")
})
it('fails creating allowance of 0 tokens', async () => {
await assertRevert(staking.allowManager(user1, 0, EMPTY_DATA), STAKING_ERRORS.ERROR_AMOUNT_ZERO)
})
it('fails creating allowance if lock exists', async () => {
await approveStakeAndLock({ staking, manager: user1, from: owner })
await assertRevert(staking.allowManager(user1, 1, EMPTY_DATA), STAKING_ERRORS.ERROR_LOCK_ALREADY_EXISTS)
})
it('increases allowance of existing lock', async () => {
await approveStakeAndLock({ staking, manager: user1, from: owner })
await staking.increaseLockAllowance(user1, DEFAULT_LOCK_AMOUNT)
const { _allowance } = await staking.getLock(owner, user1)
assertBn(_allowance, DEFAULT_LOCK_AMOUNT.mul(bn(2)), "allowed amount should match")
})
it('fails increasing allowance of non-existing', async () => {
await assertRevert(staking.increaseLockAllowance(user1, 1), STAKING_ERRORS.ERROR_LOCK_DOES_NOT_EXIST)
})
it('fails increasing allowance of existing lock by 0', async () => {
await approveStakeAndLock({ staking, manager: user1, from: owner })
await assertRevert(staking.increaseLockAllowance(user1, 0), STAKING_ERRORS.ERROR_AMOUNT_ZERO)
})
it('fails increasing allowance of existing lock if not owner or manager', async () => {
await approveStakeAndLock({ staking, manager: user1, from: owner })
await assertRevert(staking.increaseLockAllowance(user1, 1, { from: user2 }), STAKING_ERRORS.ERROR_LOCK_DOES_NOT_EXIST)
})
it('decreases allowance of existing lock by the owner', async () => {
await approveAndStake({ staking, from: owner })
await staking.allowManagerAndLock(DEFAULT_LOCK_AMOUNT, user1, DEFAULT_LOCK_AMOUNT.add(bn(1)), EMPTY_DATA)
await staking.decreaseLockAllowance(owner, user1, 1, { from: owner })
const { _allowance } = await staking.getLock(owner, user1)
assertBn(_allowance, DEFAULT_LOCK_AMOUNT, "allowed amount should match")
})
it('decreases allowance of existing lock by manager', async () => {
await approveAndStake({ staking, from: owner })
await staking.allowManagerAndLock(DEFAULT_LOCK_AMOUNT, user1, DEFAULT_LOCK_AMOUNT.add(bn(1)), EMPTY_DATA)
await staking.decreaseLockAllowance(owner, user1, 1, { from: user1 })
const { _allowance } = await staking.getLock(owner, user1)
assertBn(_allowance, DEFAULT_LOCK_AMOUNT, "allowed amount should match")
})
it('fails decreasing allowance of existing lock by 0', async () => {
await approveStakeAndLock({ staking, manager: user1, from: owner })
await assertRevert(staking.decreaseLockAllowance(owner, user1, 0), STAKING_ERRORS.ERROR_AMOUNT_ZERO)
})
it('fails decreasing allowance of existing lock to 0', async () => {
await approveStakeAndLock({ staking, manager: user1, from: owner })
await staking.unlock(owner, user1, DEFAULT_LOCK_AMOUNT, { from: user1 })
await assertRevert(staking.decreaseLockAllowance(owner, user1, DEFAULT_LOCK_AMOUNT), STAKING_ERRORS.ERROR_ALLOWANCE_ZERO)
})
it('fails decreasing allowance to less than lock', async () => {
await approveAndStake({ staking, from: owner })
await staking.allowManagerAndLock(DEFAULT_LOCK_AMOUNT, user1, DEFAULT_LOCK_AMOUNT.add(bn(1)), EMPTY_DATA)
await assertRevert(staking.decreaseLockAllowance(owner, user1, 2), STAKING_ERRORS.ERROR_NOT_ENOUGH_ALLOWANCE)
})
it('fails decreasing allowance by 3rd party', async () => {
await approveAndStake({ staking, from: owner })
await staking.allowManagerAndLock(DEFAULT_LOCK_AMOUNT, user1, DEFAULT_LOCK_AMOUNT.add(bn(1)), EMPTY_DATA)
await assertRevert(staking.decreaseLockAllowance(owner, user1, 1, { from: user2 }), STAKING_ERRORS.ERROR_CANNOT_CHANGE_ALLOWANCE)
})
it('increases amount of existing lock', async () => {
await approveStakeAndLock({ staking, manager: user1, from: owner })
await approveAndStake({ staking, from: owner })
await staking.increaseLockAllowance(user1, DEFAULT_LOCK_AMOUNT)
await staking.lock(owner, user1, DEFAULT_LOCK_AMOUNT)
const { _amount } = await staking.getLock(owner, user1)
assertBn(_amount, DEFAULT_LOCK_AMOUNT.mul(bn(2)), "locked amount should match")
})
it('fails increasing lock with 0 tokens', async () => {
await approveStakeAndLock({ staking, manager: user1, from: owner })
await approveAndStake({ staking, from: owner })
await assertRevert(staking.lock(owner, user1, 0), STAKING_ERRORS.ERROR_AMOUNT_ZERO)
})
it('fails increasing lock with more tokens than staked', async () => {
await approveStakeAndLock({ staking, manager: user1, from: owner })
await approveAndStake({ staking, from: owner })
await assertRevert(staking.lock(owner, user1, DEFAULT_STAKE_AMOUNT.mul(bn(2)).add(bn(1))), STAKING_ERRORS.ERROR_NOT_ENOUGH_BALANCE)
})
it('fails increasing lock if not owner or manager', async () => {
await approveStakeAndLock({ staking, manager: user1, from: owner })
await approveAndStake({ staking, from: owner })
await assertRevert(staking.lock(owner, user1, 1, { from: user2 }), STAKING_ERRORS.ERROR_SENDER_NOT_ALLOWED)
})
it('unlocks with only 1 lock, EOA manager', async () => {
await approveStakeAndLock({ staking, manager: user1, lockAmount: DEFAULT_LOCK_AMOUNT, from: owner })
// unlock
await staking.unlockAndRemoveManager(owner, user1, { from: user1 })
assertBn(await staking.unlockedBalanceOf(owner), DEFAULT_STAKE_AMOUNT, "Unlocked balance should match")
assertBn(await staking.lockedBalanceOf(owner), bn(0), "total locked doesnt match")
})
it('unlocks with more than 1 lock, EOA manager', async () => {
await approveStakeAndLock({ staking, manager: user1, from: owner })
// lock again
await staking.allowManagerAndLock(DEFAULT_LOCK_AMOUNT, user2, DEFAULT_LOCK_AMOUNT, EMPTY_DATA)
const previousTotalLocked = await staking.lockedBalanceOf(owner)
// unlock
await staking.unlockAndRemoveManager(owner, user1, { from: user1 })
assertBn(await staking.unlockedBalanceOf(owner), DEFAULT_STAKE_AMOUNT.sub(DEFAULT_LOCK_AMOUNT), "Unlocked balance should match")
assertBn(await staking.lockedBalanceOf(owner), previousTotalLocked.sub(bn(DEFAULT_LOCK_AMOUNT)), "total locked doesnt match")
})
it('unlocks completely, contract manager, called by owner', async () => {
await lockManager.setResult(true)
await approveStakeAndLock({ staking, manager: lockManager.address, from: owner })
// unlock
await staking.unlockAndRemoveManager(owner, lockManager.address, { from: owner })
assertBn(await staking.unlockedBalanceOf(owner), DEFAULT_STAKE_AMOUNT, "Unlocked balance should match")
assertBn(await staking.lockedBalanceOf(owner), bn(0), "total locked doesnt match")
})
it('unlocks completely, contract manager, called by manager', async () => {
await lockManager.setResult(true)
await approveStakeAndLock({ staking, manager: lockManager.address, from: owner })
// unlock
await lockManager.unlockAndRemoveManager(staking.address, owner, lockManager.address)
assertBn(await staking.unlockedBalanceOf(owner), DEFAULT_STAKE_AMOUNT, "Unlocked balance should match")
assertBn(await staking.lockedBalanceOf(owner), bn(0), "total locked doesnt match")
})
it('unlocks completely, contract manager, called by manager, even if condition is not satisfied', async () => {
// not needed, is false by default
//await lockManager.setResult(false)
await approveStakeAndLock({ staking, manager: lockManager.address, from: owner })
// unlock
await lockManager.unlockAndRemoveManager(staking.address, owner, lockManager.address)
assertBn(await staking.unlockedBalanceOf(owner), DEFAULT_STAKE_AMOUNT, "Unlocked balance should match")
assertBn(await staking.lockedBalanceOf(owner), bn(0), "total locked doesnt match")
})
it('fails calling canUnlock, EOA manager', async () => {
await approveStakeAndLock({ staking, manager: user1, from: owner })
// call canUnlock
await assertRevert(staking.canUnlock(owner, owner, user1, 0)) // no reason: its trying to call an EOA
})
it('can unlock if amount is zero', async () => {
await staking.allowManager(user1, DEFAULT_LOCK_AMOUNT, EMPTY_DATA, { from: owner })
assert.isTrue(await staking.canUnlock(owner, owner, user1, 0))
})
it('fails to unlock if it cannot unlock, EOA manager', async () => {
await approveStakeAndLock({ staking, manager: user1, from: owner })
// tries to unlock
await assertRevert(staking.unlockAndRemoveManager(owner, user1)) // no reason: its trying to call an EOA
})
it('fails to unlock if can not unlock, contract manager, called by owner', async () => {
// not needed, is false by default
// await lockManager.setResult(false)
await approveStakeAndLock({ staking, manager: lockManager.address, from: owner })
// tries to unlock
await assertRevert(staking.unlockAndRemoveManager(owner, lockManager.address, { from: owner }), STAKING_ERRORS.ERROR_CANNOT_UNLOCK)
})
it('fails to unlock if, contract manager, called by 3rd party (even if condition is true)', async () => {
await lockManager.setResult(true)
await approveStakeAndLock({ staking, manager: lockManager.address, from: owner })
// tries to unlock
await assertRevert(staking.unlockAndRemoveManager(owner, lockManager.address, { from: user1 }), STAKING_ERRORS.ERROR_CANNOT_UNLOCK)
})
it('transfers (slash) and unlocks (everything else) in one transaction', async () => {
const totalLock = bigExp(120, 18)
const transferAmount = bigExp(40, 18)
await approveStakeAndLock({ staking, manager: user1, allowanceAmount: totalLock, lockAmount: totalLock, stakeAmount: totalLock, from: owner })
// unlock and transfer
await staking.slashAndUnlock(owner, user2, totalLock.sub(transferAmount), transferAmount, { from: user1 })
assertBn(await staking.unlockedBalanceOf(owner), totalLock.sub(transferAmount), "Unlocked balance should match")
assertBn(await staking.lockedBalanceOf(owner), bn(0), "total locked doesnt match")
// lock manager
assertBn(await staking.unlockedBalanceOf(user1), bn(0), "Unlocked balance should match")
assertBn(await staking.lockedBalanceOf(user1), bn(0), "total locked doesnt match")
// recipient
assertBn(await staking.unlockedBalanceOf(user2), transferAmount, "Unlocked balance should match")
assertBn(await staking.lockedBalanceOf(user2), bn(0), "total locked doesnt match")
})
it('transfers (slash) and unlocks in one transaction', async () => {
const totalLock = bigExp(120, 18)
const transferAmount = bigExp(40, 18)
const decreaseAmount = bigExp(60, 18)
await approveStakeAndLock({ staking, manager: user1, allowanceAmount: totalLock, lockAmount: totalLock, stakeAmount: totalLock, from: owner })
// unlock and transfer
await staking.slashAndUnlock(owner, user2, decreaseAmount, transferAmount, { from: user1 })
assertBn(await staking.unlockedBalanceOf(owner), decreaseAmount, "Unlocked balance should match")
assertBn(await staking.lockedBalanceOf(owner), totalLock.sub(decreaseAmount).sub(transferAmount), "total locked doesnt match")
// lock manager
assertBn(await staking.unlockedBalanceOf(user1), bn(0), "Unlocked balance should match")
assertBn(await staking.lockedBalanceOf(user1), bn(0), "total locked doesnt match")
// recipient
assertBn(await staking.unlockedBalanceOf(user2), transferAmount, "Unlocked balance should match")
assertBn(await staking.lockedBalanceOf(user2), bn(0), "total locked doesnt match")
})
it('fails to transfer (slash) and unlocks in one transaction if unlock amount is zero', async () => {
const totalLock = bigExp(120, 18)
const transferAmount = bigExp(40, 18)
const decreaseAmount = bigExp(0, 18)
await approveStakeAndLock({ staking, manager: user1, allowanceAmount: totalLock, lockAmount: totalLock, stakeAmount: totalLock, from: owner })
// unlock and transfer
await assertRevert(staking.slashAndUnlock(owner, user2, decreaseAmount, transferAmount, { from: user1 }), STAKING_ERRORS.ERROR_AMOUNT_ZERO)
})
it('fails to transfer (slash) and unlock in one transaction if not owner nor manager', async () => {
const totalLock = bigExp(120, 18)
const transferAmount = bigExp(40, 18)
const decreaseAmount = bigExp(60, 18)
await approveStakeAndLock({ staking, manager: user1, allowanceAmount: totalLock, lockAmount: totalLock, stakeAmount: totalLock, from: owner })
// unlock and transfer
await assertRevert(staking.slashAndUnlock(owner, user2, decreaseAmount, transferAmount, { from: user2 }), STAKING_ERRORS.ERROR_NOT_ENOUGH_LOCK)
})
it('change lock amount', async () => {
await approveStakeAndLock({ staking, manager: lockManager.address, from: owner })
const { _amount: amount1 } = await staking.getLock(owner, lockManager.address)
assertBn(amount1, bn(DEFAULT_LOCK_AMOUNT), "Amount should match")
assertBn(await staking.unlockedBalanceOf(owner), DEFAULT_STAKE_AMOUNT.sub(DEFAULT_LOCK_AMOUNT), "Unlocked balance should match")
// change amount
const unlockAmount = DEFAULT_LOCK_AMOUNT.div(bn(2))
await lockManager.unlock(staking.address, owner, unlockAmount)
const { _amount: amount2 } = await staking.getLock(owner, lockManager.address)
assertBn(amount2, unlockAmount, "Amount should match")
assertBn(await staking.unlockedBalanceOf(owner), DEFAULT_STAKE_AMOUNT.sub(unlockAmount), "Unlocked balance should match")
})
it('fails to change lock amount to zero', async () => {
await approveStakeAndLock({ staking, manager: lockManager.address, from: owner })
// try to change amount
await assertRevert(lockManager.unlock(staking.address, owner, 0), STAKING_ERRORS.ERROR_AMOUNT_ZERO)
})
it('fails to change lock amount to greater than before', async () => {
await approveStakeAndLock({ staking, manager: lockManager.address, from: owner })
// try to change amount
await assertRevert(lockManager.unlock(staking.address, owner, DEFAULT_LOCK_AMOUNT.add(bn(1))), STAKING_ERRORS.ERROR_NOT_ENOUGH_LOCK)
})
it('change lock manager', async () => {
await approveStakeAndLock({ staking, manager: user1, from: owner })
assert.equal(await staking.canUnlock(user1, owner, user1, 0), true, "User 1 can unlock")
assert.equal(await staking.canUnlock(user2, owner, user1, 0), false, "User 2 can not unlock")
await assertRevert(staking.canUnlock(user2, owner, user2, 0), STAKING_ERRORS.ERROR_LOCK_DOES_NOT_EXIST) // it doesnt exist
// change manager
await staking.setLockManager(owner, user2, { from: user1 })
await assertRevert(staking.canUnlock(user1, owner, user1, 0), STAKING_ERRORS.ERROR_LOCK_DOES_NOT_EXIST) // it doesnt exist
assert.equal(await staking.canUnlock(user1, owner, user2, 0), false, "User 1 can not unlock")
assert.equal(await staking.canUnlock(user2, owner, user2, 0), true, "User 2 can unlock")
})
it('fails to change lock manager if it doesnt exist', async () => {
await assertRevert(staking.setLockManager(owner, user2, { from: user1 }), STAKING_ERRORS.ERROR_LOCK_DOES_NOT_EXIST)
})
})