bifcore-sdk-nodejs-bop
Version:
bifcore sdk nodejs
506 lines (450 loc) • 14 kB
JavaScript
'use strict'
const is = require('is-type-of')
const long = require('long')
const JSONbig = require('json-bigint')
const BigNumber = require('bignumber.js')
const keypair = require('../keypair')
const errors = require("../exception");
const proto = exports
proto._response = function (obj) {
const data = {
errorCode: obj.error_code || 0,
errorDesc: obj.error_desc || 'Success'
}
if (is.object(obj) && obj.error_code) {
if (obj.error_code === 0) {
data.result = obj.result || {}
} else {
data.errorDesc = obj.error_desc || ''
data.result = {}
}
} else {
data.result = obj
}
return data
}
proto._isEmptyString = function (str) {
if (!is.string(str)) {
throw new Error('str must be a string')
}
return (str.trim().length === 0)
}
proto.getRoute = function getRoute(param) {
let { page, page_size } = param;
let route = `?page=${page}&page_size=${page_size}`;
Object.keys(param).forEach(function (key) {
switch (key) {
case 'bid':
route += `&${key}=${param[key]}`;
break;
case 'hash':
route += `&${key}=${param[key]}`;
break;
case 'tx_id':
route += `?${key}=${param[key]}`;
break;
case 'start_time':
route += `&${key}=${param[key]}`;
break;
case 'end_time':
route += `&${key}=${param[key]}`;
break;
case 'tx_type':
route += `&${key}=${param[key]}`;
break;
case 'ledger_seq':
route += `&${key}=${param[key]}`;
break;
}
});
return route;
}
proto._postData = function (blob, signature) {
const data = {
items: [
{
transaction_blob: blob,
signatures: signature
}
]
}
return JSONbig.stringify(data)
}
proto._isBigNumber = function (object) {
return object instanceof BigNumber ||
(object && object.constructor && object.constructor.name === 'BigNumber')
}
proto._toBigNumber = function (number) {
number = number || 0
//
if (this._isBigNumber(number)) {
return number
}
return new BigNumber(number)
}
proto._stringFromBigNumber = function (number) {
return this._toBigNumber(number).toString(10)
}
proto._verifyValue = function (str) {
const reg = /^[1-9]\d*$/
return (
is.string(str) &&
reg.test(str) &&
long.fromValue(str).greaterThan(0) &&
long.fromValue(str).lessThanOrEqual(long.MAX_VALUE)
)
}
proto._verifyValue2 = function (str) {
const reg = /^[0-9]\d*$/
return (
is.string(str) &&
reg.test(str) &&
long.fromValue(str).greaterThanOrEqual(0) &&
long.fromValue(str).lessThanOrEqual(long.MAX_VALUE)
)
}
proto._isAvailableValue = function (str, from = -1, to = long.MAX_VALUE) {
const reg = /^(0|([1-9]\d*))$/
return (
is.string(str) &&
reg.test(str) &&
long.fromValue(str).greaterThan(from) &&
long.fromValue(str).lessThanOrEqual(to)
)
}
proto._responseData = function (data) {
const errorCode = 0
const errorDesc = 'Success'
return {
errorCode,
errorDesc,
result: data
}
}
proto._responseError = function (message) {
if (!message) {
throw new Error('require message')
}
const errorCode = message.CODE
return {
errorCode,
errorDesc: message.MSG
}
}
proto._isHexString = function (str) {
if ((str === '' || !is.string(str))) {
return false
}
const hexString = Buffer.from(str, 'hex').toString('hex')
return (hexString === str)
}
proto._isString = function (str) {
if (!is.string(str) ||
str.trim().length === 0) {
return false
}
return true
}
proto._isOperation = function (arr) {
let tag = true
if (!is.array(arr) || arr.length === 0) {
tag = false
return tag
}
arr.some(item => {
if (!is.object(item)) {
tag = false
return true
}
if (!item.type || !item.data) {
tag = false
return true
}
})
return tag
}
/**
*
* @param obj
* @param schema
* @returns {boolean}
* @private
*
* eg:
schema: {
required: false,
string: true,
address: true,
numeric: true,
}
*/
proto._validate = function (obj, schema) {
let tag = true
let msg = ''
if (!is.object(obj) || !is.object(schema)) {
tag = false
msg = 'INVALID_NUMBER_OF_ARG'
return {
tag,
msg
}
}
Object.keys(schema).some(item => {
// required is true
if (schema[item].required && is.undefined(obj[item])) {
obj[item] = ''
}
// numeric is true
if (!is.undefined(obj[item]) &&
schema[item].numeric &&
!this._isAvailableValue(obj[item])) {
tag = false
switch (item) {
case 'amount':
msg = 'INVALID_AMOUNT_ERROR'
break
case 'gasPrice':
msg = 'INVALID_GASPRICE_ERROR'
break
case 'feeLimit':
msg = 'INVALID_FEELIMIT_ERROR'
break
case 'ceilLedgerSeq':
msg = 'INVALID_CEILLEDGERSEQ_ERROR'
break
case 'nonce':
msg = 'INVALID_NONCE_ERROR'
break
case 'initBalance':
msg = 'INVALID_INITBALANCE_ERROR'
break
case 'signtureNumber':
msg = 'INVALID_SIGNATURENUMBER_ERROR'
break
case 'totalSupply':
msg = 'INVALID_TOKEN_TOTALSUPPLY_ERROR'
break
case 'tokenAmount':
msg = 'INVALID_TOKEN_AMOUNT_ERROR'
break
default:
msg = 'REQUEST_NULL_ERROR'
}
return true
}
// privateKeys is true
if (!is.undefined(obj[item]) &&
schema[item].privateKeys &&
!keypair.isPrivateKey(obj[item])) {
tag = false
msg = 'PRIVATEKEY_ONE_ERROR'
return true
}
if (!is.undefined(obj[item]) &&
schema[item].privateKey &&
!keypair.isPrivateKey(obj[item])) {
tag = false
msg = 'PRIVATEKEY_NULL_ERROR'
return true
}
// address is true
if (!is.undefined(obj[item]) &&
schema[item].address &&
!keypair.isAddress(obj[item])) {
tag = false
switch (item) {
case 'sourceAddress':
msg = 'INVALID_SOURCEADDRESS_ERROR'
break
case 'destAddress':
msg = 'INVALID_DESTADDRESS_ERROR'
break
case 'issuer':
msg = 'INVALID_ISSUER_ADDRESS_ERROR'
break
case 'address':
msg = 'INVALID_ADDRESS_ERROR'
break
case 'contractAddress':
msg = 'INVALID_CONTRACTADDRESS_ERROR'
break
case 'fromAddress':
msg = 'INVALID_FROMADDRESS_ERROR'
break
case 'spender':
msg = 'INVALID_SPENDER_ERROR'
break
case 'tokenOwner':
msg = 'INVALID_TOKENOWNER_ERRPR'
break
default:
msg = 'INVALID_ARGUMENTS'
}
return true
}
// hex is true
if (!is.undefined(obj[item]) &&
schema[item].hex &&
!this._isHexString(obj[item])) {
tag = false
switch (item) {
case 'metadata':
msg = 'METADATA_NOT_HEX_STRING_ERROR'
break
case 'blob':
msg = 'INVALID_SERIALIZATION_ERROR'
break
default:
msg = 'METADATA_NOT_HEX_STRING_ERROR'
}
return true
}
// string is true
if (!is.undefined(obj[item]) &&
schema[item].string &&
!this._isString(obj[item])) {
tag = false
switch (item) {
case 'from':
msg = 'INVALID_PRITX_FROM_ERROR'
break
case 'to':
msg = 'INVALID_PRITX_TO_ERROR'
break
case 'data':
msg = 'INVALID_LOG_DATA_ERROR'
break
case 'payload':
msg = 'PAYLOAD_EMPTY_ERROR'
break
case 'name':
msg = 'INVALID_TOKEN_NAME_ERROR'
break
case 'symbol':
msg = 'INVALID_TOKEN_SYMBOL_ERROR'
break
case 'key':
msg = 'INVALID_DATAKEY_ERROR'
break
case 'value':
msg = 'INVALID_DATAVALUE_ERROR'
break
default:
msg = 'INVALID_ARGUMENTS'
}
return true
}
})
return {
tag,
msg
}
}
proto._bufToHex = function (buf) {
const utf8Str = buf.toString('utf8')
return Buffer.from(utf8Str, 'utf8').toString('hex')
}
proto._isSignature = function (arr) {
let tag = true
if (!is.array(arr) || arr.length === 0) {
tag = false
return tag
}
arr.some(item => {
if (!is.object(item)) {
tag = false
return true
}
if (!item.signData || !item.publicKey) {
tag = false
return true
}
if (!this._isHexString(item.signData)) {
tag = false
return true
}
if (!keypair.isPublicKey(item.publicKey)) {
tag = false
return true
}
})
return tag
}
proto._bigNumberToString = function (obj, base) {
// setup base
base = base || 10
// check if obj is type object, not an array and does not have BN properties
if (typeof obj === 'object' && obj !== null && !Array.isArray(obj) && !('lessThan' in obj)) {
// move through plain object
Object.keys(obj).forEach(function (key) {
// recurively converty item
obj[key] = proto._bigNumberToString(obj[key], base)
})
}
// obj is an array
if (Array.isArray(obj)) {
// convert items in array
obj = obj.map(function (item) {
// convert item to a string if bignumber
return proto._bigNumberToString(item, base)
})
}
// if obj is number, convert to string
if (typeof obj === 'number') { return obj + '' }
// if not an object bypass
if (typeof obj !== 'object' || obj === null) { return obj }
// if the object to does not have BigNumber properties, bypass
if (!('toString' in obj) || !('lessThan' in obj)) { return obj }
// if object has bignumber properties, convert to string with base
return obj.toString(base)
}
proto._longToInt = function (obj) {
// check if obj is type object, not an array and does not have long properties
if (typeof obj === 'object' && obj !== null && !Array.isArray(obj) && !('low' in obj)) {
// move through plain object
Object.keys(obj).forEach(function (key) {
// recurively converty item
obj[key] = proto._longToInt(obj[key])
})
}
// obj is an array
if (Array.isArray(obj)) {
// convert items in array
obj = obj.map(function (item) {
// convert item to an int if long
return proto._longToInt(item)
})
}
// if not an object bypass
if (typeof obj !== 'object' || obj === null) { return obj }
// if the object to does not have long properties, bypass
if (!('low' in obj)) { return obj }
// if object has long properties, convert to int
return long.fromValue(obj).toNumber()
}
proto._isAvailableVersion = function (str) {
const reg = /^\d+(\.\d+)?$/
return (
is.string(str) &&
reg.test(str) &&
long.fromValue(str).greaterThanOrEqual(0) &&
long.fromValue(str).lessThanOrEqual(long.MAX_VALUE)
)
}
proto._isAvailableBu = function (str) {
const reg = /^(([1-9]\d*)+|0)(\.\d{1,8})?$/
return (
is.string(str) &&
reg.test(str) &&
long.fromValue(str).greaterThanOrEqual(0) &&
long.fromValue(str).lessThanOrEqual(long.MAX_VALUE.divide(Math.pow(10, 8)))
)
}
proto._containsInvalidUnicodeCharacters = function(str){
try {
const encoded = encodeURIComponent(str)
return encoded.length !== str.length
} catch (e) {
return true
}
}