init
This commit is contained in:
commit
44f31f8b9f
402 changed files with 47865 additions and 0 deletions
451
store/txHashKeeper.js
Normal file
451
store/txHashKeeper.js
Normal file
|
@ -0,0 +1,451 @@
|
|||
/* eslint-disable no-console */
|
||||
import { hexToNumber } from 'web3-utils'
|
||||
|
||||
import txStatus from './txStatus'
|
||||
|
||||
import { eventsType } from '@/constants'
|
||||
import { createChainIdState, parseNote } from '@/utils'
|
||||
|
||||
const initialState = createChainIdState({
|
||||
txs: {},
|
||||
govTxs: {},
|
||||
encryptedTxs: {}
|
||||
})
|
||||
|
||||
export const state = () => {
|
||||
return initialState
|
||||
}
|
||||
|
||||
export const getters = {
|
||||
txExplorerUrl: (state, getters, rootState, rootGetters) => (txHash) => {
|
||||
const { explorerUrl } = rootGetters['metamask/networkConfig']
|
||||
return explorerUrl.tx + txHash
|
||||
},
|
||||
addressExplorerUrl: (state, getters, rootState, rootGetters) => (address) => {
|
||||
const { explorerUrl } = rootGetters['metamask/networkConfig']
|
||||
return explorerUrl.address + address
|
||||
},
|
||||
blockExplorerUrl: (state, getters, rootState, rootGetters) => (block) => {
|
||||
const { explorerUrl } = rootGetters['metamask/networkConfig']
|
||||
return explorerUrl.block + block
|
||||
},
|
||||
encryptedTxs: (state, getters, rootState, rootGetters) => {
|
||||
const netId = rootGetters['metamask/netId']
|
||||
|
||||
const txsToRender = Object.entries(state[`netId${netId}`].encryptedTxs)
|
||||
.reverse()
|
||||
.map(([txHash, tx]) => {
|
||||
return {
|
||||
isEncrypted: true,
|
||||
txHash,
|
||||
status,
|
||||
...tx
|
||||
}
|
||||
})
|
||||
return txsToRender
|
||||
},
|
||||
txs: (state, getters, rootState, rootGetters) => {
|
||||
const netId = rootGetters['metamask/netId']
|
||||
const txsToRender = Object.entries(state[`netId${netId}`].txs)
|
||||
.reverse()
|
||||
.map(([txHash, tx]) => {
|
||||
return {
|
||||
txHash,
|
||||
status,
|
||||
...tx
|
||||
}
|
||||
})
|
||||
return txsToRender
|
||||
},
|
||||
allTxs: (state, getters) => {
|
||||
const { txs, encryptedTxs } = getters
|
||||
return txs.concat(encryptedTxs)
|
||||
},
|
||||
allTxsHash: (state, getters, rootState, rootGetters) => {
|
||||
const netId = rootGetters['metamask/netId']
|
||||
return Object.entries(state[`netId${netId}`].txs)
|
||||
.reverse()
|
||||
.map(([txHash]) => txHash)
|
||||
},
|
||||
txStatusClass: () => (status) => {
|
||||
let cssClass
|
||||
switch (status) {
|
||||
case txStatus.waitingForReciept:
|
||||
cssClass = 'is-loading'
|
||||
break
|
||||
case txStatus.success:
|
||||
cssClass = 'is-success'
|
||||
break
|
||||
case txStatus.fail:
|
||||
cssClass = 'is-danger'
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
return cssClass
|
||||
}
|
||||
}
|
||||
|
||||
export const mutations = {
|
||||
SAVE_TX_HASH(state, { storeType = 'txs', amount = '0', note = null, netId, txHash, status, ...rest }) {
|
||||
this._vm.$set(state[`netId${netId}`][storeType], [txHash], {
|
||||
...rest,
|
||||
status: status || txStatus.waitingForReciept,
|
||||
note,
|
||||
amount
|
||||
})
|
||||
},
|
||||
CHANGE_TX_STATUS(state, { storeType = 'txs', txHash, status, blockNumber, netId }) {
|
||||
this._vm.$set(state[`netId${netId}`][storeType][txHash], 'status', status)
|
||||
this._vm.$set(state[`netId${netId}`][storeType][txHash], 'blockNumber', blockNumber)
|
||||
},
|
||||
SET_SPENT(state, { netId, storeType = 'txs', txHash }) {
|
||||
this._vm.$set(state[`netId${netId}`][storeType][txHash], 'isSpent', true)
|
||||
},
|
||||
DELETE_TX(state, { storeType = 'txs', txHash }) {
|
||||
const netId = this._vm['metamask/netId']
|
||||
this._vm.$delete(state[`netId${netId}`][storeType], txHash)
|
||||
},
|
||||
UPDATE_DEPOSIT(state, { storeType = 'txs', txHash, netId, withdrawTxHash, timestamp, status, ...rest }) {
|
||||
const tx = state[`netId${netId}`][storeType][txHash]
|
||||
this._vm.$delete(state[`netId${netId}`][storeType], txHash)
|
||||
|
||||
this._vm.$set(state[`netId${netId}`][storeType], withdrawTxHash, {
|
||||
...tx,
|
||||
timestamp,
|
||||
depositTxHash: txHash,
|
||||
txHash: withdrawTxHash,
|
||||
depositBlock: tx.blockNumber,
|
||||
status: status || txStatus.waitingForReciept,
|
||||
...rest
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const actions = {
|
||||
async getInstances({ rootGetters }, { txs }) {
|
||||
const eventsInterface = rootGetters['application/eventsInterface']
|
||||
|
||||
const instances = txs.reduce((acc, curr) => {
|
||||
const [, currency, amount, netId] = curr.prefix.split('-')
|
||||
|
||||
const name = `${amount}${currency}`
|
||||
if (!acc[name]) {
|
||||
const service = eventsInterface.getService({ netId, amount, currency })
|
||||
acc[name] = { currency, amount, netId, service }
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
await Promise.all(
|
||||
[].concat(
|
||||
Object.values(instances).map((instance) => instance.service.updateEvents(eventsType.DEPOSIT)),
|
||||
Object.values(instances).map((instance) => instance.service.updateEvents(eventsType.WITHDRAWAL))
|
||||
)
|
||||
)
|
||||
|
||||
return instances
|
||||
},
|
||||
async checkPendingEncryptedTransaction({ dispatch, getters }) {
|
||||
const transactions = getters.encryptedTxs
|
||||
|
||||
const pendingTxs = transactions.filter((tx) => tx.status === 1)
|
||||
|
||||
const instances = await dispatch('getInstances', { txs: pendingTxs })
|
||||
|
||||
for (const tx of pendingTxs) {
|
||||
const [, currency, amount, netId] = tx.prefix.split('-')
|
||||
|
||||
dispatch('checkSpeedUpEncryptedTx', {
|
||||
netId,
|
||||
txHash: tx.txHash,
|
||||
type: eventsType.DEPOSIT,
|
||||
commitment: tx.commitmentHex,
|
||||
service: instances[`${amount}${currency}`]
|
||||
})
|
||||
}
|
||||
},
|
||||
async checkSpeedUpEncryptedTx({ commit, dispatch }, { txHash, commitment, netId, service, type }) {
|
||||
try {
|
||||
const result = await this.$provider.web3.eth.getTransactionReceipt(txHash)
|
||||
|
||||
if (result) {
|
||||
const status = result.status === '0x0' ? txStatus.fail : txStatus.success
|
||||
|
||||
commit('CHANGE_TX_STATUS', {
|
||||
netId,
|
||||
txHash,
|
||||
status,
|
||||
storeType: 'encryptedTxs',
|
||||
blockNumber: hexToNumber(result.blockNumber)
|
||||
})
|
||||
} else {
|
||||
const foundEvent = await service.findEvent({ eventName: 'commitment', eventToFind: commitment, type })
|
||||
|
||||
if (foundEvent) {
|
||||
commit('UPDATE_DEPOSIT', {
|
||||
netId,
|
||||
txHash,
|
||||
storeType: 'encryptedTxs',
|
||||
status: txStatus.success,
|
||||
timestamp: foundEvent.timestamp,
|
||||
withdrawTxHash: foundEvent.txHash,
|
||||
blockNumber: foundEvent.depositBlock
|
||||
})
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
throw new Error(`Method checkSpeedUpEncryptedTx has error ${err.message}`)
|
||||
}
|
||||
},
|
||||
async cleanEncryptedTxs({ getters, commit, dispatch }) {
|
||||
getters.encryptedTxs.forEach(({ status, txHash, type }) => {
|
||||
if (status === txStatus.fail) {
|
||||
commit('DELETE_TX', { txHash, storeType: 'encryptedTxs' })
|
||||
}
|
||||
})
|
||||
|
||||
const instances = await dispatch('getInstances', {
|
||||
txs: getters.encryptedTxs
|
||||
})
|
||||
|
||||
for (const tx of getters.encryptedTxs) {
|
||||
if (!tx.isSpent) {
|
||||
const { currency, amount, netId, nullifierHex } = parseNote(`${tx.prefix}-${tx.note}`)
|
||||
|
||||
const isSpent = await instances[`${amount}${currency}`].service.findEvent({
|
||||
eventName: 'nullifierHash',
|
||||
eventToFind: nullifierHex,
|
||||
type: eventsType.WITHDRAWAL
|
||||
})
|
||||
|
||||
if (isSpent) {
|
||||
commit('SET_SPENT', { txHash: tx.txHash, storeType: 'encryptedTxs', netId })
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
checkPendingTransaction({ getters, dispatch }) {
|
||||
const transactions = getters.txs
|
||||
|
||||
const pendingTxs = transactions.filter((tx) => tx.status === 1)
|
||||
|
||||
for (const tx of pendingTxs) {
|
||||
const [, , , netId] = tx.prefix.split('-')
|
||||
|
||||
dispatch('checkPendingSpeedUpTx', { txHash: tx.txHash, note: `${tx.prefix}-${tx.note}`, netId })
|
||||
}
|
||||
},
|
||||
async checkPendingSpeedUpTx({ commit, dispatch }, { txHash, netId, note }) {
|
||||
try {
|
||||
const result = await this.$provider.web3.eth.getTransactionReceipt(txHash)
|
||||
|
||||
if (result) {
|
||||
const status = result.status === '0x0' ? txStatus.fail : txStatus.success
|
||||
|
||||
commit('CHANGE_TX_STATUS', {
|
||||
storeType: 'txs',
|
||||
txHash,
|
||||
blockNumber: hexToNumber(result.blockNumber),
|
||||
status,
|
||||
netId
|
||||
})
|
||||
} else {
|
||||
const response = await dispatch(
|
||||
'application/loadDepositEvent',
|
||||
{ withdrawNote: note },
|
||||
{ root: true }
|
||||
)
|
||||
|
||||
if (response) {
|
||||
commit('UPDATE_DEPOSIT', {
|
||||
netId,
|
||||
txHash,
|
||||
storeType: 'txs',
|
||||
status: txStatus.success,
|
||||
timestamp: response.timestamp,
|
||||
withdrawTxHash: response.txHash,
|
||||
blockNumber: response.depositBlock
|
||||
})
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
throw new Error(`Method checkPendingSpeedUpTx has error ${err.message}`)
|
||||
}
|
||||
},
|
||||
async runTxWatcher({ commit, dispatch }, { storeType = 'txs', txHash, netId, isSaving = true }) {
|
||||
console.log('runTxWatcher storeType txHash, netId', storeType, txHash, netId)
|
||||
try {
|
||||
// eslint-disable-next-line prefer-const
|
||||
let { status, blockNumber } = await this.$provider.waitForTxReceipt({ txHash })
|
||||
status = status === '0x0' ? txStatus.fail : txStatus.success
|
||||
|
||||
if (isSaving) {
|
||||
commit('CHANGE_TX_STATUS', {
|
||||
storeType,
|
||||
txHash,
|
||||
blockNumber: hexToNumber(blockNumber),
|
||||
status,
|
||||
netId
|
||||
})
|
||||
}
|
||||
|
||||
return status === txStatus.success
|
||||
} catch (e) {
|
||||
console.error('runTxWatcher', e)
|
||||
return false
|
||||
}
|
||||
},
|
||||
async runTxWatcherWithNotifications(
|
||||
{ dispatch },
|
||||
{ title, successTitle, storeType = 'txs', txHash, netId, onSuccess, isSaving }
|
||||
) {
|
||||
try {
|
||||
const noticeId = await dispatch(
|
||||
'notice/addNotice',
|
||||
{
|
||||
notice: {
|
||||
title,
|
||||
type: 'loading',
|
||||
txHash
|
||||
}
|
||||
},
|
||||
{ root: true }
|
||||
)
|
||||
const success = await dispatch('runTxWatcher', { storeType, txHash, netId, isSaving })
|
||||
if (success) {
|
||||
dispatch(
|
||||
'notice/updateNotice',
|
||||
{
|
||||
id: noticeId,
|
||||
notice: {
|
||||
title: successTitle,
|
||||
type: 'success'
|
||||
},
|
||||
interval: 10000
|
||||
},
|
||||
{ root: true }
|
||||
)
|
||||
if (typeof onSuccess === 'function') {
|
||||
onSuccess(txHash)
|
||||
}
|
||||
} else {
|
||||
dispatch(
|
||||
'notice/updateNotice',
|
||||
{
|
||||
id: noticeId,
|
||||
notice: {
|
||||
title: 'transactionFailed',
|
||||
type: 'danger'
|
||||
}
|
||||
},
|
||||
{ root: true }
|
||||
)
|
||||
}
|
||||
return success
|
||||
} catch (e) {
|
||||
console.error('runTxWatcherWithNotifications', e)
|
||||
return false
|
||||
}
|
||||
},
|
||||
async cleanTxs({ getters, commit, dispatch }) {
|
||||
// isSpentArray
|
||||
getters.txs.forEach(({ status, txHash, type }) => {
|
||||
if (status === txStatus.fail) {
|
||||
commit('DELETE_TX', { txHash })
|
||||
}
|
||||
})
|
||||
|
||||
const instances = await dispatch('getInstances', {
|
||||
txs: getters.txs
|
||||
})
|
||||
|
||||
for (const tx of getters.txs) {
|
||||
if (tx && !tx.isSpent) {
|
||||
const { currency, amount, netId, nullifierHex } = parseNote(`${tx.prefix}-${tx.note}`)
|
||||
|
||||
const isSpent = await instances[`${amount}${currency}`].service.findEvent({
|
||||
eventName: 'nullifierHash',
|
||||
eventToFind: nullifierHex,
|
||||
type: eventsType.WITHDRAWAL
|
||||
})
|
||||
|
||||
if (isSpent) {
|
||||
commit('SET_SPENT', { txHash: tx.txHash, netId })
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
async updateDeposit(
|
||||
{ getters, commit, dispatch, rootGetters },
|
||||
{ netId, type = 'tornado', action = 'Withdraw', note, txHash, fee, amount, currency }
|
||||
) {
|
||||
const timestamp = Math.round(new Date().getTime() / 1000)
|
||||
|
||||
let txMutation = 'SAVE_TX_HASH'
|
||||
const tx = {
|
||||
txHash,
|
||||
type: action,
|
||||
amount,
|
||||
currency,
|
||||
fee,
|
||||
netId,
|
||||
timestamp,
|
||||
status: 2
|
||||
}
|
||||
|
||||
if (type === 'tornado') {
|
||||
const [tornado, , , , hexNote] = note.split('-')
|
||||
const { commitmentHex } = parseNote(note)
|
||||
tx.prefix = `${tornado}-${currency}-${amount}-${netId}`
|
||||
tx.isSpent = true
|
||||
|
||||
const encryptedTxs = getters.encryptedTxs
|
||||
const encrypted = encryptedTxs.find((tx) => {
|
||||
return tx.commitmentHex === commitmentHex
|
||||
})
|
||||
|
||||
tx.storeType = encrypted ? 'encryptedTxs' : 'txs'
|
||||
|
||||
const deposit =
|
||||
encrypted ||
|
||||
getters.txs.find(({ note }) => {
|
||||
return note === hexNote
|
||||
})
|
||||
|
||||
tx.note = encrypted ? encrypted.note : hexNote
|
||||
|
||||
const blockNumber = await dispatch('getBlockNumber', { txHash })
|
||||
tx.blockNumber = blockNumber
|
||||
|
||||
if (deposit && deposit.txHash) {
|
||||
txMutation = 'UPDATE_DEPOSIT'
|
||||
tx.txHash = deposit.txHash
|
||||
tx.withdrawTxHash = txHash
|
||||
} else {
|
||||
const events = await dispatch('application/loadDepositEvent', { withdrawNote: note }, { root: true })
|
||||
|
||||
tx.withdrawTxHash = txHash
|
||||
tx.txHash = events.txHash
|
||||
tx.depositBlock = events.depositBlock
|
||||
tx.index = events.leafIndex
|
||||
}
|
||||
}
|
||||
|
||||
commit(txMutation, tx)
|
||||
},
|
||||
async getBlockNumber({ rootState }, { txHash }) {
|
||||
try {
|
||||
const { netId } = rootState.metamask
|
||||
const { url } = rootState.settings[`netId${netId}`].rpc
|
||||
|
||||
const web3 = this.$provider.getWeb3(url)
|
||||
|
||||
const { blockNumber } = await web3.eth.getTransaction(txHash)
|
||||
|
||||
return blockNumber
|
||||
} catch (err) {
|
||||
console.log('getBlockNumber has error:', err.message)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue