1
0
mirror of https://github.com/oceanprotocol/ocean.js.git synced 2024-11-26 20:39:05 +01:00

Feature/use decimal in pool (#775)

* change default gas settings

* check allowance & fix gas estimate

* use Decimal

* fix estimateGas for new Pools
This commit is contained in:
Alex Coseru 2021-04-30 16:02:18 +03:00 committed by GitHub
parent c544eaf446
commit 3a5569b12f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 65 additions and 56 deletions

View File

@ -220,7 +220,7 @@ export class OceanPool extends Pool {
tokenAddress: string tokenAddress: string
): Promise<string> { ): Promise<string> {
const balance = await super.getReserve(poolAddress, tokenAddress) const balance = await super.getReserve(poolAddress, tokenAddress)
return String(parseFloat(balance) / 3) return new Decimal(balance).div(3).toString()
} }
/** /**
@ -449,14 +449,14 @@ export class OceanPool extends Pool {
const totalPoolTokens = await this.getPoolSharesTotalSupply(poolAddress) const totalPoolTokens = await this.getPoolSharesTotalSupply(poolAddress)
const dtReserve = await this.getDTReserve(poolAddress) const dtReserve = await this.getDTReserve(poolAddress)
const oceanReserve = await this.getOceanReserve(poolAddress) const oceanReserve = await this.getOceanReserve(poolAddress)
const dtAmount = new Decimal(poolShares)
const dtAmount = `${ .div(totalPoolTokens)
(Number(poolShares) / Number(totalPoolTokens)) * Number(dtReserve) .mul(dtReserve)
}` .toString()
const oceanAmount = `${ const oceanAmount = new Decimal(poolShares)
(Number(poolShares) / Number(totalPoolTokens)) * Number(oceanReserve) .div(totalPoolTokens)
}` .mul(oceanReserve)
.toString()
return { dtAmount, oceanAmount } return { dtAmount, oceanAmount }
} catch (e) { } catch (e) {
this.logger.error(`ERROR: Unable to get token info. ${e.message}`) this.logger.error(`ERROR: Unable to get token info. ${e.message}`)
@ -491,11 +491,7 @@ export class OceanPool extends Pool {
): Promise<string> { ): Promise<string> {
const balance = await super.getReserve(poolAddress, tokenAddress) const balance = await super.getReserve(poolAddress, tokenAddress)
if (parseFloat(balance) > 0) { if (parseFloat(balance) > 0) {
const result = new BigNumber(this.web3.utils.toWei(balance)) return new Decimal(balance).mul(POOL_MAX_AMOUNT_IN_LIMIT).toString()
.multipliedBy(POOL_MAX_AMOUNT_IN_LIMIT)
.integerValue(BigNumber.ROUND_DOWN)
.minus(1)
return this.web3.utils.fromWei(result.toString(10))
} else return '0' } else return '0'
} }
@ -510,11 +506,7 @@ export class OceanPool extends Pool {
): Promise<string> { ): Promise<string> {
const balance = await super.getReserve(poolAddress, tokenAddress) const balance = await super.getReserve(poolAddress, tokenAddress)
if (parseFloat(balance) > 0) { if (parseFloat(balance) > 0) {
const result = new BigNumber(this.web3.utils.toWei(balance)) return new Decimal(balance).mul(POOL_MAX_AMOUNT_OUT_LIMIT).toString()
.multipliedBy(POOL_MAX_AMOUNT_OUT_LIMIT)
.integerValue(BigNumber.ROUND_DOWN)
.minus(1)
return this.web3.utils.fromWei(result.toString(10))
} else return '0' } else return '0'
} }
@ -559,14 +551,13 @@ export class OceanPool extends Pool {
} }
const dtAddress = await this.getDTAddress(poolAddress) const dtAddress = await this.getDTAddress(poolAddress)
if ( if (
parseFloat(dtAmountWanted) > parseFloat(await this.getDTMaxBuyQuantity(poolAddress)) new Decimal(dtAmountWanted).greaterThan(await this.getDTMaxBuyQuantity(poolAddress))
) { ) {
this.logger.error('ERROR: Buy quantity exceeds quantity allowed') this.logger.error('ERROR: Buy quantity exceeds quantity allowed')
return null return null
} }
const calcInGivenOut = await this.getOceanNeeded(poolAddress, dtAmountWanted) const calcInGivenOut = await this.getOceanNeeded(poolAddress, dtAmountWanted)
if (new Decimal(calcInGivenOut).greaterThan(maxOceanAmount)) {
if (parseFloat(calcInGivenOut) > parseFloat(maxOceanAmount)) {
this.logger.error('ERROR: Not enough Ocean Tokens') this.logger.error('ERROR: Not enough Ocean Tokens')
return null return null
} }
@ -615,15 +606,15 @@ export class OceanPool extends Pool {
} }
const dtAddress = await this.getDTAddress(poolAddress) const dtAddress = await this.getDTAddress(poolAddress)
if ( if (
parseFloat(minimumdtAmountWanted) > new Decimal(minimumdtAmountWanted).greaterThan(
parseFloat(await this.getDTMaxBuyQuantity(poolAddress)) await this.getDTMaxBuyQuantity(poolAddress)
)
) { ) {
this.logger.error('ERROR: Buy quantity exceeds quantity allowed') this.logger.error('ERROR: Buy quantity exceeds quantity allowed')
return null return null
} }
const calcInGivenOut = await this.getOceanNeeded(poolAddress, minimumdtAmountWanted) const calcInGivenOut = await this.getOceanNeeded(poolAddress, minimumdtAmountWanted)
if (new Decimal(calcInGivenOut).greaterThan(OceanAmount)) {
if (parseFloat(calcInGivenOut) > parseFloat(OceanAmount)) {
this.logger.error('ERROR: Not enough Ocean Tokens') this.logger.error('ERROR: Not enough Ocean Tokens')
return null return null
} }
@ -672,15 +663,15 @@ export class OceanPool extends Pool {
} }
const dtAddress = await this.getDTAddress(poolAddress) const dtAddress = await this.getDTAddress(poolAddress)
if ( if (
parseFloat(oceanAmountWanted) > new Decimal(oceanAmountWanted).greaterThan(
parseFloat(await this.getOceanMaxBuyQuantity(poolAddress)) await this.getOceanMaxBuyQuantity(poolAddress)
)
) { ) {
this.logger.error('ERROR: Buy quantity exceeds quantity allowed') this.logger.error('ERROR: Buy quantity exceeds quantity allowed')
return null return null
} }
const calcOutGivenIn = await this.getOceanReceived(poolAddress, dtAmount) const calcOutGivenIn = await this.getOceanReceived(poolAddress, dtAmount)
if (new Decimal(calcOutGivenIn).lessThan(oceanAmountWanted)) {
if (parseFloat(calcOutGivenIn) < parseFloat(oceanAmountWanted)) {
this.logger.error('ERROR: Not enough datatokens') this.logger.error('ERROR: Not enough datatokens')
return null return null
} }
@ -720,7 +711,7 @@ export class OceanPool extends Pool {
): Promise<TransactionReceipt> { ): Promise<TransactionReceipt> {
const dtAddress = await this.getDTAddress(poolAddress) const dtAddress = await this.getDTAddress(poolAddress)
const maxAmount = await this.getMaxAddLiquidity(poolAddress, dtAddress) const maxAmount = await this.getMaxAddLiquidity(poolAddress, dtAddress)
if (parseFloat(amount) > parseFloat(maxAmount)) { if (new Decimal(amount).greaterThan(maxAmount)) {
this.logger.error('ERROR: Too much reserve to add') this.logger.error('ERROR: Too much reserve to add')
return null return null
} }
@ -760,23 +751,23 @@ export class OceanPool extends Pool {
): Promise<TransactionReceipt> { ): Promise<TransactionReceipt> {
const dtAddress = await this.getDTAddress(poolAddress) const dtAddress = await this.getDTAddress(poolAddress)
const maxAmount = await this.getDTMaxRemoveLiquidity(poolAddress) const maxAmount = await this.getDTMaxRemoveLiquidity(poolAddress)
if (parseFloat(amount) > parseFloat(maxAmount)) { if (new Decimal(amount).greaterThan(maxAmount)) {
this.logger.error('ERROR: Too much reserve to remove') this.logger.error('ERROR: Too much reserve to remove')
return null return null
} }
const usershares = await this.sharesBalance(account, poolAddress) const usershares = await this.sharesBalance(account, poolAddress)
if (parseFloat(usershares) < parseFloat(maximumPoolShares)) { if (new Decimal(usershares).lessThan(maximumPoolShares)) {
this.logger.error('ERROR: Not enough poolShares') this.logger.error('ERROR: Not enough poolShares')
return null return null
} }
const sharesRequired = await this.getPoolSharesRequiredToRemoveDT(poolAddress, amount) const sharesRequired = await this.getPoolSharesRequiredToRemoveDT(poolAddress, amount)
if (parseFloat(maximumPoolShares) < parseFloat(sharesRequired)) { if (new Decimal(maximumPoolShares).lessThan(sharesRequired)) {
this.logger.error('ERROR: Not enough poolShares') this.logger.error('ERROR: Not enough poolShares')
return null return null
} }
// Balancer bug fix // Balancer bug fix
if (parseFloat(maximumPoolShares) < parseFloat(sharesRequired)) if (new Decimal(maximumPoolShares).lessThan(sharesRequired))
maximumPoolShares = String(parseFloat(maximumPoolShares) * 0.9999) maximumPoolShares = new Decimal(maximumPoolShares).mul(0.9999).toString()
// Balance bug fix // Balance bug fix
return this.exitswapExternAmountOut( return this.exitswapExternAmountOut(
account, account,
@ -804,7 +795,7 @@ export class OceanPool extends Pool {
return null return null
} }
const maxAmount = await this.getOceanMaxAddLiquidity(poolAddress) const maxAmount = await this.getOceanMaxAddLiquidity(poolAddress)
if (parseFloat(amount) > parseFloat(maxAmount)) { if (new Decimal(amount).greaterThan(maxAmount)) {
this.logger.error('ERROR: Too much reserve to add') this.logger.error('ERROR: Too much reserve to add')
return null return null
} }
@ -847,7 +838,7 @@ export class OceanPool extends Pool {
return null return null
} }
const usershares = await this.sharesBalance(account, poolAddress) const usershares = await this.sharesBalance(account, poolAddress)
if (parseFloat(usershares) < parseFloat(poolShares)) { if (new Decimal(usershares).lessThan(poolShares)) {
this.logger.error('ERROR: Not enough poolShares') this.logger.error('ERROR: Not enough poolShares')
return null return null
} }
@ -880,12 +871,12 @@ export class OceanPool extends Pool {
return null return null
} }
const maxAmount = await this.getOceanMaxRemoveLiquidity(poolAddress) const maxAmount = await this.getOceanMaxRemoveLiquidity(poolAddress)
if (parseFloat(amount) > parseFloat(maxAmount)) { if (new Decimal(amount).greaterThan(maxAmount)) {
this.logger.error('ERROR: Too much reserve to remove') this.logger.error('ERROR: Too much reserve to remove')
return null return null
} }
const usershares = await this.sharesBalance(account, poolAddress) const usershares = await this.sharesBalance(account, poolAddress)
if (parseFloat(usershares) < parseFloat(maximumPoolShares)) { if (new Decimal(usershares).lessThan(maximumPoolShares)) {
this.logger.error('ERROR: Not enough poolShares') this.logger.error('ERROR: Not enough poolShares')
return null return null
} }
@ -893,13 +884,13 @@ export class OceanPool extends Pool {
poolAddress, poolAddress,
amount amount
) )
if (parseFloat(maximumPoolShares) < parseFloat(sharesRequired)) { if (new Decimal(maximumPoolShares).lessThan(sharesRequired)) {
this.logger.error('ERROR: Not enough poolShares') this.logger.error('ERROR: Not enough poolShares')
return null return null
} }
// Balancer bug fix // Balancer bug fix
if (parseFloat(maximumPoolShares) < parseFloat(sharesRequired)) if (new Decimal(maximumPoolShares).lessThan(sharesRequired))
maximumPoolShares = String(parseFloat(maximumPoolShares) * 0.9999) maximumPoolShares = new Decimal(maximumPoolShares).mul(0.9999).toString()
// Balance bug fix // Balance bug fix
return super.exitswapExternAmountOut( return super.exitswapExternAmountOut(
account, account,
@ -927,13 +918,13 @@ export class OceanPool extends Pool {
minOcean = '0' minOcean = '0'
): Promise<TransactionReceipt> { ): Promise<TransactionReceipt> {
const usershares = await this.sharesBalance(account, poolAddress) const usershares = await this.sharesBalance(account, poolAddress)
if (parseFloat(usershares) < parseFloat(poolShares)) { if (new Decimal(usershares).lessThan(poolShares)) {
this.logger.error('ERROR: Not enough poolShares') this.logger.error('ERROR: Not enough poolShares')
return null return null
} }
// Balancer bug fix // Balancer bug fix
if (parseFloat(usershares) === parseFloat(poolShares)) if (new Decimal(usershares).equals(poolShares))
poolShares = String(parseFloat(poolShares) * 0.9999) poolShares = new Decimal(poolShares).mul(0.9999).toString()
// Balance bug fix // Balance bug fix
return this.exitPool(account, poolAddress, poolShares, [minDT, minOcean]) return this.exitPool(account, poolAddress, poolShares, [minDT, minOcean])
} }
@ -975,7 +966,7 @@ export class OceanPool extends Pool {
public async getOceanNeeded(poolAddress: string, dtRequired: string): Promise<string> { public async getOceanNeeded(poolAddress: string, dtRequired: string): Promise<string> {
const dtAddress = await this.getDTAddress(poolAddress) const dtAddress = await this.getDTAddress(poolAddress)
if ( if (
parseFloat(dtRequired) > parseFloat(await this.getDTMaxBuyQuantity(poolAddress)) new Decimal(dtRequired).greaterThan(await this.getDTMaxBuyQuantity(poolAddress))
) { ) {
return '0' return '0'
} }
@ -1007,8 +998,9 @@ export class OceanPool extends Pool {
public async getDTNeeded(poolAddress: string, OceanRequired: string): Promise<string> { public async getDTNeeded(poolAddress: string, OceanRequired: string): Promise<string> {
const dtAddress = await this.getDTAddress(poolAddress) const dtAddress = await this.getDTAddress(poolAddress)
if ( if (
parseFloat(OceanRequired) > new Decimal(OceanRequired).greaterThan(
parseFloat(await this.getOceanMaxBuyQuantity(poolAddress)) await this.getOceanMaxBuyQuantity(poolAddress)
)
) { ) {
return '0' return '0'
} }
@ -1295,8 +1287,7 @@ export class OceanPool extends Pool {
tokenOutWeight, tokenOutWeight,
swapfee swapfee
) )
const slippage = (parseFloat(newPrice) * 100) / parseFloat(initialPrice) - 100 return new Decimal(newPrice).mul(100).div(initialPrice).minus(100).toString()
return String(slippage)
} }
/* Get slippage for buying some datatokens while spending exactly oceanAmount ocean tokens */ /* Get slippage for buying some datatokens while spending exactly oceanAmount ocean tokens */

