UNPKG

@aragon/apps-payroll

Version:

_**Code in Github:**_ [aragon-apps/apps/payroll](https://github.com/aragon/aragon-apps/tree/master/future-apps/payroll)

548 lines (436 loc) 30.5 kB
const PAYMENT_TYPES = require('../helpers/payment_types') const { getEvents } = require('@aragon/test-helpers/events') const { bigExp, ONE } = require('../helpers/numbers')(web3) const { NOW, TWO_MINUTES, RATE_EXPIRATION_TIME } = require('../helpers/time') const { deployContracts, createPayrollAndPriceFeed } = require('../helpers/deploy')(artifacts, web3) const { USD, ETH, ETH_RATE, deployDAI, DAI_RATE, deployANT, ANT_RATE, formatRate, inverseRate, setTokenRate } = require('../helpers/tokens')(artifacts, web3) contract('Payroll rates handling', ([owner, employee, anyone]) => { let dao, payroll, payrollBase, finance, vault, priceFeed, DAI, ANT const increaseTime = async seconds => { await payroll.mockIncreaseTime(seconds) await priceFeed.mockIncreaseTime(seconds) } before('deploy contracts and tokens', async () => { ({ dao, finance, vault, payrollBase } = await deployContracts(owner)) DAI = await deployDAI(owner, finance) ANT = await deployANT(owner, finance) await finance.deposit(ETH, bigExp(50, 18), 'Initial ETH deposit', { from: anyone, value: bigExp(50, 18) }) }) context('when the denomination token is USD', async () => { beforeEach('initialize payroll app', async () => { ({ payroll, priceFeed } = await createPayrollAndPriceFeed(dao, payrollBase, owner, NOW)) await payroll.initialize(finance.address, USD, priceFeed.address, RATE_EXPIRATION_TIME, { from: owner }) }) beforeEach('set rates and allow tokens', async () => { await setTokenRate(priceFeed, USD, ETH, ETH_RATE) await setTokenRate(priceFeed, USD, DAI, DAI_RATE) await setTokenRate(priceFeed, USD, ANT, ANT_RATE) await payroll.setAllowedToken(ETH, true, { from: owner }) await payroll.setAllowedToken(DAI.address, true, { from: owner }) await payroll.setAllowedToken(ANT.address, true, { from: owner }) }) beforeEach('add employee with salary 1 USD per second', async () => { const salary = bigExp(1, 18) await payroll.addEmployee(employee, salary, await payroll.getTimestampPublic(), 'Boss') }) beforeEach('accrue two minutes of salary', async () => { await increaseTime(TWO_MINUTES) }) context('when the employee requests only ETH', () => { beforeEach('set token allocation', async () => { await payroll.determineAllocation([ETH], [100], { from: employee }) }) it('receives the expected amount of ETH', async () => { const previousETH = await web3.eth.getBalance(employee) const previousDAI = await DAI.balanceOf(employee) const previousANT = await ANT.balanceOf(employee) const { tx, receipt, logs } = await payroll.payday(PAYMENT_TYPES.PAYROLL, 0, [inverseRate(ETH_RATE)], { from: employee }) const { gasPrice } = await web3.eth.getTransaction(tx) const txCost = gasPrice.mul(receipt.gasUsed) const events = getEvents({ logs }, 'SendPayment') assert.equal(events.length, 1, 'should have emitted one event') // expected an income of 6 ETH since we accrued 2 minutes of salary at 1 USD per second, and the ETH rate is 20 USD const currentETH = await web3.eth.getBalance(employee) assert.equal(currentETH.minus(previousETH).plus(txCost).toString(), bigExp(6, 18).toString(), 'expected current ETH amount does not match') const eventETH = events.find(e => e.args.token === ETH).args assert.equal(eventETH.exchangeRate.toString(), inverseRate(ETH_RATE).toString(), 'ETH exchange rate does not match') // no DAI income expected const currentDAI = await DAI.balanceOf(employee) assert.equal(currentDAI.toString(), previousDAI.toString(), 'expected current DAI amount does not match') // no ANT income expected const currentANT = await ANT.balanceOf(employee) assert.equal(currentANT.toString(), previousANT.toString(), 'expected current ANT amount does not match') }) }) context('when the employee requests only ANT', () => { beforeEach('set token allocation', async () => { await payroll.determineAllocation([ANT.address], [100], { from: employee }) }) it('receives the expected amount of ANT', async () => { const previousETH = await web3.eth.getBalance(employee) const previousDAI = await DAI.balanceOf(employee) const previousANT = await ANT.balanceOf(employee) const { tx, receipt, logs } = await payroll.payday(PAYMENT_TYPES.PAYROLL, 0, [inverseRate(ANT_RATE)], { from: employee }) const { gasPrice } = await web3.eth.getTransaction(tx) const txCost = gasPrice.mul(receipt.gasUsed) const events = getEvents({ logs }, 'SendPayment') assert.equal(events.length, 1, 'should have emitted one event') // no ETH income expected const currentETH = await web3.eth.getBalance(employee) assert.equal(currentETH.plus(txCost).toString(), previousETH.toString(), 'expected current ETH amount does not match') // no DAI income expected const currentDAI = await DAI.balanceOf(employee) assert.equal(currentDAI.toString(), previousDAI.toString(), 'expected current DAI amount does not match') // expected an income of 240 ANT since we accrued 2 minutes of salary at 1 USD per second, and the ANT rate is 0.5 USD const currentANT = await ANT.balanceOf(employee) assert.equal(currentANT.minus(previousANT).toString(), bigExp(240, 18).toString(), 'expected current ANT amount does not match') const eventANT = events.find(e => e.args.token === ANT.address).args assert.equal(eventANT.exchangeRate.toString(), inverseRate(ANT_RATE).toString(), 'ANT exchange rate does not match') }) }) context('when the employee requests multiple tokens', () => { beforeEach('set token allocations', async () => { await payroll.determineAllocation([ETH, DAI.address, ANT.address], [50, 25, 25], { from: employee }) }) it('receives the expected amount of tokens', async () => { const previousETH = await web3.eth.getBalance(employee) const previousDAI = await DAI.balanceOf(employee) const previousANT = await ANT.balanceOf(employee) const { tx, receipt, logs } = await payroll.payday(PAYMENT_TYPES.PAYROLL, 0, [inverseRate(ETH_RATE), inverseRate(DAI_RATE), inverseRate(ANT_RATE)], { from: employee }) const { gasPrice } = await web3.eth.getTransaction(tx) const txCost = gasPrice.mul(receipt.gasUsed) const events = getEvents({ logs }, 'SendPayment') assert.equal(events.length, 3, 'should have emitted three events') // expected an income of 3 ETH having 50% allocated, since we accrued 2 minutes of salary at 1 USD per second, and the ETH rate is 20 USD const currentETH = await web3.eth.getBalance(employee) assert.equal(currentETH.minus(previousETH).plus(txCost).toString(), bigExp(3, 18).toString(), 'expected current ETH amount does not match') const eventETH = events.find(e => e.args.token === ETH).args assert.equal(eventETH.exchangeRate.toString(), inverseRate(ETH_RATE).toString(), 'ETH exchange rate does not match') // expected an income of 30 DAI having 25% allocated, since we accrued 2 minutes of salary at 1 USD per second, and the DAI rate is 1 USD const currentDAI = await DAI.balanceOf(employee) assert.equal(currentDAI.minus(previousDAI).toString(), bigExp(30, 18).toString(), 'expected current DAI amount does not match') const eventDAI = events.find(e => e.args.token === DAI.address).args assert.equal(eventDAI.exchangeRate.toString(), inverseRate(DAI_RATE).toString(), 'DAI exchange rate does not match') // expected an income of 60 ANT having 25% allocated, since we accrued 2 minutes of salary at 1 USD per second, and the ANT rate is 0.5 USD const currentANT = await ANT.balanceOf(employee) assert.equal(currentANT.minus(previousANT).toString(), bigExp(60, 18).toString(), 'expected current ANT amount does not match') const eventANT = events.find(e => e.args.token === ANT.address).args assert.equal(eventANT.exchangeRate.toString(), inverseRate(ANT_RATE).toString(), 'ANT exchange rate does not match') }) }) }) context('when the denomination token is ETH', async () => { const ETH_TO_DAI_RATE = formatRate(ETH_RATE.div(DAI_RATE)) // 20 DAI const ETH_TO_ANT_RATE = formatRate(ETH_RATE.div(ANT_RATE)) // 40 ANT beforeEach('initialize payroll app', async () => { ({ payroll, priceFeed } = await createPayrollAndPriceFeed(dao, payrollBase, owner, NOW)) await payroll.initialize(finance.address, ETH, priceFeed.address, RATE_EXPIRATION_TIME, { from: owner }) }) beforeEach('set rates and allow tokens', async () => { // Note that we set ETH as the quote token for these tests so we don't need to apply the // inversion when checking rates await setTokenRate(priceFeed, DAI, ETH, ETH_TO_DAI_RATE) await setTokenRate(priceFeed, ANT, ETH, ETH_TO_ANT_RATE) await payroll.setAllowedToken(ETH, true, { from: owner }) await payroll.setAllowedToken(DAI.address, true, { from: owner }) await payroll.setAllowedToken(ANT.address, true, { from: owner }) }) beforeEach('add employee with salary 0.1 ETH per second', async () => { const salary = bigExp(0.1, 18) await payroll.addEmployee(employee, salary, await payroll.getTimestampPublic(), 'Boss') }) beforeEach('accrue two minutes of salary', async () => { await increaseTime(TWO_MINUTES) }) context('when the employee requests only ETH', () => { beforeEach('set token allocation', async () => { await payroll.determineAllocation([ETH], [100], { from: employee }) }) it('receives the expected amount of ETH', async () => { const previousETH = await web3.eth.getBalance(employee) const previousDAI = await DAI.balanceOf(employee) const previousANT = await ANT.balanceOf(employee) const { tx, receipt, logs } = await payroll.payday(PAYMENT_TYPES.PAYROLL, 0, [ONE], { from: employee }) const { gasPrice } = await web3.eth.getTransaction(tx) const txCost = gasPrice.mul(receipt.gasUsed) const events = getEvents({ logs }, 'SendPayment') assert.equal(events.length, 1, 'should have emitted one event') // expected an income of 12 ETH since we accrued 2 minutes of salary at 0.1 ETH per second, and the denomination token is ETH const currentETH = await web3.eth.getBalance(employee) assert.equal(currentETH.minus(previousETH).plus(txCost).toString(), bigExp(12, 18).toString(), 'expected current ETH amount does not match') const eventETH = events.find(e => e.args.token === ETH).args assert.equal(eventETH.exchangeRate.toString(), ONE.toString(), 'ETH exchange rate does not match') // no DAI income expected const currentDAI = await DAI.balanceOf(employee) assert.equal(currentDAI.toString(), previousDAI.toString(), 'expected current DAI amount does not match') // no ANT income expected const currentANT = await ANT.balanceOf(employee) assert.equal(currentANT.toString(), previousANT.toString(), 'expected current ANT amount does not match') }) }) context('when the employee requests only ANT', () => { beforeEach('set token allocation', async () => { await payroll.determineAllocation([ANT.address], [100], { from: employee }) }) it('receives the expected amount of ANT', async () => { const previousETH = await web3.eth.getBalance(employee) const previousDAI = await DAI.balanceOf(employee) const previousANT = await ANT.balanceOf(employee) const { tx, receipt, logs } = await payroll.payday(PAYMENT_TYPES.PAYROLL, 0, [ETH_TO_ANT_RATE], { from: employee }) const { gasPrice } = await web3.eth.getTransaction(tx) const txCost = gasPrice.mul(receipt.gasUsed) const events = getEvents({ logs }, 'SendPayment') assert.equal(events.length, 1, 'should have emitted one event') // no ETH income expected const currentETH = await web3.eth.getBalance(employee) assert.equal(currentETH.plus(txCost).toString(), previousETH.toString(), 'expected current ETH amount does not match') // no DAI income expected const currentDAI = await DAI.balanceOf(employee) assert.equal(currentDAI.toString(), previousDAI.toString(), 'expected current DAI amount does not match') // expected an income of 480 ANT since we accrued 2 minutes of salary at 0.1 ETH per second, and the ANT rate is 0.025 ETH const currentANT = await ANT.balanceOf(employee) assert.equal(currentANT.minus(previousANT).toString(), bigExp(480, 18).toString(), 'expected current ANT amount does not match') const eventANT = events.find(e => e.args.token === ANT.address).args assert.equal(eventANT.exchangeRate.toString(), ETH_TO_ANT_RATE.toString(), 'ANT exchange rate does not match') }) }) context('when the employee requests multiple tokens', () => { beforeEach('set token allocations', async () => { await payroll.determineAllocation([ETH, DAI.address, ANT.address], [50, 25, 25], { from: employee }) }) it('receives the expected amount of tokens', async () => { const previousETH = await web3.eth.getBalance(employee) const previousDAI = await DAI.balanceOf(employee) const previousANT = await ANT.balanceOf(employee) const { tx, receipt, logs } = await payroll.payday(PAYMENT_TYPES.PAYROLL, 0, [ONE, ETH_TO_DAI_RATE, ETH_TO_ANT_RATE], { from: employee }) const { gasPrice } = await web3.eth.getTransaction(tx) const txCost = gasPrice.mul(receipt.gasUsed) const events = getEvents({ logs }, 'SendPayment') assert.equal(events.length, 3, 'should have emitted three events') // expected an income of 6 ETH having 50% allocated, since we accrued 2 minutes of salary at 0.1 ETH per second, and the denomination token is ETH const currentETH = await web3.eth.getBalance(employee) assert.equal(currentETH.minus(previousETH).plus(txCost).toString(), bigExp(6, 18).toString(), 'expected current ETH amount does not match') const eventETH = events.find(e => e.args.token === ETH).args assert.equal(eventETH.exchangeRate.toString(), ONE.toString(), 'ETH exchange rate does not match') // expected an income of 60 DAI having 25% allocated, since we accrued 2 minutes of salary at 0.1 ETH per second, and the DAI rate is 0.05 ETH const currentDAI = await DAI.balanceOf(employee) assert.equal(currentDAI.minus(previousDAI).toString(), bigExp(60, 18).toString(), 'expected current DAI amount does not match') const eventDAI = events.find(e => e.args.token === DAI.address).args assert.equal(eventDAI.exchangeRate.toString(), ETH_TO_DAI_RATE.toString(), 'DAI exchange rate does not match') // expected an income of 120 ANT having 25% allocated, since we accrued 2 minutes of salary at 0.1 ETH per second, and the ANT rate is 0.025 ETH const currentANT = await ANT.balanceOf(employee) assert.equal(currentANT.minus(previousANT).toString(), bigExp(120, 18).toString(), 'expected current ANT amount does not match') const eventANT = events.find(e => e.args.token === ANT.address).args assert.equal(eventANT.exchangeRate.toString(), ETH_TO_ANT_RATE.toString(), 'ANT exchange rate does not match') }) }) }) context('when the denomination token is DAI', async () => { const ETH_TO_DAI_RATE = formatRate(ETH_RATE.div(DAI_RATE)) // 20 DAI const ANT_TO_DAI_RATE = formatRate(ANT_RATE.div(DAI_RATE)) // 0.5 DAI beforeEach('initialize payroll app', async () => { ({ payroll, priceFeed } = await createPayrollAndPriceFeed(dao, payrollBase, owner, NOW)) await payroll.initialize(finance.address, DAI.address, priceFeed.address, RATE_EXPIRATION_TIME, { from: owner }) }) beforeEach('set rates and allow tokens', async () => { await setTokenRate(priceFeed, DAI, ETH, ETH_TO_DAI_RATE) await setTokenRate(priceFeed, DAI, ANT, ANT_TO_DAI_RATE) await payroll.setAllowedToken(ETH, true, { from: owner }) await payroll.setAllowedToken(DAI.address, true, { from: owner }) await payroll.setAllowedToken(ANT.address, true, { from: owner }) }) beforeEach('add employee with salary 1 DAI per second', async () => { const salary = bigExp(1, 18) await payroll.addEmployee(employee, salary, await payroll.getTimestampPublic(), 'Boss') }) beforeEach('accrue two minutes of salary', async () => { await increaseTime(TWO_MINUTES) }) context('when the employee requests only ETH', () => { beforeEach('set token allocation', async () => { await payroll.determineAllocation([ETH], [100], { from: employee }) }) it('receives the expected amount of ETH', async () => { const previousETH = await web3.eth.getBalance(employee) const previousDAI = await DAI.balanceOf(employee) const previousANT = await ANT.balanceOf(employee) const { tx, receipt, logs } = await payroll.payday(PAYMENT_TYPES.PAYROLL, 0, [inverseRate(ETH_TO_DAI_RATE)], { from: employee }) const { gasPrice } = await web3.eth.getTransaction(tx) const txCost = gasPrice.mul(receipt.gasUsed) const events = getEvents({ logs }, 'SendPayment') assert.equal(events.length, 1, 'should have emitted three events') // expected an income of 6 ETH since we accrued 2 minutes of salary at 1 DAI per second, and the ETH rate is 20 DAI const currentETH = await web3.eth.getBalance(employee) assert.equal(currentETH.minus(previousETH).plus(txCost).toString(), bigExp(6, 18).toString(), 'expected current ETH amount does not match') const eventETH = events.find(e => e.args.token === ETH).args assert.equal(eventETH.exchangeRate.toString(), inverseRate(ETH_TO_DAI_RATE).toString(), 'ETH exchange rate does not match') // no DAI income expected const currentDAI = await DAI.balanceOf(employee) assert.equal(currentDAI.toString(), previousDAI.toString(), 'expected current DAI amount does not match') // no ANT income expected const currentANT = await ANT.balanceOf(employee) assert.equal(currentANT.toString(), previousANT.toString(), 'expected current ANT amount does not match') }) }) context('when the employee requests only ANT', () => { beforeEach('set token allocation', async () => { await payroll.determineAllocation([ANT.address], [100], { from: employee }) }) it('receives the expected amount of ANT', async () => { const previousETH = await web3.eth.getBalance(employee) const previousDAI = await DAI.balanceOf(employee) const previousANT = await ANT.balanceOf(employee) const { tx, receipt, logs } = await payroll.payday(PAYMENT_TYPES.PAYROLL, 0, [inverseRate(ANT_TO_DAI_RATE)], { from: employee }) const { gasPrice } = await web3.eth.getTransaction(tx) const txCost = gasPrice.mul(receipt.gasUsed) const events = getEvents({ logs }, 'SendPayment') assert.equal(events.length, 1, 'should have emitted three events') // no ETH income expected const currentETH = await web3.eth.getBalance(employee) assert.equal(currentETH.plus(txCost).toString(), previousETH.toString(), 'expected current ETH amount does not match') // no DAI income expected const currentDAI = await DAI.balanceOf(employee) assert.equal(currentDAI.toString(), previousDAI.toString(), 'expected current DAI amount does not match') // expected an income of 240 ANT since we accrued 2 minutes of salary at 1 DAI per second, and the ANT rate is 0.5 DAI const currentANT = await ANT.balanceOf(employee) assert.equal(currentANT.minus(previousANT).toString(), bigExp(240, 18).toString(), 'expected current ANT amount does not match') const eventANT = events.find(e => e.args.token === ANT.address).args assert.equal(eventANT.exchangeRate.toString(), inverseRate(ANT_TO_DAI_RATE).toString(), 'ANT exchange rate does not match') }) }) context('when the employee requests multiple tokens', () => { beforeEach('set token allocations', async () => { await payroll.determineAllocation([ETH, DAI.address, ANT.address], [50, 25, 25], { from: employee }) }) it('receives the expected amount of tokens', async () => { const previousETH = await web3.eth.getBalance(employee) const previousDAI = await DAI.balanceOf(employee) const previousANT = await ANT.balanceOf(employee) const { tx, receipt, logs } = await payroll.payday(PAYMENT_TYPES.PAYROLL, 0, [inverseRate(ETH_TO_DAI_RATE), ONE, inverseRate(ANT_TO_DAI_RATE)], { from: employee }) const { gasPrice } = await web3.eth.getTransaction(tx) const txCost = gasPrice.mul(receipt.gasUsed) const events = getEvents({ logs }, 'SendPayment') assert.equal(events.length, 3, 'should have emitted three events') // expected an income of 3 ETH having 50% allocated, since we accrued 2 minutes of salary at 1 DAI per second, and the ETH rate is 20 DAI const currentETH = await web3.eth.getBalance(employee) assert.equal(currentETH.minus(previousETH).plus(txCost).toString(), bigExp(3, 18).toString(), 'expected current ETH amount does not match') const eventETH = events.find(e => e.args.token === ETH).args assert.equal(eventETH.exchangeRate.toString(), inverseRate(ETH_TO_DAI_RATE).toString(), 'ETH exchange rate does not match') // expected an income of 30 DAI having 25% allocated, since we accrued 2 minutes of salary at 1 DAI per second, and the denomination token is DAI const currentDAI = await DAI.balanceOf(employee) assert.equal(currentDAI.minus(previousDAI).toString(), bigExp(30, 18).toString(), 'expected current DAI amount does not match') const eventDAI = events.find(e => e.args.token === DAI.address).args assert.equal(eventDAI.exchangeRate.toString(), ONE.toString(), 'DAI exchange rate does not match') // expected an income of 60 ANT having 25% allocated, since we accrued 2 minutes of salary at 1 DAI per second, and the ANT rate is 0.5 DAI const currentANT = await ANT.balanceOf(employee) assert.equal(currentANT.minus(previousANT).toString(), bigExp(60, 18).toString(), 'expected current ANT amount does not match') const eventANT = events.find(e => e.args.token === ANT.address).args assert.equal(eventANT.exchangeRate.toString(), inverseRate(ANT_TO_DAI_RATE).toString(), 'ANT exchange rate does not match') }) }) }) context('when the denomination token is ANT', async () => { const ETH_TO_ANT_RATE = formatRate(ETH_RATE.div(ANT_RATE)) // 40 ANT const DAI_TO_ANT_RATE = formatRate(DAI_RATE.div(ANT_RATE)) // 2 ANT beforeEach('initialize payroll app', async () => { ({ payroll, priceFeed } = await createPayrollAndPriceFeed(dao, payrollBase, owner, NOW)) await payroll.initialize(finance.address, ANT.address, priceFeed.address, RATE_EXPIRATION_TIME, { from: owner }) }) beforeEach('set rates and allow tokens', async () => { await setTokenRate(priceFeed, ANT, ETH, ETH_TO_ANT_RATE) await setTokenRate(priceFeed, ANT, DAI, DAI_TO_ANT_RATE) await payroll.setAllowedToken(ETH, true, { from: owner }) await payroll.setAllowedToken(DAI.address, true, { from: owner }) await payroll.setAllowedToken(ANT.address, true, { from: owner }) }) beforeEach('add employee with salary 1 ANT per second', async () => { const salary = bigExp(1, 18) await payroll.addEmployee(employee, salary, await payroll.getTimestampPublic(), 'Boss') }) beforeEach('accrue two minutes of salary', async () => { await increaseTime(TWO_MINUTES) }) context('when the employee requests only ETH', () => { beforeEach('set token allocation', async () => { await payroll.determineAllocation([ETH], [100], { from: employee }) }) it('receives the expected amount of ETH', async () => { const previousETH = await web3.eth.getBalance(employee) const previousDAI = await DAI.balanceOf(employee) const previousANT = await ANT.balanceOf(employee) const { tx, receipt, logs } = await payroll.payday(PAYMENT_TYPES.PAYROLL, 0, [inverseRate(ETH_TO_ANT_RATE)], { from: employee }) const { gasPrice } = await web3.eth.getTransaction(tx) const txCost = gasPrice.mul(receipt.gasUsed) const events = getEvents({ logs }, 'SendPayment') assert.equal(events.length, 1, 'should have emitted three events') // expected an income of 3 ETH since we accrued 2 minutes of salary at 1 ANT per second, and the ETH rate is 40 ANT const currentETH = await web3.eth.getBalance(employee) assert.equal(currentETH.minus(previousETH).plus(txCost).toString(), bigExp(3, 18).toString(), 'expected current ETH amount does not match') const eventETH = events.find(e => e.args.token === ETH).args assert.equal(eventETH.exchangeRate.toString(), inverseRate(ETH_TO_ANT_RATE).toString(), 'ETH exchange rate does not match') // no DAI income expected const currentDAI = await DAI.balanceOf(employee) assert.equal(currentDAI.toString(), previousDAI.toString(), 'expected current DAI amount does not match') // no ANT income expected const currentANT = await ANT.balanceOf(employee) assert.equal(currentANT.toString(), previousANT.toString(), 'expected current ANT amount does not match') }) }) context('when the employee requests only ANT', () => { beforeEach('set token allocation', async () => { await payroll.determineAllocation([ANT.address], [100], { from: employee }) }) it('receives the expected amount of ANT', async () => { const previousETH = await web3.eth.getBalance(employee) const previousDAI = await DAI.balanceOf(employee) const previousANT = await ANT.balanceOf(employee) const { tx, receipt, logs } = await payroll.payday(PAYMENT_TYPES.PAYROLL, 0, [ONE], { from: employee }) const { gasPrice } = await web3.eth.getTransaction(tx) const txCost = gasPrice.mul(receipt.gasUsed) const events = getEvents({ logs }, 'SendPayment') assert.equal(events.length, 1, 'should have emitted three events') // no ETH income expected const currentETH = await web3.eth.getBalance(employee) assert.equal(currentETH.plus(txCost).toString(), previousETH.toString(), 'expected current ETH amount does not match') // no DAI income expected const currentDAI = await DAI.balanceOf(employee) assert.equal(currentDAI.toString(), previousDAI.toString(), 'expected current DAI amount does not match') // expected an income of 120 ANT since we accrued 2 minutes of salary at 1 ANT per second, and the denomination token is ANT const currentANT = await ANT.balanceOf(employee) assert.equal(currentANT.minus(previousANT).toString(), bigExp(120, 18).toString(), 'expected current ANT amount does not match') const eventANT = events.find(e => e.args.token === ANT.address).args assert.equal(eventANT.exchangeRate.toString(), ONE.toString(), 'ANT exchange rate does not match') }) }) context('when the employee requests multiple tokens', () => { beforeEach('set token allocations', async () => { await payroll.determineAllocation([ETH, DAI.address, ANT.address], [50, 25, 25], { from: employee }) }) it('receives the expected amount of tokens', async () => { const previousETH = await web3.eth.getBalance(employee) const previousDAI = await DAI.balanceOf(employee) const previousANT = await ANT.balanceOf(employee) const { tx, receipt, logs } = await payroll.payday(PAYMENT_TYPES.PAYROLL, 0, [inverseRate(ETH_TO_ANT_RATE), inverseRate(DAI_TO_ANT_RATE), ONE], { from: employee }) const { gasPrice } = await web3.eth.getTransaction(tx) const txCost = gasPrice.mul(receipt.gasUsed) const events = getEvents({ logs }, 'SendPayment') assert.equal(events.length, 3, 'should have emitted three events') // expected an income of 1.5 ETH having 50% allocated, since we accrued 2 minutes of salary at 1 ANT per second, and the ETH rate is 40 ANT const currentETH = await web3.eth.getBalance(employee) assert.equal(currentETH.minus(previousETH).plus(txCost).toString(), bigExp(1.5, 18).toString(), 'expected current ETH amount does not match') const eventETH = events.find(e => e.args.token === ETH).args assert.equal(eventETH.exchangeRate.toString(), inverseRate(ETH_TO_ANT_RATE).toString(), 'ETH exchange rate does not match') // expected an income of 15 DAI having 25% allocated, since we accrued 2 minutes of salary at 1 ANT per second, and the DAI rate is 2 ANT const currentDAI = await DAI.balanceOf(employee) assert.equal(currentDAI.minus(previousDAI).toString(), bigExp(15, 18).toString(), 'expected current DAI amount does not match') const eventDAI = events.find(e => e.args.token === DAI.address).args assert.equal(eventDAI.exchangeRate.toString(), inverseRate(DAI_TO_ANT_RATE).toString(), 'DAI exchange rate does not match') // expected an income of 30 ANT having 25% allocated, since we accrued 2 minutes of salary at 1 ANT per second, and the denomination token is ANT const currentANT = await ANT.balanceOf(employee) assert.equal(currentANT.minus(previousANT).toString(), bigExp(30, 18).toString(), 'expected current ANT amount does not match') const eventANT = events.find(e => e.args.token === ANT.address).args assert.equal(eventANT.exchangeRate.toString(), ONE.toString(), 'ANT exchange rate does not match') }) }) }) })