UNPKG

bifcore-sdk-nodejs-bop

Version:
582 lines (554 loc) 22.9 kB
'use strict' const Operation = require('../validate') const errors = require('../exception') const Transaction = require('../transaction') const Query = require('../query') const BigNumber = require('bignumber.js') const keyPair = require('../keypair') const is = require('is-type-of') const config = require('../common/constant') const util = require('../common/util') const Snowflake = require('../common/snowFlakeUtils') const CRYPTO_SM2 = 0x7a const CRYPTO_ED25519 = 0x65 class Account { constructor(options = {}) { this.host = options.host this.apiKey = options.apiKey this.apiSecret= options.apiSecret } /** * Get account base information * @param {String} address * @return {Object} */ async getInfo (address, domainId) { if (domainId != null && domainId !== '' && !util._isAvailableValue(domainId)) { return util._responseError(errors.INVALID_DOMAINID_ERROR) } if (domainId == null || domainId === '') { domainId = config.INIT_ZERO } let options = { host: this.host, apiKey: this.apiKey, apiSecret: this.apiSecret } const regex = /^[A-Z0-9]{32}$/ if (!regex.test(this.apiKey)) { return util._responseError(errors.INVALID_APIKEY_ERROR) } let query = new Query(options) return query.getInfo(address, domainId) }; /** * get account info * @param request * @returns {Promise<{errorDesc: *, errorCode: *}>} */ async getAccount (request = {}) { if (is.array(request) || !is.object(request) || arguments.length === 0) { return util._responseError(errors.REQUEST_NULL_ERROR) } let { address, domainId } = request let info = await this.getInfo(address, domainId) if (info.errorCode === 0) { return util._responseData({ address: info.result.address, balance: info.result.balance, nonce: info.result.nonce }) } if (info.errorCode !== 0 && info.errorCode == config.ERRORCODE) { let infos = { errorCode: info.errorCode, errorDesc: (info.errorDesc == null || info.errorDesc === '') ? 'Account (' + address + ') not exist' : info.errorDesc, result: info.result } return infos } else if (info.errorCode !== 0 && info.errorCode == config.DOMAINID_ERRORCODE) { let domainIdInfos = { errorCode: info.errorCode, errorDesc: (info.errorDesc == null || info.errorDesc === '') ? 'DomainId (' + domainId + ') (' + address + ') not exist' : info.errorDesc, result: info.result } return domainIdInfos } else if (info.errorCode !== 0) { return info } } /** * get account balance * @param request * @returns {Promise<{errorDesc: *, errorCode: *}>} */ async getAccountBalance (request = {}) { if (is.array(request) || !is.object(request) || arguments.length === 0) { return util._responseError(errors.REQUEST_NULL_ERROR) } let { address, domainId } = request let info = await this.getInfo(address, domainId) if (info.errorCode === 0) { return util._responseData({ balance: info.result.balance }) } if (info.errorCode !== 0 && info.errorCode == config.ERRORCODE) { let infos = { errorCode: info.errorCode, errorDesc: (info.errorDesc == null || info.errorDesc === '') ? 'Account (' + address + ') not exist' : info.errorDesc, result: info.result } return infos } else if (info.errorCode !== 0 && info.errorCode == config.DOMAINID_ERRORCODE) { let domainIdInfos = { errorCode: info.errorCode, errorDesc: (info.errorDesc == null || info.errorDesc === '') ? 'DomainId (' + domainId + ') (' + address + ') not exist' : info.errorDesc, result: info.result } return domainIdInfos } else if (info.errorCode !== 0) { return info } } /** * get account privilege * @param request * @returns {Promise<{errorDesc: *, errorCode: *}>} */ async getAccountPriv (request = {}) { if (is.array(request) || !is.object(request) || arguments.length === 0) { return util._responseError(errors.REQUEST_NULL_ERROR) } let { address, domainId } = request let info = await this.getInfo(address, domainId) if (info.errorCode === 0) { return util._responseData({ address: info.result.address, priv: JSON.stringify(info.result.priv) || {} }) } if (info.errorCode !== 0 && info.errorCode == config.ERRORCODE) { let infos = { errorCode: info.errorCode, errorDesc: (info.errorDesc == null || info.errorDesc === '') ? 'Account (' + address + ') not exist' : info.errorDesc, result: info.result } return infos } else if (info.errorCode !== 0 && info.errorCode == config.DOMAINID_ERRORCODE) { let domainIdInfos = { errorCode: info.errorCode, errorDesc: (info.errorDesc == null || info.errorDesc === '') ? 'DomainId (' + domainId + ') (' + address + ') not exist' : info.errorDesc, result: info.result } return domainIdInfos } else if (info.errorCode !== 0) { return info } } /** * get account nonce * @param request * @returns {Promise<{errorDesc: *, errorCode: *}>} */ async getNonce (request = {}) { if (is.array(request) || !is.object(request) || arguments.length === 0) { return util._responseError(errors.REQUEST_NULL_ERROR) } let { address, domainId } = request let info = await this.getInfo(address, domainId) if (info.errorCode === 0) { return util._responseData({ nonce: info.result.nonce }) } if (info.errorCode !== 0 && info.errorCode == config.ERRORCODE) { let infos = { errorCode: info.errorCode, errorDesc: (info.errorDesc == null || info.errorDesc === '') ? 'Account (' + address + ') not exist' : info.errorDesc, result: info.result } return infos } else if (info.errorCode !== 0 && info.errorCode == config.DOMAINID_ERRORCODE) { let domainIdInfos = { errorCode: info.errorCode, errorDesc: (info.errorDesc == null || info.errorDesc === '') ? 'DomainId (' + domainId + ') (' + address + ') not exist' : info.errorDesc, result: info.result } return domainIdInfos } else if (info.errorCode !== 0) { return info } } /** * get account metadatas * @param request * @returns {Promise<{errorDesc: *, errorCode: *}>} */ async getMetadatas (request = {}) { if (is.array(request) || !is.object(request) || arguments.length === 0) { return util._responseError(errors.REQUEST_NULL_ERROR) } let options = { host: this.host, apiKey: this.apiKey, apiSecret: this.apiSecret } const regex = /^[A-Z0-9]{32}$/ if (!regex.test(this.apiKey)) { return util._responseError(errors.INVALID_APIKEY_ERROR) } let query = new Query(options) return query.getMetadatas(request) } /** * create account * @param request * @returns {Promise<{errorDesc: *, errorCode: *}>} */ async createAccount (request = {}) { if (is.array(request) || !is.object(request) || arguments.length === 0) { return util._responseError(errors.REQUEST_NULL_ERROR) } let { sourceAddress, privateKey, ceilLedgerSeq, remarks, destAddress, initBalance, feeLimit, gasPrice, domainId, nonceType } = request if (!util._verifyValue2(initBalance)) { return util._responseError(errors.INVALID_INITBALANCE_ERROR) } if (ceilLedgerSeq != null && ceilLedgerSeq !== '' && !util._isAvailableValue(ceilLedgerSeq)) { return util._responseError(errors.INVALID_CEILLEDGERSEQ_ERROR) } if (feeLimit != null && feeLimit !== '' && !util._isAvailableValue(feeLimit)) { return util._responseError(errors.INVALID_FEELIMIT_ERROR) } if (gasPrice != null && gasPrice !== '' && !util._isAvailableValue(gasPrice)) { return util._responseError(errors.INVALID_GASPRICE_ERROR) } if (domainId != null && domainId !== '' && !util._isAvailableValue(domainId)) { return util._responseError(errors.INVALID_DOMAINID_ERROR) } if(nonceType != null && nonceType !== '' && !(nonceType === '0' || nonceType === '1')) { return util._responseError(errors.INVALID_NONCE_TYPE_ERROR) } if(nonceType == null || nonceType === '') { nonceType = 0 } let operation = new Operation() let data = operation.accountActivateOperation(request) if (data.errorCode !== 0) { return data } let options = { host: this.host, apiKey: this.apiKey, apiSecret: this.apiSecret } if (this.apiSecret === null) { return util._responseError(errors.ITEM_HEADER_MUST_API_SECRET) } const regex = /^[A-Z0-9]{32}$/ if (!regex.test(this.apiKey)) { return util._responseError(errors.INVALID_APIKEY_ERROR) } let transaction = new Transaction(options) if (!keyPair.isAddress(sourceAddress)) { return util._responseError(errors.INVALID_ADDRESS_ERROR) } let createAccOperation = { to: destAddress, initBalance: initBalance } let operations = [createAccOperation] transaction.addOperation('activateAccount', operations) let nonce let maxLedgerSeq // 判断获取blockNumber是否需要接口获取 (目前版本不需要这块业务逻辑调整) let blockNumberFind let query = new Query(options) if(nonceType == '1') { let { result: blockNumber} = await query.getBlockNumber(domainId); blockNumberFind = blockNumber maxLedgerSeq = Number(blockNumber.header.blockNumber) + Number(Snowflake.getDefaultRangeRandom()) nonce = Snowflake.randomLenNum().toString() } else { let nonceResult = await query.getNonce(sourceAddress, domainId) if (nonceResult.errorCode !== 0) { return nonceResult } nonce = nonceResult.result.nonce nonce = new BigNumber(nonce).plus(1).toString(10) } if (feeLimit == null || feeLimit === '') { feeLimit = config.feeLimit } if (gasPrice == null || gasPrice === '') { gasPrice = config.gasPrice } if (domainId == null || domainId === '') { domainId = config.INIT_ZERO } // 获取blockNumber if (ceilLedgerSeq != null && ceilLedgerSeq !== '') { let blockNumber = await this.getBlockNumber(domainId) ceilLedgerSeq = Number(ceilLedgerSeq) + Number(blockNumber.result.header.blockNumber) } let tranactionParameter = { sourceAddress: sourceAddress, nonce: nonce, feeLimit: feeLimit, gasPrice: gasPrice, seqOffset: ceilLedgerSeq, metadata: remarks, domainId: domainId, nonceType: nonceType, maxLedgerSeq: maxLedgerSeq } transaction.buildTransaction(tranactionParameter) let privateKeyArray = [privateKey] transaction.signTransaction(privateKeyArray) const result = await transaction.submitTransaction() if (result.results[0].error_code === 0) { return util._responseData({ hash: result.results[0].hash }) } return util._response(result.results[0]) } /** * set account metadatas * @param request * @returns {Promise<{errorDesc: *, errorCode: *}>} */ async setMetadatas (request = {}) { if (is.array(request) || !is.object(request) || arguments.length === 0) { return util._responseError(errors.REQUEST_NULL_ERROR) } let { sourceAddress, privateKey, remarks, key, value, version, deleteFlag, feeLimit, gasPrice, ceilLedgerSeq, domainId, nonceType } = request if (ceilLedgerSeq != null && ceilLedgerSeq !== '' && !util._isAvailableValue(ceilLedgerSeq)) { return util._responseError(errors.INVALID_CEILLEDGERSEQ_ERROR) } if (feeLimit != null && feeLimit !== '' && !util._isAvailableValue(feeLimit)) { return util._responseError(errors.INVALID_FEELIMIT_ERROR) } if (gasPrice != null && gasPrice !== '' && !util._isAvailableValue(gasPrice)) { return util._responseError(errors.INVALID_GASPRICE_ERROR) } if (domainId != null && domainId !== '' && !util._isAvailableValue(domainId)) { return util._responseError(errors.INVALID_DOMAINID_ERROR) } if(nonceType != null && nonceType !== '' && !(nonceType === '0' || nonceType === '1')) { return util._responseError(errors.INVALID_NONCE_TYPE_ERROR) } if(nonceType == null || nonceType === '') { nonceType = 0 } // 参数校验 let operation = new Operation() let data = operation.accountSetMetadataOperation(request) if (data.errorCode !== 0) { return data } let options = { host: this.host, apiKey: this.apiKey, apiSecret: this.apiSecret } if (this.apiSecret === null) { return util._responseError(errors.ITEM_HEADER_MUST_API_SECRET) } const regex = /^[A-Z0-9]{32}$/ if (!regex.test(this.apiKey)) { return util._responseError(errors.INVALID_APIKEY_ERROR) } let transaction = new Transaction(options) if (!keyPair.isAddress(sourceAddress)) { return util._responseError(errors.INVALID_ADDRESS_ERROR) } let setMetadatas = { key: key, value: value, version: version, deleteFlag: deleteFlag } let operations = [setMetadatas] transaction.addOperation('setMetadata', operations) let nonce let maxLedgerSeq let blockNumberFind let query = new Query(options) if(nonceType == '1') { let {result: blockNumber} = await query.getBlockNumber(domainId) blockNumberFind = blockNumber maxLedgerSeq = Number(blockNumber.header.blockNumber) + Number(Snowflake.getDefaultRangeRandom()) nonce = Snowflake.randomLenNum().toString() } else { let nonceResult = await query.getNonce(sourceAddress, domainId) if (nonceResult.errorCode !== 0) { return nonceResult } nonce = nonceResult.result.nonce nonce = new BigNumber(nonce).plus(1).toString(10) } if (feeLimit == null || feeLimit === '') { feeLimit = config.feeLimit } if (gasPrice == null || gasPrice === '') { gasPrice = config.gasPrice } if (domainId == null || domainId === '') { domainId = config.INIT_ZERO } // 获取blockNumber if (ceilLedgerSeq != null && ceilLedgerSeq !== '') { let blockNumber = await this.getBlockNumber(domainId) ceilLedgerSeq = Number(ceilLedgerSeq) + Number(blockNumber.result.header.blockNumber) } let tranactionParameter = { sourceAddress: sourceAddress, nonce: nonce, feeLimit: feeLimit, gasPrice: gasPrice, metadata: remarks, seqOffset: ceilLedgerSeq, domainId: domainId, nonceType: nonceType, maxLedgerSeq: maxLedgerSeq } transaction.buildTransaction(tranactionParameter) let privateKeyArray = [privateKey] transaction.signTransaction(privateKeyArray) const result = await transaction.submitTransaction() if (result.results[0].error_code === 0) { return util._responseData({ hash: result.results[0].hash }) } return util._response(result.results[0]) } /** * set account privilege * @param request * @returns {Promise<{errorDesc: *, errorCode: *}>} */ async setPrivilege (request = {}) { if (is.array(request) || !is.object(request) || arguments.length === 0) { return util._responseError(errors.REQUEST_NULL_ERROR) } let { sourceAddress, privateKey, txThreshold, signers, typeThresholds, feeLimit, gasPrice, ceilLedgerSeq, remarks, masterWeight, domainId, nonceType } = request if (ceilLedgerSeq != null && ceilLedgerSeq !== '' && !util._isAvailableValue(ceilLedgerSeq)) { return util._responseError(errors.INVALID_CEILLEDGERSEQ_ERROR) } if (feeLimit != null && feeLimit !== '' && !util._isAvailableValue(feeLimit)) { return util._responseError(errors.INVALID_FEELIMIT_ERROR) } if (gasPrice != null && gasPrice !== '' && !util._isAvailableValue(gasPrice)) { return util._responseError(errors.INVALID_GASPRICE_ERROR) } if (domainId != null && domainId !== '' && !util._isAvailableValue(domainId)) { return util._responseError(errors.INVALID_DOMAINID_ERROR) } if (nonceType == null || nonceType === '') { nonceType = config.INIT_ZERO } else if (!(nonceType == '0' || nonceType == '1')) { return util._responseError(errors.INVALID_NONCE_TYPE_ERROR) } // 参数校验 let operation = new Operation() let data = operation.accountSetPrivilegeOperation(request) if (data.errorCode !== 0) { return data } let options = { host: this.host, apiKey: this.apiKey, apiSecret: this.apiSecret } if (this.apiSecret === null) { return util._responseError(errors.ITEM_HEADER_MUST_API_SECRET) } const regex = /^[A-Z0-9]{32}$/ if (!regex.test(this.apiKey)) { return util._responseError(errors.INVALID_APIKEY_ERROR) } let transaction = new Transaction(options) if (!keyPair.isAddress(sourceAddress)) { return util._responseError(errors.INVALID_ADDRESS_ERROR) } let setPrivilege = { txThreshold: txThreshold, signers: signers, typeThresholds: typeThresholds, masterWeight: masterWeight } let operations = [setPrivilege] transaction.addOperation('setPrivilegeOperation', operations) let nonce let maxLedgerSeq let blockNumberFind let query = new Query(options) if(nonceType == '1') { let {result: blockNumber} = await query.getBlockNumber(domainId) blockNumberFind = blockNumber maxLedgerSeq = Number(blockNumber.header.blockNumber) + Number(Snowflake.getDefaultRangeRandom()) nonce = Snowflake.randomLenNum().toString() } else { let nonceResult = await query.getNonce(sourceAddress, domainId) if (nonceResult.errorCode !== 0) { return nonceResult } nonce = nonceResult.result.nonce nonce = new BigNumber(nonce).plus(1).toString(10) } if (feeLimit == null || feeLimit === '') { feeLimit = config.feeLimit } if (gasPrice == null || gasPrice === '') { gasPrice = config.gasPrice } if (domainId == null || domainId === '') { domainId = config.INIT_ZERO } // 获取blockNumber if (ceilLedgerSeq != null && ceilLedgerSeq !== '') { let blockNumber = await this.getBlockNumber(domainId) ceilLedgerSeq = Number(ceilLedgerSeq) + Number(blockNumber.result.header.blockNumber) } let tranactionParameter = { sourceAddress: sourceAddress, nonce: nonce, feeLimit: feeLimit, gasPrice: gasPrice, metadata: remarks, seqOffset: ceilLedgerSeq, domainId: domainId, nonceType: nonceType, maxLedgerSeq: maxLedgerSeq } transaction.buildTransaction(tranactionParameter) let privateKeyArray = [privateKey] transaction.signTransaction(privateKeyArray) const result = await transaction.submitTransaction() if (result.results[0].error_code === 0) { return util._responseData({ hash: result.results[0].hash }) } return util._response(result.results[0]) } /** * getBlockNumber * @param request * @returns {Promise<{errorDesc: *, errorCode: *}>} */ async getBlockNumber (domainId) { let options = { host: this.host, apiKey: this.apiKey, apiSecret:this.apiSecret } let query = new Query(options) return query.getBlockNumber(domainId) } } module.exports = Account module.exports.CRYPTO_SM2 = CRYPTO_SM2 module.exports.CRYPTO_ED25519 = CRYPTO_ED25519