From 4534a99f87d58db3799fdc5ecf865eefde597e7f Mon Sep 17 00:00:00 2001 From: Noah Zinsmeister Date: Thu, 7 Nov 2019 17:47:55 -0500 Subject: [PATCH] changes --- contracts/UniswapV2.sol | 70 +++++----- contracts/interfaces/IUniswapV2.sol | 4 +- contracts/test/Oracle.sol | 97 ++++++++++---- test/Oracle.spec.ts | 198 ++++++++++++++-------------- test/UniswapV2.spec.ts | 73 ++++++---- 5 files changed, 254 insertions(+), 188 deletions(-) diff --git a/contracts/UniswapV2.sol b/contracts/UniswapV2.sol index 0fdbb73..329d537 100644 --- a/contracts/UniswapV2.sol +++ b/contracts/UniswapV2.sol @@ -56,14 +56,18 @@ contract UniswapV2 is IUniswapV2, ERC20("Uniswap V2", "UNI-V2", 18, 0), SafeTran initialize(chainId); } - function getReservesCumulativeAndOverflows() external view returns (uint128, uint128, uint128, uint128) { + function getReserves() external view returns (uint128, uint128) { + return (reserves.token0, reserves.token1); + } + + function getReservesCumulative() external view returns (uint128, uint128, uint128, uint128) { require(blockNumberLast > 0, "UniswapV2: NOT_INITIALIZED"); TokenData memory reservesCumulativeNext; TokenData memory reservesCumulativeOverflowsNext; // replicate the logic in update if (block.number > blockNumberLast) { - uint128 blocksElapsed = block.number.sub(blockNumberLast).downcast128(); + uint128 blocksElapsed = (block.number - blockNumberLast).downcast128(); TokenData memory remaindersMul; TokenData memory overflowsMul; @@ -91,6 +95,10 @@ contract UniswapV2 is IUniswapV2, ERC20("Uniswap V2", "UNI-V2", 18, 0), SafeTran ); } + function getBlockNumberLast() external view returns (uint256) { + return blockNumberLast; + } + function getAmountOutput(uint128 amountInput, uint128 reserveInput, uint128 reserveOutput) public pure returns (uint128 amountOutput) { @@ -101,12 +109,14 @@ contract UniswapV2 is IUniswapV2, ERC20("Uniswap V2", "UNI-V2", 18, 0), SafeTran amountOutput = (numerator / denominator).downcast128(); } - function update(TokenData memory reservesNext) private { + function update(TokenData memory balances) private { // if any blocks have gone by since the last time this function was called, we have to update if (block.number > blockNumberLast) { // make sure that this isn't the first time this function is being called if (blockNumberLast > 0) { - uint128 blocksElapsed = block.number.sub(blockNumberLast).downcast128(); + uint128 blocksElapsed = (block.number - blockNumberLast).downcast128(); + + // TODO address ratio of sum / sum of ratios / price accumulator issue // multiply previous reserves by elapsed blocks in an overflow-safe way TokenData memory remaindersMul; @@ -120,10 +130,16 @@ contract UniswapV2 is IUniswapV2, ERC20("Uniswap V2", "UNI-V2", 18, 0), SafeTran (reservesCumulative.token1, overflowsAdd.token1) = reservesCumulative.token1.oadd(remaindersMul.token1); // update cumulative reserves overflows - reservesCumulativeOverflows = TokenData({ - token0: reservesCumulativeOverflows.token0.add(overflowsMul.token0.add(overflowsAdd.token0)), - token1: reservesCumulativeOverflows.token1.add(overflowsMul.token1.add(overflowsAdd.token1)) + TokenData memory overflows = TokenData({ + token0: overflowsMul.token0.add(overflowsAdd.token0), + token1: overflowsMul.token1.add(overflowsAdd.token1) }); + if (overflows.token0 > 0 || overflows.token1 > 0) { + reservesCumulativeOverflows = TokenData({ + token0: reservesCumulativeOverflows.token0.add(overflows.token0), + token1: reservesCumulativeOverflows.token1.add(overflows.token1) + }); + } } // update the last block number @@ -131,7 +147,7 @@ contract UniswapV2 is IUniswapV2, ERC20("Uniswap V2", "UNI-V2", 18, 0), SafeTran } // update reserves - reserves = reservesNext; + reserves = balances; } function mintLiquidity(address recipient) external lock returns (uint256 liquidity) { @@ -139,7 +155,6 @@ contract UniswapV2 is IUniswapV2, ERC20("Uniswap V2", "UNI-V2", 18, 0), SafeTran token0: IERC20(token0).balanceOf(address(this)).downcast128(), token1: IERC20(token1).balanceOf(address(this)).downcast128() }); - TokenData memory amounts = TokenData({ token0: balances.token0.sub(reserves.token0), token1: balances.token1.sub(reserves.token1) @@ -161,11 +176,11 @@ contract UniswapV2 is IUniswapV2, ERC20("Uniswap V2", "UNI-V2", 18, 0), SafeTran function burnLiquidity(address recipient) external lock returns (uint128 amountToken0, uint128 amountToken1) { uint256 liquidity = balanceOf[address(this)]; - TokenData memory amounts = TokenData({ token0: (amountToken0 = (liquidity.mul(reserves.token0) / totalSupply).downcast128()), token1: (amountToken1 = (liquidity.mul(reserves.token1) / totalSupply).downcast128()) }); + require(amounts.token0 == 0 || safeTransfer(token0, recipient, amounts.token0), "UniswapV2: TRANSFER_0_FAILED"); require(amounts.token1 == 0 || safeTransfer(token1, recipient, amounts.token1), "UniswapV2: TRANSFER_1_FAILED"); @@ -178,33 +193,22 @@ contract UniswapV2 is IUniswapV2, ERC20("Uniswap V2", "UNI-V2", 18, 0), SafeTran } function swap(address input, address recipient) external lock returns (uint128 amountOutput) { - uint128 balanceInput = IERC20(input).balanceOf(address(this)).downcast128(); - - TokenData memory amounts; TokenData memory balances; + TokenData memory amounts; + if (input == token0) { - uint128 amountInput = balanceInput.sub(reserves.token0); - amounts = TokenData({ - token0: amountInput, - token1: (amountOutput = getAmountOutput(amountInput, reserves.token0, reserves.token1)) - }); - require(amounts.token1 == 0 || safeTransfer(token1, recipient, amounts.token1), "UniswapV2: TRANSFER_1_FAILED"); - balances = TokenData({ - token0: balanceInput, - token1: IERC20(token1).balanceOf(address(this)).downcast128() - }); + balances.token0 = IERC20(input).balanceOf(address(this)).downcast128(); + amounts.token0 = balances.token0.sub(reserves.token0); + amounts.token1 = (amountOutput = getAmountOutput(amounts.token0, reserves.token0, reserves.token1)); + require(safeTransfer(token1, recipient, amounts.token1), "UniswapV2: TRANSFER_1_FAILED"); + balances.token1 = IERC20(token1).balanceOf(address(this)).downcast128(); } else { require(input == token1, "UniswapV2: INVALID_INPUT"); - uint128 amountInput = balanceInput.sub(reserves.token1); - amounts = TokenData({ - token0: (amountOutput = getAmountOutput(amountInput, reserves.token1, reserves.token0)), - token1: amountInput - }); - require(amounts.token0 == 0 || safeTransfer(token0, recipient, amounts.token0), "UniswapV2: TRANSFER_0_FAILED"); - balances = TokenData({ - token0: IERC20(token0).balanceOf(address(this)).downcast128(), - token1: balanceInput - }); + balances.token1 = IERC20(input).balanceOf(address(this)).downcast128(); + amounts.token1 = balances.token1.sub(reserves.token1); + amounts.token0 = (amountOutput = getAmountOutput(amounts.token1, reserves.token1, reserves.token0)); + require(safeTransfer(token0, recipient, amounts.token0), "UniswapV2: TRANSFER_0_FAILED"); + balances.token0 = IERC20(token0).balanceOf(address(this)).downcast128(); } update(balances); diff --git a/contracts/interfaces/IUniswapV2.sol b/contracts/interfaces/IUniswapV2.sol index 3ab2450..193f986 100644 --- a/contracts/interfaces/IUniswapV2.sol +++ b/contracts/interfaces/IUniswapV2.sol @@ -15,7 +15,9 @@ interface IUniswapV2 { function token0() external view returns (address); function token1() external view returns (address); - function getReservesCumulativeAndOverflows() external view returns (uint128, uint128, uint128, uint128); + function getReserves() external view returns (uint128, uint128); + function getReservesCumulative() external view returns (uint128, uint128, uint128, uint128); + function getBlockNumberLast() external view returns (uint256); function getAmountOutput(uint128 amountInput, uint128 reserveInput, uint128 reserveOutput) external pure returns (uint128 amountOutput); diff --git a/contracts/test/Oracle.sol b/contracts/test/Oracle.sol index b2c283b..5839c4e 100644 --- a/contracts/test/Oracle.sol +++ b/contracts/test/Oracle.sol @@ -23,35 +23,48 @@ contract Oracle { uint128 constant period = 1 days; OracleStates private state = OracleStates.NeedsInitialization; + TokenData private reservesCumulative; - TimeData private lastUpdate; + TokenData private reservesCumulativeOverflows; + TokenData private currentPrice; + TimeData private updateLast; + constructor(address _exchange) public { exchange = _exchange; } - function getReservesCumulative() private view returns (TokenData memory) { - IUniswapV2 uniswapV2 = IUniswapV2(exchange); - (uint128 reservesCumulativeToken0, uint128 reservesCumulativeToken1,,) = uniswapV2.getReservesCumulativeAndOverflows(); - return TokenData({ - token0: reservesCumulativeToken0, - token1: reservesCumulativeToken1 - }); + function getReservesCumulative() private view returns (TokenData memory, TokenData memory) { + ( + uint128 reservesCumulativeToken0, + uint128 reservesCumulativeToken1, + uint128 reservesCumulativeOverflowsToken0, + uint128 reservesCumulativeOverflowsToken1 + ) = IUniswapV2(exchange).getReservesCumulative(); + return ( + TokenData(reservesCumulativeToken0, reservesCumulativeToken1), + TokenData(reservesCumulativeOverflowsToken0, reservesCumulativeOverflowsToken1) + ); } - function getTimeData() private view returns (TimeData memory) { - return TimeData({ - blockNumber: block.number.downcast128(), - blockTimestamp: block.timestamp.downcast128() - }); + function getNow() private view returns (TimeData memory) { + return TimeData(block.number.downcast128(), block.timestamp.downcast128()); + } + + function reset() private { + delete(reservesCumulative); + delete(reservesCumulativeOverflows); + delete(currentPrice); + delete(updateLast); + state = OracleStates.NeedsInitialization; } function initialize() external { require(state == OracleStates.NeedsInitialization, "Oracle: DOES_NOT_NEED_INITIALIZATION"); - reservesCumulative = getReservesCumulative(); - lastUpdate = getTimeData(); + (reservesCumulative, reservesCumulativeOverflows) = getReservesCumulative(); + updateLast = getNow(); state = OracleStates.NeedsActivation; } @@ -59,14 +72,26 @@ contract Oracle { function activate() external { require(state == OracleStates.NeedsActivation, "Oracle: DOES_NOT_NEED_ACTIVATION"); - // get the current time, ensure it's been >=1 blocks since last update, and record the update - TimeData memory currentTime = getTimeData(); - uint128 blocksElapsed = currentTime.blockNumber - lastUpdate.blockNumber; + // get the current time, ensure it's been >=1 blocks since the last update + TimeData memory _now = getNow(); + uint128 blocksElapsed = _now.blockNumber - updateLast.blockNumber; require(blocksElapsed > 0, "Oracle: INSUFFICIENT_BLOCKS_PASSED"); - lastUpdate = currentTime; - // get the current cumulative reserves, calculate the deltas, and record the new values - TokenData memory reservesCumulativeNext = getReservesCumulative(); + // get the current cumulative reserves and overflows + TokenData memory reservesCumulativeNext; + TokenData memory reservesCumulativeOverflowsNext; + (reservesCumulativeNext, reservesCumulativeOverflowsNext) = getReservesCumulative(); + + // reset if there's been an overflow + if ( + reservesCumulativeOverflows.token0 != reservesCumulativeOverflowsNext.token0 || + reservesCumulativeOverflows.token1 != reservesCumulativeOverflowsNext.token1 + ) { + reset(); + require(false, "Oracle: OVERFLOW"); + } + + // calculate the deltas, and record the new values TokenData memory deltas = TokenData({ token0: reservesCumulativeNext.token0 - reservesCumulative.token0, token1: reservesCumulativeNext.token1 - reservesCumulative.token1 @@ -79,21 +104,35 @@ contract Oracle { token1: deltas.token1 / blocksElapsed }); + updateLast = _now; + state = OracleStates.Active; } function update() external { require(state == OracleStates.Active, "Oracle: INACTIVE"); - // get the current time, ensure it's been >=1 blocks since last update, and record the update - TimeData memory currentTime = getTimeData(); - uint128 blocksElapsed = currentTime.blockNumber - lastUpdate.blockNumber; + // get the current time, ensure it's been >=1 blocks since the last update + TimeData memory _now = getNow(); + uint128 blocksElapsed = _now.blockNumber - updateLast.blockNumber; require(blocksElapsed > 0, "Oracle: INSUFFICIENT_BLOCKS_PASSED"); - uint128 timeElapsed = currentTime.blockTimestamp - lastUpdate.blockTimestamp; - lastUpdate = currentTime; + uint128 timeElapsed = _now.blockTimestamp - updateLast.blockTimestamp; - // get the current cumulative reserves, calculate the deltas, and record the new values - TokenData memory reservesCumulativeNext = getReservesCumulative(); + // get the current cumulative reserves and overflows + TokenData memory reservesCumulativeNext; + TokenData memory reservesCumulativeOverflowsNext; + (reservesCumulativeNext, reservesCumulativeOverflowsNext) = getReservesCumulative(); + + // reset if there's been an overflow + if ( + reservesCumulativeOverflows.token0 != reservesCumulativeOverflowsNext.token0 || + reservesCumulativeOverflows.token1 != reservesCumulativeOverflowsNext.token1 + ) { + reset(); + require(false, "Oracle: OVERFLOW"); + } + + // calculate the deltas, and record the new values TokenData memory deltas = TokenData({ token0: reservesCumulativeNext.token0 - reservesCumulative.token0, token1: reservesCumulativeNext.token1 - reservesCumulative.token1 @@ -115,6 +154,8 @@ contract Oracle { } else { currentPrice = averages; } + + updateLast = _now; } function getCurrentPrice() external view returns (uint128, uint128) { diff --git a/test/Oracle.spec.ts b/test/Oracle.spec.ts index 860ed9c..b86c3c7 100644 --- a/test/Oracle.spec.ts +++ b/test/Oracle.spec.ts @@ -1,126 +1,126 @@ -import path from 'path' -import chai from 'chai' -import { solidity, createMockProvider, getWallets, createFixtureLoader, deployContract } from 'ethereum-waffle' -import { Contract } from 'ethers' -import { BigNumber, bigNumberify } from 'ethers/utils' +// import path from 'path' +// import chai from 'chai' +// import { solidity, createMockProvider, getWallets, createFixtureLoader, deployContract } from 'ethereum-waffle' +// import { Contract } from 'ethers' +// import { BigNumber, bigNumberify } from 'ethers/utils' -import { expandTo18Decimals, mineBlocks } from './shared/utilities' -import { exchangeFixture, ExchangeFixture } from './shared/fixtures' +// import { expandTo18Decimals, mineBlocks } from './shared/utilities' +// import { exchangeFixture, ExchangeFixture } from './shared/fixtures' -import Oracle from '../build/Oracle.json' +// import Oracle from '../build/Oracle.json' -const ONE_DAY = 60 * 60 * 24 +// const ONE_DAY = 60 * 60 * 24 -chai.use(solidity) -const { expect } = chai +// chai.use(solidity) +// const { expect } = chai -interface OracleSnapshot { - cumulativeReserves: BigNumber[] - blockNumber: number - time: number -} +// interface OracleSnapshot { +// cumulativeReserves: BigNumber[] +// blockNumber: number +// time: number +// } -describe('Oracle', () => { - const provider = createMockProvider(path.join(__dirname, '..', 'waffle.json')) - const [wallet] = getWallets(provider) - const loadFixture = createFixtureLoader(provider, [wallet]) +// describe('Oracle', () => { +// const provider = createMockProvider(path.join(__dirname, '..', 'waffle.json')) +// const [wallet] = getWallets(provider) +// const loadFixture = createFixtureLoader(provider, [wallet]) - let token0: Contract - let token1: Contract - let exchange: Contract - let oracle: Contract - beforeEach(async () => { - const { token0: _token0, token1: _token1, exchange: _exchange } = (await loadFixture( - exchangeFixture as any - )) as ExchangeFixture - token0 = _token0 - token1 = _token1 - exchange = _exchange - oracle = await deployContract(wallet, Oracle, [exchange.address]) - }) +// let token0: Contract +// let token1: Contract +// let exchange: Contract +// let oracle: Contract +// beforeEach(async () => { +// const { token0: _token0, token1: _token1, exchange: _exchange } = (await loadFixture( +// exchangeFixture as any +// )) as ExchangeFixture +// token0 = _token0 +// token1 = _token1 +// exchange = _exchange +// oracle = await deployContract(wallet, Oracle, [exchange.address]) +// }) - async function addLiquidity(token0Amount: BigNumber, token1Amount: BigNumber) { - await token0.transfer(exchange.address, token0Amount) - await token1.transfer(exchange.address, token1Amount) - await exchange.connect(wallet).mintLiquidity(wallet.address) - } +// async function addLiquidity(token0Amount: BigNumber, token1Amount: BigNumber) { +// await token0.transfer(exchange.address, token0Amount) +// await token1.transfer(exchange.address, token1Amount) +// await exchange.connect(wallet).mintLiquidity(wallet.address) +// } - async function swap(inputToken: Contract, amount: BigNumber) { - const token0 = await exchange.token0() - const reserves = await exchange.getReserves() +// async function swap(inputToken: Contract, amount: BigNumber) { +// const token0 = await exchange.token0() +// const reserves = await exchange.getReserves() - const inputReserve = inputToken.address === token0 ? reserves[0] : reserves[1] - const outputReserve = inputToken.address === token0 ? reserves[1] : reserves[0] - const outputAmount = await exchange.getAmountOutput(amount, inputReserve, outputReserve) +// const inputReserve = inputToken.address === token0 ? reserves[0] : reserves[1] +// const outputReserve = inputToken.address === token0 ? reserves[1] : reserves[0] +// const outputAmount = await exchange.getAmountOutput(amount, inputReserve, outputReserve) - await inputToken.transfer(exchange.address, amount) - await exchange.connect(wallet).swap(inputToken.address, wallet.address) +// await inputToken.transfer(exchange.address, amount) +// await exchange.connect(wallet).swap(inputToken.address, wallet.address) - return outputAmount - } +// return outputAmount +// } - it('exchange, getCurrentPrice', async () => { - expect(await oracle.exchange()).to.eq(exchange.address) - expect(await oracle.getCurrentPrice()).to.deep.eq([0, 0].map(n => bigNumberify(n))) - }) +// it('exchange, getCurrentPrice', async () => { +// expect(await oracle.exchange()).to.eq(exchange.address) +// expect(await oracle.getCurrentPrice()).to.deep.eq([0, 0].map(n => bigNumberify(n))) +// }) - async function getOracleSnapshot(): Promise { - const cumulativeReserves = await exchange.getReservesCumulativeAndOverflows() - const blockNumber = await provider.getBlockNumber() - const time = (await provider.getBlock(blockNumber)).timestamp +// async function getOracleSnapshot(): Promise { +// const cumulativeReserves = await exchange.getReservesCumulative() +// const blockNumber = await provider.getBlockNumber() +// const time = (await provider.getBlock(blockNumber)).timestamp - return { - cumulativeReserves, - blockNumber, - time - } - } +// return { +// cumulativeReserves, +// blockNumber, +// time +// } +// } - // function getExpectedOraclePrice( - // preSnapshot: OracleSnapshot, - // postSnapshot: OracleSnapshot, - // oldPrice: BigNumber[], - // elapsedTime: number - // ) { - // return 1 - // } +// // function getExpectedOraclePrice( +// // preSnapshot: OracleSnapshot, +// // postSnapshot: OracleSnapshot, +// // oldPrice: BigNumber[], +// // elapsedTime: number +// // ) { +// // return 1 +// // } - it('updateCurrentPrice', async () => { - const token0Amount = expandTo18Decimals(5) - const token1Amount = expandTo18Decimals(10) - await addLiquidity(token0Amount, token1Amount) +// // it('updateCurrentPrice', async () => { +// // const token0Amount = expandTo18Decimals(5) +// // const token1Amount = expandTo18Decimals(10) +// // await addLiquidity(token0Amount, token1Amount) - await oracle.connect(wallet).initialize() - expect(await oracle.getCurrentPrice()).to.deep.eq([0, 0].map(n => bigNumberify(n))) +// // await oracle.connect(wallet).initialize() +// // expect(await oracle.getCurrentPrice()).to.deep.eq([0, 0].map(n => bigNumberify(n))) - await oracle.connect(wallet).activate() - expect(await oracle.getCurrentPrice()).to.deep.eq([token0Amount, token1Amount]) +// // await oracle.connect(wallet).activate() +// // expect(await oracle.getCurrentPrice()).to.deep.eq([token0Amount, token1Amount]) - const preSwapSnapshot = await getOracleSnapshot() +// // const preSwapSnapshot = await getOracleSnapshot() - const swapAmount = expandTo18Decimals(5) - const expectedToken1Amount = await swap(token0, swapAmount) - const postSwapToken0Amount = token0Amount.add(swapAmount) - const postSwapToken1Amount = token1Amount.sub(expectedToken1Amount) +// // const swapAmount = expandTo18Decimals(5) +// // const expectedToken1Amount = await swap(token0, swapAmount) +// // const postSwapToken0Amount = token0Amount.add(swapAmount) +// // const postSwapToken1Amount = token1Amount.sub(expectedToken1Amount) - const postSwapSnapshot = await getOracleSnapshot() +// // const postSwapSnapshot = await getOracleSnapshot() - const elapsedBlocks = postSwapSnapshot.blockNumber - preSwapSnapshot.blockNumber - expect(elapsedBlocks).to.eq(2) +// // const elapsedBlocks = postSwapSnapshot.blockNumber - preSwapSnapshot.blockNumber +// // expect(elapsedBlocks).to.eq(2) - await oracle.connect(wallet).update() +// // await oracle.connect(wallet).update() - const elapsedTime = postSwapSnapshot.time - preSwapSnapshot.time - if (elapsedTime === 0) { - expect(await oracle.getCurrentPrice()).to.deep.eq([token0Amount, token1Amount]) - } else { - console.log('uh oh!') - // expect(await oracle.getCurrentPrice()).to.deep.eq([token0Amount, token1Amount]) - } +// // const elapsedTime = postSwapSnapshot.time - preSwapSnapshot.time +// // if (elapsedTime === 0) { +// // expect(await oracle.getCurrentPrice()).to.deep.eq([token0Amount, token1Amount]) +// // } else { +// // console.log('uh oh!') +// // // expect(await oracle.getCurrentPrice()).to.deep.eq([token0Amount, token1Amount]) +// // } - // console.log((await oracle.getCurrentPrice()).map((p: BigNumber): string => p.toString())) +// // // console.log((await oracle.getCurrentPrice()).map((p: BigNumber): string => p.toString())) - // await mineBlocks(provider, 1, timePost + 60 * 60 * (24 / 2)) - // await oracle.connect(wallet).update() - }) -}) +// // // await mineBlocks(provider, 1, timePost + 60 * 60 * (24 / 2)) +// // // await oracle.connect(wallet).update() +// // }) +// }) diff --git a/test/UniswapV2.spec.ts b/test/UniswapV2.spec.ts index 878bf72..026a8aa 100644 --- a/test/UniswapV2.spec.ts +++ b/test/UniswapV2.spec.ts @@ -85,6 +85,32 @@ describe('UniswapV2', () => { await exchange.connect(wallet).mintLiquidity(wallet.address) } + // it('swap:gas', async () => { + // const token0Amount = expandTo18Decimals(5) + // const token1Amount = expandTo18Decimals(10) + // await addLiquidity(token0Amount, token1Amount) + + // const swapAmount = expandTo18Decimals(1) + // await token0.transfer(exchange.address, swapAmount) + // await exchange.connect(wallet).swap(token0.address, wallet.address) + + // await token0.transfer(exchange.address, swapAmount) + // console.log((await exchange.estimate.swap(token0.address, wallet.address)).toString()) + // }) + + // it('swap:gas', async () => { + // const token0Amount = expandTo18Decimals(10) + // const token1Amount = expandTo18Decimals(5) + // await addLiquidity(token0Amount, token1Amount) + + // const swapAmount = expandTo18Decimals(1) + // await token1.transfer(exchange.address, swapAmount) + // await exchange.connect(wallet).swap(token1.address, wallet.address) + + // await token1.transfer(exchange.address, swapAmount) + // console.log((await exchange.estimate.swap(token1.address, wallet.address)).toString()) + // }) + it('swap', async () => { const token0Amount = expandTo18Decimals(5) const token1Amount = expandTo18Decimals(10) @@ -92,17 +118,9 @@ describe('UniswapV2', () => { const swapAmount = expandTo18Decimals(1) const expectedOutputAmount = bigNumberify('1662497915624478906') - await token0.transfer(exchange.address, swapAmount) - console.log(await exchange.estimate.swap(token0.address, wallet.address)) - await expect( - exchange - .connect(wallet) - .swap(token0.address, wallet.address) - .then((a: any) => { - console.log(a) - }) - ) + expect(await exchange.swap) + await expect(exchange.connect(wallet).swap(token0.address, wallet.address)) .to.emit(exchange, 'Swap') .withArgs(wallet.address, wallet.address, token0.address, swapAmount, expectedOutputAmount) @@ -135,36 +153,37 @@ describe('UniswapV2', () => { expect(await token1.balanceOf(wallet.address)).to.eq(totalSupplyToken1) }) - // it('getReserves', async () => { - // expect(await exchange.getReserves()).to.deep.eq([0, 0].map(n => bigNumberify(n))) - - // const token0Amount = expandTo18Decimals(3) - // const token1Amount = expandTo18Decimals(3) - // await addLiquidity(token0Amount, token1Amount) - - // expect(await exchange.getReserves()).to.deep.eq([token0Amount, token1Amount]) - // }) - - it('getReservesCumulativeAndOverflows', async () => { - expect(await exchange.getReservesCumulativeAndOverflows()).to.deep.eq([0, 0, 0, 0].map(n => bigNumberify(n))) + it('getReserves', async () => { + expect(await exchange.getReserves()).to.deep.eq([0, 0].map(n => bigNumberify(n))) const token0Amount = expandTo18Decimals(3) const token1Amount = expandTo18Decimals(3) await addLiquidity(token0Amount, token1Amount) - const reservesCumulativePre = await exchange.getReservesCumulativeAndOverflows() - expect(reservesCumulativePre).to.deep.eq([0, 0, 0, 0].map(n => bigNumberify(n))) + expect(await exchange.getReserves()).to.deep.eq([token0Amount, token1Amount]) + }) + + it('getReservesCumulative', async () => { + await expect(exchange.getReservesCumulative()).to.be.revertedWith('UniswapV2: NOT_INITIALIZED') + + const token0Amount = expandTo18Decimals(3) + const token1Amount = expandTo18Decimals(3) + await addLiquidity(token0Amount, token1Amount) + + expect(await exchange.getReservesCumulative()).to.deep.eq( + [0, 0, 0, 0].map((n: number): BigNumber => bigNumberify(n)) + ) const dummySwapAmount = bigNumberify(1) await token0.transfer(exchange.address, dummySwapAmount) await exchange.connect(wallet).swap(token0.address, wallet.address) - const reservesCumulativePost = await exchange.getReservesCumulativeAndOverflows() + const reservesCumulativePost = await exchange.getReservesCumulative() expect(reservesCumulativePost).to.deep.eq([ token0Amount.mul(bigNumberify(2)), token1Amount.mul(bigNumberify(2)), - 0, - 0 + bigNumberify(0), + bigNumberify(0) ]) }) })