cosmos-explorer/src/libs/data/data.js
2021-12-04 15:47:48 +08:00

412 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {
Bech32, fromBase64, fromHex, toHex,
} from '@cosmjs/encoding'
import { sha256, stringToPath } from '@cosmjs/crypto'
// ledger
import TransportWebBLE from '@ledgerhq/hw-transport-web-ble'
import TransportWebUSB from '@ledgerhq/hw-transport-webusb'
import CosmosApp from 'ledger-cosmos-js'
import { LedgerSigner } from '@cosmjs/ledger-amino'
import dayjs from 'dayjs'
import duration from 'dayjs/plugin/duration'
import relativeTime from 'dayjs/plugin/relativeTime'
import utc from 'dayjs/plugin/utc'
import localeData from 'dayjs/plugin/localeData'
import { $themeColors } from '@themeConfig'
import PingWalletClient from './signing'
dayjs.extend(localeData)
dayjs.extend(duration)
dayjs.extend(relativeTime)
dayjs.extend(utc)
export function getLocalObject(name) {
const text = localStorage.getItem(name)
if (text) {
return JSON.parse(text)
}
return null
}
export function getLocalChains() {
return getLocalObject('chains')
}
export function getLocalAccounts() {
return getLocalObject('accounts')
}
export function getLocalTxHistory() {
return getLocalObject('txHistory')
}
export function setLocalTxHistory(newTx) {
const txs = getLocalTxHistory()
if (txs) {
txs.push(newTx)
return localStorage.setItem('txHistory', JSON.stringify(txs))
}
return localStorage.setItem('txHistory', JSON.stringify([newTx]))
}
export async function connectLedger(transport = 'usb') {
const trans = await transport === 'usb' ? TransportWebUSB.create() : TransportWebBLE.create()
return new CosmosApp(trans)
}
export function operatorAddressToAccount(operAddress) {
const { prefix, data } = Bech32.decode(operAddress)
if (prefix === 'iva') { // handle special cases
return Bech32.encode('iaa', data)
}
if (prefix === 'crocncl') { // handle special cases
return Bech32.encode('cro', data)
}
return Bech32.encode(prefix.replace('valoper', ''), data)
}
// TODO, not tested
export function pubkeyToAccountAddress(pubkey, prefix) {
return Bech32.encode(prefix, pubkey, 40)
}
export function addressDecode(address) {
return Bech32.decode(address)
}
export function addressEnCode(prefix, pubkey) {
return Bech32.encode(prefix, pubkey)
}
export function getUserCurrency() {
const currency = localStorage.getItem('currency')
return currency || 'usd'
}
export function setUserCurrency(currency) {
localStorage.setItem('currency', currency)
}
export function chartColors() {
const colors = ['#6610f2', '#20c997', '#000000', '#FF0000',
'#800000', '#FFFF00', '#808000', '#00FF00', '#008000', '#00FFFF',
'#008080', '#0000FF', '#000080', '#FF00FF', '#800080']
return Object.values($themeColors).concat(colors)
}
export function getUserCurrencySign() {
let s = ''
switch (getUserCurrency()) {
case 'cny':
case 'jpy':
s = '¥'
break
case 'krw':
s = '₩'
break
case 'eur':
s = '€'
break
default:
s = '$'
}
return s
}
export function consensusPubkeyToHexAddress(consensusPubkey) {
let raw = null
if (typeof consensusPubkey === 'object') {
raw = toHex(fromBase64(consensusPubkey.value))
} else {
raw = toHex(Bech32.decode(consensusPubkey).data).toUpperCase().replace('1624DE6420', '')
}
const address = toHex(sha256(fromHex(raw))).slice(0, 40).toUpperCase()
return address
}
function toSignAddress(addr) {
const { data } = addressDecode(addr)
return addressEnCode('cosmos', data)
}
function getHdPath(address) {
let hdPath = "m/44'/118/0'/0/0"
Object.values(getLocalAccounts()).forEach(item => {
const curr = item.address.find(i => i.addr === address)
if (curr && curr.hdpath) {
hdPath = curr.hdpath
}
})
// return [44, 118, 0, 0, 0]
// m/0'/1/2'/2/1000000000
return stringToPath(hdPath)
}
export async function sign(device, chainId, signerAddress, messages, fee, memo, signerData) {
let transport
let signer
switch (device) {
case 'ledgerBle':
transport = await TransportWebBLE.create()
signer = new LedgerSigner(transport, { hdPaths: [getHdPath(signerAddress)] })
break
case 'ledgerUSB':
transport = await TransportWebUSB.create()
signer = new LedgerSigner(transport, { hdPaths: [getHdPath(signerAddress)] })
break
case 'keplr':
default:
if (!window.getOfflineSigner || !window.keplr) {
throw new Error('Please install keplr extension')
}
await window.keplr.enable(chainId)
signer = window.getOfflineSigner(chainId)
// signer = window.getOfflineSignerOnlyAmino(chainId)
}
// if (signer) return signAmino(signer, signerAddress, messages, fee, memo, signerData)
// Ensure the address has some tokens to spend
const client = await PingWalletClient.offline(signer)
return client.signAmino(device === 'keplr' ? signerAddress : toSignAddress(signerAddress), messages, fee, memo, signerData)
// return signDirect(signer, signerAddress, messages, fee, memo, signerData)
}
export async function getLedgerAddress(transport = 'blu', hdPath = "m/44'/118/0'/0/0") {
const trans = transport === 'usb' ? await TransportWebUSB.create() : await TransportWebBLE.create()
const signer = new LedgerSigner(trans, { hdPaths: [stringToPath(hdPath)] })
return signer.getAccounts()
}
export function toDuration(value) {
return dayjs.duration(value).humanize()
}
// unit(y M d h m s ms)
export function timeIn(time, amount, unit = 's') {
const input = dayjs(time).add(amount, unit)
return dayjs().unix() > input.unix()
}
export function toDay(time, format = 'long') {
if (format === 'long') {
return dayjs(time).format('YYYY-MM-DD HH:mm')
}
if (format === 'date') {
return dayjs(time).format('YYYY-MM-DD')
}
if (format === 'time') {
return dayjs(time).format('HH:mm:ss')
}
if (format === 'from') {
return dayjs(time).fromNow()
}
if (format === 'to') {
return dayjs(time).toNow()
}
return dayjs(time).format('YYYY-MM-DD HH:mm:ss')
}
export function percent(num) {
return parseFloat((num * 100).toFixed(2))
}
export function abbr(string, length = 6, suffix = '...') {
if (string && string.length > length) {
return `${string.substring(0, length)}${suffix}`
}
return string
}
export function abbrRight(string, length = 6, suffix = '...') {
if (string && string.length > length) {
return `${string.substring(string.length - length)}${suffix}`
}
return string
}
export function abbrMessage(msg) {
if (Array.isArray(msg)) {
const sum = msg.map(x => abbrMessage(x)).reduce((s, c) => {
const sh = s
if (sh[c]) {
sh[c] += 1
} else {
sh[c] = 1
}
return sh
}, {})
const output = []
Object.keys(sum).forEach(k => {
output.push(`${k}×${sum[k]}`)
})
return output.join(', ')
}
if (msg.typeUrl) {
return msg.typeUrl.substring(msg.typeUrl.lastIndexOf('.') + 1).replace('Msg', '')
}
return msg.type.substring(msg.type.lastIndexOf('/') + 1).replace('Msg', '')
}
export function abbrAddress(address, length = 10) {
return address.substring(0, length).concat('...', address.substring(address.length - length))
}
export function isStringArray(value) {
let is = false
if (Array.isArray(value)) {
is = value.findIndex(x => typeof x === 'string') > -1
}
return is
}
export function isToken(value) {
let is = false
if (Array.isArray(value)) {
is = value.findIndex(x => Object.keys(x).includes('denom')) > -1
}
return is
}
export function formatTokenDenom(tokenDenom) {
if (tokenDenom) {
let denom = tokenDenom.denom_trace ? tokenDenom.denom_trace.base_denom.toUpperCase() : tokenDenom.toUpperCase()
if (denom.charAt(0) === 'U' && denom !== 'USDX') {
denom = denom.substring(1)
} else if (denom === 'BASECRO') {
denom = 'CRO'
} else if (denom.startsWith('IBC')) {
denom = 'IBC...'
} else if (denom.startsWith('NANOLIKE')) {
denom = 'LIKE'
}
return denom
}
return ''
}
export function getUnitAmount(amount, denom) {
if (denom.startsWith('basecro')) {
return String((Number(amount) * 100000000).toFixed())
}
if (denom.startsWith('rowan')) {
// eslint-disable-next-line no-undef
return (BigInt(amount) * 1000000000000000000n).toString()
}
if (denom.startsWith('nanolike')) {
// eslint-disable-next-line no-undef
return String((Number(amount) * 1000000000).toFixed())
}
return String((Number(amount) * 1000000).toFixed())
}
export function formatTokenAmount(tokenAmount, fraction = 2, denom = 'uatom') {
let amount
if (denom.startsWith('inj')) {
// eslint-disable-next-line no-undef
amount = Number(BigInt(Number(tokenAmount)) / 1000000000000000000n)
// }
} else if (denom.startsWith('rowan')) {
// eslint-disable-next-line no-undef
amount = Number(BigInt(Number(tokenAmount)) / 1000000000000000000n)
// }
} else if (denom.startsWith('basecro')) {
amount = Number(tokenAmount) / 100000000
} else if (denom.startsWith('nanolike')) {
amount = Number(tokenAmount) / 1000000000
} else {
amount = Number(tokenAmount) / 1000000
}
if (amount > 10) {
return parseFloat(amount.toFixed(fraction))
}
return parseFloat(amount)
}
export function isTestnet() {
return (window.location.hostname.startsWith('testnet')
|| window.location.search.indexOf('testnet') > -1)
}
export function formatToken(token, IBCDenom = {}, decimals = 2, withDenom = true) {
if (token) {
if (withDenom) {
return `${formatTokenAmount(token.amount, decimals, token.denom)} ${formatTokenDenom(IBCDenom[token.denom] || token.denom)}`
}
return formatTokenAmount(token.amount, decimals, token.denom)
}
return token
}
const COUNT_ABBRS = ['', 'K', 'M', 'B', 't', 'q', 's', 'S', 'o', 'n', 'd', 'U', 'D', 'T', 'Qt', 'Qd', 'Sd', 'St']
export function formatNumber(count, withAbbr = false, decimals = 2) {
const i = count === 0 ? count : Math.floor(Math.log(count) / Math.log(1000))
let result = parseFloat((count / (1000 ** i)).toFixed(decimals))
if (withAbbr && COUNT_ABBRS[i]) {
result += `${COUNT_ABBRS[i]}`
}
return result
}
export function tokenFormatter(tokens, denoms = {}) {
if (Array.isArray(tokens)) {
return tokens.map(t => formatToken(t, denoms, 2)).join()
}
return formatToken(tokens, denoms, 2)
}
export function getCachedValidators(chainName) {
const locals = localStorage.getItem(`validators-${chainName}`)
return locals
}
export function isHexAddress(v) {
const re = /^[A-Z\d]{40}$/
return re.test(v)
}
export function getStakingValidatorByHex(chainName, hex) {
const locals = localStorage.getItem(`validators-${chainName}`)
if (locals) {
const val = JSON.parse(locals).find(x => consensusPubkeyToHexAddress(x.consensus_pubkey) === hex)
if (val) {
return val.description.moniker
}
}
return abbr(hex)
}
export function getStakingValidatorByAccount(chainName, addr) {
const locals = localStorage.getItem(`validators-${chainName}`)
if (locals) {
const val = JSON.parse(locals).find(x => operatorAddressToAccount(x.operator_address) === addr)
if (val) {
return val.description.moniker
}
}
return addr
}
export function getStakingValidatorOperator(chainName, addr, length = -1) {
const locals = localStorage.getItem(`validators-${chainName}`)
if (locals) {
const val = JSON.parse(locals).find(x => x.operator_address === addr)
if (val) {
return val.description.moniker
}
}
if (length > 0) {
return addr.substring(addr.length - length)
}
return addr
}
export * from 'compare-versions'
export class Data {
}