UNPKG

swtc-lib

Version:

websocket access for jingtum blockchain

1,257 lines (1,185 loc) 36.4 kB
import { Account } from "./account" import { EventEmitter } from "events" import { OrderBook } from "./orderbook" import { Request } from "./request" import { Server } from "./server" import { Transaction } from "@swtc/transaction" import LRU from "lru-cache" import sha1 from "sha1" import { IRemoteOptions, IRequestLedgerOptions, IRequestAccountsOptions, IRequestTxOptions, IRequestAccountInfoOptions, IRequestAccountTumsOptions, IRequestAccountRelationsOptions, IRequestAccountOffersOptions, IRequestAccountTxOptions, IRequestOrderBookOptions, IRequestBrokerageOptions, IRequestSignerListOptions } from "./types" import { // IMarker, // IAmount, // ISwtcTxOptions, IPaymentTxOptions, IOfferCreateTxOptions, IOfferCancelTxOptions, IContractInitTxOptions, IContractInvokeTxOptions, IContractDeployTxOptions, IContractCallTxOptions, ISignTxOptions, IAccountSetTxOptions, IRelationTxOptions, ISignerListTxOptions, ISignFirstTxOptions, ISignOtherTxOptions } from "./types" const Wallet = Transaction.Wallet const utils = Transaction.utils // var LEDGER_OPTIONS = ["closed", "header", "current"] function getRelationType(type) { switch (type) { case "trust": return 0 case "authorize": return 1 case "freeze": return 3 default: return null } } /** * main handler for backend system * one remote object one server, not many * options onfiguration Parameters: * { * local_sign: false, // default sign tx in jingtumd * server: 'wss://s.jingtum.com:5020', // only support one server * } * @param options * @constructor */ class Remote extends EventEmitter { public static Wallet: any = Wallet public static Account = Account public static OrderBook = OrderBook public static Transaction: any = Transaction public static utils: any = utils public static XLIB = Wallet.config.XLIB || {} public type public readonly AbiCoder: any = null public readonly Tum3: any = null public readonly _token public readonly _local_sign protected _issuer private _url: string = `ws://${Remote.XLIB.default_ws || "ws.swtclib.ca:5020"}` private _url_failover: string = `ws://${Remote.XLIB.default_ws_failover || "ws-failover.swtclib.ca:5020"}` private _server private _status private _requests private _cache private _paths private _solidity: boolean = false private _timeout: number = 20 * 1000 private _failover: boolean = false constructor(options: IRemoteOptions = { local_sign: true }) { super() const _opts = options || {} if (_opts.hasOwnProperty("timeout")) { const timeout = Number(_opts.timeout) this._timeout = timeout > 5 * 1000 ? timeout : 20 * 1000 } this._local_sign = true if (_opts.solidity) { this._solidity = true try { this.AbiCoder = require("tum3-eth-abi").AbiCoder this.Tum3 = require("swtc-tum3") } catch (error) { throw Error( "install tum3-eth-abi and swtc-tum3 to enable solidity support" ) } } if (!_opts.hasOwnProperty("server")) { this._failover = true } else { if (typeof _opts.server !== "string") { this.type = new TypeError("server config not supplied") return this } this._url = _opts.server } if (_opts.hasOwnProperty("server_failover")) { if (typeof _opts.server_failover !== "string") { this.type = new TypeError("server_failover config not supplied") return this } this._url_failover = _opts.server_failover } if (_opts.failover) { this._failover = true } this._server = new Server(this, this._url) this._status = { ledger_index: 0 } this._requests = {} this._token = options.token || Wallet.token || "swt" this._issuer = options.issuer || Wallet.config.issuer || "jGa9J9TkqtBcUoHe2zqhVFFbgUVED6o9or" this._cache = new LRU({ max: 100, maxAge: 1000 * 60 * 5 }) // 100 size, 5 min this._paths = new LRU({ max: 100, maxAge: 1000 * 60 * 5 }) // 2100 size, 5 min this.on("newListener", type => { if (!this._server.isConnected()) return if (type === "removeListener") return if (type === "transactions") { this.subscribe("transactions").submit() } if (type === "ledger_closed") { this.subscribe("ledger").submit() } }) this.on("removeListener", type => { if (!this._server.isConnected()) return if (type === "transactions") { this.unsubscribe("transactions").submit() } if (type === "ledger_closed") { this.unsubscribe("ledger").submit() } }) } // show instance basic configuration public config() { return { _local_sign: this._local_sign, _failover: this._failover, _url: this._url, _url_failover: this._url_failover, _url_active: this._server._url, _token: this._token, _issuer: this._issuer, _solidity: this._solidity, _timeout: this._timeout } } // makeCurrency and makeAmount public makeCurrency(currency = this._token, issuer = this._issuer) { return Wallet.makeCurrency(currency, issuer) } public makeAmount(value = 1, currency = this._token, issuer = this._issuer) { return Wallet.makeAmount(value, currency, issuer) } /** * connect first on every case * callback(error, result) * @param callback * @returns {*} */ public connect(callback) { if (!this._server) return callback("server not ready") this._server.connect(callback) } public connectPromise() { return new Promise((resolve, reject) => { if (!this._server) return reject(new Error("server not ready")) this._server .connectPromise() .then(result => resolve(result)) .catch(error => { if (!this._failover) { reject(error) } else { if (this._server._url === this._url) { this._server = new Server(this, this._url_failover) } else { this._server = new Server(this, this._url) } this._server .connectPromise() .then(result_failover => resolve(result_failover)) .catch(error_failover => reject(error_failover)) } }) }) } /** * disconnect manual, no reconnect */ public disconnect() { if (!this._server) return this._server.disconnect() } /** * check is remote is connected to jingtumd */ public isConnected() { return this._server.isConnected() } /** * handle message from backend, and dispatch * @param data */ public _handleMessage(e) { let data let try_again = false try { data = JSON.parse(e.data) if (typeof data !== "object") return switch (data.type) { case "ledgerClosed": this._handleLedgerClosed(data) break case "serverStatus": this._handleServerStatus(data) break case "response": this._handleResponse(data) break case "transaction": this._handleTransaction(data) break case "path_find": this._handlePathFind(data) break } } catch (error) { try_again = true } if (try_again) { try { data = JSON.parse(e) if (typeof data !== "object") return switch (data.type) { case "ledgerClosed": this._handleLedgerClosed(data) break case "serverStatus": this._handleServerStatus(data) break case "response": this._handleResponse(data) break case "transaction": this._handleTransaction(data) break case "path_find": this._handlePathFind(data) break } } catch (error) { try_again = false } } } /** * request to server and backend * @param command * @param data * @param filter * @param callback * @private */ public _submit(command, data, filter, callback: any) { const req_id = this._server.sendMessage(command, data) this._requests[req_id] = { command, data, filter, callback } } // ---------------------- info request -------------------- /** * request server info * return version, ledger, state and node id * no option is required * @returns {Request} */ public requestServerInfo() { return new Request(this, "server_info", data => { return { complete_ledgers: data.info.complete_ledgers, ledger: data.info.validated_ledger.hash, public_key: data.info.pubkey_node, state: data.info.server_state, peers: data.info.peers, version: "skywelld-" + data.info.build_version } }) } /** * request peers info * return version, ledger, state and node id * no option is required * @returns {Request} */ public requestPeers() { return new Request(this, "peers", data => { return data }) } /** * request last closed ledger index and hash * @returns {Request} */ public requestLedgerClosed() { return new Request(this, "ledger_closed", data => { return { // fee_base: data.fee_base, ledger_hash: data.ledger_hash, ledger_index: data.ledger_index // reserve_base: data.reserve_base, // reserve_inc: data.reserve_base, // txn_count: data.txn_count, // validated: data.validated_ledgers } }) } /** * get one ledger info * options parameters : { * ledger_index: Number, * ledger_hash: hash, string * } * if no options, return last closed ledger * @param options * @returns {Request} */ public requestLedger(options: IRequestLedgerOptions) { // if (typeof options !== 'object') { // return new Error('invalid options type'); // } const cmd = "ledger" let filter = true const request = new Request(this, cmd, data => { const ledger = data.ledger || data.closed.ledger if (!filter) { return ledger } return { accepted: ledger.accepted, ledger_hash: ledger.hash, ledger_index: ledger.ledger_index, parent_hash: ledger.parent_hash, close_time: ledger.close_time_human, total_coins: ledger.total_coins } }) if (options === null || typeof options !== "object") { request.message.type = new Error("invalid options type") return request } if ( options.ledger_index && !/^[1-9]\d{0,9}$/.test(String(options.ledger_index)) ) { // 支持0-10位数字查询 request.message.ledger_index = new Error("invalid ledger_index") return request } if (options.ledger_index) { request.message.ledger_index = Number(options.ledger_index) } if (utils.isValidHash(options.ledger_hash)) { request.message.ledger_hash = options.ledger_hash } if ("full" in options && typeof options.full === "boolean") { request.message.full = options.full filter = false } if ("expand" in options && typeof options.expand === "boolean") { request.message.expand = options.expand filter = false } if ( "transactions" in options && typeof options.transactions === "boolean" ) { request.message.transactions = options.transactions filter = false } if ("accounts" in options && typeof options.accounts === "boolean") { request.message.accounts = options.accounts filter = false } return request } /* * get all accounts at some ledger_index */ public requestAccounts(options: IRequestAccountsOptions) { const request = new Request(this, "account_count") if (options === null || typeof options !== "object") { request.message.type = new Error("invalid options type") return request } if ( options.ledger_index && !/^[1-9]\d{0,9}$/.test(String(options.ledger_index)) ) { // 支持0-10位数字查询 request.message.ledger_index = new Error("invalid ledger_index") return request } if (options.ledger_index) { request.message.ledger_index = Number(options.ledger_index) } if (utils.isValidHash(options.ledger_hash)) { request.message.ledger_hash = options.ledger_hash } if (options.marker) { request.message.marker = options.marker } return request } /** * for tx command * @param options * options: { * hash: tx hash, string * } * @returns {Request} */ public requestTx(options: IRequestTxOptions) { const request = new Request(this, "tx") if (options === null || typeof options !== "object") { request.message.type = new Error("invalid options type") return request } const hash = options.hash if (!utils.isValidHash(hash)) { request.message.hash = new Error("invalid tx hash") return request } request.message.transaction = hash return request } /** * account info * @param options, options: * account(required): the query account * ledger(option): specify ledger, ledger can be: * ledger_index=xxx, ledger_hash=xxx, or ledger=closed|current|validated * @returns {Request} */ public requestAccountInfo(options: IRequestAccountInfoOptions) { const request = new Request(this) if (options === null || typeof options !== "object") { request.message.type = new Error("invalid options type") return request } return this.__requestAccount("account_info", options, request) } /** * account tums * return account supports currency, including * send currency and receive currency * @param * account(required): the query account * ledger(option): specify ledger, ledger can be: * ledger_index=xxx, ledger_hash=xxx, or ledger=closed|current|validated * no limit * @returns {Request} */ public requestAccountTums(options: IRequestAccountTumsOptions) { const request = new Request(this) if (options === null || typeof options !== "object") { request.message.type = new Error("invalid options type") return request } return this.__requestAccount("account_currencies", options, request) } /** * account relations * @param options * type: relation type * account(required): the query account * ledger(option): specify ledger, ledger can be: * ledger_index=xxx, ledger_hash=xxx, or ledger=closed|current|validated * limit min is 200, * marker for more relations * @returns {Request} */ public requestAccountRelations(options: IRequestAccountRelationsOptions) { const request = new Request(this) if (options === null || typeof options !== "object") { request.message.type = new Error("invalid options type") return request } if (!~Transaction.RelationTypes.indexOf(options.type)) { request.message.relation_type = new Error("invalid realtion type") return request } switch (options.type) { case "trust": return this.__requestAccount("account_lines", options, request) case "authorize": case "freeze": return this.__requestAccount("account_relation", options, request) } request.message.msg = new Error("relation should not go here") return request } /** * account offers * options parameters * @param options * account(required): the query account * ledger(option): specify ledger, ledger can be: * ledger_index=xxx, ledger_hash=xxx, or ledger=closed|current|validated * limit min is 200, marker * @returns {Request} */ public requestAccountOffers(options: IRequestAccountOffersOptions) { const request = new Request(this) if (options === null || typeof options !== "object") { request.message.type = new Error("invalid options type") return request } return this.__requestAccount("account_offers", options, request) } /** * account tx * options parameters * account(required): the query account * ledger(option): specify ledger, ledger can be: * ledger_index=xxx, ledger_hash=xxx, or ledger=closed|current|validated * limit limit output tx record * ledger_min default 0, ledger_max default -1 * marker: {ledger:xxx, seq: x} * descending, if returns recently tx records * @returns {Request} */ public requestAccountTx(options: IRequestAccountTxOptions) { const request = new Request(this, "account_tx", data => { const results = [] for (const data_transaction of data.transactions) { results.push(utils.processTx(data_transaction, options.account)) } data.transactions = results return data }) if (options === null || typeof options !== "object") { request.message.type = new Error("invalid options type") return request } if (!utils.isValidAddress(options.account)) { request.message.account = new Error("account parameter is invalid") return request } request.message.account = options.account if (options.ledger_min && Number(options.ledger_min)) { request.message.ledger_index_min = Number(options.ledger_min) } else { request.message.ledger_index_min = 0 } if (options.ledger_max && Number(options.ledger_max)) { request.message.ledger_index_max = Number(options.ledger_max) } else { request.message.ledger_index_max = -1 } if (options.limit && Number(options.limit)) { request.message.limit = Number(options.limit) } if (options.offset && Number(options.offset)) { request.message.offset = Number(options.offset) } if ( typeof options.marker === "object" && !Number.isNaN(Number(options.marker.ledger)) && !Number.isNaN(Number(options.marker.seq)) ) { request.message.marker = options.marker } if (options.forward && typeof options.forward === "boolean") { // true 正向;false反向 request.message.forward = options.forward } return request } /** * request order book, * options {gets: {currency: , issuer: }, pays: {currency: ', issuer: '}} * for order pair AAA/BBB * to get bids, gets=AAA, pays=BBB * to get asks, gets=BBB, pays=AAA * for bids orders are ordered by price desc * for asks orders are ordered by price asc * TODO format data * @param options * @returns {Request} */ public requestOrderBook(options: IRequestOrderBookOptions) { const request = new Request(this, "book_offers") if (options === null || typeof options !== "object") { request.message.type = new Error("invalid options type") return request } const taker_gets = options.taker_gets || options.pays if (!utils.isValidAmount0(taker_gets)) { request.message.taker_gets = new Error("invalid taker gets amount") return request } const taker_pays = options.taker_pays || options.gets if (!utils.isValidAmount0(taker_pays)) { request.message.taker_pays = new Error("invalid taker pays amount") return request } options.limit = Number(options.limit) if (!options.limit) { options.limit = 300 } request.message.taker_gets = taker_gets request.message.taker_pays = taker_pays request.message.taker = options.taker ? options.taker : Wallet.getAccountOne() request.message.limit = options.limit return request } /* * request brokerage, * @param options * @returns {Request} * */ public requestBrokerage(options: IRequestBrokerageOptions) { const request = new Request(this, "Fee_Info") if (options === null || typeof options !== "object") { request.message.type = new Error("invalid options type") return request } const account = options.account if (!utils.isValidAddress(account)) { request.message.account = new Error("account parameter is invalid") return request } request.message.account = account request.message.ledger_index = "validated" return request } /* * request signerlist, * @param options * @returns {Request} * */ public requestSignerList(options: IRequestSignerListOptions) { const request = new Request(this, "account_objects") if (options === null || typeof options !== "object") { request.message.type = new Error("invalid options type") return request } const account = options.account if (!utils.isValidAddress(account)) { request.message.account = new Error("account parameter is invalid") return request } request.message.account = account return request } // ---------------------- path find request -------------------- /** * @param options * { * account: acccount|from|source, account to find path * destination: destination|to|dst, destiantion account * amount: the amount destination will received * } * @returns {Request} */ public requestPathFind(options) { const request = new Request(this, "path_find", data => { const request2 = new Request(this, "path_find") request2.message.subcommand = "close" request2.submit() const _result = [] for (const item of data.alternatives) { const key = sha1(JSON.stringify(item)) this._paths.set(key, { path: JSON.stringify(item.paths_computed), choice: item.source_amount }) _result.push({ choice: utils.parseAmount(item.source_amount), key }) } return _result }) if (options === null || typeof options !== "object") { request.message.type = new Error("invalid options type") return request } const account = options.account const dest = options.destination const amount = options.amount if (!utils.isValidAddress(account)) { request.message.source_account = new Error("invalid source account") return request } if (!utils.isValidAddress(dest)) { request.message.destination_account = new Error( "invalid destination account" ) return request } if (!utils.isValidAmount(amount)) { request.message.destination_amount = new Error("invalid amount") return request } request.message.subcommand = "create" request.message.source_account = account request.message.destination_account = dest request.message.destination_amount = utils.ToAmount(amount) return request } /** * payment * @param options * source|from|account source account, required * destination|to destination account, required * amount payment amount, required * @returns {Transaction} */ public buildPaymentTx(options: IPaymentTxOptions) { return Transaction.buildPaymentTx(options, this) } public initContract(options: IContractInitTxOptions) { return Transaction.initContractTx(options, this) } public invokeContract(options: IContractInvokeTxOptions) { return Transaction.invokeContractTx(options, this) } public initContractTx(options: IContractInitTxOptions) { return Transaction.initContractTx(options, this) } public invokeContractTx(options: IContractInvokeTxOptions) { return Transaction.invokeContractTx(options, this) } public buildContractInitTx(options: IContractInitTxOptions) { return Transaction.initContractTx(options, this) } public buildContractInvokeTx(options: IContractInvokeTxOptions) { return Transaction.invokeContractTx(options, this) } public buildContractDeployTx(options: IContractDeployTxOptions) { return Transaction.deployContractTx(options, this) } public buildContractCallTx(options: IContractCallTxOptions) { return Transaction.callContractTx(options, this) } public AlethEvent = function(options) { const request = new Request(this, "aleth_eventlog", data => data) if (typeof options !== "object") { request.message.obj = new Error("invalid options type") return request } const des = options.destination const abi = options.abi if (!utils.isValidAddress(des)) { request.message.des = new Error("invalid destination") return request } if (!abi) { request.message.abi = new Error("not found abi") return request } if (!Array.isArray(abi)) { request.message.params = new Error("invalid abi: type error.") return request } this.abi = abi request.message.Destination = des return request } /** * contract * @param options * account, required * amount, required * payload, required * @returns {Transaction} */ public deployContractTx(options: IContractDeployTxOptions) { return Transaction.deployContractTx(options, this) } /** * contract * @param options * account, required * des, required * params, required * @returns {Transaction} */ public callContractTx(options: IContractCallTxOptions) { return Transaction.callContractTx(options, this) } public buildSignTx(options: ISignTxOptions) { return Transaction.buildSignTx(options, this) } /** * Brokerage 设置挂单手续费 * @param options * account, required * mol|molecule, required * den|denominator, required * app, required * amount, required * @returns {Transaction} */ public buildBrokerageTx(options) { return Transaction.buildBrokerageTx(options, this) } /** * add wallet relation set * @param options * type: Transaction.RelationTypes * source|from|account source account, required * limit limt amount, required * quality_out, optional * quality_in, optional * @returns {Transaction} */ public buildRelationTx(options: IRelationTxOptions) { return Transaction.buildRelationTx(options, this) } /** * account information set * @param options * type: Transaction.AccountSetTypes * @returns {Transaction} */ public buildAccountSetTx(options: IAccountSetTxOptions) { return Transaction.buildAccountSetTx(options, this) } /** * offer create * @param options * type: 'Sell' or 'Buy' * source|from|account maker account, required * taker_gets|pays amount to take out, required * taker_pays|gets amount to take in, required * @returns {Transaction} */ public buildOfferCreateTx(options: IOfferCreateTxOptions) { return Transaction.buildOfferCreateTx(options, this) } /** * offer cancel * @param options * source|from|account source account, required * sequence, required * @returns {Transaction} */ public buildOfferCancelTx(options: IOfferCancelTxOptions) { return Transaction.buildOfferCancelTx(options, this) } /** * build multisign tx * @param options * source|from|account source account, required * threshold, required * lists, required * @returns {Transaction} */ public buildSignerListTx(options: ISignerListTxOptions) { return Transaction.buildSignerListTx(options, this) } public buildSignFirstTx(options: ISignFirstTxOptions) { // 首签账号添加SigningPubKey字段 return Transaction.buildSignFirstTx(options) } public buildSignOtherTx(options: ISignOtherTxOptions) { // 其他账号签名只需把返回结果提交回去即可 return Transaction.buildSignOtherTx(options, this) } public buildMultisignedTx(tx_json) { // 提交多重签名 return Transaction.buildMultisignedTx(tx_json, this) } public buildTx(tx_json) { // 通过tx_json创建Transaction对象 return Transaction.buildTx(tx_json, this) } // ---------------------- subscribe -------------------- /** * @param streams * @returns {Request} */ public subscribe(streams) { const request = new Request(this, "subscribe") if (streams) { request.message.streams = Array.isArray(streams) ? streams : [streams] } return request } /** * @param streams * @returns {Request} */ public unsubscribe(streams) { const request = new Request(this, "unsubscribe") if (streams) { request.message.streams = Array.isArray(streams) ? streams : [streams] } return request } /** * stub function for account event * @returns {Account} */ public createAccountStub() { return new Account(this) } /** stub function for order book * * @returns {OrderBook} */ public createOrderBookStub() { return new OrderBook(this) } /** * update server ledger status * TODO * supply data to outside include ledger, reserve and fee * @param data * @private */ private _handleLedgerClosed(data) { if (data.ledger_index > this._status.ledger_index) { this._status.ledger_index = data.ledger_index this._status.ledger_time = data.ledger_time this._status.reserve_base = data.reserve_base this._status.reserve_inc = data.reserve_inc this._status.fee_base = data.fee_base this._status.fee_ref = data.fee_ref this.emit("ledger_closed", data) } } /** * TODO * supply data to outside about server status * @param data * @private */ private _handleServerStatus(data) { // TODO check data format this._updateServerStatus(data) this.emit("server_status", data) } /** * update remote state and server state * @param data * @private */ private _updateServerStatus(data) { this._status.load_base = data.load_base this._status.load_factor = data.load_factor if (data.pubkey_node) { this._status.pubkey_node = data.pubkey_node } this._status.server_status = data.server_status const online = ~Server.onlineStates.indexOf(data.server_status) this._server._setState(online ? "online" : "offline") } /** * handle response by every websocket request * @param data * @private */ private _handleResponse(data) { const req_id = data.id if ( typeof req_id !== "number" || req_id < 0 || req_id > this._requests.length ) { return } const request = this._requests[req_id] // pass process it when null callback if (request.data && request.data.abi) { data.abi = request.data.abi } delete this._requests[req_id] delete data.id // check if data contain server info if (data.result && data.status === "success" && data.result.server_status) { this._updateServerStatus(data.result) } if (this._solidity) { // return to callback if (data.status === "success") { const result = request.filter(data.result) if ( result.ContractState && result.tx_json.TransactionType === "AlethContract" && result.tx_json.Method === 1 ) { // 调用合约时,如果是获取变量,则转换一下 const method = utils.hexToString(result.tx_json.MethodSignature) result.func = method.substring(0, method.indexOf("(")) // 函数名 result.func_parms = method .substring(method.indexOf("(") + 1, method.indexOf(")")) .split(",") // 函数参数 if (result.func_parms.length === 1 && result.func_parms[0] === "") { // 没有参数,返回空数组 result.func_parms = [] } if (result.engine_result === "tesSUCCESS") { const abi = new this.AbiCoder() const types = utils.getTypes(data.abi, result.func) result.ContractState = abi.decodeParameters( types, result.ContractState ) types.forEach((type, i) => { if (type === "address") { const adr = result.ContractState[i].slice(2) const buf = new Buffer(20) buf.write(adr, 0, "hex") result.ContractState[ i ] = Wallet.KeyPair.addressCodec.encodeAddress(buf) } }) } } if (result.AlethLog) { const logValue = [] const item = { address: "", data: {} } const logs = result.AlethLog logs.forEach(log => { const _log = JSON.parse(log.item) const _adr = _log.address.slice(2) const buf = new Buffer(20) buf.write(_adr, 0, "hex") item.address = Wallet.KeyPair.addressCodec.encodeAddress(buf) const abi = new this.AbiCoder() data.abi .filter(json => { return json.type === "event" }) .map(json => { const types = json.inputs.map(input => { return input.type }) const foo = json.name + "(" + types.join(",") + ")" if (abi.encodeEventSignature(foo) === _log.topics[0]) { const data2 = abi.decodeLog( json.inputs, _log.data, _log.topics ) json.inputs.forEach((input, i) => { if (input.type === "address") { const _adr2 = data2[i].slice(2) const buf2 = new Buffer(20) buf2.write(_adr2, 0, "hex") item.data[i] = Wallet.KeyPair.addressCodec.encodeAddress( buf2 ) } else { item.data[i] = data2[i] } }) } }) logValue.push(item) }) result.AlethLog = logValue } request && request.callback(null, result) } else if (data.status === "error") { request && request.callback(data.error_message || data.error_exception) } } else { if (data.status === "success") { const result = request.filter(data.result) request && request.callback(null, result) } else if (data.status === "error") { request && request.callback(data.error_message || data.error_exception) } } } /** * handle transaction type response * TODO supply more friendly transaction data * @param data * @private */ private _handleTransaction(data) { const tx = data.transaction.hash if (this._cache.get(tx)) return this._cache.set(tx, 1) this.emit("transactions", data) } /** * emit path find date to other * TODO supply more friendly data * @param data * @private */ private _handlePathFind(data) { this.emit("path_find", data) } /** * request account info, internal function * @param type * @param options * @returns {Request} * @private */ private __requestAccount(type, options, request) { // var request = new Request(this, type, filter); request._command = type const account = options.account const ledger = options.ledger const peer = options.peer let limit = options.limit const marker = options.marker // if (marker && (Number(ledger) <= 0 || !utils.isValidHash(ledger))) { // throw new Error('marker needs a ledger_index or ledger_hash'); // } request.message.relation_type = getRelationType(options.type) if (account) { if (!utils.isValidAddress(account)) { request.message.account = new Error("invalid account") return request } else { request.message.account = account } } request.selectLedger(ledger) if (peer && utils.isValidAddress(peer)) { request.message.peer = peer } if (Number(limit)) { limit = Number(limit) if (limit < 0) limit = 0 if (limit > 1e9) limit = 1e9 request.message.limit = limit } if (marker) { request.message.marker = marker } return request } } export { Remote }