Commit 3f22d17e authored by Moody Salem's avatar Moody Salem Committed by GitHub

Add methods for minimum amount out and maximum amount in for easy calculation...

Add methods for minimum amount out and maximum amount in for easy calculation of transaction parameters (#23)
parent e5b779f6
import { Token } from 'entities/token'
import invariant from 'tiny-invariant' import invariant from 'tiny-invariant'
import { TradeType } from '../constants' import { ONE, TradeType, ZERO } from '../constants'
import { sortedInsert } from '../utils'
import { Fraction, TokenAmount } from './fractions'
import { Percent } from './fractions/percent'
import { Price } from './fractions/price'
import { Pair } from './pair' import { Pair } from './pair'
import { Route } from './route' import { Route } from './route'
import { TokenAmount } from './fractions'
import { Price } from './fractions/price'
import { Percent } from './fractions/percent'
import { Token } from 'entities/token'
import { sortedInsert } from '../utils'
function getSlippage(midPrice: Price, inputAmount: TokenAmount, outputAmount: TokenAmount): Percent { function getSlippage(midPrice: Price, inputAmount: TokenAmount, outputAmount: TokenAmount): Percent {
const exactQuote = midPrice.raw.multiply(inputAmount.raw) const exactQuote = midPrice.raw.multiply(inputAmount.raw)
...@@ -115,6 +115,35 @@ export class Trade { ...@@ -115,6 +115,35 @@ export class Trade {
this.slippage = getSlippage(route.midPrice, inputAmount, outputAmount) this.slippage = getSlippage(route.midPrice, inputAmount, outputAmount)
} }
// get the minimum amount that must be received from this trade for the given allowed slippage
public minimumAmountOut(additionalSlippageTolerance: Percent): TokenAmount {
invariant(!additionalSlippageTolerance.lessThan(ZERO), 'ADDITIONAL_SLIPPAGE_TOLERANCE')
if (this.tradeType === TradeType.EXACT_OUTPUT) {
return this.outputAmount
} else {
return new TokenAmount(
this.outputAmount.token,
new Fraction(ONE)
.add(additionalSlippageTolerance)
.invert()
.multiply(this.outputAmount.raw).quotient
)
}
}
// get the maximum amount in that can be spent via this trade for the given allowed slippage
public maximumAmountIn(additionalSlippageTolerance: Percent): TokenAmount {
invariant(!additionalSlippageTolerance.lessThan(ZERO), 'ADDITIONAL_SLIPPAGE_TOLERANCE')
if (this.tradeType === TradeType.EXACT_INPUT) {
return this.inputAmount
} else {
return new TokenAmount(
this.inputAmount.token,
new Fraction(ONE).add(additionalSlippageTolerance).multiply(this.inputAmount.raw).quotient
)
}
}
// given a list of pairs, and a fixed amount in, returns the top `maxNumResults` trades that go from an input token // given a list of pairs, and a fixed amount in, returns the top `maxNumResults` trades that go from an input token
// amount to an output token, making at most `maxHops` hops // amount to an output token, making at most `maxHops` hops
// note this does not consider aggregation, as routes are linear. it's possible a better route exists by splitting // note this does not consider aggregation, as routes are linear. it's possible a better route exists by splitting
......
import { ChainId, Token, TokenAmount, Pair, Trade } from '../src'
import JSBI from 'jsbi' import JSBI from 'jsbi'
import { ChainId, Pair, Percent, Route, Token, TokenAmount, Trade, TradeType } from '../src'
describe('Trade', () => { describe('Trade', () => {
const token0 = new Token(ChainId.MAINNET, '0x0000000000000000000000000000000000000001', 18, 't0') const token0 = new Token(ChainId.MAINNET, '0x0000000000000000000000000000000000000001', 18, 't0')
...@@ -85,6 +85,118 @@ describe('Trade', () => { ...@@ -85,6 +85,118 @@ describe('Trade', () => {
}) })
}) })
describe('#maximumAmountIn', () => {
describe('tradeType = EXACT_INPUT', () => {
const exactIn = new Trade(
new Route([pair_0_1, pair_1_2], token0),
new TokenAmount(token0, JSBI.BigInt(100)),
TradeType.EXACT_INPUT
)
it('throws if less than 0', () => {
expect(() => exactIn.maximumAmountIn(new Percent(JSBI.BigInt(-1), JSBI.BigInt(100)))).toThrow(
'ADDITIONAL_SLIPPAGE_TOLERANCE'
)
})
it('returns exact if 0', () => {
expect(exactIn.maximumAmountIn(new Percent(JSBI.BigInt(0), JSBI.BigInt(100)))).toEqual(exactIn.inputAmount)
})
it('returns exact if nonzero', () => {
expect(exactIn.maximumAmountIn(new Percent(JSBI.BigInt(0), JSBI.BigInt(100)))).toEqual(
new TokenAmount(token0, JSBI.BigInt(100))
)
expect(exactIn.maximumAmountIn(new Percent(JSBI.BigInt(5), JSBI.BigInt(100)))).toEqual(
new TokenAmount(token0, JSBI.BigInt(100))
)
expect(exactIn.maximumAmountIn(new Percent(JSBI.BigInt(200), JSBI.BigInt(100)))).toEqual(
new TokenAmount(token0, JSBI.BigInt(100))
)
})
})
describe('tradeType = EXACT_OUTPUT', () => {
const exactOut = new Trade(
new Route([pair_0_1, pair_1_2], token0),
new TokenAmount(token2, JSBI.BigInt(100)),
TradeType.EXACT_OUTPUT
)
it('throws if less than 0', () => {
expect(() => exactOut.maximumAmountIn(new Percent(JSBI.BigInt(-1), JSBI.BigInt(100)))).toThrow(
'ADDITIONAL_SLIPPAGE_TOLERANCE'
)
})
it('returns exact if 0', () => {
expect(exactOut.maximumAmountIn(new Percent(JSBI.BigInt(0), JSBI.BigInt(100)))).toEqual(exactOut.inputAmount)
})
it('returns slippage amount if nonzero', () => {
expect(exactOut.maximumAmountIn(new Percent(JSBI.BigInt(0), JSBI.BigInt(100)))).toEqual(
new TokenAmount(token0, JSBI.BigInt(156))
)
expect(exactOut.maximumAmountIn(new Percent(JSBI.BigInt(5), JSBI.BigInt(100)))).toEqual(
new TokenAmount(token0, JSBI.BigInt(163))
)
expect(exactOut.maximumAmountIn(new Percent(JSBI.BigInt(200), JSBI.BigInt(100)))).toEqual(
new TokenAmount(token0, JSBI.BigInt(468))
)
})
})
})
describe('#minimumAmountOut', () => {
describe('tradeType = EXACT_INPUT', () => {
const exactIn = new Trade(
new Route([pair_0_1, pair_1_2], token0),
new TokenAmount(token0, JSBI.BigInt(100)),
TradeType.EXACT_INPUT
)
it('throws if less than 0', () => {
expect(() => exactIn.minimumAmountOut(new Percent(JSBI.BigInt(-1), JSBI.BigInt(100)))).toThrow(
'ADDITIONAL_SLIPPAGE_TOLERANCE'
)
})
it('returns exact if 0', () => {
expect(exactIn.minimumAmountOut(new Percent(JSBI.BigInt(0), JSBI.BigInt(100)))).toEqual(exactIn.outputAmount)
})
it('returns exact if nonzero', () => {
expect(exactIn.minimumAmountOut(new Percent(JSBI.BigInt(0), JSBI.BigInt(100)))).toEqual(
new TokenAmount(token2, JSBI.BigInt(69))
)
expect(exactIn.minimumAmountOut(new Percent(JSBI.BigInt(5), JSBI.BigInt(100)))).toEqual(
new TokenAmount(token2, JSBI.BigInt(65))
)
expect(exactIn.minimumAmountOut(new Percent(JSBI.BigInt(200), JSBI.BigInt(100)))).toEqual(
new TokenAmount(token2, JSBI.BigInt(23))
)
})
})
describe('tradeType = EXACT_OUTPUT', () => {
const exactOut = new Trade(
new Route([pair_0_1, pair_1_2], token0),
new TokenAmount(token2, JSBI.BigInt(100)),
TradeType.EXACT_OUTPUT
)
it('throws if less than 0', () => {
expect(() => exactOut.minimumAmountOut(new Percent(JSBI.BigInt(-1), JSBI.BigInt(100)))).toThrow(
'ADDITIONAL_SLIPPAGE_TOLERANCE'
)
})
it('returns exact if 0', () => {
expect(exactOut.minimumAmountOut(new Percent(JSBI.BigInt(0), JSBI.BigInt(100)))).toEqual(exactOut.outputAmount)
})
it('returns slippage amount if nonzero', () => {
expect(exactOut.minimumAmountOut(new Percent(JSBI.BigInt(0), JSBI.BigInt(100)))).toEqual(
new TokenAmount(token2, JSBI.BigInt(100))
)
expect(exactOut.minimumAmountOut(new Percent(JSBI.BigInt(5), JSBI.BigInt(100)))).toEqual(
new TokenAmount(token2, JSBI.BigInt(100))
)
expect(exactOut.minimumAmountOut(new Percent(JSBI.BigInt(200), JSBI.BigInt(100)))).toEqual(
new TokenAmount(token2, JSBI.BigInt(100))
)
})
})
})
describe('#bestTradeExactOut', () => { describe('#bestTradeExactOut', () => {
it('throws with empty pairs', () => { it('throws with empty pairs', () => {
expect(() => Trade.bestTradeExactOut([], token0, new TokenAmount(token2, JSBI.BigInt(100)))).toThrow('PAIRS') expect(() => Trade.bestTradeExactOut([], token0, new TokenAmount(token2, JSBI.BigInt(100)))).toThrow('PAIRS')
......
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