Commit e95375ab authored by Noah Zinsmeister's avatar Noah Zinsmeister

exchange -> pair

parent 90095700
......@@ -15,11 +15,11 @@ export class Price extends Fraction {
static fromRoute(route: Route): Price {
const prices: Price[] = []
for (const [i, exchange] of route.exchanges.entries()) {
for (const [i, pair] of route.pairs.entries()) {
prices.push(
route.path[i].equals(exchange.token0)
? new Price(exchange.reserve0.token, exchange.reserve1.token, exchange.reserve0.raw, exchange.reserve1.raw)
: new Price(exchange.reserve1.token, exchange.reserve0.token, exchange.reserve1.raw, exchange.reserve0.raw)
route.path[i].equals(pair.token0)
? new Price(pair.reserve0.token, pair.reserve1.token, pair.reserve0.raw, pair.reserve1.raw)
: new Price(pair.reserve1.token, pair.reserve0.token, pair.reserve1.raw, pair.reserve0.raw)
)
}
return prices.slice(1).reduce((accumulator, currentValue) => accumulator.multiply(currentValue), prices[0])
......
export * from './token'
export * from './exchange'
export * from './pair'
export * from './route'
export * from './trade'
......
......@@ -16,7 +16,7 @@ import { TokenAmount } from './fractions/tokenAmount'
let CACHE: { [token0Address: string]: { [token1Address: string]: string } } = {}
export class Exchange {
export class Pair {
public readonly liquidityToken: Token
private readonly tokenAmounts: [TokenAmount, TokenAmount]
......@@ -44,13 +44,13 @@ export class Exchange {
tokenA: Token,
tokenB: Token,
provider = getDefaultProvider(getNetwork(tokenA.chainId))
): Promise<Exchange> {
const address = Exchange.getAddress(tokenA, tokenB)
): Promise<Pair> {
const address = Pair.getAddress(tokenA, tokenB)
const balances = await Promise.all([
new Contract(tokenA.address, ERC20, provider).balanceOf(address),
new Contract(tokenB.address, ERC20, provider).balanceOf(address)
])
return new Exchange(new TokenAmount(tokenA, balances[0]), new TokenAmount(tokenB, balances[1]))
return new Pair(new TokenAmount(tokenA, balances[0]), new TokenAmount(tokenB, balances[1]))
}
constructor(tokenAmountA: TokenAmount, tokenAmountB: TokenAmount) {
......@@ -59,7 +59,7 @@ export class Exchange {
: [tokenAmountB, tokenAmountA]
this.liquidityToken = new Token(
tokenAmounts[0].token.chainId,
Exchange.getAddress(tokenAmounts[0].token, tokenAmounts[1].token),
Pair.getAddress(tokenAmounts[0].token, tokenAmounts[1].token),
18,
'UNI-V2',
'Uniswap V2'
......@@ -88,7 +88,7 @@ export class Exchange {
return token.equals(this.token0) ? this.reserve0 : this.reserve1
}
getOutputAmount(inputAmount: TokenAmount): [TokenAmount, Exchange] {
getOutputAmount(inputAmount: TokenAmount): [TokenAmount, Pair] {
invariant(inputAmount.token.equals(this.token0) || inputAmount.token.equals(this.token1), 'TOKEN')
if (JSBI.equal(this.reserve0.raw, ZERO) || JSBI.equal(this.reserve1.raw, ZERO)) {
throw new InsufficientReservesError()
......@@ -105,10 +105,10 @@ export class Exchange {
if (JSBI.equal(outputAmount.raw, ZERO)) {
throw new InsufficientInputAmountError()
}
return [outputAmount, new Exchange(inputReserve.add(inputAmount), outputReserve.subtract(outputAmount))]
return [outputAmount, new Pair(inputReserve.add(inputAmount), outputReserve.subtract(outputAmount))]
}
getInputAmount(outputAmount: TokenAmount): [TokenAmount, Exchange] {
getInputAmount(outputAmount: TokenAmount): [TokenAmount, Pair] {
invariant(outputAmount.token.equals(this.token0) || outputAmount.token.equals(this.token1), 'TOKEN')
if (
JSBI.equal(this.reserve0.raw, ZERO) ||
......@@ -126,7 +126,7 @@ export class Exchange {
outputAmount.token.equals(this.token0) ? this.token1 : this.token0,
JSBI.add(JSBI.divide(numerator, denominator), ONE)
)
return [inputAmount, new Exchange(inputReserve.add(inputAmount), outputReserve.subtract(outputAmount))]
return [inputAmount, new Pair(inputReserve.add(inputAmount), outputReserve.subtract(outputAmount))]
}
getLiquidityMinted(totalSupply: TokenAmount, tokenAmountA: TokenAmount, tokenAmountB: TokenAmount): TokenAmount {
......
import invariant from 'tiny-invariant'
import { Token } from './token'
import { Exchange } from './exchange'
import { Pair } from './pair'
import { Price } from './fractions/price'
export class Route {
public readonly exchanges: Exchange[]
public readonly pairs: Pair[]
public readonly path: Token[]
public readonly midPrice: Price
constructor(exchanges: Exchange[], input: Token) {
invariant(exchanges.length > 0, 'EXCHANGES')
constructor(pairs: Pair[], input: Token) {
invariant(pairs.length > 0, 'PAIRS')
invariant(
exchanges.map(exchange => exchange.token0.chainId === exchanges[0].token0.chainId).every(x => x),
pairs.map(pair => pair.token0.chainId === pairs[0].token0.chainId).every(x => x),
'CHAIN_IDS'
)
const path = [input]
for (const [i, exchange] of exchanges.entries()) {
for (const [i, pair] of pairs.entries()) {
const currentInput = path[i]
invariant(currentInput.equals(exchange.token0) || currentInput.equals(exchange.token1), 'PATH')
const output = currentInput.equals(exchange.token0) ? exchange.token1 : exchange.token0
invariant(currentInput.equals(pair.token0) || currentInput.equals(pair.token1), 'PATH')
const output = currentInput.equals(pair.token0) ? pair.token1 : pair.token0
path.push(output)
}
invariant(path.length === new Set(path).size, 'PATH')
this.exchanges = exchanges
this.pairs = pairs
this.path = path
this.midPrice = Price.fromRoute(this)
}
......
......@@ -2,7 +2,7 @@ import invariant from 'tiny-invariant'
import JSBI from 'jsbi'
import { TradeType } from '../constants'
import { Exchange } from './exchange'
import { Pair } from './pair'
import { Route } from './route'
import { Fraction, TokenAmount } from './fractions'
import { Price } from './fractions/price'
......@@ -45,22 +45,22 @@ export class Trade {
constructor(route: Route, amount: TokenAmount, tradeType: TradeType) {
invariant(amount.token.equals(tradeType === TradeType.EXACT_INPUT ? route.input : route.output), 'TOKEN')
const amounts: TokenAmount[] = new Array(route.path.length)
const nextExchanges: Exchange[] = new Array(route.exchanges.length)
const nextPairs: Pair[] = new Array(route.pairs.length)
if (tradeType === TradeType.EXACT_INPUT) {
amounts[0] = amount
for (let i = 0; i < route.path.length - 1; i++) {
const exchange = route.exchanges[i]
const [outputAmount, nextExchange] = exchange.getOutputAmount(amounts[i])
const pair = route.pairs[i]
const [outputAmount, nextPair] = pair.getOutputAmount(amounts[i])
amounts[i + 1] = outputAmount
nextExchanges[i] = nextExchange
nextPairs[i] = nextPair
}
} else {
amounts[amounts.length - 1] = amount
for (let i = route.path.length - 1; i > 0; i--) {
const exchange = route.exchanges[i - 1]
const [inputAmount, nextExchange] = exchange.getInputAmount(amounts[i])
const pair = route.pairs[i - 1]
const [inputAmount, nextPair] = pair.getInputAmount(amounts[i])
amounts[i - 1] = inputAmount
nextExchanges[i - 1] = nextExchange
nextPairs[i - 1] = nextPair
}
}
......@@ -71,7 +71,7 @@ export class Trade {
this.inputAmount = inputAmount
this.outputAmount = outputAmount
this.executionPrice = new Price(route.input, route.output, inputAmount.raw, outputAmount.raw)
const nextMidPrice = Price.fromRoute(new Route(nextExchanges, route.input))
const nextMidPrice = Price.fromRoute(new Route(nextPairs, route.input))
this.nextMidPrice = nextMidPrice
this.slippage = getSlippage(route.midPrice, inputAmount, outputAmount)
this.midPricePercentChange = getPercentChange(route.midPrice, nextMidPrice)
......
import { ChainId, WETH, Token, Exchange } from '../src'
import { ChainId, WETH, Token, Pair } from '../src'
describe('data', () => {
it('Token', async () => {
......@@ -11,9 +11,9 @@ describe('data', () => {
expect(token.decimals).toEqual(9)
})
it('Exchange', async () => {
it('Pair', async () => {
const token = new Token(ChainId.RINKEBY, '0xc7AD46e0b8a400Bb3C915120d284AafbA8fc4735', 18) // DAI
const exchange = await Exchange.fetchData(WETH[ChainId.RINKEBY], token)
expect(exchange.liquidityToken.address).toEqual('0x3DDd4674C99979EAd4a3160f12567c90a07f0e94')
const pair = await Pair.fetchData(WETH[ChainId.RINKEBY], token)
expect(pair.liquidityToken.address).toEqual('0x3DDd4674C99979EAd4a3160f12567c90a07f0e94')
})
})
import { ChainId, WETH as _WETH, TradeType, Rounding, Token, TokenAmount, Exchange, Route, Trade } from '../src'
import { ChainId, WETH as _WETH, TradeType, Rounding, Token, TokenAmount, Pair, Route, Trade } from '../src'
const ADDRESSES = [
'0x0000000000000000000000000000000000000001',
......@@ -30,18 +30,18 @@ describe('entities', () => {
})
})
let exchanges: Exchange[]
it('Exchange', () => {
exchanges = [
new Exchange(
let pairs: Pair[]
it('Pair', () => {
pairs = [
new Pair(
new TokenAmount(tokens[0], decimalize(1, tokens[0].decimals)),
new TokenAmount(tokens[1], decimalize(1, tokens[1].decimals))
),
new Exchange(
new Pair(
new TokenAmount(tokens[1], decimalize(1, tokens[1].decimals)),
new TokenAmount(tokens[2], decimalize(1, tokens[2].decimals))
),
new Exchange(
new Pair(
new TokenAmount(tokens[2], decimalize(1, tokens[2].decimals)),
new TokenAmount(WETH, decimalize(1234, WETH.decimals))
)
......@@ -50,8 +50,8 @@ describe('entities', () => {
let route: Route
it('Route', () => {
route = new Route(exchanges, tokens[0])
expect(route.exchanges).toEqual(exchanges)
route = new Route(pairs, tokens[0])
expect(route.pairs).toEqual(pairs)
expect(route.path).toEqual(tokens.concat([WETH]))
expect(route.input).toEqual(tokens[0])
expect(route.output).toEqual(WETH)
......@@ -99,7 +99,7 @@ describe('entities', () => {
it('TradeType.EXACT_INPUT', () => {
route = new Route(
[
new Exchange(
new Pair(
new TokenAmount(tokens[1], decimalize(5, tokens[1].decimals)),
new TokenAmount(WETH, decimalize(10, WETH.decimals))
)
......@@ -153,7 +153,7 @@ describe('entities', () => {
if ([9, 18].includes(tokens[1].decimals)) {
const route = new Route(
[
new Exchange(
new Pair(
new TokenAmount(tokens[1], decimalize(1, tokens[1].decimals)),
new TokenAmount(
WETH,
......
import { ChainId, Token, TokenAmount, Exchange, InsufficientInputAmountError } from '../src'
import { ChainId, Token, TokenAmount, Pair, InsufficientInputAmountError } from '../src'
describe('miscellaneous', () => {
it('getLiquidityMinted:0', async () => {
const tokenA = new Token(ChainId.RINKEBY, '0x0000000000000000000000000000000000000001', 18)
const tokenB = new Token(ChainId.RINKEBY, '0x0000000000000000000000000000000000000002', 18)
const exchange = new Exchange(new TokenAmount(tokenA, '0'), new TokenAmount(tokenB, '0'))
const pair = new Pair(new TokenAmount(tokenA, '0'), new TokenAmount(tokenB, '0'))
expect(() => {
exchange.getLiquidityMinted(
new TokenAmount(exchange.liquidityToken, '0'),
pair.getLiquidityMinted(
new TokenAmount(pair.liquidityToken, '0'),
new TokenAmount(tokenA, '1000'),
new TokenAmount(tokenB, '1000')
)
}).toThrow(InsufficientInputAmountError)
expect(() => {
exchange.getLiquidityMinted(
new TokenAmount(exchange.liquidityToken, '0'),
pair.getLiquidityMinted(
new TokenAmount(pair.liquidityToken, '0'),
new TokenAmount(tokenA, '1000000'),
new TokenAmount(tokenB, '1')
)
}).toThrow(InsufficientInputAmountError)
const liquidity = exchange.getLiquidityMinted(
new TokenAmount(exchange.liquidityToken, '0'),
const liquidity = pair.getLiquidityMinted(
new TokenAmount(pair.liquidityToken, '0'),
new TokenAmount(tokenA, '1001'),
new TokenAmount(tokenB, '1001')
)
......@@ -34,12 +34,12 @@ describe('miscellaneous', () => {
it('getLiquidityMinted:!0', async () => {
const tokenA = new Token(ChainId.RINKEBY, '0x0000000000000000000000000000000000000001', 18)
const tokenB = new Token(ChainId.RINKEBY, '0x0000000000000000000000000000000000000002', 18)
const exchange = new Exchange(new TokenAmount(tokenA, '10000'), new TokenAmount(tokenB, '10000'))
const pair = new Pair(new TokenAmount(tokenA, '10000'), new TokenAmount(tokenB, '10000'))
expect(
exchange
pair
.getLiquidityMinted(
new TokenAmount(exchange.liquidityToken, '10000'),
new TokenAmount(pair.liquidityToken, '10000'),
new TokenAmount(tokenA, '2000'),
new TokenAmount(tokenB, '2000')
)
......@@ -50,13 +50,13 @@ describe('miscellaneous', () => {
it('getLiquidityValue:!feeOn', async () => {
const tokenA = new Token(ChainId.RINKEBY, '0x0000000000000000000000000000000000000001', 18)
const tokenB = new Token(ChainId.RINKEBY, '0x0000000000000000000000000000000000000002', 18)
const exchange = new Exchange(new TokenAmount(tokenA, '1000'), new TokenAmount(tokenB, '1000'))
const pair = new Pair(new TokenAmount(tokenA, '1000'), new TokenAmount(tokenB, '1000'))
{
const liquidityValue = exchange.getLiquidityValue(
const liquidityValue = pair.getLiquidityValue(
tokenA,
new TokenAmount(exchange.liquidityToken, '1000'),
new TokenAmount(exchange.liquidityToken, '1000'),
new TokenAmount(pair.liquidityToken, '1000'),
new TokenAmount(pair.liquidityToken, '1000'),
false
)
expect(liquidityValue.token.equals(tokenA)).toBe(true)
......@@ -65,10 +65,10 @@ describe('miscellaneous', () => {
// 500
{
const liquidityValue = exchange.getLiquidityValue(
const liquidityValue = pair.getLiquidityValue(
tokenA,
new TokenAmount(exchange.liquidityToken, '1000'),
new TokenAmount(exchange.liquidityToken, '500'),
new TokenAmount(pair.liquidityToken, '1000'),
new TokenAmount(pair.liquidityToken, '500'),
false
)
expect(liquidityValue.token.equals(tokenA)).toBe(true)
......@@ -77,10 +77,10 @@ describe('miscellaneous', () => {
// tokenB
{
const liquidityValue = exchange.getLiquidityValue(
const liquidityValue = pair.getLiquidityValue(
tokenB,
new TokenAmount(exchange.liquidityToken, '1000'),
new TokenAmount(exchange.liquidityToken, '1000'),
new TokenAmount(pair.liquidityToken, '1000'),
new TokenAmount(pair.liquidityToken, '1000'),
false
)
expect(liquidityValue.token.equals(tokenB)).toBe(true)
......@@ -91,12 +91,12 @@ describe('miscellaneous', () => {
it('getLiquidityValue:feeOn', async () => {
const tokenA = new Token(ChainId.RINKEBY, '0x0000000000000000000000000000000000000001', 18)
const tokenB = new Token(ChainId.RINKEBY, '0x0000000000000000000000000000000000000002', 18)
const exchange = new Exchange(new TokenAmount(tokenA, '1000'), new TokenAmount(tokenB, '1000'))
const pair = new Pair(new TokenAmount(tokenA, '1000'), new TokenAmount(tokenB, '1000'))
const liquidityValue = exchange.getLiquidityValue(
const liquidityValue = pair.getLiquidityValue(
tokenA,
new TokenAmount(exchange.liquidityToken, '500'),
new TokenAmount(exchange.liquidityToken, '500'),
new TokenAmount(pair.liquidityToken, '500'),
new TokenAmount(pair.liquidityToken, '500'),
true,
'250000' // 500 ** 2
)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment