1
0
mirror of https://github.com/oceanprotocol/ocean.js.git synced 2024-11-26 20:39:05 +01:00
ocean.js/src/utils/TokenUtils.ts
Miquel A. Cabot f8a42d9559
Issue-#1409: Excessive contract calls (#1424)
* add decimals parameter to unitsToAmount() and amountToUnits()

* unify use of amountToUnits() and unitsToAmount()

* use tokenDecimals in TokenUtils

* add tokenDecimals to functions in SideStaking

* add parameters to doc comments

* calculate amountToUnits and unitsToAmount using  decimals in FixedRateExchange

* remove unused amountToUnits() function from SideStaking

* use decimals in unitsToAmount() function in Pool

* add tokenInDecimals and tokenOutDecimals to TokenInOutMarket interface

* use decimals in amountToUnits() function in Pool

* fix errors related to pool decimals

Co-authored-by: mihaisc <mihai.scarlat@smartcontrol.ro>
2022-05-03 19:06:39 +03:00

133 lines
3.8 KiB
TypeScript

import Decimal from 'decimal.js'
import { Contract } from 'web3-eth-contract'
import { amountToUnits, getFairGasPrice, unitsToAmount } from './ContractUtils'
import { minAbi } from './minAbi'
import LoggerInstance from './Logger'
import { TransactionReceipt } from 'web3-core'
import Web3 from 'web3'
import { GASLIMIT_DEFAULT } from './Constants'
/**
* Estimate gas cost for approval function
* @param {String} account
* @param {String} tokenAddress
* @param {String} spender
* @param {String} amount
* @param {String} force
* @param {Contract} contractInstance optional contract instance
* @return {Promise<number>}
*/
export async function estApprove(
web3: Web3,
account: string,
tokenAddress: string,
spender: string,
amount: string,
contractInstance?: Contract
): Promise<number> {
const tokenContract = contractInstance || new web3.eth.Contract(minAbi, tokenAddress)
const gasLimitDefault = GASLIMIT_DEFAULT
let estGas
try {
estGas = await tokenContract.methods
.approve(spender, amount)
.estimateGas({ from: account }, (err, estGas) => (err ? gasLimitDefault : estGas))
} catch (e) {
estGas = gasLimitDefault
LoggerInstance.error('estimate gas failed for approve!', e)
}
return estGas
}
/**
* Approve spender to spent amount tokens
* @param {String} account
* @param {String} tokenAddress
* @param {String} spender
* @param {String} amount (always expressed as wei)
* @param {boolean} 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
* @param {number} tokenDecimals optional number of decimals of the token
*/
export async function approve(
web3: Web3,
account: string,
tokenAddress: string,
spender: string,
amount: string,
force = false,
tokenDecimals?: number
): Promise<TransactionReceipt | string> {
const tokenContract = new web3.eth.Contract(minAbi, tokenAddress)
if (!force) {
const currentAllowence = await allowance(web3, tokenAddress, account, spender)
if (new Decimal(currentAllowence).greaterThanOrEqualTo(new Decimal(amount))) {
return currentAllowence
}
}
let result = null
const amountFormatted = await amountToUnits(web3, tokenAddress, amount, tokenDecimals)
const estGas = await estApprove(
web3,
account,
tokenAddress,
spender,
amountFormatted,
tokenContract
)
try {
result = await tokenContract.methods.approve(spender, amountFormatted).send({
from: account,
gas: estGas + 1,
gasPrice: await getFairGasPrice(web3, null)
})
} catch (e) {
LoggerInstance.error(
`ERRPR: Failed to approve spender to spend tokens : ${e.message}`
)
}
return result
}
/**
* Get Allowance for any erc20
* @param {Web3} web3
* @param {String } tokenAdress
* @param {String} account
* @param {String} spender
* @param {number} tokenDecimals optional number of decimals of the token
*/
export async function allowance(
web3: Web3,
tokenAddress: string,
account: string,
spender: string,
tokenDecimals?: number
): Promise<string> {
const tokenContract = new web3.eth.Contract(minAbi, tokenAddress)
const trxReceipt = await tokenContract.methods.allowance(account, spender).call()
return await unitsToAmount(web3, tokenAddress, trxReceipt, tokenDecimals)
}
/**
* Get balance for any erc20
* @param {Web3} web3
* @param {String} tokenAdress
* @param {String} owner
* @param {String} spender
* @param {number} tokenDecimals optional number of decimals of the token
*/
export async function balance(
web3: Web3,
tokenAddress: string,
account: string,
tokenDecimals?: number
): Promise<string> {
const tokenContract = new web3.eth.Contract(minAbi, tokenAddress)
const trxReceipt = await tokenContract.methods.balanceOf(account).call()
return await unitsToAmount(web3, tokenAddress, trxReceipt, tokenDecimals)
}