diff --git a/api/web3.js b/api/web3.js index 3570cb8d..a483e0f2 100644 --- a/api/web3.js +++ b/api/web3.js @@ -41,11 +41,18 @@ export function toErcDecimals(balance, ercDecimals = 18) { * @typedef {import('web3-core/types/index.d.ts').Transaction & import('web3-core/types/index.d.ts').TransactionReceipt & {confirmations: number, timestamp: number}} Web3Tx */ +/** + * @typedef {Promise} PromiseWithEmitter + * @property {function} on + * @property {function} once + * @property {function} unsubscribe + */ + /** * @param {string} hash * @param {number} [confirmationCount = CONFIRMATION_COUNT] * @param {number} [chainId] - * @return {Promise} + * @return {PromiseWithEmitter} */ export function subscribeTransaction(hash, { confirmationCount = CONFIRMATION_COUNT, @@ -53,41 +60,19 @@ export function subscribeTransaction(hash, { } = {}) { let isUnsubscribed = false; const emitter = new Emitter(); - if (!getProviderHostByChain(chainId)) { - return Promise.reject(new Error(`Can't subscribe to tx, chainId ${chainId} is not supported`)); + let txPromise; + try { + const providerHost = getProviderHostByChain(chainId); + if (providerHost) { + // keep provider for this tx, because later it can be changed + const ethSaved = new Eth(getProviderHostByChain(chainId)); + txPromise = _subscribeTransaction(hash, confirmationCount, ethSaved, emitter); + } else { + txPromise = Promise.reject(new Error(`Can't subscribe to tx, chainId ${chainId} is not supported`)); + } + } catch (error) { + txPromise = Promise.reject(error); } - // keep provider for this tx, because later it can be changed - const ethSaved = new Eth(getProviderHostByChain(chainId)); - - const txPromise = waitTxInBlock(hash) - .then((tx) => { - return Promise.all([ethSaved.getTransactionReceipt(hash), ethSaved.getBlock(tx.blockNumber), getConfirmations(tx), Promise.resolve(tx)]); - }) - .then(([receipt, block, confirmations, txData]) => { - const tx = { - // input, hash from tx - ...txData, - // logs, status from receipt - ...receipt, - confirmations, - timestamp: block.timestamp * 1000, - }; - emitter.emit('confirmation', tx); - - if (!tx.status) { - throw new Error('Transaction failed'); - } - - if (confirmations >= confirmationCount) { - return tx; - } else { - return waitConfirmations(tx); - } - }) - .then((tx) => { - emitter.emit('confirmed', tx); - return tx; - }); // proxy `.on` and `.once` proxyEmitter(txPromise, emitter); @@ -117,9 +102,57 @@ export function subscribeTransaction(hash, { // return target; // } } +} + +/** + * + * @param {string} hash + * @param {number} confirmationCount + * @param {Eth} ethProvider + * @param {Emitter} emitter + * @return {Promise} + * @private + */ +function _subscribeTransaction(hash, confirmationCount, ethProvider, emitter) { + let isUnsubscribed = false; + + return waitTxInBlock(hash) + .then((tx) => { + return Promise.all([ + ethProvider.getTransactionReceipt(hash), + ethProvider.getBlock(tx.blockNumber), + getConfirmations(tx), + Promise.resolve(tx), + ]); + }) + .then(([receipt, block, confirmations, txData]) => { + const tx = { + // input, hash from tx + ...txData, + // logs, status from receipt + ...receipt, + confirmations, + timestamp: block.timestamp * 1000, + }; + emitter.emit('confirmation', tx); + + if (!tx.status) { + throw new Error('Transaction failed'); + } + + if (confirmations >= confirmationCount) { + return tx; + } else { + return waitConfirmations(tx); + } + }) + .then((tx) => { + emitter.emit('confirmed', tx); + return tx; + }); function waitTxInBlock(hash) { - return ethSaved.getTransaction(hash) + return ethProvider.getTransaction(hash) .then((tx) => { // reject if (isUnsubscribed) { @@ -158,11 +191,11 @@ export function subscribeTransaction(hash, { } else { return waitConfirmations(tx); } - }); + }); } function getConfirmations(tx) { - return getBlockNumber(ethSaved) + return getBlockNumber(ethProvider) .then((currentBlock) => { return currentBlock - tx.blockNumber + 1; }); diff --git a/components/HubDepositForm.vue b/components/HubDepositForm.vue index 027d7c60..cdb1a095 100644 --- a/components/HubDepositForm.vue +++ b/components/HubDepositForm.vue @@ -147,6 +147,9 @@ export default { const discountModifier = 1 - this.discount; return new Big(coinItem?.commission || 0.01).times(discountModifier).toString(); }, + hubFeeRatePercent() { + return new Big(this.hubFeeRate).times(100).toString(); + }, // fee to HUB bridge calculated in COIN hubFee() { // x / (1 - x) @@ -287,6 +290,7 @@ export default { getDiscountForHolder(newVal) .then((discount) => this.discountMinter = discount); }, + immediate: true, }, coinContractAddress: { handler() { @@ -695,7 +699,7 @@ export default {
{{ pretty(hubFee) }} {{ form.coin }}
{{ $td('Bridge fee', 'form.hub-withdraw-hub-fee') }} - ({{ hubFeeRate * 100 }}%) + ({{ hubFeeRatePercent }}%) diff --git a/components/HubDepositTxListItem.vue b/components/HubDepositTxListItem.vue index a1ec57d3..16656864 100644 --- a/components/HubDepositTxListItem.vue +++ b/components/HubDepositTxListItem.vue @@ -73,25 +73,23 @@ export default { } }); - //@TODO this.tokenInfoPromise may be null - //@TODO rework to Promise.all([txWatcher, txInfoPromise]) //@TODO store transfer in tx // subscribe on transfer for send txs - this.txWatcher.then((tx) => { - this.tokenInfoPromise - .then(() => { - if (this.tokenInfo.type === TX_PURPOSE.SEND) { - this.transferWatcher = subscribeTransfer(tx.hash) - .on('update', (transfer) => { - this.transfer = transfer; - }) - .catch((error) => { - if (error.message !== 'unsubscribed') { - console.log(error); - } - }); - } - }); + Promise.all([ + this.txWatcher, + this.tokenInfoPromise, + ]).then(([tx]) => { + if (this.tokenInfo?.type === TX_PURPOSE.SEND) { + this.transferWatcher = subscribeTransfer(tx.hash) + .on('update', (transfer) => { + this.transfer = transfer; + }) + .catch((error) => { + if (error.message !== 'unsubscribed') { + console.log(error); + } + }); + } }); }, data() { diff --git a/components/HubWithdrawForm.vue b/components/HubWithdrawForm.vue index 6ca7cd20..6c1f8d7c 100644 --- a/components/HubWithdrawForm.vue +++ b/components/HubWithdrawForm.vue @@ -100,6 +100,9 @@ export default { const discountModifier = 1 - this.discount; return new Big(this.externalToken?.commission || 0.01).times(discountModifier).toString(); }, + hubFeeRatePercent() { + return new Big(this.hubFeeRate).times(100).toString(); + }, coinPrice() { const priceItem = this.priceList.find((item) => item.name === this.externalToken?.denom); return priceItem ? priceItem.value / 10 ** 18 : '0'; @@ -193,6 +196,7 @@ export default { getDiscountForHolder(newVal) .then((discount) => this.discountEth = discount); }, + immediate: true, }, }, mounted() { @@ -414,7 +418,7 @@ export default {
{{ pretty(hubFee) }} {{ form.coin }}
{{ $td('Bridge fee', 'form.hub-withdraw-hub-fee') }} - ({{ hubFeeRate * 100 }}%) + ({{ hubFeeRatePercent }}%) @@ -478,7 +482,7 @@ export default {
{{ pretty(hubFee) }} {{ form.coin }}
{{ $td('Bridge fee', 'form.hub-withdraw-hub-fee') }} - ({{ prettyRound(hubFeeRate * 100) }}%) + ({{ hubFeeRatePercent }}%)