Jump to content
Professor Hantzen

Multiple Ripple balances viewer in node.js

Recommended Posts

'use strict';
const RippleAPI = require('ripple-lib').RippleAPI;
const api = new RippleAPI({server: 'wss://s1.ripple.com:443'});

const acntA = 'r**************1';
const acntB = 'r**************2';
const acntC = 'r**************3';
const acntD = 'r**************4';
const acntE = 'r**************5';
const acntF = 'r**************6';

var myStash = [acntF, acntA, acntB, acntC, acntD, acntE];

api.connect().then(() => {

    for (var i = 0; i < myStash.length; i++) {
        var acnt = myStash;
        api.getBalances(acnt).then(balances => {
            console.log(JSON.stringify(balances, null, 2));
        });
    }

});

Edited by Duke67

Share this post


Link to post
Share on other sites
1 hour ago, Duke67 said:

'use strict';

Sure, but I'm not a fan of ripple-lib/rippleAPI - it's changed so much it's been a nightmare to develop with, and ripple-lib in particular was very bloated (not sure on RippleAPI?).  I run latency and memory sensitive applications mostly, so I tend to roll everything myself with the rippled websocket interface - it's about as fast and lean as you can get, hasn't changed in the past four years and requires only a single websocket. A little more coding is required, but I'm used to it. :)

Share this post


Link to post
Share on other sites

Also, the main purpose of my script was to format the output to be more readable than raw JSON.  It can also output in CSV format for importing into spreadsheet.

Out of interest - why do you define the accounts separately and then build an array from them?  Couldn't you just:

Quote

'use strict';

const RippleAPI = require('ripple-lib').RippleAPI;

const api = new RippleAPI({server: 'wss://s1.ripple.com:443'});

var myStash = [
    'r**************1', // acntA
    'r**************2', // acntB
    'r**************3', // etc
    'r**************4'
];

api.connect().then(() => {
    for (var index = 0; index < myStash.length; index++) {
        
        var acnt = myStash[index];
        api.getBalances(acnt).then(balances => {
            
            console.log(JSON.stringify(balances, null, 2));
        
        });
    
    }
});

 

And I believe you missed the [index] on myStash in the for loop (fixed above - had to change the variable name as the forum thinks i is a code for italics). It also doesn't close the connection, but I'll leave that fix for someone who loves nested asynchronous javascript promises... ;)

Edited by Professor Hantzen

Share this post


Link to post
Share on other sites

For tax purposes and to get a quick overview of my accounts and to get to learn the promisses stuff in nodejs I once created the following script. It makes use of the data-api to be able to also get historical data.

You can use it as follows (if you name the script 'totals'):  totals [date=<dd-mm-yyyy>] [time=<hh:mm:ss>] [account=<account_list>]

Quote

#! /usr/local/bin/node

'use strict'

var accounts =
[
  "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
  "rGSRqpUQAschCY5rdoRAXnnCvoGpq5toZ1"
]

const https = require('https')

var emptyAccounts = new Set()

var dd = new Date()

try {
  process.argv.forEach(arg => {
    let [param, value] = arg.split("=")
    switch(param) {
      case 'date':
        let [D,M,Y] = value.split("-")
        dd.setFullYear(Y)
        dd.setMonth(M-1)
        dd.setDate(D)
        break
      case 'time':
        let [hh,mm,ss] = value.split(":")
        dd.setHours(hh)
        dd.setMinutes(mm)
        dd.setSeconds(ss)
        break
      case 'account':
        if (value !== 'all') {
          accounts = value.split(',')
        }
        break
      default:
        if ((process.argv[0] !== param) && (process.argv[1] !== param)) {
          throw(`Unknown keyword '${param}'`)
        }
    }
  })
}
catch(e) {
  console.error(e)
  console.error(`Usage: ${process.argv[0]} ${process.argv[1]} [date=<dd-mm-yyyy>] [time=<hh:mm:ss>] [accounts=<file>]`)
  process.exit(1)
}

var dateTime = dd.toISOString().substring(0,19) + 'Z'

function getURL(url) {
  return new Promise((resolve, reject) => {
    https.get(url, res => {
      var body = ''
      res.on('data', chunk => {
        body += chunk
      })
      res.on('end', () => {
        try {
          resolve(JSON.parse(body))
        }
        catch(e) {
          reject(Error(`Unable to parse to JSON: ${e}\n${body}`))
        }
      })
    }).on('error', err => {
      reject(Error(`Retrieving "${url}": ${err.message}`))
    })
  })
}


