exchange -> pair

This commit is contained in:
Noah Zinsmeister
2020-03-17 18:05:28 -04:00
parent 170a739f08
commit 1136544ac8
13 changed files with 22637 additions and 22650 deletions

1
.gitignore vendored
View File

@ -1,2 +1 @@
build/
node_modules/

File diff suppressed because one or more lines are too long

View File

@ -18,7 +18,7 @@
{
"indexed": false,
"internalType": "address",
"name": "exchange",
"name": "pair",
"type": "address"
},
{
@ -28,7 +28,7 @@
"type": "uint256"
}
],
"name": "ExchangeCreated",
"name": "PairCreated",
"type": "event"
},
{
@ -40,11 +40,11 @@
"type": "uint256"
}
],
"name": "allExchanges",
"name": "allPairs",
"outputs": [
{
"internalType": "address",
"name": "exchange",
"name": "pair",
"type": "address"
}
],
@ -55,7 +55,7 @@
{
"constant": true,
"inputs": [],
"name": "allExchangesLength",
"name": "allPairsLength",
"outputs": [
{
"internalType": "uint256",
@ -81,11 +81,11 @@
"type": "address"
}
],
"name": "createExchange",
"name": "createPair",
"outputs": [
{
"internalType": "address",
"name": "exchange",
"name": "pair",
"type": "address"
}
],
@ -137,11 +137,11 @@
"type": "address"
}
],
"name": "getExchange",
"name": "getPair",
"outputs": [
{
"internalType": "address",
"name": "exchange",
"name": "pair",
"type": "address"
}
],
@ -213,7 +213,7 @@
{
"indexed": false,
"internalType": "address",
"name": "exchange",
"name": "pair",
"type": "address"
},
{
@ -223,7 +223,7 @@
"type": "uint256"
}
],
"name": "ExchangeCreated",
"name": "PairCreated",
"type": "event"
},
{
@ -235,11 +235,11 @@
"type": "uint256"
}
],
"name": "allExchanges",
"name": "allPairs",
"outputs": [
{
"internalType": "address",
"name": "exchange",
"name": "pair",
"type": "address"
}
],
@ -250,7 +250,7 @@
{
"constant": true,
"inputs": [],
"name": "allExchangesLength",
"name": "allPairsLength",
"outputs": [
{
"internalType": "uint256",
@ -276,11 +276,11 @@
"type": "address"
}
],
"name": "createExchange",
"name": "createPair",
"outputs": [
{
"internalType": "address",
"name": "exchange",
"name": "pair",
"type": "address"
}
],
@ -332,11 +332,11 @@
"type": "address"
}
],
"name": "getExchange",
"name": "getPair",
"outputs": [
{
"internalType": "address",
"name": "exchange",
"name": "pair",
"type": "address"
}
],

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,41 +1,40 @@
pragma solidity =0.5.16;
import './interfaces/IUniswapV2Factory.sol';
import './UniswapV2Exchange.sol';
import './interfaces/IUniswapV2Exchange.sol';
import './UniswapV2Pair.sol';
contract UniswapV2Factory is IUniswapV2Factory {
address public feeTo;
address public feeToSetter;
mapping(address => mapping(address => address)) public getExchange;
address[] public allExchanges;
mapping(address => mapping(address => address)) public getPair;
address[] public allPairs;
event ExchangeCreated(address indexed token0, address indexed token1, address exchange, uint);
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
constructor(address _feeToSetter) public {
feeToSetter = _feeToSetter;
}
function allExchangesLength() external view returns (uint) {
return allExchanges.length;
function allPairsLength() external view returns (uint) {
return allPairs.length;
}
function createExchange(address tokenA, address tokenB) external returns (address exchange) {
function createPair(address tokenA, address tokenB) external returns (address pair) {
require(tokenA != tokenB, 'UniswapV2: IDENTICAL_ADDRESSES');
(address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
require(token0 != address(0), 'UniswapV2: ZERO_ADDRESS');
require(getExchange[token0][token1] == address(0), 'UniswapV2: EXCHANGE_EXISTS'); // single check is sufficient
bytes memory exchangeBytecode = type(UniswapV2Exchange).creationCode;
require(getPair[token0][token1] == address(0), 'UniswapV2: PAIR_EXISTS'); // single check is sufficient
bytes memory bytecode = type(UniswapV2Pair).creationCode;
bytes32 salt = keccak256(abi.encodePacked(token0, token1));
assembly {
exchange := create2(0, add(exchangeBytecode, 32), mload(exchangeBytecode), salt)
pair := create2(0, add(bytecode, 32), mload(bytecode), salt)
}
IUniswapV2Exchange(exchange).initialize(token0, token1);
getExchange[token0][token1] = exchange;
getExchange[token1][token0] = exchange; // populate mapping in the reverse direction
allExchanges.push(exchange);
emit ExchangeCreated(token0, token1, exchange, allExchanges.length);
IUniswapV2Pair(pair).initialize(token0, token1);
getPair[token0][token1] = pair;
getPair[token1][token0] = pair; // populate mapping in the reverse direction
allPairs.push(pair);
emit PairCreated(token0, token1, pair, allPairs.length);
}
function setFeeTo(address _feeTo) external {

View File

@ -1,6 +1,6 @@
pragma solidity =0.5.16;
import './interfaces/IUniswapV2Exchange.sol';
import './interfaces/IUniswapV2Pair.sol';
import './UniswapV2ERC20.sol';
import './libraries/Math.sol';
import './libraries/UQ112x112.sol';
@ -8,7 +8,7 @@ import './interfaces/IERC20.sol';
import './interfaces/IUniswapV2Factory.sol';
import './interfaces/IUniswapV2Callee.sol';
contract UniswapV2Exchange is IUniswapV2Exchange, UniswapV2ERC20 {
contract UniswapV2Pair is IUniswapV2Pair, UniswapV2ERC20 {
using SafeMath for uint;
using UQ112x112 for uint224;

View File

@ -1,16 +1,16 @@
pragma solidity =0.5.16;
interface IUniswapV2Factory {
event ExchangeCreated(address indexed token0, address indexed token1, address exchange, uint);
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function getExchange(address tokenA, address tokenB) external view returns (address exchange);
function allExchanges(uint) external view returns (address exchange);
function allExchangesLength() external view returns (uint);
function getPair(address tokenA, address tokenB) external view returns (address pair);
function allPairs(uint) external view returns (address pair);
function allPairsLength() external view returns (uint);
function createExchange(address tokenA, address tokenB) external returns (address exchange);
function createPair(address tokenA, address tokenB) external returns (address pair);
function setFeeTo(address) external;
function setFeeToSetter(address) external;

View File

@ -1,6 +1,6 @@
pragma solidity =0.5.16;
interface IUniswapV2Exchange {
interface IUniswapV2Pair {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);

View File

@ -7,7 +7,7 @@ import { solidity, MockProvider, createFixtureLoader } from 'ethereum-waffle'
import { getCreate2Address } from './shared/utilities'
import { factoryFixture } from './shared/fixtures'
import UniswapV2Exchange from '../build/UniswapV2Exchange.json'
import UniswapV2Pair from '../build/UniswapV2Pair.json'
chai.use(solidity)
@ -31,43 +31,43 @@ describe('UniswapV2Factory', () => {
factory = fixture.factory
})
it('feeTo, feeToSetter, allExchanges, allExchangesLength', async () => {
it('feeTo, feeToSetter, allPairsLength', async () => {
expect(await factory.feeTo()).to.eq(AddressZero)
expect(await factory.feeToSetter()).to.eq(wallet.address)
expect(await factory.allExchangesLength()).to.eq(0)
expect(await factory.allPairsLength()).to.eq(0)
})
async function createExchange(tokens: [string, string]) {
const bytecode = `0x${UniswapV2Exchange.evm.bytecode.object}`
async function createPair(tokens: [string, string]) {
const bytecode = `0x${UniswapV2Pair.evm.bytecode.object}`
const create2Address = getCreate2Address(factory.address, tokens, bytecode)
await expect(factory.createExchange(...tokens))
.to.emit(factory, 'ExchangeCreated')
await expect(factory.createPair(...tokens))
.to.emit(factory, 'PairCreated')
.withArgs(TEST_ADDRESSES[0], TEST_ADDRESSES[1], create2Address, bigNumberify(1))
await expect(factory.createExchange(...tokens)).to.be.reverted // UniswapV2: EXCHANGE_EXISTS
await expect(factory.createExchange(...tokens.slice().reverse())).to.be.reverted // UniswapV2: EXCHANGE_EXISTS
expect(await factory.getExchange(...tokens)).to.eq(create2Address)
expect(await factory.getExchange(...tokens.slice().reverse())).to.eq(create2Address)
expect(await factory.allExchanges(0)).to.eq(create2Address)
expect(await factory.allExchangesLength()).to.eq(1)
await expect(factory.createPair(...tokens)).to.be.reverted // UniswapV2: PAIR_EXISTS
await expect(factory.createPair(...tokens.slice().reverse())).to.be.reverted // UniswapV2: PAIR_EXISTS
expect(await factory.getPair(...tokens)).to.eq(create2Address)
expect(await factory.getPair(...tokens.slice().reverse())).to.eq(create2Address)
expect(await factory.allPairs(0)).to.eq(create2Address)
expect(await factory.allPairsLength()).to.eq(1)
const exchange = new Contract(create2Address, JSON.stringify(UniswapV2Exchange.abi), provider)
expect(await exchange.factory()).to.eq(factory.address)
expect(await exchange.token0()).to.eq(TEST_ADDRESSES[0])
expect(await exchange.token1()).to.eq(TEST_ADDRESSES[1])
const pair = new Contract(create2Address, JSON.stringify(UniswapV2Pair.abi), provider)
expect(await pair.factory()).to.eq(factory.address)
expect(await pair.token0()).to.eq(TEST_ADDRESSES[0])
expect(await pair.token1()).to.eq(TEST_ADDRESSES[1])
}
it('createExchange', async () => {
await createExchange(TEST_ADDRESSES)
it('createPair', async () => {
await createPair(TEST_ADDRESSES)
})
it('createExchange:reverse', async () => {
await createExchange(TEST_ADDRESSES.slice().reverse() as [string, string])
it('createPair:reverse', async () => {
await createPair(TEST_ADDRESSES.slice().reverse() as [string, string])
})
it('createExchange:gas', async () => {
const gasCost = await factory.estimate.createExchange(...TEST_ADDRESSES)
console.log(`Gas required for createExchange: ${gasCost}`)
it('createPair:gas', async () => {
const gasCost = await factory.estimate.createPair(...TEST_ADDRESSES)
console.log(`Gas required for createPair: ${gasCost}`)
})
it('setFeeTo', async () => {

View File

@ -4,7 +4,7 @@ import { solidity, MockProvider, createFixtureLoader } from 'ethereum-waffle'
import { BigNumber, bigNumberify } from 'ethers/utils'
import { expandTo18Decimals, mineBlock, encodePrice } from './shared/utilities'
import { exchangeFixture } from './shared/fixtures'
import { pairFixture } from './shared/fixtures'
import { AddressZero } from 'ethers/constants'
const MINIMUM_LIQUIDITY = bigNumberify(10).pow(3)
@ -15,7 +15,7 @@ const overrides = {
gasLimit: 9999999
}
describe('UniswapV2Exchange', () => {
describe('UniswapV2Pair', () => {
const provider = new MockProvider({
hardfork: 'istanbul',
mnemonic: 'horn horn horn horn horn horn horn horn horn horn horn horn',
@ -27,46 +27,46 @@ describe('UniswapV2Exchange', () => {
let factory: Contract
let token0: Contract
let token1: Contract
let exchange: Contract
let pair: Contract
beforeEach(async () => {
const fixture = await loadFixture(exchangeFixture)
const fixture = await loadFixture(pairFixture)
factory = fixture.factory
token0 = fixture.token0
token1 = fixture.token1
exchange = fixture.exchange
pair = fixture.pair
})
it('mint', async () => {
const token0Amount = expandTo18Decimals(1)
const token1Amount = expandTo18Decimals(4)
await token0.transfer(exchange.address, token0Amount)
await token1.transfer(exchange.address, token1Amount)
await token0.transfer(pair.address, token0Amount)
await token1.transfer(pair.address, token1Amount)
const expectedLiquidity = expandTo18Decimals(2)
await expect(exchange.mint(wallet.address, overrides))
.to.emit(exchange, 'Transfer')
await expect(pair.mint(wallet.address, overrides))
.to.emit(pair, 'Transfer')
.withArgs(AddressZero, AddressZero, MINIMUM_LIQUIDITY)
// commented out because of this bug: https://github.com/EthWorks/Waffle/issues/100
// .to.emit(exchange, 'Transfer')
// .to.emit(pair, 'Transfer')
// .withArgs(AddressZero, wallet.address, expectedLiquidity.sub(MINIMUM_LIQUIDITY))
.to.emit(exchange, 'Sync')
.to.emit(pair, 'Sync')
.withArgs(token0Amount, token1Amount)
.to.emit(exchange, 'Mint')
.to.emit(pair, 'Mint')
.withArgs(wallet.address, token0Amount, token1Amount)
expect(await exchange.totalSupply()).to.eq(expectedLiquidity)
expect(await exchange.balanceOf(wallet.address)).to.eq(expectedLiquidity.sub(MINIMUM_LIQUIDITY))
expect(await token0.balanceOf(exchange.address)).to.eq(token0Amount)
expect(await token1.balanceOf(exchange.address)).to.eq(token1Amount)
const reserves = await exchange.getReserves()
expect(await pair.totalSupply()).to.eq(expectedLiquidity)
expect(await pair.balanceOf(wallet.address)).to.eq(expectedLiquidity.sub(MINIMUM_LIQUIDITY))
expect(await token0.balanceOf(pair.address)).to.eq(token0Amount)
expect(await token1.balanceOf(pair.address)).to.eq(token1Amount)
const reserves = await pair.getReserves()
expect(reserves[0]).to.eq(token0Amount)
expect(reserves[1]).to.eq(token1Amount)
})
async function addLiquidity(token0Amount: BigNumber, token1Amount: BigNumber) {
await token0.transfer(exchange.address, token0Amount)
await token1.transfer(exchange.address, token1Amount)
await exchange.mint(wallet.address, overrides)
await token0.transfer(pair.address, token0Amount)
await token1.transfer(pair.address, token1Amount)
await pair.mint(wallet.address, overrides)
}
const swapTestCases: BigNumber[][] = [
[1, 5, 10, '1662497915624478906'],
@ -83,11 +83,11 @@ describe('UniswapV2Exchange', () => {
it(`getInputPrice:${i}`, async () => {
const [swapAmount, token0Amount, token1Amount, expectedOutputAmount] = swapTestCase
await addLiquidity(token0Amount, token1Amount)
await token0.transfer(exchange.address, swapAmount)
await expect(exchange.swap(0, expectedOutputAmount.add(1), wallet.address, '0x', overrides)).to.be.revertedWith(
await token0.transfer(pair.address, swapAmount)
await expect(pair.swap(0, expectedOutputAmount.add(1), wallet.address, '0x', overrides)).to.be.revertedWith(
'UniswapV2: K'
)
await exchange.swap(0, expectedOutputAmount, wallet.address, '0x', overrides)
await pair.swap(0, expectedOutputAmount, wallet.address, '0x', overrides)
})
})
@ -101,11 +101,11 @@ describe('UniswapV2Exchange', () => {
it(`optimistic:${i}`, async () => {
const [outputAmount, token0Amount, token1Amount, inputAmount] = optimisticTestCase
await addLiquidity(token0Amount, token1Amount)
await token0.transfer(exchange.address, inputAmount)
await expect(exchange.swap(outputAmount.add(1), 0, wallet.address, '0x', overrides)).to.be.revertedWith(
await token0.transfer(pair.address, inputAmount)
await expect(pair.swap(outputAmount.add(1), 0, wallet.address, '0x', overrides)).to.be.revertedWith(
'UniswapV2: K'
)
await exchange.swap(outputAmount, 0, wallet.address, '0x', overrides)
await pair.swap(outputAmount, 0, wallet.address, '0x', overrides)
})
})
@ -116,20 +116,20 @@ describe('UniswapV2Exchange', () => {
const swapAmount = expandTo18Decimals(1)
const expectedOutputAmount = bigNumberify('1662497915624478906')
await token0.transfer(exchange.address, swapAmount)
await expect(exchange.swap(0, expectedOutputAmount, wallet.address, '0x', overrides))
await token0.transfer(pair.address, swapAmount)
await expect(pair.swap(0, expectedOutputAmount, wallet.address, '0x', overrides))
.to.emit(token1, 'Transfer')
.withArgs(exchange.address, wallet.address, expectedOutputAmount)
.to.emit(exchange, 'Sync')
.withArgs(pair.address, wallet.address, expectedOutputAmount)
.to.emit(pair, 'Sync')
.withArgs(token0Amount.add(swapAmount), token1Amount.sub(expectedOutputAmount))
.to.emit(exchange, 'Swap')
.to.emit(pair, 'Swap')
.withArgs(wallet.address, swapAmount, 0, 0, expectedOutputAmount, wallet.address)
const reserves = await exchange.getReserves()
const reserves = await pair.getReserves()
expect(reserves[0]).to.eq(token0Amount.add(swapAmount))
expect(reserves[1]).to.eq(token1Amount.sub(expectedOutputAmount))
expect(await token0.balanceOf(exchange.address)).to.eq(token0Amount.add(swapAmount))
expect(await token1.balanceOf(exchange.address)).to.eq(token1Amount.sub(expectedOutputAmount))
expect(await token0.balanceOf(pair.address)).to.eq(token0Amount.add(swapAmount))
expect(await token1.balanceOf(pair.address)).to.eq(token1Amount.sub(expectedOutputAmount))
const totalSupplyToken0 = await token0.totalSupply()
const totalSupplyToken1 = await token1.totalSupply()
expect(await token0.balanceOf(wallet.address)).to.eq(totalSupplyToken0.sub(token0Amount).sub(swapAmount))
@ -143,20 +143,20 @@ describe('UniswapV2Exchange', () => {
const swapAmount = expandTo18Decimals(1)
const expectedOutputAmount = bigNumberify('453305446940074565')
await token1.transfer(exchange.address, swapAmount)
await expect(exchange.swap(expectedOutputAmount, 0, wallet.address, '0x', overrides))
await token1.transfer(pair.address, swapAmount)
await expect(pair.swap(expectedOutputAmount, 0, wallet.address, '0x', overrides))
.to.emit(token0, 'Transfer')
.withArgs(exchange.address, wallet.address, expectedOutputAmount)
.to.emit(exchange, 'Sync')
.withArgs(pair.address, wallet.address, expectedOutputAmount)
.to.emit(pair, 'Sync')
.withArgs(token0Amount.sub(expectedOutputAmount), token1Amount.add(swapAmount))
.to.emit(exchange, 'Swap')
.to.emit(pair, 'Swap')
.withArgs(wallet.address, 0, swapAmount, expectedOutputAmount, 0, wallet.address)
const reserves = await exchange.getReserves()
const reserves = await pair.getReserves()
expect(reserves[0]).to.eq(token0Amount.sub(expectedOutputAmount))
expect(reserves[1]).to.eq(token1Amount.add(swapAmount))
expect(await token0.balanceOf(exchange.address)).to.eq(token0Amount.sub(expectedOutputAmount))
expect(await token1.balanceOf(exchange.address)).to.eq(token1Amount.add(swapAmount))
expect(await token0.balanceOf(pair.address)).to.eq(token0Amount.sub(expectedOutputAmount))
expect(await token1.balanceOf(pair.address)).to.eq(token1Amount.add(swapAmount))
const totalSupplyToken0 = await token0.totalSupply()
const totalSupplyToken1 = await token1.totalSupply()
expect(await token0.balanceOf(wallet.address)).to.eq(totalSupplyToken0.sub(token0Amount).add(expectedOutputAmount))
@ -170,13 +170,13 @@ describe('UniswapV2Exchange', () => {
// ensure that setting price{0,1}CumulativeLast for the first time doesn't affect our gas math
await mineBlock(provider, (await provider.getBlock('latest')).timestamp + 1)
await exchange.sync(overrides)
await pair.sync(overrides)
const swapAmount = expandTo18Decimals(1)
const expectedOutputAmount = bigNumberify('453305446940074565')
await token1.transfer(exchange.address, swapAmount)
await token1.transfer(pair.address, swapAmount)
await mineBlock(provider, (await provider.getBlock('latest')).timestamp + 1)
const gasCost = await exchange.estimate.swap(expectedOutputAmount, 0, wallet.address, '0x', overrides)
const gasCost = await pair.estimate.swap(expectedOutputAmount, 0, wallet.address, '0x', overrides)
console.log(`Gas required for swap: ${gasCost}`)
})
@ -186,24 +186,24 @@ describe('UniswapV2Exchange', () => {
await addLiquidity(token0Amount, token1Amount)
const expectedLiquidity = expandTo18Decimals(3)
await exchange.transfer(exchange.address, expectedLiquidity.sub(MINIMUM_LIQUIDITY))
await expect(exchange.burn(wallet.address, overrides))
.to.emit(exchange, 'Transfer')
.withArgs(exchange.address, AddressZero, expectedLiquidity.sub(MINIMUM_LIQUIDITY))
await pair.transfer(pair.address, expectedLiquidity.sub(MINIMUM_LIQUIDITY))
await expect(pair.burn(wallet.address, overrides))
.to.emit(pair, 'Transfer')
.withArgs(pair.address, AddressZero, expectedLiquidity.sub(MINIMUM_LIQUIDITY))
// commented out because of this bug: https://github.com/EthWorks/Waffle/issues/100
// .to.emit(token0, 'Transfer')
// .withArgs(exchange.address, wallet.address, token0Amount.sub(1000))
// .withArgs(pair.address, wallet.address, token0Amount.sub(1000))
// .to.emit(token1, 'Transfer')
// .withArgs(exchange.address, wallet.address, token1Amount.sub(1000))
.to.emit(exchange, 'Sync')
// .withArgs(pair.address, wallet.address, token1Amount.sub(1000))
.to.emit(pair, 'Sync')
.withArgs(1000, 1000)
.to.emit(exchange, 'Burn')
.to.emit(pair, 'Burn')
.withArgs(wallet.address, token0Amount.sub(1000), token1Amount.sub(1000), wallet.address)
expect(await exchange.balanceOf(wallet.address)).to.eq(0)
expect(await exchange.totalSupply()).to.eq(MINIMUM_LIQUIDITY)
expect(await token0.balanceOf(exchange.address)).to.eq(1000)
expect(await token1.balanceOf(exchange.address)).to.eq(1000)
expect(await pair.balanceOf(wallet.address)).to.eq(0)
expect(await pair.totalSupply()).to.eq(MINIMUM_LIQUIDITY)
expect(await token0.balanceOf(pair.address)).to.eq(1000)
expect(await token1.balanceOf(pair.address)).to.eq(1000)
const totalSupplyToken0 = await token0.totalSupply()
const totalSupplyToken1 = await token1.totalSupply()
expect(await token0.balanceOf(wallet.address)).to.eq(totalSupplyToken0.sub(1000))
@ -215,32 +215,32 @@ describe('UniswapV2Exchange', () => {
const token1Amount = expandTo18Decimals(3)
await addLiquidity(token0Amount, token1Amount)
const blockTimestamp = (await exchange.getReserves())[2]
const blockTimestamp = (await pair.getReserves())[2]
await mineBlock(provider, blockTimestamp + 1)
await exchange.sync(overrides)
await pair.sync(overrides)
const initialPrice = encodePrice(token0Amount, token1Amount)
expect(await exchange.price0CumulativeLast()).to.eq(initialPrice[0])
expect(await exchange.price1CumulativeLast()).to.eq(initialPrice[1])
expect((await exchange.getReserves())[2]).to.eq(blockTimestamp + 1)
expect(await pair.price0CumulativeLast()).to.eq(initialPrice[0])
expect(await pair.price1CumulativeLast()).to.eq(initialPrice[1])
expect((await pair.getReserves())[2]).to.eq(blockTimestamp + 1)
const swapAmount = expandTo18Decimals(3)
await token0.transfer(exchange.address, swapAmount)
await token0.transfer(pair.address, swapAmount)
await mineBlock(provider, blockTimestamp + 10)
// swap to a new price eagerly instead of syncing
await exchange.swap(0, expandTo18Decimals(1), wallet.address, '0x', overrides) // make the price nice
await pair.swap(0, expandTo18Decimals(1), wallet.address, '0x', overrides) // make the price nice
expect(await exchange.price0CumulativeLast()).to.eq(initialPrice[0].mul(10))
expect(await exchange.price1CumulativeLast()).to.eq(initialPrice[1].mul(10))
expect((await exchange.getReserves())[2]).to.eq(blockTimestamp + 10)
expect(await pair.price0CumulativeLast()).to.eq(initialPrice[0].mul(10))
expect(await pair.price1CumulativeLast()).to.eq(initialPrice[1].mul(10))
expect((await pair.getReserves())[2]).to.eq(blockTimestamp + 10)
await mineBlock(provider, blockTimestamp + 20)
await exchange.sync(overrides)
await pair.sync(overrides)
const newPrice = encodePrice(expandTo18Decimals(6), expandTo18Decimals(2))
expect(await exchange.price0CumulativeLast()).to.eq(initialPrice[0].mul(10).add(newPrice[0].mul(10)))
expect(await exchange.price1CumulativeLast()).to.eq(initialPrice[1].mul(10).add(newPrice[1].mul(10)))
expect((await exchange.getReserves())[2]).to.eq(blockTimestamp + 20)
expect(await pair.price0CumulativeLast()).to.eq(initialPrice[0].mul(10).add(newPrice[0].mul(10)))
expect(await pair.price1CumulativeLast()).to.eq(initialPrice[1].mul(10).add(newPrice[1].mul(10)))
expect((await pair.getReserves())[2]).to.eq(blockTimestamp + 20)
})
it('feeTo:off', async () => {
@ -250,13 +250,13 @@ describe('UniswapV2Exchange', () => {
const swapAmount = expandTo18Decimals(1)
const expectedOutputAmount = bigNumberify('996006981039903216')
await token1.transfer(exchange.address, swapAmount)
await exchange.swap(expectedOutputAmount, 0, wallet.address, '0x', overrides)
await token1.transfer(pair.address, swapAmount)
await pair.swap(expectedOutputAmount, 0, wallet.address, '0x', overrides)
const expectedLiquidity = expandTo18Decimals(1000)
await exchange.transfer(exchange.address, expectedLiquidity.sub(MINIMUM_LIQUIDITY))
await exchange.burn(wallet.address, overrides)
expect(await exchange.totalSupply()).to.eq(MINIMUM_LIQUIDITY)
await pair.transfer(pair.address, expectedLiquidity.sub(MINIMUM_LIQUIDITY))
await pair.burn(wallet.address, overrides)
expect(await pair.totalSupply()).to.eq(MINIMUM_LIQUIDITY)
})
it('feeTo:on', async () => {
@ -268,18 +268,18 @@ describe('UniswapV2Exchange', () => {
const swapAmount = expandTo18Decimals(1)
const expectedOutputAmount = bigNumberify('996006981039903216')
await token1.transfer(exchange.address, swapAmount)
await exchange.swap(expectedOutputAmount, 0, wallet.address, '0x', overrides)
await token1.transfer(pair.address, swapAmount)
await pair.swap(expectedOutputAmount, 0, wallet.address, '0x', overrides)
const expectedLiquidity = expandTo18Decimals(1000)
await exchange.transfer(exchange.address, expectedLiquidity.sub(MINIMUM_LIQUIDITY))
await exchange.burn(wallet.address, overrides)
expect(await exchange.totalSupply()).to.eq(MINIMUM_LIQUIDITY.add('249750499251388'))
expect(await exchange.balanceOf(other.address)).to.eq('249750499251388')
await pair.transfer(pair.address, expectedLiquidity.sub(MINIMUM_LIQUIDITY))
await pair.burn(wallet.address, overrides)
expect(await pair.totalSupply()).to.eq(MINIMUM_LIQUIDITY.add('249750499251388'))
expect(await pair.balanceOf(other.address)).to.eq('249750499251388')
// using 1000 here instead of the symbolic MINIMUM_LIQUIDITY because the amounts only happen to be equal...
// ...because the initial liquidity amounts were equal
expect(await token0.balanceOf(exchange.address)).to.eq(bigNumberify(1000).add('249501683697445'))
expect(await token1.balanceOf(exchange.address)).to.eq(bigNumberify(1000).add('250000187312969'))
expect(await token0.balanceOf(pair.address)).to.eq(bigNumberify(1000).add('249501683697445'))
expect(await token1.balanceOf(pair.address)).to.eq(bigNumberify(1000).add('250000187312969'))
})
})

View File

@ -6,7 +6,7 @@ import { expandTo18Decimals } from './utilities'
import ERC20 from '../../build/ERC20.json'
import UniswapV2Factory from '../../build/UniswapV2Factory.json'
import UniswapV2Exchange from '../../build/UniswapV2Exchange.json'
import UniswapV2Pair from '../../build/UniswapV2Pair.json'
interface FactoryFixture {
factory: Contract
@ -21,25 +21,25 @@ export async function factoryFixture(_: Web3Provider, [wallet]: Wallet[]): Promi
return { factory }
}
interface ExchangeFixture extends FactoryFixture {
interface PairFixture extends FactoryFixture {
token0: Contract
token1: Contract
exchange: Contract
pair: Contract
}
export async function exchangeFixture(provider: Web3Provider, [wallet]: Wallet[]): Promise<ExchangeFixture> {
export async function pairFixture(provider: Web3Provider, [wallet]: Wallet[]): Promise<PairFixture> {
const { factory } = await factoryFixture(provider, [wallet])
const tokenA = await deployContract(wallet, ERC20, [expandTo18Decimals(10000)], overrides)
const tokenB = await deployContract(wallet, ERC20, [expandTo18Decimals(10000)], overrides)
await factory.createExchange(tokenA.address, tokenB.address, overrides)
const exchangeAddress = await factory.getExchange(tokenA.address, tokenB.address)
const exchange = new Contract(exchangeAddress, JSON.stringify(UniswapV2Exchange.abi), provider).connect(wallet)
await factory.createPair(tokenA.address, tokenB.address, overrides)
const pairAddress = await factory.getPair(tokenA.address, tokenB.address)
const pair = new Contract(pairAddress, JSON.stringify(UniswapV2Pair.abi), provider).connect(wallet)
const token0Address = (await exchange.token0()).address
const token0Address = (await pair.token0()).address
const token0 = tokenA.address === token0Address ? tokenA : tokenB
const token1 = tokenA.address === token0Address ? tokenB : tokenA
return { factory, token0, token1, exchange }
return { factory, token0, token1, pair }
}