import BigNumber from 'bignumber.js' import { get } from 'svelte/store' import { _ } from 'svelte-i18n' import defaultCopy from './i18n/en.json' import type { EthereumTransactionData } from 'bnc-sdk' import type { CustomNotification, Notification, NotificationType } from './types.js' import { validateTransactionHandlerReturn } from './validation.js' import { state } from './store/index.js' import { addNotification } from './store/actions.js' import updateBalances from './update-balances.js' import { updateTransaction } from './streams.js' export function handleTransactionUpdates( transaction: EthereumTransactionData ): void { const customized = state.get().notify.transactionHandler(transaction) const invalid = validateTransactionHandlerReturn(customized) if (invalid) { throw invalid } if (transaction.eventCode === 'txConfirmed') { updateBalances([transaction.watchedAddress, transaction.counterparty]) } const notification = transactionEventToNotification(transaction, customized) addNotification(notification) updateTransaction(transaction) } export function transactionEventToNotification( transaction: EthereumTransactionData, customization: CustomNotification | boolean | void ): Notification { const { id, hash, startTime, eventCode, direction, counterparty, value, asset, network } = transaction const type: NotificationType = eventToType(eventCode) const key = `${id || hash}-${ (typeof customization === 'object' && customization.eventCode) || eventCode }` const counterpartyShortened: string | undefined = counterparty && counterparty.substring(0, 4) + '...' + counterparty.substring(counterparty.length - 4) const formattedValue = new BigNumber(value || 0) .div(new BigNumber('1000000000000000000')) .toString(10) const formatterOptions = counterparty && value ? { messageId: `notify.watched['${eventCode}']`, values: { verb: eventCode === 'txConfirmed' ? direction === 'incoming' ? 'received' : 'sent' : direction === 'incoming' ? 'receiving' : 'sending', formattedValue, preposition: direction === 'incoming' ? 'from' : 'to', counterpartyShortened, asset } } : { messageId: `notify.transaction['${eventCode}']`, values: { formattedValue, asset } } const formatter = get(_) const notificationDefaultMessages = defaultCopy.notify const typeKey: keyof typeof notificationDefaultMessages = counterparty ? 'watched' : 'transaction' const notificationMessageType = notificationDefaultMessages[typeKey] const defaultMessage = notificationMessageType[eventCode as keyof typeof notificationMessageType] const message = formatter(formatterOptions.messageId, { values: formatterOptions.values, default: defaultMessage }) let notification = { id: id || hash, type, key, network, startTime: startTime || Date.now(), eventCode, message, autoDismiss: typeToDismissTimeout( (typeof customization === 'object' && customization.type) || type ) } if (typeof customization === 'object') { notification = { ...notification, ...customization } } return notification } export function eventToType(eventCode: string | undefined): NotificationType { switch (eventCode) { case 'txSent': case 'txPool': return 'pending' case 'txSpeedUp': case 'txCancel': case 'txRequest': case 'txRepeat': case 'txAwaitingApproval': case 'txConfirmReminder': case 'txStuck': return 'hint' case 'txError': case 'txSendFail': case 'txFailed': case 'txDropped': case 'nsfFail': case 'txUnderpriced': return 'error' case 'txConfirmed': return 'success' default: return 'hint' } } export function typeToDismissTimeout(type: string): number { switch (type) { case 'success': case 'hint': return 4000 default: return 0 } }