Commit e95375ab authored by Noah Zinsmeister's avatar Noah Zinsmeister

exchange -> pair

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