From 8de3d29b2fbe02b680dc587b87b4f30472f35890 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Mon, 12 Oct 2020 03:03:06 -0700 Subject: [PATCH 01/26] add pool validation and helpers --- src/balancer/OceanPool.ts | 337 +++++++++++++++++++++++++--- src/balancer/Pool.ts | 190 +++++++++++++++- test/unit/balancer/Balancer.test.ts | 83 ++++++- 3 files changed, 564 insertions(+), 46 deletions(-) diff --git a/src/balancer/OceanPool.ts b/src/balancer/OceanPool.ts index 930d92e6..2c5c2196 100644 --- a/src/balancer/OceanPool.ts +++ b/src/balancer/OceanPool.ts @@ -3,6 +3,7 @@ import { AbiItem } from 'web3-utils/types' import { TransactionReceipt } from 'web3-core' import { Pool } from './Pool' import { EventData, Filter } from 'web3-eth-contract' +import { parse } from 'path' declare type PoolTransactionType = 'swap' | 'join' | 'exit' @@ -143,6 +144,189 @@ export class OceanPool extends Pool { return super.getReserve(poolAddress, dtAddress) } + /** + * Returns max amount that you can buy. + * @param poolAddress + * @param tokenAddress + */ + public async getMaxBuyQuantity( + poolAddress: string, + tokenAddress: string + ): Promise { + const balance = await super.getReserve(poolAddress, tokenAddress) + return String(parseFloat(balance) / 3) + } + + /** + * Returns tokenInAmount required to get tokenOutAmount + * @param poolAddress + * @param tokenInAddress + * @param tokenOutAddress + * @param tokenOutAmount + */ + public async calcInGivenOut( + poolAddress: string, + tokenInAddress: string, + tokenOutAddress: string, + tokenOutAmount: string + ): Promise { + const result = await super.calcInGivenOut( + poolAddress, + await super.getReserve(poolAddress, tokenInAddress), + await super.getDenormalizedWeight(poolAddress, tokenInAddress), + await super.getReserve(poolAddress, tokenOutAddress), + await super.getDenormalizedWeight(poolAddress, tokenOutAddress), + tokenOutAmount, + await this.getSwapFee(poolAddress) + ) + + return result + } + + /** + * Returns tokenOutAmount given tokenInAmount + * @param poolAddress + * @param tokenInAddress + * @param tokenOutAddress + * @param tokenInAmount + */ + public async calcOutGivenIn( + poolAddress: string, + tokenInAddress: string, + tokenOutAddress: string, + tokenInAmount: string + ): Promise { + const result = await super.calcOutGivenIn( + poolAddress, + await super.getReserve(poolAddress, tokenInAddress), + await super.getDenormalizedWeight(poolAddress, tokenInAddress), + await super.getReserve(poolAddress, tokenOutAddress), + await super.getDenormalizedWeight(poolAddress, tokenOutAddress), + tokenInAmount, + await super.getSwapFee(poolAddress) + ) + + return result + } + + /** + * Returns no of shares receved for adding a token to the pool + * @param poolAddress + * @param tokenInAddress + * @param tokenInAmount + */ + public async calcPoolOutGivenSingleIn( + poolAddress: string, + tokenInAddress: string, + tokenInAmount: string + ): Promise { + const result = super.calcPoolOutGivenSingleIn( + poolAddress, + await super.getReserve(poolAddress, tokenInAddress), + await super.getDenormalizedWeight(poolAddress, tokenInAddress), + await super.getPoolSharesTotalSupply(poolAddress), + await super.getTotalDenormalizedWeight(poolAddress), + tokenInAmount, + await super.getSwapFee(poolAddress) + ) + return result + } + + /** + * Returns no of tokens required to get a specific no of poolShares + * @param poolAddress + * @param tokenInAddress + * @param poolShares + */ + public async calcSingleInGivenPoolOut( + poolAddress: string, + tokenInAddress: string, + poolShares: string + ): Promise { + const result = super.calcSingleInGivenPoolOut( + poolAddress, + await super.getReserve(poolAddress, tokenInAddress), + await super.getDenormalizedWeight(poolAddress, tokenInAddress), + await super.getPoolSharesTotalSupply(poolAddress), + await super.getTotalDenormalizedWeight(poolAddress), + poolShares, + await super.getSwapFee(poolAddress) + ) + return result + } + + /** + * Returns no of tokens received for spending a specific no of poolShares + * @param poolAddress + * @param tokenOutAddress + * @param poolShares + */ + public async calcSingleOutGivenPoolIn( + poolAddress: string, + tokenOutAddress: string, + poolShares: string + ): Promise { + const result = super.calcSingleOutGivenPoolIn( + poolAddress, + await super.getReserve(poolAddress, tokenOutAddress), + await super.getDenormalizedWeight(poolAddress, tokenOutAddress), + await super.getPoolSharesTotalSupply(poolAddress), + await super.getTotalDenormalizedWeight(poolAddress), + poolShares, + await super.getSwapFee(poolAddress) + ) + return result + } + + /** + * Returns no of pool shares required to receive a specified amount of tokens + * @param poolAddress + * @param tokenOutAddress + * @param tokenOutAmount + */ + public async calcPoolInGivenSingleOut( + poolAddress: string, + tokenOutAddress: string, + tokenOutAmount: string + ): Promise { + const result = super.calcPoolInGivenSingleOut( + poolAddress, + await super.getReserve(poolAddress, tokenOutAddress), + await super.getDenormalizedWeight(poolAddress, tokenOutAddress), + await super.getPoolSharesTotalSupply(poolAddress), + await super.getTotalDenormalizedWeight(poolAddress), + tokenOutAmount, + await super.getSwapFee(poolAddress) + ) + return result + } + + /** + * Returns max amount of tokens that you can add to the pool + * @param poolAddress + * @param tokenAddress + */ + public async getMaxAddLiquidity( + poolAddress: string, + tokenAddress: string + ): Promise { + const balance = await super.getReserve(poolAddress, tokenAddress) + return String(parseFloat(balance) / 2) + } + + /** + * Returns max amount of tokens that you can withdraw from the pool + * @param poolAddress + * @param tokenAddress + */ + public async getMaxRemoveLiquidity( + poolAddress: string, + tokenAddress: string + ): Promise { + const balance = await super.getReserve(poolAddress, tokenAddress) + return String(parseFloat(balance) / 3) + } + /** * Buy Data Token from a pool * @param {String} account @@ -155,31 +339,51 @@ export class OceanPool extends Pool { public async buyDT( account: string, poolAddress: string, - amount: string, - oceanAmount: string, - maxPrice: string + dtAmountWanted: string, + maxOceanAmount: string, + maxPrice?: string ): Promise { if (this.oceanAddress == null) { console.error('oceanAddress is not defined') return null } + if (!maxPrice) { + maxPrice = String(2 ** 256 - 1) + } const dtAddress = await this.getDTAddress(poolAddress) + if ( + parseFloat(dtAmountWanted) > + parseFloat(await this.getMaxBuyQuantity(poolAddress, dtAddress)) + ) { + console.error('Buy quantity exceeds quantity allowed') + return null + } + const calcInGivenOut = await this.calcInGivenOut( + poolAddress, + this.oceanAddress, + dtAddress, + dtAmountWanted + ) + if (parseFloat(calcInGivenOut) > parseFloat(maxOceanAmount)) { + console.error('Not enough Ocean Tokens') + return null + } // TODO - check balances first await super.approve( account, this.oceanAddress, poolAddress, - this.web3.utils.toWei(oceanAmount) + this.web3.utils.toWei(maxOceanAmount) ) return this.swapExactAmountOut( account, poolAddress, this.oceanAddress, - oceanAmount, + maxOceanAmount, dtAddress, - amount, + dtAmountWanted, maxPrice ) } @@ -188,7 +392,7 @@ export class OceanPool extends Pool { * Sell Data Token * @param {String} account * @param {String} poolAddress - * @param {String} amount Data Token amount + * @param {String} amount Data Token amount to be sold * @param {String} oceanAmount Ocean Token amount expected * @param {String} maxPrice Minimum price to sell * @return {TransactionReceipt} @@ -196,23 +400,43 @@ export class OceanPool extends Pool { public async sellDT( account: string, poolAddress: string, - amount: string, - oceanAmount: string, - minPrice: string + dtAmount: string, + oceanAmountWanted: string, + maxPrice?: string ): Promise { + if (!maxPrice) { + maxPrice = String(2 ** 256 - 1) + } if (this.oceanAddress == null) { console.error('oceanAddress is not defined') return null } const dtAddress = await this.getDTAddress(poolAddress) - return this.swapExactAmountOut( + if ( + parseFloat(oceanAmountWanted) > + parseFloat(await this.getMaxBuyQuantity(poolAddress, this.oceanAddress)) + ) { + console.error('Buy quantity exceeds quantity allowed') + return null + } + const calcOutGivenIn = await this.calcOutGivenIn( + poolAddress, + dtAddress, + this.oceanAddress, + dtAmount + ) + if (parseFloat(calcOutGivenIn) < parseFloat(oceanAmountWanted)) { + console.error('Not enough Data Tokens') + return null + } + return this.swapExactAmountIn( account, poolAddress, dtAddress, - amount, + dtAmount, this.oceanAddress, - oceanAmount, - minPrice + oceanAmountWanted, + maxPrice ) } @@ -229,6 +453,11 @@ export class OceanPool extends Pool { amount: string ): Promise { const dtAddress = await this.getDTAddress(poolAddress) + const maxAmount = await this.getMaxAddLiquidity(poolAddress, dtAddress) + if (parseFloat(amount) > parseFloat(maxAmount)) { + console.error('Too much reserve to add') + return null + } await super.approve(account, dtAddress, poolAddress, this.web3.utils.toWei(amount)) const result = await super.joinswapExternAmountIn( account, @@ -254,7 +483,23 @@ export class OceanPool extends Pool { maximumPoolShares: string ): Promise { const dtAddress = await this.getDTAddress(poolAddress) - // TODO Check balance of PoolShares before doing exit + const maxAmount = await this.getMaxRemoveLiquidity(poolAddress, dtAddress) + if (parseFloat(amount) > parseFloat(maxAmount)) { + console.error('Too much reserve to remove') + return null + } + const usershares = await this.sharesBalance(account, poolAddress) + if (parseFloat(usershares) < parseFloat(maximumPoolShares)) { + console.error('Not enough poolShares') + return null + } + if ( + parseFloat(maximumPoolShares) < + parseFloat(await this.calcPoolInGivenSingleOut(poolAddress, dtAddress, amount)) + ) { + console.error('Not enough poolShares') + return null + } return this.exitswapExternAmountOut( account, poolAddress, @@ -280,6 +525,11 @@ export class OceanPool extends Pool { console.error('oceanAddress is not defined') return null } + const maxAmount = await this.getMaxAddLiquidity(poolAddress, this.oceanAddress) + if (parseFloat(amount) > parseFloat(maxAmount)) { + console.error('Too much reserve to add') + return null + } await super.approve( account, this.oceanAddress, @@ -303,7 +553,7 @@ export class OceanPool extends Pool { * @param {String} amount Ocean Token amount in OCEAN * @return {TransactionReceipt} */ - public removeOceanLiquidity( + public async removeOceanLiquidity( account: string, poolAddress: string, amount: string, @@ -313,7 +563,25 @@ export class OceanPool extends Pool { console.error('oceanAddress is not defined') return null } - // TODO Check balance of PoolShares before doing exit + const maxAmount = await this.getMaxRemoveLiquidity(poolAddress, this.oceanAddress) + if (parseFloat(amount) > parseFloat(maxAmount)) { + console.error('Too much reserve to remove') + return null + } + const usershares = await this.sharesBalance(account, poolAddress) + if (parseFloat(usershares) < parseFloat(maximumPoolShares)) { + console.error('Not enough poolShares') + return null + } + if ( + parseFloat(maximumPoolShares) < + parseFloat( + await this.calcPoolInGivenSingleOut(poolAddress, this.oceanAddress, amount) + ) + ) { + console.error('Not enough poolShares') + return null + } return super.exitswapExternAmountOut( account, poolAddress, @@ -323,6 +591,27 @@ export class OceanPool extends Pool { ) } + /** + * Remove pool liquidity + * @param {String} account + * @param {String} poolAddress + * @param {String} poolShares + * @return {TransactionReceipt} + */ + public async removePoolLiquidity( + account: string, + poolAddress: string, + poolShares: string + ): Promise { + const usershares = await this.sharesBalance(account, poolAddress) + if (parseFloat(usershares) < parseFloat(poolShares)) { + console.error('Not enough poolShares') + return null + } + + return this.exitPool(account, poolAddress, poolShares, ['0', '0']) + } + /** * Get Data Token price from pool * @param {String} poolAddress @@ -358,19 +647,7 @@ export class OceanPool extends Pool { public async getOceanNeeded(poolAddress: string, dtRequired: string): Promise { const dtAddress = await this.getDTAddress(poolAddress) - const tokenBalanceIn = await this.getReserve(poolAddress, this.oceanAddress) - const tokenWeightIn = await this.getDenormalizedWeight(poolAddress, this.oceanAddress) - const tokenBalanceOut = await this.getReserve(poolAddress, dtAddress) - const tokenWeightOut = await this.getDenormalizedWeight(poolAddress, dtAddress) - const swapFee = await this.getSwapFee(poolAddress) - return super.calcInGivenOut( - tokenBalanceIn, - tokenWeightIn, - tokenBalanceOut, - tokenWeightOut, - dtRequired, - swapFee - ) + return this.calcInGivenOut(poolAddress, this.oceanAddress, dtAddress, dtRequired) } /** diff --git a/src/balancer/Pool.ts b/src/balancer/Pool.ts index c5b2799e..c5345a02 100644 --- a/src/balancer/Pool.ts +++ b/src/balancer/Pool.ts @@ -270,6 +270,23 @@ export class Pool extends PoolFactory { return result } + /** + * Get total supply of pool shares + * @param {String} poolAddress + * @return {String} + */ + async getPoolSharesTotalSupply(poolAddress: string): Promise { + const pool = new this.web3.eth.Contract(this.poolABI, poolAddress) + let amount = null + try { + const result = await pool.methods.totalSupply().call() + amount = this.web3.utils.fromWei(result) + } catch (e) { + console.error(e) + } + return amount + } + /** * Get tokens composing this pool * @param {String} poolAddress @@ -594,7 +611,7 @@ export class Pool extends PoolFactory { account: string, poolAddress: string, poolAmountIn: string, - minAmountsOut: string + minAmountsOut: string[] ): Promise { const pool = new this.web3.eth.Contract(this.poolABI, poolAddress, { from: account @@ -799,6 +816,7 @@ export class Pool extends PoolFactory { } public async calcInGivenOut( + poolAddress: string, tokenBalanceIn: string, tokenWeightIn: string, tokenBalanceOut: string, @@ -806,14 +824,168 @@ export class Pool extends PoolFactory { tokenAmountOut: string, swapFee: string ): Promise { - const weightRatio = new Decimal(tokenWeightOut).div(new Decimal(tokenWeightIn)) - const diff = new Decimal(tokenBalanceOut).minus(tokenAmountOut) - const y = new Decimal(tokenBalanceOut).div(diff) - const foo = y.pow(weightRatio).minus(new Decimal(1)) - const tokenAmountIn = new Decimal(tokenBalanceIn) - .times(foo) - .div(new Decimal(1).minus(new Decimal(swapFee))) + const pool = new this.web3.eth.Contract(this.poolABI, poolAddress) + let amount = null + try { + const result = await pool.methods + .calcInGivenOut( + this.web3.utils.toWei(tokenBalanceIn), + this.web3.utils.toWei(tokenWeightIn), + this.web3.utils.toWei(tokenBalanceOut), + this.web3.utils.toWei(tokenWeightOut), + this.web3.utils.toWei(tokenAmountOut), + this.web3.utils.toWei(swapFee) + ) + .call() + amount = this.web3.utils.fromWei(result) + } catch (e) { + console.error(e) + } + return amount + } - return tokenAmountIn.toString() + public async calcOutGivenIn( + poolAddress: string, + tokenBalanceIn: string, + tokenWeightIn: string, + tokenBalanceOut: string, + tokenWeightOut: string, + tokenAmountIn: string, + swapFee: string + ): Promise { + const pool = new this.web3.eth.Contract(this.poolABI, poolAddress) + let amount = null + try { + const result = await pool.methods + .calcOutGivenIn( + this.web3.utils.toWei(tokenBalanceIn), + this.web3.utils.toWei(tokenWeightIn), + this.web3.utils.toWei(tokenBalanceOut), + this.web3.utils.toWei(tokenWeightOut), + this.web3.utils.toWei(tokenAmountIn), + this.web3.utils.toWei(swapFee) + ) + .call() + amount = this.web3.utils.fromWei(result) + } catch (e) { + console.error(e) + } + return amount + } + + public async calcPoolOutGivenSingleIn( + poolAddress: string, + tokenBalanceIn: string, + tokenWeightIn: string, + poolSupply: string, + totalWeight: string, + tokenAmountIn: string, + swapFee: string + ): Promise { + const pool = new this.web3.eth.Contract(this.poolABI, poolAddress) + let amount = null + try { + const result = await pool.methods + .calcPoolOutGivenSingleIn( + this.web3.utils.toWei(tokenBalanceIn), + this.web3.utils.toWei(tokenWeightIn), + this.web3.utils.toWei(poolSupply), + this.web3.utils.toWei(totalWeight), + this.web3.utils.toWei(tokenAmountIn), + this.web3.utils.toWei(swapFee) + ) + .call() + amount = this.web3.utils.fromWei(result) + } catch (e) { + console.error(e) + } + return amount + } + + public async calcSingleInGivenPoolOut( + poolAddress: string, + tokenBalanceIn: string, + tokenWeightIn: string, + poolSupply: string, + totalWeight: string, + poolAmountOut: string, + swapFee: string + ): Promise { + const pool = new this.web3.eth.Contract(this.poolABI, poolAddress) + let amount = null + try { + const result = await pool.methods + .calcSingleInGivenPoolOut( + this.web3.utils.toWei(tokenBalanceIn), + this.web3.utils.toWei(tokenWeightIn), + this.web3.utils.toWei(poolSupply), + this.web3.utils.toWei(totalWeight), + this.web3.utils.toWei(poolAmountOut), + this.web3.utils.toWei(swapFee) + ) + .call() + amount = this.web3.utils.fromWei(result) + } catch (e) { + console.error(e) + } + return amount + } + + public async calcSingleOutGivenPoolIn( + poolAddress: string, + tokenBalanceOut: string, + tokenWeightOut: string, + poolSupply: string, + totalWeight: string, + poolAmountIn: string, + swapFee: string + ): Promise { + const pool = new this.web3.eth.Contract(this.poolABI, poolAddress) + let amount = null + try { + const result = await pool.methods + .calcSingleOutGivenPoolIn( + this.web3.utils.toWei(tokenBalanceOut), + this.web3.utils.toWei(tokenWeightOut), + this.web3.utils.toWei(poolSupply), + this.web3.utils.toWei(totalWeight), + this.web3.utils.toWei(poolAmountIn), + this.web3.utils.toWei(swapFee) + ) + .call() + amount = this.web3.utils.fromWei(result) + } catch (e) { + console.error(e) + } + return amount + } + + public async calcPoolInGivenSingleOut( + poolAddress: string, + tokenBalanceOut: string, + tokenWeightOut: string, + poolSupply: string, + totalWeight: string, + tokenAmountOut: string, + swapFee: string + ): Promise { + const pool = new this.web3.eth.Contract(this.poolABI, poolAddress) + let amount = null + try { + const result = await pool.methods + .calcPoolInGivenSingleOut( + this.web3.utils.toWei(tokenBalanceOut), + this.web3.utils.toWei(tokenWeightOut), + this.web3.utils.toWei(poolSupply), + this.web3.utils.toWei(totalWeight), + this.web3.utils.toWei(tokenAmountOut), + this.web3.utils.toWei(swapFee) + ) + .call() + amount = this.web3.utils.fromWei(result) + } catch (e) { + console.error(e) + } + return amount } } diff --git a/test/unit/balancer/Balancer.test.ts b/test/unit/balancer/Balancer.test.ts index e166088b..04a8e650 100644 --- a/test/unit/balancer/Balancer.test.ts +++ b/test/unit/balancer/Balancer.test.ts @@ -27,7 +27,7 @@ describe('Balancer flow', () => { let contracts: TestContractHandler let datatoken: DataTokens let tokenAddress: string - let consoleDebug: false + let consoleDebug: true let greatPool: string const tokenAmount = '1000' const transferAmount = '200' @@ -185,12 +185,29 @@ describe('Balancer flow', () => { assert(Number(bobDtBalance) > 0) assert(Number(bobOceanBalance) > 0) }) + it('Bob should get maximum DT liquidity that he can add to pool ', async () => { + const maxDT = await Pool.getMaxAddLiquidity(greatPool, tokenAddress) + if (consoleDebug) console.error('maxDT:' + maxDT) + assert(parseFloat(maxDT) > 0) + }) + + it('Bob should fail to add more than maximum DT liquidity that he can add to pool ', async () => { + const maxDT = await Pool.getMaxAddLiquidity(greatPool, tokenAddress) + const tx = await Pool.addDTLiquidity(bob, greatPool, String(parseFloat(maxDT) * 2)) + assert(tx === null) + }) it('Bob should add DT liquidity to pool ', async () => { + const maxDT = await Pool.getMaxAddLiquidity(greatPool, tokenAddress) + if (consoleDebug) console.error('maxDT:' + maxDT) const currentDtReserve = await Pool.getDTReserve(greatPool) if (consoleDebug) console.log('currentDtReserve:' + currentDtReserve) const bobDtBalance = await datatoken.balance(tokenAddress, bob) if (consoleDebug) console.log('BOB DT Balance:' + bobDtBalance) - await Pool.addDTLiquidity(bob, greatPool, bobDtBalance) + await Pool.addDTLiquidity( + bob, + greatPool, + String(Math.min(parseFloat(maxDT), parseFloat(bobDtBalance))) + ) const newbobDtBalance = await datatoken.balance(tokenAddress, bob) @@ -204,7 +221,23 @@ describe('Balancer flow', () => { assert(parseFloat(newDtReserve) > parseFloat(currentDtReserve)) assert(parseFloat(sharesBalance) > 0) }) - + it('Bob should get maximum DT liquidity that he can remove from pool ', async () => { + const maxDT = await Pool.getMaxRemoveLiquidity(greatPool, tokenAddress) + if (consoleDebug) console.log('maxDT:' + maxDT) + assert(parseFloat(maxDT) > 0) + }) + it('Bob should fail to remove more than maximum DT liquidity that he can remove from the pool ', async () => { + const maxDT = await Pool.getMaxRemoveLiquidity(greatPool, tokenAddress) + if (consoleDebug) console.log('maxDT:' + maxDT) + const poolShares = await Pool.sharesBalance(bob, greatPool) + const tx = await Pool.removeDTLiquidity( + bob, + greatPool, + String(parseFloat(maxDT) * 2), + poolShares + ) + assert(tx === null) + }) it('Bob should remove DT liquidity from pool ', async () => { const currentDtReserve = await Pool.getDTReserve(greatPool) if (consoleDebug) console.log('currentDtReserve:' + currentDtReserve) @@ -212,7 +245,14 @@ describe('Balancer flow', () => { if (consoleDebug) console.log('bobDtBalance:' + bobDtBalance) const poolShares = await Pool.sharesBalance(bob, greatPool) if (consoleDebug) console.log('poolShares:' + poolShares) - await Pool.removeDTLiquidity(bob, greatPool, '0.75', poolShares) + const maxDT = await Pool.getMaxRemoveLiquidity(greatPool, tokenAddress) + if (consoleDebug) console.log('maxDT:' + maxDT) + await Pool.removeDTLiquidity( + bob, + greatPool, + String(Math.min(parseFloat(maxDT), parseFloat('0.75'))), + poolShares + ) const newDtReserve = await Pool.getDTReserve(greatPool) if (consoleDebug) console.log('newDtReserve:' + newDtReserve) @@ -225,13 +265,28 @@ describe('Balancer flow', () => { assert(parseFloat(poolShares) > parseFloat(newpoolShares)) }) + it('Bob should get maximum Ocean liquidity that he can add to pool ', async () => { + const maxOcean = await Pool.getMaxAddLiquidity(greatPool, oceanTokenAddress) + assert(parseFloat(maxOcean) > 0) + }) + + it('Bob should fail to add more than maximum Ocean liquidity that he can add to pool ', async () => { + const maxOcean = await Pool.getMaxAddLiquidity(greatPool, oceanTokenAddress) + const tx = await Pool.addOceanLiquidity( + bob, + greatPool, + String(parseFloat(maxOcean) * 2) + ) + assert(tx === null) + }) + it('Bob should add Ocean liquidity to pool ', async () => { const currentDtReserve = await Pool.getOceanReserve(greatPool) const bobDtBalance = await datatoken.balance(oceanTokenAddress, bob) if (consoleDebug) console.log('currentDtReserve:' + currentDtReserve) if (consoleDebug) console.log('bobDtBalance:' + bobDtBalance) - - await Pool.addOceanLiquidity(bob, greatPool, '1') + const maxOcean = await Pool.getMaxAddLiquidity(greatPool, oceanTokenAddress) + await Pool.addOceanLiquidity(bob, greatPool, maxOcean) const newbobDtBalance = await datatoken.balance(oceanTokenAddress, bob) @@ -245,7 +300,21 @@ describe('Balancer flow', () => { assert(parseFloat(newDtReserve) > parseFloat(currentDtReserve)) assert(parseFloat(sharesBalance) > 0) }) - + it('Bob should get maximum Ocean liquidity that he can remove from pool ', async () => { + const maxOcean = await Pool.getMaxRemoveLiquidity(greatPool, oceanTokenAddress) + assert(parseFloat(maxOcean) > 0) + }) + it('Bob should fail to remove more than maximum Ocean liquidity that he can remove from the pool ', async () => { + const maxOcean = await Pool.getMaxRemoveLiquidity(greatPool, oceanTokenAddress) + const poolShares = await Pool.sharesBalance(bob, greatPool) + const tx = await Pool.removeOceanLiquidity( + bob, + greatPool, + String(parseFloat(maxOcean) * 2), + poolShares + ) + assert(tx === null) + }) it('Bob should remove Ocean liquidity from pool ', async () => { const currentDtReserve = await Pool.getOceanReserve(greatPool) const bobDtBalance = await datatoken.balance(oceanTokenAddress, bob) From d2b770a9823ea0fa4252fedba6033c0634d38d5f Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Mon, 12 Oct 2020 03:51:42 -0700 Subject: [PATCH 02/26] more helpers --- src/balancer/OceanPool.ts | 98 +++++++++++++++++++++++++++++++++------ 1 file changed, 84 insertions(+), 14 deletions(-) diff --git a/src/balancer/OceanPool.ts b/src/balancer/OceanPool.ts index 2c5c2196..f3072eb9 100644 --- a/src/balancer/OceanPool.ts +++ b/src/balancer/OceanPool.ts @@ -301,6 +301,56 @@ export class OceanPool extends Pool { return result } + /** + * Returns no of pool shares required to receive specified amount of DT + * @param poolAddress + * @param dtAmount + */ + public async getPoolSharesRequiredToRemoveDT( + poolAddress: string, + dtAmount: string + ): Promise { + const dtAddress = await this.getDTAddress(poolAddress) + return this.calcPoolInGivenSingleOut(poolAddress, dtAddress, dtAmount) + } + + /** + * Returns DT amnount received after spending poolShares + * @param poolAddress + * @param poolShares + */ + public async getPoolSharesForRemoveDT( + poolAddress: string, + poolShares: string + ): Promise { + const dtAddress = await this.getDTAddress(poolAddress) + return this.calcSingleOutGivenPoolIn(poolAddress, dtAddress, poolShares) + } + + /** + * Returns no of pool shares required to receive specified amount of DT + * @param poolAddress + * @param dtAmount + */ + public async getPoolSharesRequiredToRemoveOcean( + poolAddress: string, + oceanAmount: string + ): Promise { + return this.calcPoolInGivenSingleOut(poolAddress, this.oceanAddress, oceanAmount) + } + + /** + * Returns DT amnount received after spending poolShares + * @param poolAddress + * @param poolShares + */ + public async getPoolSharesForRemoveOcean( + poolAddress: string, + poolShares: string + ): Promise { + return this.calcSingleOutGivenPoolIn(poolAddress, this.oceanAddress, poolShares) + } + /** * Returns max amount of tokens that you can add to the pool * @param poolAddress @@ -327,6 +377,25 @@ export class OceanPool extends Pool { return String(parseFloat(balance) / 3) } + /** + * Returns max amount of DT that you can withdraw from the pool + * @param poolAddress + * @param tokenAddress + */ + public async getDTMaxRemoveLiquidity(poolAddress: string): Promise { + const dtAddress = await this.getDTAddress(poolAddress) + return this.getMaxRemoveLiquidity(poolAddress, dtAddress) + } + + /** + * Returns max amount of Ocean that you can withdraw from the pool + * @param poolAddress + * @param tokenAddress + */ + public async getOceanMaxRemoveLiquidity(poolAddress: string): Promise { + return this.getMaxRemoveLiquidity(poolAddress, this.oceanAddress) + } + /** * Buy Data Token from a pool * @param {String} account @@ -358,12 +427,7 @@ export class OceanPool extends Pool { console.error('Buy quantity exceeds quantity allowed') return null } - const calcInGivenOut = await this.calcInGivenOut( - poolAddress, - this.oceanAddress, - dtAddress, - dtAmountWanted - ) + const calcInGivenOut = await this.getOceanNeeded(poolAddress, dtAmountWanted) if (parseFloat(calcInGivenOut) > parseFloat(maxOceanAmount)) { console.error('Not enough Ocean Tokens') @@ -419,12 +483,8 @@ export class OceanPool extends Pool { console.error('Buy quantity exceeds quantity allowed') return null } - const calcOutGivenIn = await this.calcOutGivenIn( - poolAddress, - dtAddress, - this.oceanAddress, - dtAmount - ) + const calcOutGivenIn = await this.getOceanReceived(poolAddress, dtAmount) + if (parseFloat(calcOutGivenIn) < parseFloat(oceanAmountWanted)) { console.error('Not enough Data Tokens') return null @@ -483,7 +543,7 @@ export class OceanPool extends Pool { maximumPoolShares: string ): Promise { const dtAddress = await this.getDTAddress(poolAddress) - const maxAmount = await this.getMaxRemoveLiquidity(poolAddress, dtAddress) + const maxAmount = await this.getDTMaxRemoveLiquidity(poolAddress) if (parseFloat(amount) > parseFloat(maxAmount)) { console.error('Too much reserve to remove') return null @@ -563,7 +623,7 @@ export class OceanPool extends Pool { console.error('oceanAddress is not defined') return null } - const maxAmount = await this.getMaxRemoveLiquidity(poolAddress, this.oceanAddress) + const maxAmount = await this.getOceanMaxRemoveLiquidity(poolAddress) if (parseFloat(amount) > parseFloat(maxAmount)) { console.error('Too much reserve to remove') return null @@ -650,6 +710,16 @@ export class OceanPool extends Pool { return this.calcInGivenOut(poolAddress, this.oceanAddress, dtAddress, dtRequired) } + public async getOceanReceived(poolAddress: string, dtSold: string): Promise { + const dtAddress = await this.getDTAddress(poolAddress) + return this.calcOutGivenIn(poolAddress, dtAddress, this.oceanAddress, dtSold) + } + + public async getDTNeeded(poolAddress: string, OceanRequired: string): Promise { + const dtAddress = await this.getDTAddress(poolAddress) + return this.calcInGivenOut(poolAddress, dtAddress, this.oceanAddress, OceanRequired) + } + /** * Search all pools created by an address * @param {String} account If empty, will return all pools ever created by anybody From f856ef705823dbc64b0b4361448dfa8e133db03f Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Mon, 12 Oct 2020 04:07:13 -0700 Subject: [PATCH 03/26] add getDTMaxAddLiquidity and getOceanMaxAddLiquidity --- src/balancer/OceanPool.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/balancer/OceanPool.ts b/src/balancer/OceanPool.ts index f3072eb9..be77891a 100644 --- a/src/balancer/OceanPool.ts +++ b/src/balancer/OceanPool.ts @@ -351,6 +351,23 @@ export class OceanPool extends Pool { return this.calcSingleOutGivenPoolIn(poolAddress, this.oceanAddress, poolShares) } + /** + * Returns max DT amount that you can add to the pool + * @param poolAddress + */ + public async getDTMaxAddLiquidity(poolAddress: string): Promise { + const dtAddress = await this.getDTAddress(poolAddress) + return this.getMaxAddLiquidity(poolAddress, dtAddress) + } + + /** + * Returns max Ocean amount that you can add to the pool + * @param poolAddress + */ + public async getOceanMaxAddLiquidity(poolAddress: string): Promise { + return this.getMaxAddLiquidity(poolAddress, this.oceanAddress) + } + /** * Returns max amount of tokens that you can add to the pool * @param poolAddress From a148ae7613d7ecd9628ccc78ca7cc28ab3a25739 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Mon, 12 Oct 2020 04:35:48 -0700 Subject: [PATCH 04/26] add getDTMaxBuyQuantity & getOceanMaxBuyQuantity --- src/balancer/OceanPool.ts | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/balancer/OceanPool.ts b/src/balancer/OceanPool.ts index be77891a..c52ac60c 100644 --- a/src/balancer/OceanPool.ts +++ b/src/balancer/OceanPool.ts @@ -157,6 +157,24 @@ export class OceanPool extends Pool { return String(parseFloat(balance) / 3) } + /** + * Returns max amount of OCEAN that you can buy. + * @param poolAddress + * @param tokenAddress + */ + public async getOceanMaxBuyQuantity(poolAddress: string): Promise { + return this.getMaxBuyQuantity(poolAddress, this.oceanAddress) + } + + /** + * Returns max amount of DT that you can buy. + * @param poolAddress + * @param tokenAddress + */ + public async getDTMaxBuyQuantity(poolAddress: string): Promise { + return this.getMaxBuyQuantity(poolAddress, await this.getDTAddress(poolAddress)) + } + /** * Returns tokenInAmount required to get tokenOutAmount * @param poolAddress @@ -438,8 +456,7 @@ export class OceanPool extends Pool { } const dtAddress = await this.getDTAddress(poolAddress) if ( - parseFloat(dtAmountWanted) > - parseFloat(await this.getMaxBuyQuantity(poolAddress, dtAddress)) + parseFloat(dtAmountWanted) > parseFloat(await this.getDTMaxBuyQuantity(poolAddress)) ) { console.error('Buy quantity exceeds quantity allowed') return null @@ -495,7 +512,7 @@ export class OceanPool extends Pool { const dtAddress = await this.getDTAddress(poolAddress) if ( parseFloat(oceanAmountWanted) > - parseFloat(await this.getMaxBuyQuantity(poolAddress, this.oceanAddress)) + parseFloat(await this.getOceanMaxBuyQuantity(poolAddress)) ) { console.error('Buy quantity exceeds quantity allowed') return null @@ -572,7 +589,7 @@ export class OceanPool extends Pool { } if ( parseFloat(maximumPoolShares) < - parseFloat(await this.calcPoolInGivenSingleOut(poolAddress, dtAddress, amount)) + parseFloat(await this.getPoolSharesRequiredToRemoveDT(poolAddress, amount)) ) { console.error('Not enough poolShares') return null @@ -652,9 +669,7 @@ export class OceanPool extends Pool { } if ( parseFloat(maximumPoolShares) < - parseFloat( - await this.calcPoolInGivenSingleOut(poolAddress, this.oceanAddress, amount) - ) + parseFloat(await this.getPoolSharesRequiredToRemoveOcean(poolAddress, amount)) ) { console.error('Not enough poolShares') return null From 3ddf64f1dfeb6e2494c4cf1d5aba38301fab2c62 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Mon, 12 Oct 2020 04:42:17 -0700 Subject: [PATCH 05/26] removed typo --- src/balancer/OceanPool.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/balancer/OceanPool.ts b/src/balancer/OceanPool.ts index c52ac60c..d81abf6c 100644 --- a/src/balancer/OceanPool.ts +++ b/src/balancer/OceanPool.ts @@ -3,7 +3,7 @@ import { AbiItem } from 'web3-utils/types' import { TransactionReceipt } from 'web3-core' import { Pool } from './Pool' import { EventData, Filter } from 'web3-eth-contract' -import { parse } from 'path' + declare type PoolTransactionType = 'swap' | 'join' | 'exit' From a5339e14e88938397c23a05496903c88ba5e8a72 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Mon, 12 Oct 2020 04:42:56 -0700 Subject: [PATCH 06/26] typo --- src/balancer/OceanPool.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/balancer/OceanPool.ts b/src/balancer/OceanPool.ts index d81abf6c..57ede37e 100644 --- a/src/balancer/OceanPool.ts +++ b/src/balancer/OceanPool.ts @@ -4,7 +4,6 @@ import { TransactionReceipt } from 'web3-core' import { Pool } from './Pool' import { EventData, Filter } from 'web3-eth-contract' - declare type PoolTransactionType = 'swap' | 'join' | 'exit' export interface PoolDetails { From c712b159e9486f337ce27ad02e1e015b58edf8a2 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Mon, 12 Oct 2020 06:56:54 -0700 Subject: [PATCH 07/26] bump contracts to 0.5.5 --- .travis.yml | 2 +- package-lock.json | 6 +++--- package.json | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 22a952ca..1b4232b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ before_script: - export ADDRESS_FILE="${HOME}/.ocean/ocean-contracts/artifacts/address.json" - export AQUARIUS_URI="http://172.15.0.5:5000" - export DEPLOY_CONTRACTS=true - - export CONTRACTS_VERSION=v0.5.3 + - export CONTRACTS_VERSION=v0.5.5 - bash -x start_ocean.sh --no-dashboard 2>&1 > start_ocean.log & - cd .. - ./scripts/waitforcontracts.sh diff --git a/package-lock.json b/package-lock.json index 26007423..5315647e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -939,9 +939,9 @@ } }, "@oceanprotocol/contracts": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@oceanprotocol/contracts/-/contracts-0.5.3.tgz", - "integrity": "sha512-gJ8qQACJgxOPIrPE0OFQ09iYXBAisOGg56EmelQlsMUgp0yY0DKgBntDP83S/Ho1yBjGygqfxCjQrPH63hh/PA==" + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@oceanprotocol/contracts/-/contracts-0.5.5.tgz", + "integrity": "sha512-Omwlh3KxPm2JOuLd6DW4teAQhGaIv0fRTopCvctey0XGsf3DcbJpwS0A0YfgLQnvCyyVMKsiq90YCqpJ3SO/cw==" }, "@octokit/auth-token": { "version": "2.4.2", diff --git a/package.json b/package.json index 7874b86d..63f80027 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ }, "dependencies": { "@ethereum-navigator/navigator": "^0.5.0", - "@oceanprotocol/contracts": "^0.5.3", + "@oceanprotocol/contracts": "^0.5.5", "decimal.js": "^10.2.0", "fs": "0.0.1-security", "lzma": "^2.3.2", From eb60a4217fcec000b055b8208eed4929c9d64893 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Mon, 12 Oct 2020 07:37:39 -0700 Subject: [PATCH 08/26] use addresses from contracts --- src/utils/ConfigHelper.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/utils/ConfigHelper.ts b/src/utils/ConfigHelper.ts index 13aac9d6..b146a530 100644 --- a/src/utils/ConfigHelper.ts +++ b/src/utils/ConfigHelper.ts @@ -68,7 +68,7 @@ const configs: ConfigHelperConfig[] = [ export class ConfigHelper { /* Load contract addresses from env ADDRESS_FILE (generated by ocean-contracts) */ - public getAddressesFromEnv(): Partial { + public getAddressesFromEnv(network: string): Partial { try { const data = JSON.parse( fs.readFileSync( @@ -78,13 +78,14 @@ export class ConfigHelper { ) ) - const { DTFactory, BFactory, FixedRateExchange, Metadata } = data?.ganache + const { DTFactory, BFactory, FixedRateExchange, Metadata, Ocean } = data[network] const configAddresses: Partial = { factoryAddress: DTFactory, poolFactoryAddress: BFactory, fixedRateExchangeAddress: FixedRateExchange, metadataContractAddress: Metadata, + oceanTokenAddress: Ocean, ...(process.env.AQUARIUS_URI && { metadataStoreUri: process.env.AQUARIUS_URI }) } @@ -107,10 +108,8 @@ export class ConfigHelper { return null } - if (network === 'development') { - const contractAddressesConfig = this.getAddressesFromEnv() - config = { ...config, ...contractAddressesConfig } - } + const contractAddressesConfig = this.getAddressesFromEnv(config.network) + config = { ...config, ...contractAddressesConfig } const nodeUri = infuraProjectId ? `${config.nodeUri}/${infuraProjectId}` From 007328d74e8f2075ec0d6fcc58b9954cd486f626 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Mon, 12 Oct 2020 08:15:08 -0700 Subject: [PATCH 09/26] update getOrderHistory to generate signature --- src/datatokens/Datatokens.ts | 6 ++++++ src/ocean/Assets.ts | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/datatokens/Datatokens.ts b/src/datatokens/Datatokens.ts index bfe34f98..192fb82c 100644 --- a/src/datatokens/Datatokens.ts +++ b/src/datatokens/Datatokens.ts @@ -417,4 +417,10 @@ export class DataTokens { } return null } + + public getStartOrderEventSignature(): string { + const abi = this.datatokensABI as AbiItem[] + const eventdata = abi.find((o) => (o.name = 'OrderStarted')) + return this.web3.eth.abi.encodeEventSignature(eventdata as any) + } } diff --git a/src/ocean/Assets.ts b/src/ocean/Assets.ts index 1d3232a4..1fcee03e 100644 --- a/src/ocean/Assets.ts +++ b/src/ocean/Assets.ts @@ -612,10 +612,11 @@ export class Assets extends Instantiable { ): Promise { const results: Order[] = [] const address = account.getId().toLowerCase() + const { datatokens } = this.ocean const events = await this.web3.eth.getPastLogs({ topics: [ [ - '0xe1c4fa794edfa8f619b8257a077398950357b9c6398528f94480307352f9afcc', + datatokens.getStartOrderEventSignature(), null, '0x000000000000000000000000' + address.substring(address.length - 40) ] From 413f3c7ae2fda028ead1c6bdc275c16b4e8216eb Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Mon, 12 Oct 2020 08:15:37 -0700 Subject: [PATCH 10/26] increase sleep in tests while waitting for aqua events monitor --- test/integration/ComputeFlow.test.ts | 2 +- test/integration/Marketplaceflow.test.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/integration/ComputeFlow.test.ts b/test/integration/ComputeFlow.test.ts index f47661bb..dcee2d67 100644 --- a/test/integration/ComputeFlow.test.ts +++ b/test/integration/ComputeFlow.test.ts @@ -445,7 +445,7 @@ describe('Compute flow', () => { alice ) assert(newDdo !== null) - await sleep(6000) + await sleep(60000) const metaData = await ocean.assets.getServiceByType(ddo.id, 'compute') assert.equal( metaData.attributes.main.privacy.allowRawAlgorithm, diff --git a/test/integration/Marketplaceflow.test.ts b/test/integration/Marketplaceflow.test.ts index 6b3e538e..631c6877 100644 --- a/test/integration/Marketplaceflow.test.ts +++ b/test/integration/Marketplaceflow.test.ts @@ -112,7 +112,7 @@ describe('Marketplace flow', () => { ) ddo = await ocean.assets.create(asset, alice, [service1], tokenAddress) assert(ddo.dataToken === tokenAddress) - await sleep(6000) + await sleep(60000) }) it('Alice mints 100 tokens', async () => { @@ -212,7 +212,7 @@ describe('Marketplace flow', () => { } const newDdo = await ocean.assets.editMetadata(ddo.id, newMetaData, alice) assert(newDdo !== null) - await sleep(6000) + await sleep(60000) const metaData = await ocean.assets.getServiceByType(ddo.id, 'metadata') assert.equal(metaData.attributes.main.name, newMetaData.title) assert.equal( From a4b6f17552b8b8cfd242e579b337f13f1f071ecb Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Mon, 12 Oct 2020 08:50:16 -0700 Subject: [PATCH 11/26] fix travis --- scripts/waitforcontracts.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/waitforcontracts.sh b/scripts/waitforcontracts.sh index eef49198..087c5a2e 100755 --- a/scripts/waitforcontracts.sh +++ b/scripts/waitforcontracts.sh @@ -3,3 +3,4 @@ if [ "${DEPLOY_CONTRACTS}" = "true" ]; then sleep 2 done fi +cat "${HOME}/.ocean/ocean-contracts/artifacts/address.json" From cddc99b92a7ee89a17d2ba3b103d7ac4b60c0dce Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Mon, 12 Oct 2020 08:59:49 -0700 Subject: [PATCH 12/26] travis debug --- scripts/waitforcontracts.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/waitforcontracts.sh b/scripts/waitforcontracts.sh index 087c5a2e..894284e5 100755 --- a/scripts/waitforcontracts.sh +++ b/scripts/waitforcontracts.sh @@ -3,4 +3,6 @@ if [ "${DEPLOY_CONTRACTS}" = "true" ]; then sleep 2 done fi +ls -lh "${HOME}/.ocean/ocean-contracts/" +ls -lh "${HOME}/.ocean/ocean-contracts/artifacts/" cat "${HOME}/.ocean/ocean-contracts/artifacts/address.json" From e061f042512910796b04fe325e40f6ff709da3c8 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Mon, 12 Oct 2020 09:07:41 -0700 Subject: [PATCH 13/26] fix travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1b4232b8..6c2d5aeb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,7 @@ before_script: - git checkout v3 - export ADDRESS_FILE="${HOME}/.ocean/ocean-contracts/artifacts/address.json" - export AQUARIUS_URI="http://172.15.0.5:5000" - - export DEPLOY_CONTRACTS=true + - export DEPLOY_CONTRACTS="true" - export CONTRACTS_VERSION=v0.5.5 - bash -x start_ocean.sh --no-dashboard 2>&1 > start_ocean.log & - cd .. From 3d4a596b8b30c8d88e98d7eab2eea7883891f7a7 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Mon, 12 Oct 2020 09:28:51 -0700 Subject: [PATCH 14/26] more travis debug --- scripts/waitforcontracts.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/waitforcontracts.sh b/scripts/waitforcontracts.sh index 894284e5..77a89ea7 100755 --- a/scripts/waitforcontracts.sh +++ b/scripts/waitforcontracts.sh @@ -3,6 +3,7 @@ if [ "${DEPLOY_CONTRACTS}" = "true" ]; then sleep 2 done fi +cat "barge/start_ocean.log" ls -lh "${HOME}/.ocean/ocean-contracts/" ls -lh "${HOME}/.ocean/ocean-contracts/artifacts/" cat "${HOME}/.ocean/ocean-contracts/artifacts/address.json" From 6114621b536be8c987d10289a2f6638a0a29a57a Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Mon, 12 Oct 2020 10:09:47 -0700 Subject: [PATCH 15/26] fix travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 6c2d5aeb..efe7a710 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,7 @@ before_script: - cd barge - git checkout v3 - export ADDRESS_FILE="${HOME}/.ocean/ocean-contracts/artifacts/address.json" + - touch ADDRESS_FILE - export AQUARIUS_URI="http://172.15.0.5:5000" - export DEPLOY_CONTRACTS="true" - export CONTRACTS_VERSION=v0.5.5 From e3d293edc9b942c312c9efea371271a410809e49 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Mon, 12 Oct 2020 10:29:02 -0700 Subject: [PATCH 16/26] fix travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index efe7a710..9c5e8374 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,7 +21,7 @@ before_script: - cd barge - git checkout v3 - export ADDRESS_FILE="${HOME}/.ocean/ocean-contracts/artifacts/address.json" - - touch ADDRESS_FILE + - echo "{}" >> $ADDRESS_FILE - export AQUARIUS_URI="http://172.15.0.5:5000" - export DEPLOY_CONTRACTS="true" - export CONTRACTS_VERSION=v0.5.5 From e9889d3bc560add6024d3438d86582c13b338a9a Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Mon, 12 Oct 2020 10:31:46 -0700 Subject: [PATCH 17/26] fix travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9c5e8374..edb5951a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,7 +21,7 @@ before_script: - cd barge - git checkout v3 - export ADDRESS_FILE="${HOME}/.ocean/ocean-contracts/artifacts/address.json" - - echo "{}" >> $ADDRESS_FILE + - bash -x echo "{}" >> $ADDRESS_FILE - export AQUARIUS_URI="http://172.15.0.5:5000" - export DEPLOY_CONTRACTS="true" - export CONTRACTS_VERSION=v0.5.5 From e4592017909962c21aba7bff888564f4aeea6cf2 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Mon, 12 Oct 2020 10:38:17 -0700 Subject: [PATCH 18/26] fix travis --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index edb5951a..0a226b0a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,7 +21,8 @@ before_script: - cd barge - git checkout v3 - export ADDRESS_FILE="${HOME}/.ocean/ocean-contracts/artifacts/address.json" - - bash -x echo "{}" >> $ADDRESS_FILE + - touch $ADDRESS_FILE + - echo "{}" >> $ADDRESS_FILE - export AQUARIUS_URI="http://172.15.0.5:5000" - export DEPLOY_CONTRACTS="true" - export CONTRACTS_VERSION=v0.5.5 From 190785f9cd688a53e983f8a30ec27272be1fd662 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Mon, 12 Oct 2020 10:41:19 -0700 Subject: [PATCH 19/26] fix travis --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 0a226b0a..2521ab75 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,9 @@ before_script: - cd barge - git checkout v3 - export ADDRESS_FILE="${HOME}/.ocean/ocean-contracts/artifacts/address.json" + - mkdir "${HOME}/.ocean/" + - mkdir "${HOME}/.ocean/ocean-contracts/" + - mkdir "${HOME}/.ocean/ocean-contracts/artifacts" - touch $ADDRESS_FILE - echo "{}" >> $ADDRESS_FILE - export AQUARIUS_URI="http://172.15.0.5:5000" From ea352125e27cf07b2fff3610cd433ec51ee917fc Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Mon, 12 Oct 2020 12:01:54 -0700 Subject: [PATCH 20/26] fix history --- src/datatokens/Datatokens.ts | 7 +++++-- src/ocean/Assets.ts | 38 +++++++++++++++++------------------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/datatokens/Datatokens.ts b/src/datatokens/Datatokens.ts index 192fb82c..62d01f5a 100644 --- a/src/datatokens/Datatokens.ts +++ b/src/datatokens/Datatokens.ts @@ -420,7 +420,10 @@ export class DataTokens { public getStartOrderEventSignature(): string { const abi = this.datatokensABI as AbiItem[] - const eventdata = abi.find((o) => (o.name = 'OrderStarted')) - return this.web3.eth.abi.encodeEventSignature(eventdata as any) + const eventdata = abi.find(function (o) { + if (o.name === 'OrderStarted' && o.type === 'event') return o + }) + const topic = this.web3.eth.abi.encodeEventSignature(eventdata as any) + return topic } } diff --git a/src/ocean/Assets.ts b/src/ocean/Assets.ts index 1fcee03e..6ddd3cfe 100644 --- a/src/ocean/Assets.ts +++ b/src/ocean/Assets.ts @@ -613,15 +613,11 @@ export class Assets extends Instantiable { const results: Order[] = [] const address = account.getId().toLowerCase() const { datatokens } = this.ocean + const topic1 = '0x000000000000000000000000' + address.substring(2) const events = await this.web3.eth.getPastLogs({ - topics: [ - [ - datatokens.getStartOrderEventSignature(), - null, - '0x000000000000000000000000' + address.substring(address.length - 40) - ] - ], - fromBlock: fromBlock || 0 + topics: [[datatokens.getStartOrderEventSignature(), null, topic1]], + fromBlock: fromBlock || 0, + toBlock: 'latest' }) for (let i = 0; i < events.length; i++) { const order: Order = { @@ -632,18 +628,20 @@ export class Assets extends Instantiable { consumer: '0x' + events[i].topics[1].substring(events[i].topics[1].length - 40), payer: '0x' + events[i].topics[2].substring(events[i].topics[2].length - 40) } - const params = this.web3.eth.abi.decodeParameters( - ['uint256', 'uint256', 'uint256', 'uint256'], - events[i].data - ) - order.serviceId = parseInt(params[1]) - order.timestamp = parseInt(params[2]) - order.amount = this.web3.utils.fromWei(params[0]) - order.did = didPrefixed(didNoZeroX(order.dtAddress)) - const service = await this.getServiceByIndex(order.did, order.serviceId) - order.serviceType = service.type - if (!serviceType || (serviceType && serviceType === service.type)) - results.push(order) + try { + const params = this.web3.eth.abi.decodeParameters( + ['uint256', 'uint256', 'uint256', 'uint256'], + events[i].data + ) + order.serviceId = parseInt(params[1]) + order.timestamp = parseInt(params[2]) + order.amount = this.web3.utils.fromWei(params[0]) + order.did = didPrefixed(didNoZeroX(order.dtAddress)) + const service = await this.getServiceByIndex(order.did, order.serviceId) + order.serviceType = service.type + if (!serviceType || (serviceType && serviceType === service.type)) + results.push(order) + } catch (e) {} } return results } From 002a38d487ffacb54f04b74679da528d282b873c Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Mon, 12 Oct 2020 14:29:44 -0700 Subject: [PATCH 21/26] add more pool tests --- src/balancer/OceanPool.ts | 29 +++++++------ src/balancer/Pool.ts | 12 ++++-- test/unit/balancer/Balancer.test.ts | 65 +++++++++++++++++++++++------ 3 files changed, 78 insertions(+), 28 deletions(-) diff --git a/src/balancer/OceanPool.ts b/src/balancer/OceanPool.ts index 57ede37e..8acde680 100644 --- a/src/balancer/OceanPool.ts +++ b/src/balancer/OceanPool.ts @@ -3,6 +3,8 @@ import { AbiItem } from 'web3-utils/types' import { TransactionReceipt } from 'web3-core' import { Pool } from './Pool' import { EventData, Filter } from 'web3-eth-contract' +import BigNumber from 'bignumber.js' +import Decimal from 'decimal.js' declare type PoolTransactionType = 'swap' | 'join' | 'exit' @@ -336,7 +338,7 @@ export class OceanPool extends Pool { * @param poolAddress * @param poolShares */ - public async getPoolSharesForRemoveDT( + public async getDTRemovedforPoolShares( poolAddress: string, poolShares: string ): Promise { @@ -357,11 +359,11 @@ export class OceanPool extends Pool { } /** - * Returns DT amnount received after spending poolShares + * Returns Ocean amnount received after spending poolShares * @param poolAddress * @param poolShares */ - public async getPoolSharesForRemoveOcean( + public async getOceanRemovedforPoolShares( poolAddress: string, poolShares: string ): Promise { @@ -395,7 +397,11 @@ export class OceanPool extends Pool { tokenAddress: string ): Promise { const balance = await super.getReserve(poolAddress, tokenAddress) - return String(parseFloat(balance) / 2) + const result = new BigNumber(this.web3.utils.toWei(balance)) + .dividedBy(3) + .integerValue(BigNumber.ROUND_DOWN) + .minus(1) + return this.web3.utils.fromWei(result.toString()) } /** @@ -408,7 +414,11 @@ export class OceanPool extends Pool { tokenAddress: string ): Promise { const balance = await super.getReserve(poolAddress, tokenAddress) - return String(parseFloat(balance) / 3) + const result = new BigNumber(this.web3.utils.toWei(balance)) + .dividedBy(3) + .integerValue(BigNumber.ROUND_DOWN) + .minus(1) + return this.web3.utils.fromWei(result.toString()) } /** @@ -450,9 +460,6 @@ export class OceanPool extends Pool { console.error('oceanAddress is not defined') return null } - if (!maxPrice) { - maxPrice = String(2 ** 256 - 1) - } const dtAddress = await this.getDTAddress(poolAddress) if ( parseFloat(dtAmountWanted) > parseFloat(await this.getDTMaxBuyQuantity(poolAddress)) @@ -501,9 +508,6 @@ export class OceanPool extends Pool { oceanAmountWanted: string, maxPrice?: string ): Promise { - if (!maxPrice) { - maxPrice = String(2 ** 256 - 1) - } if (this.oceanAddress == null) { console.error('oceanAddress is not defined') return null @@ -522,6 +526,7 @@ export class OceanPool extends Pool { console.error('Not enough Data Tokens') return null } + await super.approve(account, dtAddress, poolAddress, this.web3.utils.toWei(dtAmount)) return this.swapExactAmountIn( account, poolAddress, @@ -618,7 +623,7 @@ export class OceanPool extends Pool { console.error('oceanAddress is not defined') return null } - const maxAmount = await this.getMaxAddLiquidity(poolAddress, this.oceanAddress) + const maxAmount = await this.getOceanMaxAddLiquidity(poolAddress) if (parseFloat(amount) > parseFloat(maxAmount)) { console.error('Too much reserve to add') return null diff --git a/src/balancer/Pool.ts b/src/balancer/Pool.ts index c5345a02..c09f5955 100644 --- a/src/balancer/Pool.ts +++ b/src/balancer/Pool.ts @@ -2,9 +2,13 @@ import Web3 from 'web3' import { AbiItem } from 'web3-utils/types' import { TransactionReceipt } from 'web3-core' import Decimal from 'decimal.js' +import BigNumber from 'bignumber.js' import jsonpoolABI from '@oceanprotocol/contracts/artifacts/BPool.json' import { PoolFactory } from './PoolFactory' +const MaxUint256: BigNumber = new BigNumber( + '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' +) /** * Provides an interface to Balancer BPool & BFactory */ @@ -500,7 +504,7 @@ export class Pool extends PoolFactory { tokenAmountIn: string, tokenOut: string, minAmountOut: string, - maxPrice: string + maxPrice?: string ): Promise { const pool = new this.web3.eth.Contract(this.poolABI, poolAddress, { from: account @@ -513,7 +517,7 @@ export class Pool extends PoolFactory { this.web3.utils.toWei(tokenAmountIn), tokenOut, this.web3.utils.toWei(minAmountOut), - this.web3.utils.toWei(maxPrice) + maxPrice ? this.web3.utils.toWei(maxPrice) : MaxUint256 ) .send({ from: account, gas: this.GASLIMIT_DEFAULT }) } catch (e) { @@ -540,7 +544,7 @@ export class Pool extends PoolFactory { maxAmountIn: string, tokenOut: string, minAmountOut: string, - maxPrice: string + maxPrice?: string ): Promise { const pool = new this.web3.eth.Contract(this.poolABI, poolAddress, { from: account @@ -553,7 +557,7 @@ export class Pool extends PoolFactory { this.web3.utils.toWei(maxAmountIn), tokenOut, this.web3.utils.toWei(minAmountOut), - this.web3.utils.toWei(maxPrice) + maxPrice ? this.web3.utils.toWei(maxPrice) : MaxUint256 ) .send({ from: account, gas: this.GASLIMIT_DEFAULT }) } catch (e) { diff --git a/test/unit/balancer/Balancer.test.ts b/test/unit/balancer/Balancer.test.ts index 04a8e650..124e6a58 100644 --- a/test/unit/balancer/Balancer.test.ts +++ b/test/unit/balancer/Balancer.test.ts @@ -177,27 +177,35 @@ describe('Balancer flow', () => { assert(pools.length > 0) greatPool = pools[0] }) - it('Bob should buy a DT ', async () => { + it('Bob should buy 2 DT ', async () => { const maxPrice = parseFloat(currentDtPrice) * 2 - await Pool.buyDT(bob, greatPool, '1', '2', String(maxPrice)) + await Pool.buyDT(bob, greatPool, '2', '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 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) + }) it('Bob should get maximum DT liquidity that he can add to pool ', async () => { - const maxDT = await Pool.getMaxAddLiquidity(greatPool, tokenAddress) + const maxDT = await Pool.getDTMaxAddLiquidity(greatPool) if (consoleDebug) console.error('maxDT:' + maxDT) assert(parseFloat(maxDT) > 0) }) it('Bob should fail to add more than maximum DT liquidity that he can add to pool ', async () => { - const maxDT = await Pool.getMaxAddLiquidity(greatPool, tokenAddress) + const maxDT = await Pool.getDTMaxAddLiquidity(greatPool) const tx = await Pool.addDTLiquidity(bob, greatPool, String(parseFloat(maxDT) * 2)) assert(tx === null) }) it('Bob should add DT liquidity to pool ', async () => { - const maxDT = await Pool.getMaxAddLiquidity(greatPool, tokenAddress) + const maxDT = await Pool.getDTMaxAddLiquidity(greatPool) if (consoleDebug) console.error('maxDT:' + maxDT) const currentDtReserve = await Pool.getDTReserve(greatPool) if (consoleDebug) console.log('currentDtReserve:' + currentDtReserve) @@ -222,12 +230,26 @@ describe('Balancer flow', () => { assert(parseFloat(sharesBalance) > 0) }) it('Bob should get maximum DT liquidity that he can remove from pool ', async () => { - const maxDT = await Pool.getMaxRemoveLiquidity(greatPool, tokenAddress) + const maxDT = await Pool.getDTMaxRemoveLiquidity(greatPool) if (consoleDebug) console.log('maxDT:' + maxDT) assert(parseFloat(maxDT) > 0) }) + it('Bob should know how many Pool Shares he needs to remove 1 DT ', async () => { + const poolShares = await Pool.getPoolSharesRequiredToRemoveDT(greatPool, '1') + if (consoleDebug) console.log('poolShares:' + poolShares) + assert(parseFloat(poolShares) > 0) + }) + it('Bob should know how many DT gets in exchange of his Pool Shares', async () => { + const poolShares = await Pool.getDTRemovedforPoolShares( + greatPool, + await Pool.sharesBalance(bob, greatPool) + ) + if (consoleDebug) console.log('poolShares:' + poolShares) + assert(parseFloat(poolShares) > 0) + }) + it('Bob should fail to remove more than maximum DT liquidity that he can remove from the pool ', async () => { - const maxDT = await Pool.getMaxRemoveLiquidity(greatPool, tokenAddress) + const maxDT = await Pool.getDTMaxRemoveLiquidity(greatPool) if (consoleDebug) console.log('maxDT:' + maxDT) const poolShares = await Pool.sharesBalance(bob, greatPool) const tx = await Pool.removeDTLiquidity( @@ -266,12 +288,12 @@ describe('Balancer flow', () => { }) it('Bob should get maximum Ocean liquidity that he can add to pool ', async () => { - const maxOcean = await Pool.getMaxAddLiquidity(greatPool, oceanTokenAddress) + const maxOcean = await Pool.getOceanMaxAddLiquidity(greatPool) assert(parseFloat(maxOcean) > 0) }) it('Bob should fail to add more than maximum Ocean liquidity that he can add to pool ', async () => { - const maxOcean = await Pool.getMaxAddLiquidity(greatPool, oceanTokenAddress) + const maxOcean = await Pool.getOceanMaxAddLiquidity(greatPool) const tx = await Pool.addOceanLiquidity( bob, greatPool, @@ -285,8 +307,13 @@ describe('Balancer flow', () => { const bobDtBalance = await datatoken.balance(oceanTokenAddress, bob) if (consoleDebug) console.log('currentDtReserve:' + currentDtReserve) if (consoleDebug) console.log('bobDtBalance:' + bobDtBalance) - const maxOcean = await Pool.getMaxAddLiquidity(greatPool, oceanTokenAddress) - await Pool.addOceanLiquidity(bob, greatPool, maxOcean) + const maxOcean = await Pool.getOceanMaxAddLiquidity(greatPool) + + await Pool.addOceanLiquidity( + bob, + greatPool, + String(Math.min(parseFloat(maxOcean), parseFloat(bobDtBalance))) + ) const newbobDtBalance = await datatoken.balance(oceanTokenAddress, bob) @@ -305,7 +332,7 @@ describe('Balancer flow', () => { assert(parseFloat(maxOcean) > 0) }) it('Bob should fail to remove more than maximum Ocean liquidity that he can remove from the pool ', async () => { - const maxOcean = await Pool.getMaxRemoveLiquidity(greatPool, oceanTokenAddress) + const maxOcean = await Pool.getOceanMaxRemoveLiquidity(greatPool) const poolShares = await Pool.sharesBalance(bob, greatPool) const tx = await Pool.removeOceanLiquidity( bob, @@ -315,6 +342,20 @@ describe('Balancer flow', () => { ) assert(tx === null) }) + it('Bob should know how many Pool Shares he needs to remove 1 OCEAN ', async () => { + const poolShares = await Pool.getPoolSharesRequiredToRemoveOcean(greatPool, '1') + if (consoleDebug) console.log('poolShares:' + poolShares) + assert(parseFloat(poolShares) > 0) + }) + it('Bob should know how many OCEAN gets in exchange of his Pool Shares', async () => { + const poolShares = await Pool.getOceanRemovedforPoolShares( + greatPool, + await Pool.sharesBalance(bob, greatPool) + ) + if (consoleDebug) console.log('poolShares:' + poolShares) + assert(parseFloat(poolShares) > 0) + }) + it('Bob should remove Ocean liquidity from pool ', async () => { const currentDtReserve = await Pool.getOceanReserve(greatPool) const bobDtBalance = await datatoken.balance(oceanTokenAddress, bob) From 6fd0dc0c1f90329527c495453d7dfa2b3efd9442 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Mon, 12 Oct 2020 23:12:53 -0700 Subject: [PATCH 22/26] fix #341 --- src/balancer/OceanPool.ts | 64 +++++++++++++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 12 deletions(-) diff --git a/src/balancer/OceanPool.ts b/src/balancer/OceanPool.ts index 8acde680..02565607 100644 --- a/src/balancer/OceanPool.ts +++ b/src/balancer/OceanPool.ts @@ -80,16 +80,28 @@ export class OceanPool extends Pool { const oceanWeight = 10 - parseFloat(weight) const oceanAmount = (parseFloat(amount) * oceanWeight) / parseFloat(weight) this.dtAddress = token - - await this.approve(account, token, address, this.web3.utils.toWei(String(amount))) - await this.approve( + let txid + txid = await this.approve( + account, + token, + address, + this.web3.utils.toWei(String(amount)) + ) + if (!txid) { + console.error('DT approve failed') + return null + } + txid = await this.approve( account, this.oceanAddress, address, this.web3.utils.toWei(String(oceanAmount)) ) - - await super.setup( + if (!txid) { + console.error('OCEAN approve failed') + return null + } + txid = await super.setup( account, address, token, @@ -100,7 +112,10 @@ export class OceanPool extends Pool { this.web3.utils.toWei(String(oceanWeight)), this.web3.utils.toWei(fee) ) - + if (!txid) { + console.error('Pool creation failed') + return null + } return address } @@ -415,7 +430,7 @@ export class OceanPool extends Pool { ): Promise { const balance = await super.getReserve(poolAddress, tokenAddress) const result = new BigNumber(this.web3.utils.toWei(balance)) - .dividedBy(3) + .dividedBy(4) .integerValue(BigNumber.ROUND_DOWN) .minus(1) return this.web3.utils.fromWei(result.toString()) @@ -474,13 +489,16 @@ export class OceanPool extends Pool { return null } // TODO - check balances first - await super.approve( + const txid = await super.approve( account, this.oceanAddress, poolAddress, this.web3.utils.toWei(maxOceanAmount) ) - + if (!txid) { + console.error('OCEAN approve failed') + return null + } return this.swapExactAmountOut( account, poolAddress, @@ -526,7 +544,16 @@ export class OceanPool extends Pool { console.error('Not enough Data Tokens') return null } - await super.approve(account, dtAddress, poolAddress, this.web3.utils.toWei(dtAmount)) + const txid = await super.approve( + account, + dtAddress, + poolAddress, + this.web3.utils.toWei(dtAmount) + ) + if (!txid) { + console.error('DT approve failed') + return null + } return this.swapExactAmountIn( account, poolAddress, @@ -556,7 +583,16 @@ export class OceanPool extends Pool { console.error('Too much reserve to add') return null } - await super.approve(account, dtAddress, poolAddress, this.web3.utils.toWei(amount)) + const txid = await super.approve( + account, + dtAddress, + poolAddress, + this.web3.utils.toWei(amount) + ) + if (!txid) { + console.error('DT approve failed') + return null + } const result = await super.joinswapExternAmountIn( account, poolAddress, @@ -628,12 +664,16 @@ export class OceanPool extends Pool { console.error('Too much reserve to add') return null } - await super.approve( + const txid = await super.approve( account, this.oceanAddress, poolAddress, this.web3.utils.toWei(amount) ) + if (!txid) { + console.error('OCEAN approve failed') + return null + } const result = await super.joinswapExternAmountIn( account, poolAddress, From e1c011163644954cb6ad7b624c980907b65ca55c Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Mon, 12 Oct 2020 23:44:16 -0700 Subject: [PATCH 23/26] add more tests --- test/unit/balancer/Balancer.test.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/unit/balancer/Balancer.test.ts b/test/unit/balancer/Balancer.test.ts index 124e6a58..d5208885 100644 --- a/test/unit/balancer/Balancer.test.ts +++ b/test/unit/balancer/Balancer.test.ts @@ -171,6 +171,10 @@ describe('Balancer flow', () => { const requiredOcean = await Pool.getOceanNeeded(alicePoolAddress, '1') assert(Number(requiredOcean) > 0) }) + it('Get amount of DT needed to buy 1 Ocean', async () => { + const requiredOcean = await Pool.getDTNeeded(alicePoolAddress, '1') + assert(Number(requiredOcean) > 0) + }) it('Bob should search for pools with this DT', async () => { const pools = await Pool.searchPoolforDT(tokenAddress) @@ -379,6 +383,18 @@ describe('Balancer flow', () => { assert(parseFloat(poolShares) > parseFloat(newpoolShares)) }) + it('ALice should remove all liquidity', async () => { + const aliceShares = await Pool.sharesBalance(alice, greatPool) + const aliceDtBalance = await datatoken.balance(tokenAddress, alice) + const aliceOceanBalance = await datatoken.balance(oceanTokenAddress, alice) + await Pool.removePoolLiquidity(alice, greatPool, aliceShares) + const newAliceDtBalance = await datatoken.balance(tokenAddress, alice) + const newAliceOceanBalance = await datatoken.balance(oceanTokenAddress, alice) + const newAliceShares = await Pool.sharesBalance(alice, greatPool) + assert(parseFloat(aliceDtBalance) < parseFloat(newAliceDtBalance)) + assert(parseFloat(aliceOceanBalance) < parseFloat(newAliceOceanBalance)) + assert(parseFloat(aliceShares) > parseFloat(newAliceShares)) + }) it('ALice should get all the pools that she created', async () => { const alicePools = await Pool.getPoolsbyCreator(alice) assert(alicePools.length > 0) From 9a536264d8dd90987a0eaeb2a7a6fc5800021b59 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Tue, 13 Oct 2020 02:30:09 -0700 Subject: [PATCH 24/26] fix error messages --- src/balancer/OceanPool.ts | 82 ++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/src/balancer/OceanPool.ts b/src/balancer/OceanPool.ts index 02565607..ac97abad 100644 --- a/src/balancer/OceanPool.ts +++ b/src/balancer/OceanPool.ts @@ -65,15 +65,15 @@ export class OceanPool extends Pool { fee: string ): Promise { if (this.oceanAddress == null) { - console.error('oceanAddress is not defined') + console.error('ERROR: oceanAddress is not defined') return null } if (parseFloat(fee) > 0.1) { - console.error('Swap fee too high. The maximum allowed swapFee is 0.1 (10%).') + console.error('ERROR: Swap fee too high. The maximum allowed swapFee is 0.1 (10%).') return null } if (parseFloat(weight) > 9 || parseFloat(weight) < 1) { - console.error('Weight out of bounds (min 1, max9)') + console.error('ERROR: Weight out of bounds (min 1, max9)') return null } const address = await super.createPool(account) @@ -88,7 +88,7 @@ export class OceanPool extends Pool { this.web3.utils.toWei(String(amount)) ) if (!txid) { - console.error('DT approve failed') + console.error('ERROR: Failed to call approve DT token') return null } txid = await this.approve( @@ -98,7 +98,7 @@ export class OceanPool extends Pool { this.web3.utils.toWei(String(oceanAmount)) ) if (!txid) { - console.error('OCEAN approve failed') + console.error('ERROR: Failed to call approve OCEAN token') return null } txid = await super.setup( @@ -113,7 +113,7 @@ export class OceanPool extends Pool { this.web3.utils.toWei(fee) ) if (!txid) { - console.error('Pool creation failed') + console.error('ERROR: Failed to create a new pool') return null } return address @@ -144,7 +144,7 @@ export class OceanPool extends Pool { */ public async getOceanReserve(poolAddress: string): Promise { if (this.oceanAddress == null) { - console.error('oceanAddress is not defined') + console.error('ERROR: oceanAddress is not defined') return null } return super.getReserve(poolAddress, this.oceanAddress) @@ -412,11 +412,13 @@ export class OceanPool extends Pool { tokenAddress: string ): Promise { const balance = await super.getReserve(poolAddress, tokenAddress) - const result = new BigNumber(this.web3.utils.toWei(balance)) - .dividedBy(3) - .integerValue(BigNumber.ROUND_DOWN) - .minus(1) - return this.web3.utils.fromWei(result.toString()) + if (parseFloat(balance) > 0) { + const result = new BigNumber(this.web3.utils.toWei(balance)) + .dividedBy(3) + .integerValue(BigNumber.ROUND_DOWN) + .minus(1) + return this.web3.utils.fromWei(result.toString()) + } else return '0' } /** @@ -429,11 +431,13 @@ export class OceanPool extends Pool { tokenAddress: string ): Promise { const balance = await super.getReserve(poolAddress, tokenAddress) - const result = new BigNumber(this.web3.utils.toWei(balance)) - .dividedBy(4) - .integerValue(BigNumber.ROUND_DOWN) - .minus(1) - return this.web3.utils.fromWei(result.toString()) + if (parseFloat(balance) > 0) { + const result = new BigNumber(this.web3.utils.toWei(balance)) + .dividedBy(4) + .integerValue(BigNumber.ROUND_DOWN) + .minus(1) + return this.web3.utils.fromWei(result.toString()) + } else return '0' } /** @@ -472,20 +476,20 @@ export class OceanPool extends Pool { maxPrice?: string ): Promise { if (this.oceanAddress == null) { - console.error('oceanAddress is not defined') + console.error('ERROR: undefined ocean token contract address') return null } const dtAddress = await this.getDTAddress(poolAddress) if ( parseFloat(dtAmountWanted) > parseFloat(await this.getDTMaxBuyQuantity(poolAddress)) ) { - console.error('Buy quantity exceeds quantity allowed') + console.error('ERROR: Buy quantity exceeds quantity allowed') return null } const calcInGivenOut = await this.getOceanNeeded(poolAddress, dtAmountWanted) if (parseFloat(calcInGivenOut) > parseFloat(maxOceanAmount)) { - console.error('Not enough Ocean Tokens') + console.error('ERROR: Not enough Ocean Tokens') return null } // TODO - check balances first @@ -496,7 +500,7 @@ export class OceanPool extends Pool { this.web3.utils.toWei(maxOceanAmount) ) if (!txid) { - console.error('OCEAN approve failed') + console.error('ERROR: OCEAN approve failed') return null } return this.swapExactAmountOut( @@ -527,7 +531,7 @@ export class OceanPool extends Pool { maxPrice?: string ): Promise { if (this.oceanAddress == null) { - console.error('oceanAddress is not defined') + console.error('ERROR: oceanAddress is not defined') return null } const dtAddress = await this.getDTAddress(poolAddress) @@ -535,13 +539,13 @@ export class OceanPool extends Pool { parseFloat(oceanAmountWanted) > parseFloat(await this.getOceanMaxBuyQuantity(poolAddress)) ) { - console.error('Buy quantity exceeds quantity allowed') + console.error('ERROR: Buy quantity exceeds quantity allowed') return null } const calcOutGivenIn = await this.getOceanReceived(poolAddress, dtAmount) if (parseFloat(calcOutGivenIn) < parseFloat(oceanAmountWanted)) { - console.error('Not enough Data Tokens') + console.error('ERROR: Not enough Data Tokens') return null } const txid = await super.approve( @@ -551,7 +555,7 @@ export class OceanPool extends Pool { this.web3.utils.toWei(dtAmount) ) if (!txid) { - console.error('DT approve failed') + console.error('ERROR: DT approve failed') return null } return this.swapExactAmountIn( @@ -580,7 +584,7 @@ export class OceanPool extends Pool { const dtAddress = await this.getDTAddress(poolAddress) const maxAmount = await this.getMaxAddLiquidity(poolAddress, dtAddress) if (parseFloat(amount) > parseFloat(maxAmount)) { - console.error('Too much reserve to add') + console.error('ERROR: Too much reserve to add') return null } const txid = await super.approve( @@ -590,7 +594,7 @@ export class OceanPool extends Pool { this.web3.utils.toWei(amount) ) if (!txid) { - console.error('DT approve failed') + console.error('ERROR: DT approve failed') return null } const result = await super.joinswapExternAmountIn( @@ -619,19 +623,19 @@ export class OceanPool extends Pool { const dtAddress = await this.getDTAddress(poolAddress) const maxAmount = await this.getDTMaxRemoveLiquidity(poolAddress) if (parseFloat(amount) > parseFloat(maxAmount)) { - console.error('Too much reserve to remove') + console.error('ERROR: Too much reserve to remove') return null } const usershares = await this.sharesBalance(account, poolAddress) if (parseFloat(usershares) < parseFloat(maximumPoolShares)) { - console.error('Not enough poolShares') + console.error('ERROR: Not enough poolShares') return null } if ( parseFloat(maximumPoolShares) < parseFloat(await this.getPoolSharesRequiredToRemoveDT(poolAddress, amount)) ) { - console.error('Not enough poolShares') + console.error('ERROR: Not enough poolShares') return null } return this.exitswapExternAmountOut( @@ -656,12 +660,12 @@ export class OceanPool extends Pool { amount: string ): Promise { if (this.oceanAddress == null) { - console.error('oceanAddress is not defined') + console.error('ERROR: oceanAddress is not defined') return null } const maxAmount = await this.getOceanMaxAddLiquidity(poolAddress) if (parseFloat(amount) > parseFloat(maxAmount)) { - console.error('Too much reserve to add') + console.error('ERROR: Too much reserve to add') return null } const txid = await super.approve( @@ -671,7 +675,7 @@ export class OceanPool extends Pool { this.web3.utils.toWei(amount) ) if (!txid) { - console.error('OCEAN approve failed') + console.error('ERROR: OCEAN approve failed') return null } const result = await super.joinswapExternAmountIn( @@ -698,24 +702,24 @@ export class OceanPool extends Pool { maximumPoolShares: string ): Promise { if (this.oceanAddress == null) { - console.error('oceanAddress is not defined') + console.error('ERROR: oceanAddress is not defined') return null } const maxAmount = await this.getOceanMaxRemoveLiquidity(poolAddress) if (parseFloat(amount) > parseFloat(maxAmount)) { - console.error('Too much reserve to remove') + console.error('ERROR: Too much reserve to remove') return null } const usershares = await this.sharesBalance(account, poolAddress) if (parseFloat(usershares) < parseFloat(maximumPoolShares)) { - console.error('Not enough poolShares') + console.error('ERROR: Not enough poolShares') return null } if ( parseFloat(maximumPoolShares) < parseFloat(await this.getPoolSharesRequiredToRemoveOcean(poolAddress, amount)) ) { - console.error('Not enough poolShares') + console.error('ERROR: Not enough poolShares') return null } return super.exitswapExternAmountOut( @@ -741,7 +745,7 @@ export class OceanPool extends Pool { ): Promise { const usershares = await this.sharesBalance(account, poolAddress) if (parseFloat(usershares) < parseFloat(poolShares)) { - console.error('Not enough poolShares') + console.error('ERROR: Not enough poolShares') return null } @@ -755,7 +759,7 @@ export class OceanPool extends Pool { */ public async getDTPrice(poolAddress: string): Promise { if (this.oceanAddress == null) { - console.error('oceanAddress is not defined') + console.error('ERROR: oceanAddress is not defined') return null } return this.getOceanNeeded(poolAddress, '1') From d13b8816b32c75912ab671336e9ef24012ee8557 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Tue, 13 Oct 2020 04:22:45 -0700 Subject: [PATCH 25/26] increase timeout for tests --- test/integration/ComputeFlow.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/ComputeFlow.test.ts b/test/integration/ComputeFlow.test.ts index dcee2d67..ede18100 100644 --- a/test/integration/ComputeFlow.test.ts +++ b/test/integration/ComputeFlow.test.ts @@ -283,7 +283,7 @@ describe('Compute flow', () => { tokenAddressAlgorithm ) assert(algorithmAsset.dataToken === tokenAddressAlgorithm) - await sleep(6000) + await sleep(60000) }) it('Alice mints 100 DTs and tranfers them to the compute marketplace', async () => { From 049288f3cf985dd09775c39494c031c641d46f08 Mon Sep 17 00:00:00 2001 From: alexcos20 Date: Tue, 13 Oct 2020 04:53:53 -0700 Subject: [PATCH 26/26] small refactor --- src/balancer/OceanPool.ts | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/balancer/OceanPool.ts b/src/balancer/OceanPool.ts index ac97abad..c66b8997 100644 --- a/src/balancer/OceanPool.ts +++ b/src/balancer/OceanPool.ts @@ -151,7 +151,7 @@ export class OceanPool extends Pool { } /** - * Get Data Token balance of a pool + * Get datatoken balance of a pool * @param {String} poolAddress * @return {String} */ @@ -460,10 +460,10 @@ export class OceanPool extends Pool { } /** - * Buy Data Token from a pool + * Buy datatoken from a pool * @param {String} account * @param {String} poolAddress - * @param {String} amount Data Token amount + * @param {String} amount datatoken amount * @param {String} oceanAmount Ocean Token amount payed * @param {String} maxPrice Maximum price to pay * @return {TransactionReceipt} @@ -515,10 +515,10 @@ export class OceanPool extends Pool { } /** - * Sell Data Token + * Sell datatoken * @param {String} account * @param {String} poolAddress - * @param {String} amount Data Token amount to be sold + * @param {String} amount datatoken amount to be sold * @param {String} oceanAmount Ocean Token amount expected * @param {String} maxPrice Minimum price to sell * @return {TransactionReceipt} @@ -545,7 +545,7 @@ export class OceanPool extends Pool { const calcOutGivenIn = await this.getOceanReceived(poolAddress, dtAmount) if (parseFloat(calcOutGivenIn) < parseFloat(oceanAmountWanted)) { - console.error('ERROR: Not enough Data Tokens') + console.error('ERROR: Not enough datatokens') return null } const txid = await super.approve( @@ -570,10 +570,10 @@ export class OceanPool extends Pool { } /** - * Add Data Token amount to pool liquidity + * Add datatoken amount to pool liquidity * @param {String} account * @param {String} poolAddress - * @param {String} amount Data Token amount + * @param {String} amount datatoken amount * @return {TransactionReceipt} */ public async addDTLiquidity( @@ -608,10 +608,10 @@ export class OceanPool extends Pool { } /** - * Remove Data Token amount from pool liquidity + * Remove datatoken amount from pool liquidity * @param {String} account * @param {String} poolAddress - * @param {String} amount Data Token amount + * @param {String} amount datatoken amount * @return {TransactionReceipt} */ public async removeDTLiquidity( @@ -736,12 +736,16 @@ export class OceanPool extends Pool { * @param {String} account * @param {String} poolAddress * @param {String} poolShares + * @param {String} minDT Minimum DT expected (defaults 0) + * @param {String} poolShares Minim Ocean expected (defaults 0) * @return {TransactionReceipt} */ public async removePoolLiquidity( account: string, poolAddress: string, - poolShares: string + poolShares: string, + minDT = '0', + minOcean = '0' ): Promise { const usershares = await this.sharesBalance(account, poolAddress) if (parseFloat(usershares) < parseFloat(poolShares)) { @@ -749,11 +753,11 @@ export class OceanPool extends Pool { return null } - return this.exitPool(account, poolAddress, poolShares, ['0', '0']) + return this.exitPool(account, poolAddress, poolShares, [minDT, minOcean]) } /** - * Get Data Token price from pool + * Get datatoken price from pool * @param {String} poolAddress * @return {String} */ @@ -766,7 +770,7 @@ export class OceanPool extends Pool { } /** - * Search all pools that have Data Token in their composition + * Search all pools that have datatoken in their composition * @param {String} dtAddress * @return {String[]} */