From 6424caca697e8f2875b52df0721cf3e63d8e8ce0 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Mon, 16 Nov 2020 04:20:06 -0800 Subject: [PATCH] add computeBuySlippage and computeSellSlippage --- src/balancer/OceanPool.ts | 124 ++++++++++++++++++++++++++++ src/balancer/Pool.ts | 27 ++++++ test/unit/balancer/Balancer.test.ts | 35 +++++--- 3 files changed, 173 insertions(+), 13 deletions(-) diff --git a/src/balancer/OceanPool.ts b/src/balancer/OceanPool.ts index d1363236..08fddfd9 100644 --- a/src/balancer/OceanPool.ts +++ b/src/balancer/OceanPool.ts @@ -1222,4 +1222,128 @@ export class OceanPool extends Pool { } return result } + + private async computeSlippage( + poolAddress: string, + tokenInBalance: string, + tokenInWeight: string, + tokenOutBalance: string, + tokenOutWeight: string, + newTokenInBalance: string, + newTokenOutBalance: string, + swapfee: string + ) { + const initialPrice = await super.calcSpotPrice( + poolAddress, + tokenInBalance, + tokenInWeight, + tokenOutBalance, + tokenOutWeight, + swapfee + ) + + const newPrice = await super.calcSpotPrice( + poolAddress, + newTokenInBalance, + tokenInWeight, + newTokenOutBalance, + tokenOutWeight, + swapfee + ) + console.log( + 'In:' + + tokenInBalance + + ', Out:' + + tokenOutBalance + + '| NEW In:' + + newTokenInBalance + + ', Out:' + + newTokenOutBalance + ) + console.log('initial Price:' + initialPrice) + console.log('new price:' + newPrice) + const slippage = (parseFloat(newPrice) * 100) / parseFloat(initialPrice) - 100 + console.log('Slippage:' + slippage) + return String(slippage) + } + + /* Get slippage for buying some datatokens while spending exactly oceanAmount ocean tokens */ + public async computeBuySlippage( + poolAddress: string, + oceanAmount: string + ): Promise { + const dtAddress = await this.getDTAddress(poolAddress) + const dtWeight = await super.getDenormalizedWeight(poolAddress, dtAddress) + const oceanWeight = await super.getDenormalizedWeight(poolAddress, this.oceanAddress) + const dtReserve = await super.getReserve(poolAddress, dtAddress) + const oceanReserve = await super.getReserve(poolAddress, dtAddress) + const swapFee = await super.getSwapFee(poolAddress) + const dtReceived = await super.calcOutGivenIn( + poolAddress, + oceanReserve, + oceanWeight, + dtReserve, + dtWeight, + oceanAmount, + swapFee + ) + const newDtReserve = new BigNumber(this.web3.utils.toWei(dtReserve)).minus( + this.web3.utils.toWei(dtReceived) + ) + const newOceanReserve = new BigNumber(this.web3.utils.toWei(oceanReserve)).plus( + this.web3.utils.toWei(oceanAmount) + ) + const slippage = await this.computeSlippage( + poolAddress, + oceanReserve, + oceanWeight, + dtReserve, + dtWeight, + this.web3.utils.fromWei(newOceanReserve.toString()), + this.web3.utils.fromWei(newDtReserve.toString()), + swapFee + ) + console.log('Buy slippage:' + slippage) + return slippage + } + + /* Get slippage for selling an exact amount of datatokens to get some ocean tokens */ + public async computeSellSlippage( + poolAddress: string, + dtAmount: string + ): Promise { + const dtAddress = await this.getDTAddress(poolAddress) + const dtWeight = await super.getDenormalizedWeight(poolAddress, dtAddress) + const oceanWeight = await super.getDenormalizedWeight(poolAddress, this.oceanAddress) + const dtReserve = await super.getReserve(poolAddress, dtAddress) + const oceanReserve = await super.getReserve(poolAddress, dtAddress) + const swapFee = await super.getSwapFee(poolAddress) + const oceanReceived = await super.calcOutGivenIn( + poolAddress, + dtReserve, + dtWeight, + oceanReserve, + oceanWeight, + dtAmount, + swapFee + ) + const newDtReserve = new BigNumber(this.web3.utils.toWei(dtReserve)).plus( + this.web3.utils.toWei(dtAmount) + ) + const newOceanReserve = new BigNumber(this.web3.utils.toWei(oceanReserve)).minus( + this.web3.utils.toWei(oceanReceived) + ) + const slippage = await this.computeSlippage( + poolAddress, + dtReserve, + dtWeight, + oceanReserve, + oceanWeight, + this.web3.utils.fromWei(newDtReserve.toString()), + this.web3.utils.fromWei(newOceanReserve.toString()), + swapFee + ) + console.log('Sell slippage:' + slippage) + return slippage + } } diff --git a/src/balancer/Pool.ts b/src/balancer/Pool.ts index 5d068b4a..d97b8cd0 100644 --- a/src/balancer/Pool.ts +++ b/src/balancer/Pool.ts @@ -975,6 +975,33 @@ export class Pool extends PoolFactory { return price } + public async calcSpotPrice( + poolAddress: string, + tokenBalanceIn: string, + tokenWeightIn: string, + tokenBalanceOut: string, + tokenWeightOut: string, + swapFee: string + ): Promise { + const pool = new this.web3.eth.Contract(this.poolABI, poolAddress) + let amount = '0' + try { + const result = await pool.methods + .calcSpotPrice( + this.web3.utils.toWei(tokenBalanceIn), + this.web3.utils.toWei(tokenWeightIn), + this.web3.utils.toWei(tokenBalanceOut), + this.web3.utils.toWei(tokenWeightOut), + this.web3.utils.toWei(swapFee) + ) + .call() + amount = this.web3.utils.fromWei(result) + } catch (e) { + this.logger.error('ERROR: Failed to call calcSpotPrice') + } + return amount + } + public async calcInGivenOut( poolAddress: string, tokenBalanceIn: string, diff --git a/test/unit/balancer/Balancer.test.ts b/test/unit/balancer/Balancer.test.ts index ad88dfd0..8fa9f3a4 100644 --- a/test/unit/balancer/Balancer.test.ts +++ b/test/unit/balancer/Balancer.test.ts @@ -115,13 +115,13 @@ describe('Balancer flow', () => { assert(Pool !== null) }) - it('Alice mints 1000 tokens', async () => { + it('Alice mints 2000 tokens', async () => { await datatoken.mint(tokenAddress, alice, tokenAmount) }) - it('Alice mints 1000 Ocean tokens', async () => { + it('Alice mints 2000 Ocean tokens', async () => { await oceandatatoken.mint(oceanTokenAddress, alice, tokenAmount) }) - it('Alice transfers 200 ocean token to Bob', async () => { + it('Alice transfers 500 ocean token to Bob', async () => { await datatoken.transfer(oceanTokenAddress, bob, transferAmount, alice) }) it('Alice creates a new OceanPool pool', async () => { @@ -212,27 +212,36 @@ describe('Balancer flow', () => { assert(pools.length > 0) greatPool = pools[0] }) - it('Bob should buy 2 DT ', async () => { - await Pool.buyDT(bob, greatPool, '2', '4') + it('Bob should buy 1 DT ', async () => { + await Pool.buyDT(bob, greatPool, '1', '4') const bobDtBalance = await datatoken.balance(tokenAddress, bob) const bobOceanBalance = await datatoken.balance(oceanTokenAddress, bob) assert(Number(bobDtBalance) > 0) assert(Number(bobOceanBalance) > 0) }) - it('Bob should spend 5 Oceans to buy at least 1 DT ', async () => { - await Pool.buyDTWithExactOcean(bob, greatPool, '1', '5') + it('Bob should spend 2 Oceans to buy at least 0.1 DT ', async () => { + await Pool.buyDTWithExactOcean(bob, greatPool, '0.1', '2') const bobDtBalance = await datatoken.balance(tokenAddress, bob) const bobOceanBalance = await datatoken.balance(oceanTokenAddress, bob) assert(Number(bobDtBalance) > 0) assert(Number(bobOceanBalance) > 0) }) + it('Bob should get slippage for buying some DT with 5 Ocean Tokens ', async () => { + const slippage = await Pool.computeBuySlippage(greatPool, '5') + assert(Number(slippage) > 0) + }) + it('Bob should get slippage for selling 1 DT', async () => { + const slippage = await Pool.computeSellSlippage(greatPool, '1') + assert(Number(slippage) > 0) + }) it('Bob should sell 1 DT ', async () => { - const maxPrice = parseFloat(currentDtPrice) * 2 - await Pool.sellDT(bob, greatPool, '1', '1') const bobDtBalance = await datatoken.balance(tokenAddress, bob) const bobOceanBalance = await datatoken.balance(oceanTokenAddress, bob) - assert(Number(bobDtBalance) === 1) - assert(Number(bobOceanBalance) > 0) + await Pool.sellDT(bob, greatPool, '1', '0.1') + const newbobDtBalance = await datatoken.balance(tokenAddress, bob) + const newbobOceanBalance = await datatoken.balance(oceanTokenAddress, bob) + assert(Number(newbobDtBalance) < Number(bobDtBalance)) + assert(Number(newbobOceanBalance) > Number(bobOceanBalance)) }) it('Bob should get maximum DT liquidity that he can add to pool ', async () => { const maxDT = await Pool.getDTMaxAddLiquidity(greatPool) @@ -255,7 +264,7 @@ describe('Balancer flow', () => { await Pool.addDTLiquidity( bob, greatPool, - String(Math.min(parseFloat(maxDT), parseFloat(bobDtBalance))) + String(Math.min(parseFloat(maxDT), parseFloat(bobDtBalance) / 2)) ) const newbobDtBalance = await datatoken.balance(tokenAddress, bob) @@ -313,7 +322,7 @@ describe('Balancer flow', () => { await Pool.removeDTLiquidity( bob, greatPool, - String(Math.min(parseFloat(maxDT), parseFloat('0.75'))), + String(Math.min(parseFloat(maxDT), parseFloat('0.1'))), poolShares )