Skip to content

Commit

Permalink
Hub: fix subscribeTransaction, fix imediate discount wathcer
Browse files Browse the repository at this point in the history
  • Loading branch information
shrpne committed Dec 6, 2021
1 parent d384837 commit 34549ca
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 58 deletions.
109 changes: 71 additions & 38 deletions api/web3.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,53 +41,38 @@ 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<Web3Tx>}
* @return {PromiseWithEmitter<Web3Tx>}
*/
export function subscribeTransaction(hash, {
confirmationCount = CONFIRMATION_COUNT,
chainId,
} = {}) {
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);
Expand Down Expand Up @@ -117,9 +102,57 @@ export function subscribeTransaction(hash, {
// return target;
// }
}
}

/**
*
* @param {string} hash
* @param {number} confirmationCount
* @param {Eth} ethProvider
* @param {Emitter} emitter
* @return {Promise<Web3Tx>}
* @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) {
Expand Down Expand Up @@ -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;
});
Expand Down
6 changes: 5 additions & 1 deletion components/HubDepositForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -287,6 +290,7 @@ export default {
getDiscountForHolder(newVal)
.then((discount) => this.discountMinter = discount);
},
immediate: true,
},
coinContractAddress: {
handler() {
Expand Down Expand Up @@ -695,7 +699,7 @@ export default {
<div class="form-field__input is-not-empty">{{ pretty(hubFee) }} {{ form.coin }}</div>
<span class="form-field__label">
{{ $td('Bridge fee', 'form.hub-withdraw-hub-fee') }}
({{ hubFeeRate * 100 }}%)
({{ hubFeeRatePercent }}%)
</span>
</div>
</div>
Expand Down
32 changes: 15 additions & 17 deletions components/HubDepositTxListItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
8 changes: 6 additions & 2 deletions components/HubWithdrawForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -193,6 +196,7 @@ export default {
getDiscountForHolder(newVal)
.then((discount) => this.discountEth = discount);
},
immediate: true,
},
},
mounted() {
Expand Down Expand Up @@ -414,7 +418,7 @@ export default {
<div class="form-field__input is-not-empty">{{ pretty(hubFee) }} {{ form.coin }}</div>
<span class="form-field__label">
{{ $td('Bridge fee', 'form.hub-withdraw-hub-fee') }}
({{ hubFeeRate * 100 }}%)
({{ hubFeeRatePercent }}%)
</span>
</div>
</div>
Expand Down Expand Up @@ -478,7 +482,7 @@ export default {
<div class="form-field__input is-not-empty">{{ pretty(hubFee) }} {{ form.coin }}</div>
<span class="form-field__label">
{{ $td('Bridge fee', 'form.hub-withdraw-hub-fee') }}
({{ prettyRound(hubFeeRate * 100) }}%)
({{ hubFeeRatePercent }}%)
</span>
</div>
</div>
Expand Down

0 comments on commit 34549ca

Please sign in to comment.