UNPKG

myria-core-sdk

Version:

Latest version SDK

353 lines 29.8 kB
import BigNumber from 'bignumber.js'; import _ from 'lodash'; // Contracts import { ConfirmationType } from '../types/CommonTypes'; import { normalizeResponse, OUTCOMES } from './helpers'; // /** // * Myria Contract // */ export default class MContract { constructor(provider, networkId, web3, contractInfo, sendOptions = {}) { this.web3 = web3; this.defaultOptions = { gas: null, gasPrice: undefined, value: 0, from: null, confirmations: 0, confirmationType: ConfirmationType.Confirmed, gasMultiplier: 1.5, ...sendOptions, }; this.networkId = networkId; this.accountAddress = this.web3.eth.defaultAccount; this.contractInfo = contractInfo; this.setContractProvider(contractInfo.contract, contractInfo.json, provider, networkId); this.currentTxHash = ''; } setDefaultAccount(account) { this.accountAddress = account; } setProvider(provider, networkId) { this.networkId = networkId; } setContractProvider(contract, contractJson, provider, networkId) { // Deployed smart contract address const deployedInfo = contractJson.networks[networkId]; contract.options.address = deployedInfo && deployedInfo.address; } async call(method, specificOptions = {}) { const { blockNumber, ...otherOptions } = this.toCallOptions({ ...this.defaultOptions, ...specificOptions, }); return await method.call(otherOptions, blockNumber || 'latest'); } createTimeoutPromise(timeout, promi) { /* eslint-disable */ return new Promise((resolve, _) => { setTimeout(() => { promi.on('transactionHash', (txHash) => { console.log('Tx hash => ', txHash); this.currentTxHash = txHash; resolve(normalizeResponse({ transactionHash: txHash, isNetworkTimeout: true, message: 'Your transaction is taking longer than usual to verify due to Ethereum network congestion.' })); promi.off(); }); }, timeout); }); /* eslint-disable */ } async send(contract, method, specificOptions = {}) { const sendOptions = { ...this.defaultOptions, ...specificOptions, }; const result = await this._send(contract, method, sendOptions); return result; } async _send(contract, method, sendOptions = {}) { const { confirmations, confirmationType, gasMultiplier, enabledTimeout, timeout, ...txOptions } = sendOptions; if (confirmationType && !Object.values(ConfirmationType).includes(confirmationType)) { throw new Error(`Invalid confirmation type: ${confirmationType}`); } if (confirmationType === ConfirmationType.Simulate && !txOptions.gas) { const gasEstimate = await this.estimateGas(method, txOptions); txOptions.gas = Math.floor(gasEstimate * gasMultiplier); if (confirmationType === ConfirmationType.Simulate) { return { gasEstimate, gas: txOptions.gas, }; } } let hashOutcome = OUTCOMES.INITIAL; let confirmationOutcome = OUTCOMES.INITIAL; if (confirmationType === ConfirmationType.Sender) { const data = method.encodeABI(); const from = txOptions.from || this.web3.defaultAccount; if (from === null) { throw new Error('Cannot sendTransaction with from=null'); } if (_.isNil(txOptions.nonce)) { throw new Error('Cannot sendTransaction with nonce=null'); } const nonceIsHexString = (typeof txOptions.nonce === 'string') && txOptions.nonce.includes('0x'); const nonceBn = new BigNumber(txOptions.nonce, nonceIsHexString ? 16 : 10); console.log('Pre-submit on-chain', JSON.stringify({ gas: txOptions.gas, value: txOptions.value, gasPrice: txOptions.gasPrice, to: contract.options.address, from, nonce: nonceBn.toNumber(), data, })); if (!txOptions.gas) { throw new Error("Gas is required"); } const stPromi = this.web3.eth.sendTransaction({ gas: Number(txOptions.gas) || 500000, value: txOptions.value, gasPrice: txOptions.gasPrice, to: contract.options.address, from, nonce: nonceBn.toNumber(), data, }); /* eslint-disable @typescript-eslint/no-floating-promises */ const stPromise = new Promise((resolve, reject) => { stPromi.on('error', (error) => { if (hashOutcome === OUTCOMES.INITIAL) { hashOutcome = OUTCOMES.REJECTED; reject(error); stPromi.off(); } }); stPromi.on('transactionHash', (txHash) => { if (hashOutcome === OUTCOMES.INITIAL) { hashOutcome = OUTCOMES.RESOLVED; resolve(txHash); stPromi.off(); } }); }); const stResult = await stPromise; /* eslint-disable @typescript-eslint/no-floating-promises */ return normalizeResponse({ transactionHash: stResult }); } // const promi: PromiEvent<Contract> | any = method.send( // this.toNativeSendOptions(txOptions) as any, // ); const from = txOptions.from || this.web3.defaultAccount; if (from === null) { throw new Error('Cannot sendTransaction with from=null'); } if (_.isNil(txOptions.nonce)) { throw new Error('Cannot sendTransaction with nonce=null'); } const data = method.encodeABI(); const nonceIsHexString = (typeof txOptions.nonce === 'string') && txOptions.nonce.includes('0x'); const nonceBn = new BigNumber(txOptions.nonce, nonceIsHexString ? 16 : 10); console.log('Pre-submit on-chain', JSON.stringify({ gas: txOptions.gas, value: txOptions.value, gasPrice: txOptions.gasPrice, to: contract.options.address, from, nonce: nonceBn.toNumber(), data, })); const promi = this.web3.eth.sendTransaction({ gas: Number(txOptions.gas), value: txOptions.value, gasPrice: txOptions.gasPrice, to: contract.options.address, from, nonce: nonceBn.toNumber(), data, }); let transactionHash; let hashPromise; let confirmationPromise; if (confirmationType && [ ConfirmationType.Hash, ConfirmationType.Both, ].includes(confirmationType)) { hashPromise = new Promise((resolve, reject) => { promi.on('error', (error) => { if (hashOutcome === OUTCOMES.INITIAL) { hashOutcome = OUTCOMES.REJECTED; reject(error); promi.off(); } }); promi.on('transactionHash', (txHash) => { if (hashOutcome === OUTCOMES.INITIAL) { hashOutcome = OUTCOMES.RESOLVED; resolve(txHash); if (confirmationType !== ConfirmationType.Both) { promi.off(); } } }); }); transactionHash = await hashPromise; } // Type of confirmed transaction to make sure // the transaction is confirmed if (confirmationType && [ ConfirmationType.Confirmed, ConfirmationType.Both, ].includes(confirmationType)) { if (enabledTimeout) { confirmationPromise = Promise.race([ new Promise((resolve, reject) => { promi.on('transactionHash', (txHash) => { console.log('Tx hash => ', txHash); this.currentTxHash = txHash; }); promi.on('error', (error) => { if (confirmationOutcome === OUTCOMES.INITIAL && (confirmationType === ConfirmationType.Confirmed || hashOutcome === OUTCOMES.RESOLVED)) { confirmationOutcome = OUTCOMES.REJECTED; const errMessage = error.toString(); const minedOnchainTxErr = '50 blocks'; const minedTimeout = 'mined within 750 seconds'; console.log('Error msg =>', JSON.stringify(error)); console.log('Current tx hash =>', JSON.stringify(error)); if (errMessage && !errMessage.includes(minedOnchainTxErr) && !errMessage.includes(minedTimeout) && !this.currentTxHash) { confirmationOutcome = OUTCOMES.REJECTED; reject(error); promi.off(); } else if (errMessage && (errMessage.includes(minedOnchainTxErr) || errMessage.includes(minedTimeout)) && this.currentTxHash.length > 0) { confirmationOutcome = OUTCOMES.RESOLVED; resolve(normalizeResponse({ transactionHash: this.currentTxHash, isNetworkTimeout: true, message: 'Your transaction is taking longer than usual to verify due to Ethereum network congestion.' })); promi.off(); } else { confirmationOutcome = OUTCOMES.REJECTED; reject(error); promi.off(); } } }); if (confirmations) { promi.on('confirmation', (confNumber, receipt) => { if (confNumber >= confirmations) { if (confirmationOutcome === OUTCOMES.INITIAL) { confirmationOutcome = OUTCOMES.RESOLVED; resolve(receipt); promi.off(); } } }); } else { promi.on('receipt', (receipt) => { confirmationOutcome = OUTCOMES.RESOLVED; resolve(receipt); promi.off(); }); } }), this.createTimeoutPromise(timeout || 300000, promi), ]); } else { confirmationPromise = new Promise((resolve, reject) => { promi.on('error', (error) => { if (confirmationOutcome === OUTCOMES.INITIAL && (confirmationType === ConfirmationType.Confirmed || hashOutcome === OUTCOMES.RESOLVED)) { console.log('Error => ', error); confirmationOutcome = OUTCOMES.REJECTED; reject(error); promi.off(); } }); if (confirmations) { promi.on('confirmation', (confNumber, receipt) => { if (confNumber >= confirmations) { if (confirmationOutcome === OUTCOMES.INITIAL) { confirmationOutcome = OUTCOMES.RESOLVED; resolve(receipt); promi.off(); } } }); } else { promi.on('receipt', (receipt) => { confirmationOutcome = OUTCOMES.RESOLVED; resolve(receipt); promi.off(); }); } }); } } if (confirmationType === ConfirmationType.Hash) { return normalizeResponse({ transactionHash }); } if (confirmationType === ConfirmationType.Confirmed) { return confirmationPromise; } return normalizeResponse({ transactionHash, confirmation: confirmationPromise, }); } async estimateGas(method, txOptions) { const estimateOptions = this.toEstimateOptions(txOptions); try { const gasEstimate = await method.estimateGas(estimateOptions); return gasEstimate; } catch (error) { error.transactionData = { ...estimateOptions, data: method.encodeABI(), to: method._parent._address, }; throw error; } } // ============ Parse Options ============ toEstimateOptions(options) { return _.pick(options, [ 'from', 'value', ]); } toCallOptions(options) { return _.pick(options, [ 'from', 'value', 'blockNumber', ]); } toNativeSendOptions(options) { return _.pick(options, [ 'from', 'value', 'gasPrice', 'gas', 'nonce', ]); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29udHJhY3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvY29yZS9Db250cmFjdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLFNBQVMsTUFBTSxjQUFjLENBQUM7QUFDckMsT0FBTyxDQUFDLE1BQU0sUUFBUSxDQUFDO0FBY3ZCLFlBQVk7QUFDWixPQUFPLEVBRUwsZ0JBQWdCLEVBS2pCLE1BQU0sc0JBQXNCLENBQUM7QUFDOUIsT0FBTyxFQUFFLGlCQUFpQixFQUFFLFFBQVEsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQWN4RCxNQUFNO0FBQ04sb0JBQW9CO0FBQ3BCLE1BQU07QUFDTixNQUFNLENBQUMsT0FBTyxPQUFPLFNBQVM7SUFXNUIsWUFDRSxRQUFrQixFQUNsQixTQUFpQixFQUNqQixJQUFVLEVBQ1YsWUFBMEIsRUFDMUIsY0FBMkIsRUFBRTtRQUU3QixJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQztRQUNqQixJQUFJLENBQUMsY0FBYyxHQUFHO1lBQ3BCLEdBQUcsRUFBRSxJQUFJO1lBQ1QsUUFBUSxFQUFFLFNBQVM7WUFDbkIsS0FBSyxFQUFFLENBQUM7WUFDUixJQUFJLEVBQUUsSUFBSTtZQUNWLGFBQWEsRUFBRSxDQUFDO1lBQ2hCLGdCQUFnQixFQUFFLGdCQUFnQixDQUFDLFNBQVM7WUFDNUMsYUFBYSxFQUFFLEdBQUc7WUFDbEIsR0FBRyxXQUFXO1NBQ2YsQ0FBQztRQUVGLElBQUksQ0FBQyxTQUFTLEdBQUcsU0FBUyxDQUFDO1FBQzNCLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsY0FBd0IsQ0FBQztRQUM3RCxJQUFJLENBQUMsWUFBWSxHQUFHLFlBQVksQ0FBQztRQUNqQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsWUFBWSxDQUFDLFFBQVEsRUFBRSxZQUFZLENBQUMsSUFBSSxFQUFFLFFBQVEsRUFBRSxTQUFTLENBQUMsQ0FBQztR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