View File

@ -134,12 +134,14 @@ export class Pool extends PoolFactory {
* @param {String} tokenAddress * @param {String} tokenAddress
* @param {String} spender * @param {String} spender
* @param {String} amount (always expressed as wei) * @param {String} amount (always expressed as wei)
* @param {String} force if true, will overwrite any previous allowence. Else, will check if allowence is enough and will not send a transaction if it's not needed
*/ */
async approve( async approve(
account: string, account: string,
tokenAddress: string, tokenAddress: string,
spender: string, spender: string,
amount: string amount: string,
force = false
): Promise<TransactionReceipt> { ): Promise<TransactionReceipt> {
const minABI = [ const minABI = [
{ {
@ -169,6 +171,13 @@ export class Pool extends PoolFactory {
const token = new this.web3.eth.Contract(minABI, tokenAddress, { const token = new this.web3.eth.Contract(minABI, tokenAddress, {
from: account from: account
}) })
if (!force) {
const currentAllowence = await this.allowance(tokenAddress, account, spender)
if (new Decimal(currentAllowence).greaterThanOrEqualTo(amount)) {
// we have enough
return null
}
}
let result = null let result = null
const gasLimitDefault = this.GASLIMIT_DEFAULT const gasLimitDefault = this.GASLIMIT_DEFAULT
let estGas let estGas
@ -890,7 +899,7 @@ export class Pool extends PoolFactory {
) )
.send({ .send({
from: account, from: account,
gas: this.GASLIMIT_DEFAULT, gas: estGas + 1,
gasPrice: await getFairGasPrice(this.web3) gasPrice: await getFairGasPrice(this.web3)
}) })
} catch (e) { } catch (e) {

View File

@ -45,10 +45,19 @@ export class PoolFactory {
from: account from: account
}) })
let txid = null let txid = null
const gasLimitDefault = this.GASLIMIT_DEFAULT
let estGas
try { try {
txid = await factory.methods estGas = await factory.methods
.newBPool() .newBPool()
.send({ from: account, gas: this.GASLIMIT_DEFAULT }) .estimateGas({ from: account }, (err, estGas) => (err ? gasLimitDefault : estGas))
} catch (e) {
this.logger.log('Error estimate gas newBPool')
this.logger.log(e)
estGas = gasLimitDefault
}
try {
txid = await factory.methods.newBPool().send({ from: account, gas: estGas + 1 })
// pooladdress = transactiondata.events.BPoolRegistered.returnValues[0] // pooladdress = transactiondata.events.BPoolRegistered.returnValues[0]
} catch (e) { } catch (e) {
this.logger.error(`ERROR: Failed to create new pool: ${e.message}`) this.logger.error(`ERROR: Failed to create new pool: ${e.message}`)

View File

@ -3,5 +3,5 @@ import Web3 from 'web3'
export async function getFairGasPrice(web3: Web3): Promise<string> { export async function getFairGasPrice(web3: Web3): Promise<string> {
const x = new BigNumber(await web3.eth.getGasPrice()) const x = new BigNumber(await web3.eth.getGasPrice())
return x.multipliedBy(1.25).integerValue(BigNumber.ROUND_DOWN).toString(10) return x.multipliedBy(1.05).integerValue(BigNumber.ROUND_DOWN).toString(10)
} }