From 0ed974c253fc802f60417bffc2a46d108902593a Mon Sep 17 00:00:00 2001 From: Bogdan Fazakas Date: Tue, 26 Oct 2021 15:16:45 +0300 Subject: [PATCH] split estGas for the methods in ERC20 Datatoken --- src/datatokens/Datatoken.ts | 522 +++++++++++++++++++++++++++--------- 1 file changed, 401 insertions(+), 121 deletions(-) diff --git a/src/datatokens/Datatoken.ts b/src/datatokens/Datatoken.ts index 0ffc6746..5c7587e5 100644 --- a/src/datatokens/Datatoken.ts +++ b/src/datatokens/Datatoken.ts @@ -4,6 +4,7 @@ import { TransactionReceipt } from 'web3-eth' import defaultDatatokensABI from '@oceanprotocol/contracts/artifacts/contracts/templates/ERC20Template.sol/ERC20Template.json' import Decimal from 'decimal.js' import { LoggerInstance, getFairGasPrice } from '../utils' +import { Contract } from 'web3-eth-contract' /** * ERC20 ROLES @@ -32,6 +33,38 @@ export class Datatoken { this.startBlock = startBlock || 0 } + /** + * Estimate gas cost for mint method + * @param {String} dtAddress Datatoken address + * @param {String} spender Spender address + * @param {string} amount Number of datatokens, as number. Will be converted to wei + * @param {String} address User adress + * @param {Contract} contractInstance optional contract instance + * @return {Promise} + */ + public async estGasApprove( + dtAddress: string, + spender: string, + amount: string, + address: string, + contractInstance?: Contract + ): Promise { + const dtContract = + contractInstance || new this.web3.eth.Contract(this.datatokensABI, dtAddress) + + // Estimate gas cost for mint method + const gasLimitDefault = this.GASLIMIT_DEFAULT + let estGas + try { + estGas = await dtContract.methods + .approve(spender, this.web3.utils.toWei(amount)) + .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) + } catch (e) { + estGas = gasLimitDefault + } + return estGas + } + /** * Approve * @param {String} dtAddress Datatoken address @@ -48,16 +81,13 @@ export class Datatoken { ): Promise { const dtContract = new this.web3.eth.Contract(this.datatokensABI, dtAddress) - // Estimate gas cost for mint method - const gasLimitDefault = this.GASLIMIT_DEFAULT - let estGas - try { - estGas = await dtContract.methods - .approve(spender, this.web3.utils.toWei(amount)) - .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) - } catch (e) { - estGas = gasLimitDefault - } + const estGas = await this.estGasApprove( + dtAddress, + spender, + amount, + address, + dtContract + ) // Call mint contract method const trxReceipt = await dtContract.methods @@ -70,6 +100,38 @@ export class Datatoken { return trxReceipt } + /** + * Estimate gas cost for mint method + * @param {String} dtAddress Datatoken address + * @param {String} address Minter address + * @param {String} amount Number of datatokens, as number. Will be converted to wei + * @param {String} toAddress only if toAddress is different from the minter + * @param {Contract} contractInstance optional contract instance + * @return {Promise} + */ + public async estGasMint( + dtAddress: string, + address: string, + amount: string, + toAddress?: string, + contractInstance?: Contract + ): Promise { + const dtContract = + contractInstance || new this.web3.eth.Contract(this.datatokensABI, dtAddress) + + const gasLimitDefault = this.GASLIMIT_DEFAULT + let estGas + try { + estGas = await dtContract.methods + .mint(toAddress || address, this.web3.utils.toWei(amount)) + .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) + } catch (e) { + estGas = gasLimitDefault + } + + return estGas + } + /** * Mint * @param {String} dtAddress Datatoken address @@ -92,18 +154,13 @@ export class Datatoken { const capAvailble = await this.getCap(dtAddress) if (new Decimal(capAvailble).gte(amount)) { - // Estimate gas cost for mint method - const gasLimitDefault = this.GASLIMIT_DEFAULT - let estGas - try { - estGas = await dtContract.methods - .mint(toAddress || address, this.web3.utils.toWei(amount)) - .estimateGas({ from: address }, (err, estGas) => - err ? gasLimitDefault : estGas - ) - } catch (e) { - estGas = gasLimitDefault - } + const estGas = await this.estGasMint( + dtAddress, + address, + amount, + toAddress, + dtContract + ) // Call mint contract method const trxReceipt = await dtContract.methods @@ -119,6 +176,36 @@ export class Datatoken { } } + /** + * Estimate gas cost for addMinter method + * @param {String} dtAddress Datatoken address + * @param {String} address User address + * @param {String} minter User which is going to be a Minter + * @param {Contract} contractInstance optional contract instance + * @return {Promise} + */ + public async estGasAddMinter( + dtAddress: string, + address: string, + minter: string, + contractInstance?: Contract + ): Promise { + const dtContract = + contractInstance || new this.web3.eth.Contract(this.datatokensABI, dtAddress) + + // Estimate gas cost for addMinter method + const gasLimitDefault = this.GASLIMIT_DEFAULT + let estGas + try { + estGas = await dtContract.methods + .addMinter(minter) + .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) + } catch (e) { + estGas = gasLimitDefault + } + return estGas + } + /** * Add Minter for an ERC20 datatoken * only ERC20Deployer can succeed @@ -137,15 +224,7 @@ export class Datatoken { // should check ERC20Deployer role using erc721 level .. // Estimate gas cost for addMinter method - const gasLimitDefault = this.GASLIMIT_DEFAULT - let estGas - try { - estGas = await dtContract.methods - .addMinter(minter) - .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) - } catch (e) { - estGas = gasLimitDefault - } + const estGas = await this.estGasAddMinter(dtAddress, address, minter, dtContract) // Call addMinter function of the contract const trxReceipt = await dtContract.methods.addMinter(minter).send({ @@ -158,19 +237,21 @@ export class Datatoken { } /** - * Revoke Minter permission for an ERC20 datatoken - * only ERC20Deployer can succeed + * Estimate gas for removeMinter method * @param {String} dtAddress Datatoken address * @param {String} address User address * @param {String} minter User which will be removed from Minter permission - * @return {Promise} transactionId + * @param {Contract} contractInstance optional contract instance + * @return {Promise} */ - public async removeMinter( + public async estGasRemoveMinter( dtAddress: string, address: string, - minter: string - ): Promise { - const dtContract = new this.web3.eth.Contract(this.datatokensABI, dtAddress) + minter: string, + contractInstance?: Contract + ): Promise { + const dtContract = + contractInstance || new this.web3.eth.Contract(this.datatokensABI, dtAddress) // should check ERC20Deployer role using erc721 level .. @@ -185,6 +266,29 @@ export class Datatoken { estGas = gasLimitDefault } + return estGas + } + + /** + * Revoke Minter permission for an ERC20 datatoken + * only ERC20Deployer can succeed + * @param {String} dtAddress Datatoken address + * @param {String} address User address + * @param {String} minter User which will be removed from Minter permission + * @param {Contract} contractInstance optional contract instance + * @return {Promise} + */ + public async removeMinter( + dtAddress: string, + address: string, + minter: string + ): Promise { + const dtContract = new this.web3.eth.Contract(this.datatokensABI, dtAddress) + + // should check ERC20Deployer role using erc721 level .. + + const estGas = await this.estGasRemoveMinter(dtAddress, address, minter, dtContract) + // Call dtContract function of the contract const trxReceipt = await dtContract.methods.removeMinter(minter).send({ from: address, @@ -195,6 +299,37 @@ export class Datatoken { return trxReceipt } + /** + * Estimate gas for addFeeManager method + * @param {String} dtAddress Datatoken address + * @param {String} address User address + * @param {String} feeManager User which is going to be a Minter + * @param {Contract} contractInstance optional contract instance + * @return {Promise} + */ + public async estGasAddFeeManager( + dtAddress: string, + address: string, + feeManager: string, + contractInstance?: Contract + ): Promise { + const dtContract = + contractInstance || new this.web3.eth.Contract(this.datatokensABI, dtAddress) + + // Estimate gas for addFeeManager method + const gasLimitDefault = this.GASLIMIT_DEFAULT + let estGas + try { + estGas = await dtContract.methods + .addFeeManager(feeManager) + .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) + } catch (e) { + estGas = gasLimitDefault + } + + return estGas + } + /** * Add FeeManager for an ERC20 datatoken * only ERC20Deployer can succeed @@ -212,16 +347,12 @@ export class Datatoken { // should check ERC20Deployer role using erc721 level .. - // Estimate gas for addFeeManager method - const gasLimitDefault = this.GASLIMIT_DEFAULT - let estGas - try { - estGas = await dtContract.methods - .addFeeManager(feeManager) - .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) - } catch (e) { - estGas = gasLimitDefault - } + const estGas = await this.estGasAddFeeManager( + dtAddress, + address, + feeManager, + dtContract + ) // Call addFeeManager function of the contract const trxReceipt = await dtContract.methods.addFeeManager(feeManager).send({ @@ -233,6 +364,35 @@ export class Datatoken { return trxReceipt } + /** + * Estimate gas for removeFeeManager method + * @param {String} dtAddress Datatoken address + * @param {String} address User address + * @param {String} feeManager User which will be removed from FeeManager permission + * @param {Contract} contractInstance optional contract instance + * @return {Promise} + */ + public async estGasRemoveFeeManager( + dtAddress: string, + address: string, + feeManager: string, + contractInstance?: Contract + ): Promise { + const dtContract = + contractInstance || new this.web3.eth.Contract(this.datatokensABI, dtAddress) + + const gasLimitDefault = this.GASLIMIT_DEFAULT + let estGas + try { + estGas = await dtContract.methods + .removeFeeManager(feeManager) + .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) + } catch (e) { + estGas = gasLimitDefault + } + return estGas + } + /** * Revoke FeeManager permission for an ERC20 datatoken * only ERC20Deployer can succeed @@ -249,17 +409,12 @@ export class Datatoken { const dtContract = new this.web3.eth.Contract(this.datatokensABI, dtAddress) // should check ERC20Deployer role using erc721 level .. - - // Estimate gas for removeFeeManager method - const gasLimitDefault = this.GASLIMIT_DEFAULT - let estGas - try { - estGas = await dtContract.methods - .removeFeeManager(feeManager) - .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) - } catch (e) { - estGas = gasLimitDefault - } + const estGas = await this.estGasRemoveFeeManager( + dtAddress, + address, + feeManager, + dtContract + ) // Call removeFeeManager function of the contract const trxReceipt = await dtContract.methods.removeFeeManager(feeManager).send({ @@ -271,6 +426,35 @@ export class Datatoken { return trxReceipt } + /** + * Estimate gas for setFeeCollector method + * @param dtAddress datatoken address where we want to clean permissions address + * @param address Caller address + * @param feeCollector User to be set as new fee collector + * @param {Contract} contractInstance optional contract instance + * @return {Promise} + */ + public async estGasSetFeeCollector( + dtAddress: string, + address: string, + feeCollector: string, + contractInstance?: Contract + ): Promise { + const dtContract = + contractInstance || new this.web3.eth.Contract(this.datatokensABI, dtAddress) + + const gasLimitDefault = this.GASLIMIT_DEFAULT + let estGas + try { + estGas = await dtContract.methods + .setFeeCollector(feeCollector) + .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) + } catch (e) { + estGas = gasLimitDefault + } + return estGas + } + /** * Set a new fee Collector, if feeCollector is address(0), feeCollector is NFT Owner * only NFT owner can call @@ -289,16 +473,12 @@ export class Datatoken { throw new Error(`Caller is not Fee Manager`) } - // Estimate gas for setFeeCollector method - const gasLimitDefault = this.GASLIMIT_DEFAULT - let estGas - try { - estGas = await dtContract.methods - .setFeeCollector(feeCollector) - .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) - } catch (e) { - estGas = gasLimitDefault - } + const estGas = await this.estGasSetFeeCollector( + dtAddress, + address, + feeCollector, + dtContract + ) // Call setFeeCollector method of the contract const trxReceipt = await dtContract.methods.setFeeCollector(feeCollector).send({ @@ -338,6 +518,37 @@ export class Datatoken { return this.transferWei(dtAddress, toAddress, weiAmount, address) } + /** + * Estimate gas for transfer method + * @param {String} dtAddress Datatoken address + * @param {String} toAddress Receiver address + * @param {String} amount Number of datatokens, as number. Expressed as wei + * @param {String} address User adress + * @param {Contract} contractInstance optional contract instance + * @return {Promise} + */ + public async estGasTransfer( + dtAddress: string, + toAddress: string, + amount: string, + address: string, + contractInstance?: Contract + ): Promise { + const dtContract = + contractInstance || new this.web3.eth.Contract(this.datatokensABI, dtAddress) + + const gasLimitDefault = this.GASLIMIT_DEFAULT + let estGas + try { + estGas = await dtContract.methods + .transfer(toAddress, amount) + .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) + } catch (e) { + estGas = gasLimitDefault + } + return estGas + } + /** * Transfer in wei from address to toAddress * @param {String} dtAddress Datatoken address @@ -354,19 +565,13 @@ export class Datatoken { ): Promise { const dtContract = new this.web3.eth.Contract(this.datatokensABI, dtAddress) try { - // Estimate gas for transfer method - const gasLimitDefault = this.GASLIMIT_DEFAULT - let estGas - try { - estGas = await dtContract.methods - .transfer(toAddress, amount) - .estimateGas({ from: address }, (err, estGas) => - err ? gasLimitDefault : estGas - ) - } catch (e) { - estGas = gasLimitDefault - } - + const estGas = await this.estGasTransfer( + dtAddress, + toAddress, + amount, + address, + dtContract + ) // Call transfer function of the contract const trxReceipt = await dtContract.methods.transfer(toAddress, amount).send({ from: address, @@ -380,6 +585,52 @@ export class Datatoken { } } + /** Estimate gas cost for startOrder method + * @param {String} dtAddress Datatoken address + * @param {String} address User address which calls + * @param {String} consumer Consumer Address + * @param {String} amount Amount of tokens that is going to be transfered + * @param {Number} serviceId Service index in the metadata + * @param {String} mpFeeAddress Consume marketplace fee address + * @param {String} feeToken address of the token marketplace wants to add fee on top + * @param {String} feeAmount amount of feeToken to be transferred to mpFeeAddress on top, will be converted to WEI + * @param {Contract} contractInstance optional contract instance + * @return {Promise} + */ + public async estGasStartOrder( + dtAddress: string, + address: string, + consumer: string, + amount: string, + serviceId: number, + mpFeeAddress: string, + feeToken: string, + feeAmount: string, + contractInstance?: Contract + ): Promise { + const dtContract = + contractInstance || new this.web3.eth.Contract(this.datatokensABI, dtAddress) + + // Estimate gas for startOrder method + const gasLimitDefault = this.GASLIMIT_DEFAULT + let estGas + try { + estGas = await dtContract.methods + .startOrder( + consumer, + this.web3.utils.toWei(amount), + serviceId, + mpFeeAddress, + feeToken, + this.web3.utils.toWei(feeAmount) + ) + .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) + } catch (e) { + estGas = gasLimitDefault + } + return estGas + } + /** Start Order: called by payer or consumer prior ordering a service consume on a marketplace. * @param {String} dtAddress Datatoken address * @param {String} address User address which calls @@ -404,25 +655,17 @@ export class Datatoken { const dtContract = new this.web3.eth.Contract(this.datatokensABI, dtAddress) if (!mpFeeAddress) mpFeeAddress = '0x0000000000000000000000000000000000000000' try { - // Estimate gas for startOrder method - const gasLimitDefault = this.GASLIMIT_DEFAULT - let estGas - try { - estGas = await dtContract.methods - .startOrder( - consumer, - this.web3.utils.toWei(amount), - serviceId, - mpFeeAddress, - feeToken, - this.web3.utils.toWei(feeAmount) - ) - .estimateGas({ from: address }, (err, estGas) => - err ? gasLimitDefault : estGas - ) - } catch (e) { - estGas = gasLimitDefault - } + const estGas = await this.estGasStartOrder( + dtAddress, + address, + consumer, + amount, + serviceId, + mpFeeAddress, + feeToken, + feeAmount, + dtContract + ) const trxReceipt = await dtContract.methods .startOrder( @@ -445,6 +688,34 @@ export class Datatoken { } } + /** Estimate gas for setData method + * @param {String} dtAddress Datatoken address + * @param {String} address User address + * @param {String} value Data to be stored into 725Y standard + * @param {Contract} contractInstance optional contract instance + * @return {Promise} + */ + public async estGasSetData( + dtAddress: string, + address: string, + value: string, + contractInstance?: Contract + ): Promise { + const dtContract = + contractInstance || new this.web3.eth.Contract(this.datatokensABI, dtAddress) + + const gasLimitDefault = this.GASLIMIT_DEFAULT + let estGas + try { + estGas = await dtContract.methods + .setData(value) + .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) + } catch (e) { + estGas = gasLimitDefault + } + return estGas + } + /** setData * This function allows to store data with a preset key (keccak256(ERC20Address)) into NFT 725 Store * only ERC20Deployer can succeed @@ -460,16 +731,7 @@ export class Datatoken { ): Promise { const dtContract = new this.web3.eth.Contract(this.datatokensABI, dtAddress) - // Estimate gas for setData method - const gasLimitDefault = this.GASLIMIT_DEFAULT - let estGas - try { - estGas = await dtContract.methods - .setData(value) - .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) - } catch (e) { - estGas = gasLimitDefault - } + const estGas = await this.estGasSetData(dtAddress, address, value, dtContract) // Call setData function of the contract const trxReceipt = await dtContract.methods.setData(value).send({ @@ -481,6 +743,33 @@ export class Datatoken { return trxReceipt } + /** Estimate gas for cleanPermissions method + * @param dtAddress Datatoken address where we want to clean permissions + * @param address User adress + * @param {Contract} contractInstance optional contract instance + * @return {Promise} + */ + public async estGasCleanPermissions( + dtAddress: string, + address: string, + contractInstance?: Contract + ): Promise { + const dtContract = + contractInstance || new this.web3.eth.Contract(this.datatokensABI, dtAddress) + + const gasLimitDefault = this.GASLIMIT_DEFAULT + let estGas + try { + estGas = await dtContract.methods + .cleanPermissions() + .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) + } catch (e) { + estGas = gasLimitDefault + } + + return estGas + } + /** * Clean erc20level Permissions (minters, feeManagers and reset the feeCollector) for an ERC20 datatoken * Only NFT Owner (at 721 level) can call it. @@ -494,16 +783,7 @@ export class Datatoken { ): Promise { const dtContract = new this.web3.eth.Contract(this.datatokensABI, dtAddress) - // Estimate gas for cleanPermissions method - const gasLimitDefault = this.GASLIMIT_DEFAULT - let estGas - try { - estGas = await dtContract.methods - .cleanPermissions() - .estimateGas({ from: address }, (err, estGas) => (err ? gasLimitDefault : estGas)) - } catch (e) { - estGas = gasLimitDefault - } + const estGas = await this.estGasCleanPermissions(dtAddress, address, dtContract) // Call cleanPermissions function of the contract const trxReceipt = await dtContract.methods.cleanPermissions().send({