import { Big } from "big.js" ; import { unMarshalBinaryLengthPrefixed , unMarshalBinaryBare } from "../amino" ; import { NETWORK_PREFIX_MAPPING } from "../client" ; import * as crypto from "../crypto" ; import Transaction from "../tx" ; import { Token , AppAccount , OpenOrder , TradingPair , OrderBook , TokenOfList , TokenBalance , Coin , AminoPrefix , abciQueryResponseResult , StdTx , ResponseDeliverTx , } from "../types" ; import { validateSymbol , validateTradingPair , validateOffsetLimit , convertObjectArrayNum , getMsgByAminoPrefix , } from "../utils" ; import BaseRpc from "./baseRpc" ; /**
 * The Binance Chain Node rpc client
 */ class RpcClient extends BaseRpc { private netWork : keyof typeof NETWORK_PREFIX_MAPPING ; param { String } uriString param { String } netWork constructor ( uriString = "localhost:27146" , netWork ) { super ( uriString ) ; this . netWork = netWork || "mainnet" ; } param { Transaction } signedTx return { Promise } async broadcastDelegate ( signedTx ) { const encoded = signedTx . serialize ( ) ; const res = await this . broadcastTxSync ( { tx : Buffer . from ( encoded , "hex" ) , } ) ; if ( `${ res . code }` === "0" ) { return res ; } else { throw new Error ( `broadcastDelegate: non-zero status code ${ res . code }` ) ; } } getBech32Prefix ( ) { if ( this . netWork === "mainnet" ) { return "bnb" ; } if ( this . netWork === "testnet" ) { return "tbnb" ; } return "" ; } param { String } symbol returns { Object } async getTokenInfo ( symbol ) { validateSymbol ( symbol ) ; const path = "/tokens/info/" + symbol ; const res = await this . abciQuery ( { path } ) ; const bytes = Buffer . from ( res . response . value , "base64" ) ; const tokenInfo = new Token ( ) ; unMarshalBinaryLengthPrefixed ( bytes , tokenInfo ) ; const bech32Prefix = this . getBech32Prefix ( ) ; const ownerAddress = crypto . encodeAddress ( tokenInfo . owner , bech32Prefix ) ; delete tokenInfo . aminoPrefix ; return { ... tokenInfo , owner : ownerAddress } ; } param { Number } offset param { Number } limit returns { Array } async listAllTokens ( offset , limit ) { validateOffsetLimit ( offset , limit ) ; const path = `tokens/list/${ offset }/${ limit }` ; const res = await this . abciQuery ( { path } ) ; const bytes = Buffer . from ( res . response . value , "base64" ) ; const tokenArr = [ new TokenOfList ( ) ] ; const { val : tokenList } = unMarshalBinaryLengthPrefixed ( bytes , tokenArr ) ; unMarshalBinaryLengthPrefixed ( bytes , tokenList ) ; return tokenList . map ( ( item ) => ( { ... item , owner : crypto . encodeAddress ( item . owner , this . getBech32Prefix ( ) ) , } ) ) ; } param { String } address returns { Object } async getAccount ( address ) { const res = await this . abciQuery ( { path : `/account/${ address }` , } ) ; const accountInfo = new AppAccount ( ) ; const bytes = Buffer . from ( res . response . value , "base64" ) ; unMarshalBinaryBare ( bytes , accountInfo ) ; const bech32Prefix = this . getBech32Prefix ( ) ; return { name : accountInfo . name , locked : accountInfo . locked , frozen : accountInfo . frozen , base : { ... accountInfo . base , address : crypto . encodeAddress ( accountInfo . base . address , bech32Prefix ) , } , } ; } param { Array } balances async getBalances ( address ) { const account = await this . getAccount ( address ) ; let coins = [ ] ; const balances = [ ] ; if ( account ) { coins = ( account . base && account . base . coins ) || [ ] ; convertObjectArrayNum < any > ( coins , [ "amount" ] ) ; convertObjectArrayNum < any > ( account . locked , [ "amount" ] ) ; convertObjectArrayNum < any > ( account . frozen , [ "amount" ] ) ; } coins . forEach ( ( item ) => { const locked = account . locked . find ( ( lockedItem ) => item . denom === lockedItem . denom ) || { } ; const frozen = account . frozen . find ( ( frozenItem ) => item . denom === frozenItem . denom ) || { } ; const bal = new TokenBalance ( ) ; bal . symbol = item . denom ; bal . free = + new Big ( item . amount ) . toString ( ) ; bal . locked = locked . amount || 0 ; bal . frozen = frozen . amount || 0 ; balances . push ( bal ) ; } ) ; return balances ; } param { String } address param { String } symbol returns { Object } async getBalance ( address , symbol ) { validateSymbol ( symbol ) ; const balances = await this . getBalances ( address ) ; const bal = balances . find ( ( item ) => item . symbol . toUpperCase ( ) === symbol . toUpperCase ( ) ) ; return bal ; } param { String } address param { String } symbol returns { Object } async getOpenOrders ( address , symbol ) { const path = `/dex/openorders/${ symbol }/${ address }` ; const res = await this . abciQuery ( { path } ) ; const bytes = Buffer . from ( res . response . value , "base64" ) ; const result = [ new OpenOrder ( ) ] ; const { val : openOrders } = unMarshalBinaryLengthPrefixed ( bytes , result ) ; convertObjectArrayNum ( openOrders , [ "price" , "quantity" , "cumQty" ] ) ; return openOrders ; } param { Number } offset param { Number } limit returns { Array } async getTradingPairs ( offset , limit ) { validateOffsetLimit ( offset , limit ) ; const path = `/dex/pairs/${ offset }/${ limit }` ; const res = await this . abciQuery ( { path } ) ; const bytes = Buffer . from ( res . response . value , "base64" ) ; const result = [ new TradingPair ( ) ] ; const { val : tradingPairs } = unMarshalBinaryLengthPrefixed ( bytes , result ) ; convertObjectArrayNum ( tradingPairs , [ "list_price" , "tick_size" , "lot_size" ] ) ; return tradingPairs ; } param { String } tradePair returns { Array } async getDepth ( tradePair ) { validateTradingPair ( tradePair ) ; const path = `dex/orderbook/${ tradePair }` ; const res = await this . abciQuery ( { path } ) ; const bytes = Buffer . from ( res . response . value , "base64" ) ; const result = new OrderBook ( ) ; const { val : depth } = unMarshalBinaryLengthPrefixed ( bytes , result ) ; convertObjectArrayNum ( depth . levels , [ "buyQty" , "buyPrice" , "sellQty" , "sellPrice" , ] ) ; return depth ; } async getTxByHash ( hash , prove = true ) { if ( ! Buffer . isBuffer ( hash ) ) { hash = Buffer . from ( hash , "hex" ) ; } const res = await this . tx ( { hash , prove , } ) ; const txBytes = Buffer . from ( res . tx , "base64" ) ; const msgAminoPrefix = txBytes . slice ( 8 , 12 ) . toString ( "hex" ) ; const msgType = getMsgByAminoPrefix ( msgAminoPrefix ) ; const type = { msg : [ msgType . defaultMsg ( ) ] , signatures : [ { pub_key : Buffer . from ( "" ) , signature : Buffer . from ( "" ) , account_number : 0 , sequence : 0 , } , ] , memo : "" , source : 0 , data : "" , aminoPrefix : AminoPrefix . StdTx , } ; const { val : result } = unMarshalBinaryLengthPrefixed ( txBytes , type ) ; const txResult = this . parseTxResult ( res . tx_result ) ; return { ... res , tx : result , tx_result : txResult } ; } private parseTxResult ( txResult ) { if ( txResult . data ) { txResult . data = Buffer . from ( txResult . data , "base64" ) . toString ( ) ; } if ( txResult . events && txResult . events . length > 0 ) { for ( let i = 0 ; i < txResult . events . length ; i ++ ) { const event = txResult . events [ i ] ; if ( event . attributes && event . attributes . length > 0 ) { event . attributes = event . attributes . map ( ( item ) => ( { key : Buffer . from ( item . key , "base64" ) . toString ( ) , value : Buffer . from ( item . value , "base64" ) . toString ( ) , } ) ) ; } } } if ( txResult . tags && txResult . tags . length > 0 ) { txResult . tags = txResult . tags . map ( ( item ) => ( { key : Buffer . from ( item . key , "base64" ) . toString ( ) , value : Buffer . from ( item . value , "base64" ) . toString ( ) , } ) ) ; } return { ... txResult } ; } } export default RpcClient ;