123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- /* global artifacts, web3, contract */
- require('chai').use(require('bn-chai')(web3.utils.BN)).use(require('chai-as-promised')).should()
- const { toBN } = require('web3-utils')
- const { takeSnapshot, revertSnapshot, mineBlock } = require('../scripts/ganacheHelper')
- const { tornadoFormula, reverseTornadoFormula } = require('../src/utils')
- const Torn = artifacts.require('TORNMock')
- const RewardSwap = artifacts.require('RewardSwapMock')
- const tornConfig = require('torn-token')
- const RLP = require('rlp')
- const MONTH = toBN(60 * 60 * 24 * 30)
- const DURATION = toBN(60 * 60 * 24 * 365)
- // Set time to beginning of a second
- async function timeReset() {
- const delay = 1000 - new Date().getMilliseconds()
- await new Promise((resolve) => setTimeout(resolve, delay))
- await mineBlock()
- }
- async function getNextAddr(sender, offset = 0) {
- const nonce = await web3.eth.getTransactionCount(sender)
- return (
- '0x' +
- web3.utils
- .sha3(RLP.encode([sender, Number(nonce) + Number(offset)]))
- .slice(12)
- .substring(14)
- )
- }
- contract('RewardSwap', (accounts) => {
- let torn
- let rewardSwap
- let amount
- const tornCap = toBN(tornConfig.torn.cap)
- const miningCap = toBN(tornConfig.torn.distribution.miningV2.amount)
- const initialTornBalance = toBN(tornConfig.miningV2.initialBalance)
- let yearLiquidity
- let delta = toBN(100000) // 0.0000000000001 torn error
- // eslint-disable-next-line no-unused-vars
- const sender = accounts[0]
- const recipient = accounts[1]
- // eslint-disable-next-line no-unused-vars
- const relayer = accounts[2]
- let snapshotId
- const thirtyDays = 30 * 24 * 3600
- const poolWeight = 1e11
- before(async () => {
- const swapExpectedAddr = await getNextAddr(accounts[0], 1)
- torn = await Torn.new(sender, thirtyDays, [
- { to: swapExpectedAddr, amount: miningCap.toString() },
- { to: sender, amount: tornCap.sub(miningCap).toString() },
- ])
- rewardSwap = await RewardSwap.new(
- torn.address,
- sender,
- miningCap.toString(),
- initialTornBalance.toString(),
- poolWeight,
- )
- yearLiquidity = miningCap.sub(initialTornBalance)
- amount = toBN(await rewardSwap.poolWeight()).mul(toBN(7)) // 10**10
- snapshotId = await takeSnapshot()
- })
- beforeEach(async () => {
- await timeReset()
- })
- describe('#formula test', () => {
- it('should work', async () => {
- let formulaReturn
- let expectedReturn
- amount = amount.mul(toBN(5))
- for (let i = 1; i < 11; i++) {
- amount = amount.div(toBN(i))
- formulaReturn = tornadoFormula({ balance: initialTornBalance, amount })
- expectedReturn = await rewardSwap.getExpectedReturn(amount)
- expectedReturn.sub(formulaReturn).should.be.lte.BN(delta)
- }
- })
- })
- describe('#constructor', () => {
- it('should initialize', async () => {
- const tokenFromContract = await rewardSwap.torn()
- tokenFromContract.should.be.equal(torn.address)
- })
- })
- it('should return as expected', async () => {
- const balanceBefore = await torn.balanceOf(recipient)
- const expectedReturn = await rewardSwap.getExpectedReturn(amount)
- await rewardSwap.swap(recipient, amount, { from: sender })
- const balanceAfter = await torn.balanceOf(recipient)
- balanceAfter.sub(balanceBefore).should.be.eq.BN(expectedReturn)
- })
- it('reverse rate', async () => {
- const tokens = await rewardSwap.getExpectedReturn(amount)
- const balance = await rewardSwap.tornVirtualBalance()
- const points = reverseTornadoFormula({ balance, tokens })
- points.sub(amount).should.be.lt.BN(toBN(1))
- })
- it('should be approximately additive', async () => {
- const amount = toBN(10).pow(toBN(10)).mul(toBN(2))
- const delta = toBN('1000') // max floating point error
- const balanceBefore1 = await torn.balanceOf(recipient)
- await rewardSwap.swap(recipient, amount, { from: sender })
- const balanceAfter1 = await torn.balanceOf(recipient)
- await revertSnapshot(snapshotId.result)
- snapshotId = await takeSnapshot()
- const balanceBefore2 = await torn.balanceOf(recipient)
- await rewardSwap.swap(recipient, amount.div(toBN(2)), { from: sender })
- await rewardSwap.swap(recipient, amount.div(toBN(2)), { from: sender })
- const balanceAfter2 = await torn.balanceOf(recipient)
- balanceBefore1.sub(balanceBefore2).should.be.lt.BN(delta)
- balanceAfter1.sub(balanceAfter2).should.be.lt.BN(delta)
- })
- describe('#swap', () => {
- it('should work as uniswap without vested tokens', async () => {
- const startTimestamp = await rewardSwap.startTimestamp()
- await rewardSwap.setTimestamp(startTimestamp)
- const expectedTokens = await rewardSwap.getExpectedReturn(amount)
- const formulaReturn = tornadoFormula({ balance: initialTornBalance, amount })
- expectedTokens.sub(formulaReturn).should.be.lte.BN(delta)
- const tornVirtualBalance = await rewardSwap.tornVirtualBalance()
- tornVirtualBalance.should.be.eq.BN(initialTornBalance)
- const balanceBefore = await torn.balanceOf(recipient)
- await rewardSwap.swap(recipient, amount, { from: sender })
- const balanceAfter = await torn.balanceOf(recipient)
- balanceAfter.should.be.eq.BN(balanceBefore.add(expectedTokens))
- })
- it('should work with vested tokens (a half of year passed)', async () => {
- let startTimestamp = await rewardSwap.startTimestamp()
- const currentTimestamp = startTimestamp.add(DURATION.div(toBN(2)))
- await rewardSwap.setTimestamp(currentTimestamp)
- const tornVirtualBalance = await rewardSwap.tornVirtualBalance()
- tornVirtualBalance.should.be.eq.BN(yearLiquidity.div(toBN(2)).add(initialTornBalance))
- const formulaReturn = tornadoFormula({ balance: tornVirtualBalance, amount })
- const expectedTokens = await rewardSwap.getExpectedReturn(amount)
- expectedTokens.sub(formulaReturn).should.be.lte.BN(delta)
- const balanceBefore = await torn.balanceOf(recipient)
- await rewardSwap.swap(recipient, amount, { from: sender })
- const balanceAfter = await torn.balanceOf(recipient)
- balanceAfter.should.be.eq.BN(balanceBefore.add(expectedTokens))
- })
- it('should not add any tokens after one year', async () => {
- let startTimestamp = await rewardSwap.startTimestamp()
- let currentTimestamp = startTimestamp.add(DURATION)
- await rewardSwap.setTimestamp(currentTimestamp)
- let tornVirtualBalance = await rewardSwap.tornVirtualBalance()
- tornVirtualBalance.should.be.eq.BN(miningCap)
- const formulaReturn = tornadoFormula({ balance: tornVirtualBalance, amount })
- const expectedTokens = await rewardSwap.getExpectedReturn(amount)
- expectedTokens.sub(formulaReturn).should.be.lte.BN(delta)
- currentTimestamp = currentTimestamp.add(MONTH)
- await rewardSwap.setTimestamp(currentTimestamp)
- tornVirtualBalance = await rewardSwap.tornVirtualBalance()
- tornVirtualBalance.should.be.eq.BN(miningCap)
- })
- })
- afterEach(async () => {
- await revertSnapshot(snapshotId.result)
- // eslint-disable-next-line require-atomic-updates
- snapshotId = await takeSnapshot()
- })
- })
|