@kazeblockchain/kazejs
Version:
Javascript libraries for Kaze wallet
176 lines (162 loc) • 5.94 kB
JavaScript
import axios from 'axios'
import { Balance, Claims } from '../wallet'
import { ASSET_ID } from '../consts'
import { Fixed8 } from '../utils'
import { networks, httpsOnly, timeout } from '../settings'
import logger from '../logging'
import RPCClient from '../rpc/client'
import { raceToSuccess } from './common'
const log = logger('api')
export const name = 'Kazescan'
var cachedRPC = null
/**
* Returns the appropriate Kazescan endpoint.
* @param {string} net - 'MainNet', 'TestNet' or a custom Kazescan-like url.
* @return {string} - URL
*/
export const getAPIEndpoint = net => {
if (networks[net]) return networks[net].extra.Kazescan
return net
}
/**
* Returns an appropriate RPC endpoint retrieved from a Kazescan endpoint.
* @param {string} net - 'MainNet', 'TestNet' or a custom Kazescan-like url.
* @return {Promise<string>} - URL
*/
export const getRPCEndpoint = net => {
const apiEndpoint = getAPIEndpoint(net)
return axios.get(apiEndpoint + '/v1/get_all_nodes').then(({ data }) => {
let nodes = data.sort((a, b) => b.height - a.height)
if (httpsOnly) nodes = nodes.filter(n => n.url.includes('https://'))
if (nodes.length === 0) throw new Error('No eligible nodes found!')
const heightThreshold = nodes[0].height - 1
const goodNodes = nodes.filter(n => n.height >= heightThreshold)
const urls = goodNodes.map(n => n.url)
if (urls.includes(cachedRPC)) {
return new RPCClient(cachedRPC).ping().then(num => {
if (num <= timeout.ping) return cachedRPC
cachedRPC = null
return getRPCEndpoint(net)
})
}
const clients = urls.map(u => new RPCClient(u))
return raceToSuccess(clients.map(c => c.ping().then(_ => c.net)))
})
.then(fastestUrl => {
cachedRPC = fastestUrl
return fastestUrl
})
}
/**
* Gat balances for an address.
* @param {string} net - 'MainNet', 'TestNet' or a custom Kazescan-like url.
* @param {string} address - Address to check.
* @return {Promise<Balance>}
*/
export const getBalance = (net, address) => {
const apiEndpoint = getAPIEndpoint(net)
return axios.get(apiEndpoint + '/v1/get_balance/' + address).then(res => {
if (res.data.address !== address && res.data.balance === null) return new Balance({ address: res.data.address })
const bal = new Balance({ address: res.data.address, net })
res.data.balance.map(b => {
bal.addAsset(b.asset, {
balance: b.amount,
unspent: parseUnspent(b.unspent)
})
})
log.info(`Retrieved Balance for ${address} from Kazescan ${net}`)
return bal
})
}
/**
* Get claimable amounts for an address.
* @param {string} net - 'MainNet', 'TestNet' or a custom Kazescan-like url.
* @param {string} address - Address to check.
* @return {Promise<Claims>}
*/
export const getClaims = (net, address) => {
const apiEndpoint = getAPIEndpoint(net)
return axios.get(apiEndpoint + '/v1/get_claimable/' + address).then(res => {
if (res.address !== address && res.data.claimable === null) return new Claims({ address: res.data.address })
const claims = parseClaims(res.data.claimable)
log.info(`Retrieved Balance for ${address} from Kazescan ${net}`)
return new Claims({ net, address: res.data.address, claims })
})
}
/**
* Gets the maximum amount of STREAM claimable after spending all KAZE.
* @param {string} net - 'MainNet', 'TestNet' or a custom Kazescan-like url.
* @param {string} address - Address to check.
* @return {Promise<Fixed8>}
*/
export const getMaxClaimAmount = (net, address) => {
const apiEndpoint = getAPIEndpoint(net)
return axios.get(apiEndpoint + '/v1/get_unclaimed/' + address).then(res => {
log.info(
`Retrieved maximum amount of STREAM claimable after spending all KAZE for ${address} from Kazescan ${net}`
)
return new Fixed8(res.data.unclaimed || 0)
})
}
const parseUnspent = unspentArr => {
return unspentArr.map(coin => {
return {
index: coin.n,
txid: coin.txid,
value: coin.value
}
})
}
const parseClaims = claimArr => {
return claimArr.map(c => {
return {
start: new Fixed8(c.start_height),
end: new Fixed8(c.end_height),
index: c.n,
claim: new Fixed8(c.unclaimed),
txid: c.txid,
value: c.value
}
})
}
/**
* Get the current height of the light wallet DB
* @param {string} net - 'MainNet' or 'TestNet'.
* @return {Promise<number>} Current height.
*/
export const getWalletDBHeight = net => {
const apiEndpoint = getAPIEndpoint(net)
return axios.get(apiEndpoint + '/v1/get_height').then(response => {
return parseInt(response.data.height)
})
}
/**
* Get transaction history for an account
* @param {string} net - 'MainNet' or 'TestNet'.
* @param {string} address - Address to check.
* @return {Promise<PastTransaction[]>} A listof PastTransactionPastTransaction[]
*/
export const getTransactionHistory = (net, address) => {
const apiEndpoint = getAPIEndpoint(net)
return axios
.get(apiEndpoint + '/v1/get_last_transactions_by_address/' + address)
.then(response => {
log.info(`Retrieved History for ${address} from Kazescan ${net}`)
return parseTxHistory(response.data, address)
})
}
function parseTxHistory (rawTxs, address) {
return rawTxs.map(tx => {
const vin = tx.vin.filter(i => i.address_hash === address)
const vout = tx.vouts.filter(o => o.address_hash === address)
const change = {
KAZE: vin.filter(i => i.asset === ASSET_ID.KAZE).reduce((p, c) => p.add(c.value), new Fixed8(0)),
STREAM: vout.filter(i => i.asset === ASSET_ID.STREAM).reduce((p, c) => p.add(c.value), new Fixed8(0))
}
return {
txid: tx.txid,
blockHeight: new Fixed8(tx.block_height),
change
}
})
}