diff --git a/src/contracts/tokens/Datatoken.ts b/src/contracts/tokens/Datatoken.ts index 7a9a4fbb..e2f58eb0 100644 --- a/src/contracts/tokens/Datatoken.ts +++ b/src/contracts/tokens/Datatoken.ts @@ -4,7 +4,7 @@ import { TransactionReceipt } from 'web3-eth' import Decimal from 'decimal.js' import ERC20Template from '@oceanprotocol/contracts/artifacts/contracts/templates/ERC20Template.sol/ERC20Template.json' import ERC20TemplateEnterprise from '@oceanprotocol/contracts/artifacts/contracts/templates/ERC20TemplateEnterprise.sol/ERC20TemplateEnterprise.json' -import { calculateEstimatedGas, ZERO_ADDRESS } from '../../utils' +import { amountToUnits, calculateEstimatedGas, ZERO_ADDRESS } from '../../utils' import { ConsumeMarketFee, FreOrderParams, @@ -606,7 +606,7 @@ export class Datatoken extends SmartContract { ): Promise { const dtContract = this.getContract(dtAddress, null, this.abiEnterprise) - const freContractParams = this.getFreOrderParams(freParams) + const freContractParams = await this.getFreOrderParams(freParams) const estGas = await calculateEstimatedGas( address, @@ -680,11 +680,17 @@ export class Datatoken extends SmartContract { const dtContract = this.getContract(dtAddress) - const estGas = await calculateEstimatedGas(address, dtContract.methods.setData, value) + const valueHex = this.web3.utils.asciiToHex(value) + + const estGas = await calculateEstimatedGas( + address, + dtContract.methods.setData, + valueHex + ) if (estimateGas) return estGas // Call setData function of the contract - const trxReceipt = await dtContract.methods.setData(value).send({ + const trxReceipt = await dtContract.methods.setData(valueHex).send({ from: address, gas: estGas + 1, gasPrice: await this.getFairGasPrice() @@ -863,12 +869,23 @@ export class Datatoken extends SmartContract { return returnValues } - private getFreOrderParams(freParams: FreOrderParams): any { + private async getFreOrderParams(freParams: FreOrderParams): Promise { return { exchangeContract: freParams.exchangeContract, exchangeId: freParams.exchangeId, - maxBaseTokenAmount: Web3.utils.toWei(freParams.maxBaseTokenAmount), - swapMarketFee: Web3.utils.toWei(freParams.swapMarketFee), + maxBaseTokenAmount: await amountToUnits( + this.web3, + freParams.baseTokenAddress, + freParams.maxBaseTokenAmount, + freParams.baseTokenDecimals + ), + swapMarketFee: await amountToUnits( + this.web3, + freParams.baseTokenAddress, + freParams.swapMarketFee, + freParams.baseTokenDecimals + ), + marketFeeAddress: freParams.marketFeeAddress } } diff --git a/src/contracts/tokens/NFT.ts b/src/contracts/tokens/NFT.ts index d628078e..7f1d4495 100644 --- a/src/contracts/tokens/NFT.ts +++ b/src/contracts/tokens/NFT.ts @@ -1,7 +1,7 @@ import { AbiItem } from 'web3-utils' import { TransactionReceipt } from 'web3-eth' import ERC721Template from '@oceanprotocol/contracts/artifacts/contracts/templates/ERC721Template.sol/ERC721Template.json' -import { generateDtName, calculateEstimatedGas } from '../../utils' +import { generateDtName, calculateEstimatedGas, setContractDefaults } from '../../utils' import { MetadataProof, MetadataAndTokenURI, NftRoles } from '../../@types' import { SmartContract } from '..' @@ -720,6 +720,47 @@ export class Nft extends SmartContract { return isDatatokenDeployer } + /** setData + * This function allows to store data with a preset key (keccak256(ERC20Address)) into NFT 725 Store + * only ERC20Deployer can succeed + * @param nftAddress erc721 contract adress + * @param address user adress + * @param key Key of the data to be stored into 725Y standard + * @param value Data to be stored into 725Y standard + * @return {Promise} transactionId + */ + public async setData( + nftAddress: string, + address: string, + key: string, + value: string + ): Promise { + if ((await this.getNftPermissions(nftAddress, address)).store !== true) { + throw new Error(`User is not ERC20 store updater`) + } + + const nftContract = this.getContract(nftAddress) + + const keyHash = this.web3.utils.keccak256(key) + const valueHex = this.web3.utils.asciiToHex(value) + + const estGas = await calculateEstimatedGas( + address, + nftContract.methods.setNewData, + keyHash, + valueHex + ) + + // Call setData function of the contract + const trxReceipt = await nftContract.methods.setNewData(keyHash, valueHex).send({ + from: address, + gas: estGas + 1, + gasPrice: await this.getFairGasPrice() + }) + + return trxReceipt + } + /** Gets data at a given `key` * @param {String} nftAddress NFT contract address * @param {String} key the key which value to retrieve @@ -727,8 +768,9 @@ export class Nft extends SmartContract { */ public async getData(nftAddress: string, key: string): Promise { const nftContract = this.getContract(nftAddress) - const data = await nftContract.methods.getData(key).call() - return data + const keyHash = this.web3.utils.keccak256(key) + const data = await nftContract.methods.getData(keyHash).call() + return data ? this.web3.utils.hexToAscii(data) : null } /** Gets data at a given `key` diff --git a/src/utils/ContractUtils.ts b/src/utils/ContractUtils.ts index e698950d..abcb7d2f 100644 --- a/src/utils/ContractUtils.ts +++ b/src/utils/ContractUtils.ts @@ -58,14 +58,11 @@ export async function amountToUnits( decimals = 18 } BigNumber.config({ EXPONENTIAL_AT: 50 }) - try { - const amountFormatted = new BigNumber(amount).times( - new BigNumber(10).exponentiatedBy(decimals) - ) - return amountFormatted.toFixed(0) - } catch (e) { - LoggerInstance.error(`ERROR: FAILED TO CALL DECIMALS(), USING 18', ${e.message}`) - } + + const amountFormatted = new BigNumber(amount).times( + new BigNumber(10).exponentiatedBy(decimals) + ) + return amountFormatted.toFixed(0) } /** diff --git a/src/utils/TokenUtils.ts b/src/utils/TokenUtils.ts index 82cff69b..b27ff66b 100644 --- a/src/utils/TokenUtils.ts +++ b/src/utils/TokenUtils.ts @@ -1,12 +1,14 @@ import Decimal from 'decimal.js' import { TransactionReceipt } from 'web3-core' import Web3 from 'web3' +import BigNumber from 'bignumber.js' import { amountToUnits, calculateEstimatedGas, getFairGasPrice, unitsToAmount, - minAbi + minAbi, + LoggerInstance } from '.' /** @@ -52,6 +54,54 @@ export async function approve( return trxReceipt } +/** + * Approve spender to spent amount tokens + * @param {String} account + * @param {String} tokenAddress + * @param {String} spender + * @param {String} amount amount of ERC20 tokens (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 + */ +export async function approveWei( + web3: Web3, + account: string, + tokenAddress: string, + spender: string, + amount: string, + force = false, + estimateGas?: G +): Promise { + const tokenContract = new web3.eth.Contract(minAbi, tokenAddress) + if (!force) { + const currentAllowence = await allowanceWei(web3, tokenAddress, account, spender) + if (new BigNumber(currentAllowence).gt(new BigNumber(amount))) { + return null + } + } + let result = null + + const estGas = await calculateEstimatedGas( + account, + tokenContract.methods.approve, + spender, + amount + ) + if (estimateGas) return estGas + + try { + result = await tokenContract.methods.approve(spender, amount).send({ + from: account, + gas: estGas + 1, + gasPrice: await getFairGasPrice(web3, null) + }) + } catch (e) { + LoggerInstance.error( + `ERROR: Failed to approve spender to spend tokens : ${e.message}` + ) + } + return result +} + /** * Moves amount tokens from the caller’s account to recipient. * @param {String} account @@ -130,6 +180,24 @@ export async function balance( return await unitsToAmount(web3, tokenAddress, trxReceipt, tokenDecimals) } +/** + * Get Allowance for any erc20 + * @param {Web3} web3 + * @param {String} tokenAdress + * @param {String} account + * @param {String} spender + */ +export async function allowanceWei( + web3: Web3, + tokenAddress: string, + account: string, + spender: string, + tokenDecimals?: number +): Promise { + const tokenContract = new web3.eth.Contract(minAbi, tokenAddress) + return await tokenContract.methods.allowance(account, spender).call() +} + /** * Get decimals for any Datatoken * @param {Web3} web3