classic-ui/store/token.js
Danil Kovtonyuk 44f31f8b9f
init
2022-04-22 13:14:19 +10:00

223 lines
7.4 KiB
JavaScript

/* eslint-disable no-console */
/* eslint-disable import/order */
import Web3 from 'web3'
import networkConfig from '@/networkConfig'
import ERC20ABI from '@/abis/ERC20.abi.json'
const { numberToHex, toBN, toWei } = require('web3-utils')
const BN = require('bn.js')
const zero = new BN(0)
const negative1 = new BN(-1)
export const state = () => {
return {
approvalAmount: 'unlimited',
allowance: '',
balance: ''
}
}
export const getters = {
tokenContract: (state, getters, rootState, rootGetters) => ({ currency, netId }) => {
const config = networkConfig[`netId${netId}`]
const { url } = rootState.settings[`netId${netId}`].rpc
const address = config.tokens[currency].tokenAddress
const web3 = new Web3(url)
return new web3.eth.Contract(ERC20ABI, address)
},
// similar to fromWei from web3
toDecimals: (state, getters, rootState, rootGetters) => (value, decimals, fixed) => {
const { currency } = rootState.application.selectedStatistic
decimals = decimals || rootGetters['metamask/networkConfig'].tokens[currency].decimals
fixed = fixed || 2
value = new BN(value)
const negative = value.lt(zero)
const base = new BN('10').pow(new BN(decimals))
const baseLength = base.toString(10).length - 1 || 1
if (negative) {
value = value.mul(negative1)
}
let fraction = value.mod(base).toString(10)
while (fraction.length < baseLength) {
fraction = `0${fraction}`
}
fraction = fraction.match(/^([0-9]*[1-9]|0)(0*)/)[1]
const whole = value.div(base).toString(10)
if (fixed && fraction !== '0') {
fraction = fraction.slice(0, fixed)
}
value = `${whole}${fraction === '0' ? '' : `.${fraction}`}`
if (negative) {
value = `-${value}`
}
return value
},
// similar to toWei from web3
fromDecimals: (state, getters, rootState, rootGetters) => (value, decimals) => {
const { currency } = rootState.application.selectedStatistic
decimals = decimals || rootGetters['metamask/networkConfig'].tokens[currency].decimals
value = value.toString()
let ether = value.toString()
const base = new BN('10').pow(new BN(decimals))
const baseLength = base.toString(10).length - 1 || 1
const negative = ether.substring(0, 1) === '-'
if (negative) {
ether = ether.substring(1)
}
if (ether === '.') {
throw new Error(this.app.i18n.t('unitInvalidValue', { value }))
}
// Split it into a whole and fractional part
const comps = ether.split('.')
if (comps.length > 2) {
throw new Error(this.app.i18n.t('tooManyDecimalPoints', { value }))
}
let whole = comps[0]
let fraction = comps[1]
if (!whole) {
whole = '0'
}
if (!fraction) {
fraction = '0'
}
if (fraction.length > baseLength) {
throw new Error(this.app.i18n.t('tooManyDecimalPlaces', { value }))
}
while (fraction.length < baseLength) {
fraction += '0'
}
whole = new BN(whole)
fraction = new BN(fraction)
let wei = whole.mul(base).add(fraction)
if (negative) {
wei = wei.mul(negative)
}
return new BN(wei.toString(10), 10)
},
isSufficientAllowance: (state, getters, rootState, rootGetters) => {
const { currency, amount } = rootState.application.selectedInstance
const { decimals } = rootGetters['metamask/networkConfig'].tokens[currency]
return toBN(state.allowance).gte(toBN(getters.fromDecimals(amount, decimals)))
},
isSufficientBalance: (state, getters, rootState, rootGetters) => {
const ethBalance = rootState.metamask.ethBalance
const { currency, amount } = rootState.application.selectedInstance
const { decimals } = rootGetters['metamask/networkConfig'].tokens[currency]
const nativeCurrency = rootGetters['metamask/nativeCurrency']
if (currency === nativeCurrency) {
return toBN(ethBalance).gte(toBN(toWei(amount.toString())))
} else {
return toBN(state.balance).gte(toBN(getters.fromDecimals(amount, decimals)))
}
},
getSymbol: (state, getters, rootState, rootGetters) => (currency) => {
const tokens = rootGetters['metamask/networkConfig'].tokens
if (tokens[currency]) {
return tokens[currency].symbol
}
return currency.toUpperCase()
}
}
export const mutations = {
SET_APPROVAL_AMOUNT(state, { approvalAmount }) {
state.approvalAmount = approvalAmount
},
SAVE_ALLOWANCE(state, { allowance }) {
this._vm.$set(state, 'allowance', allowance)
},
SAVE_BALANCE(state, { balance }) {
this._vm.$set(state, 'balance', balance)
}
}
export const actions = {
async approve({ rootState, getters, dispatch, rootGetters, state }) {
try {
const netId = rootGetters['metamask/netId']
const { currency } = rootState.application.selectedInstance
const { decimals } = rootGetters['metamask/networkConfig'].tokens[currency]
const tokenInstance = getters.tokenContract({ currency, netId })
const tornadoProxy = rootGetters['application/tornadoProxyContract']({ netId })
const { ethAccount } = rootState.metamask
const amountToApprove =
state.approvalAmount === 'unlimited'
? toBN('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')
: toBN(getters.fromDecimals(state.approvalAmount, decimals))
const data = tokenInstance.methods
.approve(tornadoProxy._address, amountToApprove.toString())
.encodeABI()
const gas = await tokenInstance.methods
.approve(tornadoProxy._address, amountToApprove.toString())
.estimateGas({
from: ethAccount
})
const callParams = {
method: 'eth_sendTransaction',
params: {
to: tokenInstance._address,
gas: numberToHex(gas + 30000),
data
},
watcherParams: {
title: 'approve',
successTitle: 'approved'
},
isSaving: false
}
await dispatch('metamask/sendTransaction', callParams, { root: true })
} catch (e) {
console.error('approve action', e)
throw new Error(e.message)
}
},
async fetchTokenAllowance({ getters, rootGetters, commit, rootState }) {
const netId = rootGetters['metamask/netId']
const { currency } = rootState.application.selectedInstance
const { ethAccount } = rootState.metamask
try {
const tornadoInstance = rootGetters['application/tornadoProxyContract']({ netId })
const nativeCurrency = rootGetters['metamask/nativeCurrency']
if (currency !== nativeCurrency && ethAccount) {
const tokenInstance = getters.tokenContract({ currency, netId })
const allowance = await tokenInstance.methods.allowance(ethAccount, tornadoInstance._address).call()
commit('SAVE_ALLOWANCE', { allowance })
}
} catch (e) {
console.error('fetchTokenAllowance', e.message)
}
},
async fetchTokenBalance({ state, getters, rootGetters, commit, rootState }) {
try {
const netId = rootGetters['metamask/netId']
const { currency } = rootState.application.selectedInstance
const { ethAccount } = rootState.metamask
const nativeCurrency = rootGetters['metamask/nativeCurrency']
if (currency !== nativeCurrency && ethAccount) {
const tokenInstance = getters.tokenContract({ currency, netId })
const balance = await tokenInstance.methods.balanceOf(ethAccount).call()
commit('SAVE_BALANCE', { balance })
}
} catch (e) {
console.error('fetchTokenBalance', e.message)
}
}
}