function getLedger(date) {
  return getURL('https://data.ripple.com/v2/ledgers/' + date).then(response => {
    if (response.result === 'error') {
      throw(Error(`Getting ledger: ${response.message}`))
    } else {
      return(response.ledger.seqNum)
    }
  })
}


function getBalances(account, sequence, retry = 2) {
  return getURL('https://data.ripple.com/v2/accounts/' + account + '/balances?ledger_index=' + sequence).then(response => {
    if (response.result === 'error') {
      // no balances found, account does not exist yet?
      if (retry > 0) {
        // try again
        return getBalances(account, sequence, --retry)
      } else {
        emptyAccounts.add(account)
        return []
      }
    } else {
      return response.balances
    }
  })
}


function getValueInXRP(amount, currency, issuer, sequence, retry = 2) {
  if (currency === 'XRP') {
    var URL = 'https://data.ripple.com/v2/normalize?amount=' + amount + '&currency=' + currency + '&sequence=' + sequence
  } else {
    var URL = 'https://data.ripple.com/v2/normalize?amount=' + amount + '&currency=' + currency + '&sequence=' + sequence + '&issuer=' + issuer
  }

  return getURL(URL).then(response => {
    if (response.result === 'error') {
      // no value found, currency doesn't exit yet?
      if (retry > 0) {
        // try again
        return getValueInXRP(amount, currency, issuer, sequence, --retry)
      } else {
        console.log("huh?")
        return 0
      }
    } else {
      return parseFloat(response.converted)
    }
  })
}


function showResult(result, XRPresult, totalXRP, USDrate, EURrate) {
  console.log("----------------------------------")
  console.log(dd.toString().split('(')[0])
  console.log("----------------------------------")

  accounts.sort().forEach(account => {
    if (emptyAccounts.has(account)) account = account + ' <== no balances returned'
    console.log(account)
  })

  console.log("----------------------------------")

  Object.keys(result).sort().forEach(key => {
    console.log(`- ${key} : ${result[key].toPrecision(7)}`)
  })

  console.log("----------------------------------")
  console.log(`Total in XRP: ${totalXRP.toFixed(0)}`)
  console.log(`Total in USD: ${(totalXRP / USDrate).toFixed(2)}`)
  console.log(`Total in EUR: ${(totalXRP / EURrate).toFixed(2)}`)
  console.log("----------------------------------")
}


getLedger(dateTime).then(sequence => {
  let result = {}
  let XRPresult = {}
  let totalXRP = 0
  let getUSDrateURL = 'https://data.ripple.com/v2/exchange_rates/USD+rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B/XRP?date=' + dd.toISOString()
  let USDrate = 0
  let getEURrateURL = 'https://data.ripple.com/v2/exchange_rates/EUR+rhub8VRN55s94qWKDv6jmDy1pUykJzF3wq/XRP?date=' + dd.toISOString()
  let EURrate = 0

  return Promise.all(
    accounts.map(account => {
      return getBalances(account, sequence).then(balances => {
        return Promise.all(
          balances.map(balance => {
            if (result[balance.currency] === undefined) {
              if (parseFloat(balance.value) != 0) {
                result[balance.currency] = parseFloat(balance.value)
                return getValueInXRP(balance.value, balance.currency, balance.counterparty, sequence).then(valueInXRP => {
                  XRPresult[balance.currency] = valueInXRP
                  totalXRP += valueInXRP
                })
              }
            } else {
              result[balance.currency] += parseFloat(balance.value)
              return getValueInXRP(balance.value, balance.currency, balance.counterparty, sequence).then(valueInXRP => {
                XRPresult[balance.currency] += valueInXRP
                totalXRP += valueInXRP
              })
            }
          })
        )
      })
    }).concat(
      getURL(getUSDrateURL).then(response => { USDrate = parseFloat(response.rate) }),
      getURL(getEURrateURL).then(response => { EURrate = parseFloat(response.rate) })
    )
  ).then(() => {
      return showResult(result, XRPresult, totalXRP, USDrate, EURrate)
  })
}).catch(console.error)

 

Edited by jn_r

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...