diff --git a/index.js b/index.js index 0c4b6545..0760c084 100644 --- a/index.js +++ b/index.js @@ -1,8 +1,15 @@ +const api = require("./lib/api"); +const auth = require("./lib/auth"); +const broadcast = require("./lib/broadcast"); +const formatter = require("./lib/formatter")(api); +const memo = require("./lib/auth/memo"); +const config = require("./lib/config"); + module.exports = { - api: require('./lib/api'), - auth: require('./lib/auth'), - broadcast: require('./lib/broadcast'), - formatter: require('./lib/formatter'), - memo: require('./lib/auth/memo'), - config: require('./lib/config'), + api: api, + auth: auth, + broadcast: broadcast, + formatter: formatter, + memo: memo, + config: config }; diff --git a/package.json b/package.json index dbb1ada6..e7773b9d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "steem", - "version": "0.5.14", + "version": "0.5.15-beta.1", "description": "Steem.js the JavaScript API for Steem blockchain", "main": "index.js", "scripts": { diff --git a/src/broadcast/index.js b/src/broadcast/index.js index 5d8b56d3..9ace415e 100644 --- a/src/broadcast/index.js +++ b/src/broadcast/index.js @@ -2,13 +2,14 @@ import Promise from 'bluebird'; import newDebug from 'debug'; import noop from 'lodash/noop'; -import formatter from '../formatter'; +import formatterFactory from '../formatter'; import operations from './operations.json'; import steemApi from '../api'; import steemAuth from '../auth'; import { camelCase } from '../util'; const debug = newDebug('steem:broadcast'); +const formatter = formatterFactory(steemApi); const steemBroadcast = {}; diff --git a/src/browser.js b/src/browser.js index 1669fd12..8d223e64 100644 --- a/src/browser.js +++ b/src/browser.js @@ -1,16 +1,22 @@ +const api = require("./api"); +const auth = require("./auth"); +const broadcast = require("./broadcast"); +const config = require("./config"); +const formatter = require("./formatter")(api); + const steem = { - api: require('./api'), - auth: require('./auth'), - broadcast: require('./broadcast'), - config: require('./config'), - formatter: require('./formatter'), + api, + auth, + broadcast, + config, + formatter }; -if (typeof window !== 'undefined') { +if (typeof window !== "undefined") { window.steem = steem; } -if (typeof global !== 'undefined') { +if (typeof global !== "undefined") { global.steem = steem; } diff --git a/src/formatter.js b/src/formatter.js index 31dde36e..809cb29e 100644 --- a/src/formatter.js +++ b/src/formatter.js @@ -1,34 +1,190 @@ -module.exports = { - reputation: function (reputation) { - if (reputation == null) return reputation; - reputation = parseInt(reputation); - var rep = String(reputation); - var neg = rep.charAt(0) === '-'; - rep = neg ? rep.substring(1) : rep; - var str = rep; - var leadingDigits = parseInt(str.substring(0, 4)); - var log = Math.log(leadingDigits) / Math.log(10); - var n = str.length - 1; - var out = n + (log - parseInt(log)); - if (isNaN(out)) out = 0; - out = Math.max(out - 9, 0); - out = (neg ? -1 : 1) * out; - out = (out * 9) + 25; - out = parseInt(out); - return out; - }, - - vestToSteem: function (vestingShares, totalVestingShares, totalVestingFundSteem) { - return parseFloat(totalVestingFundSteem) * (parseFloat(vestingShares) / parseFloat(totalVestingShares)); - }, - - commentPermlink: function (parentAuthor, parentPermlink) { - var timeStr = new Date().toISOString().replace(/[^a-zA-Z0-9]+/g, '').toLowerCase(); - parentPermlink = parentPermlink.replace(/(-\d{8}t\d{9}z)/g, ''); - return 're-' + parentAuthor + '-' + parentPermlink + '-' + timeStr; - }, - - amount: function (amount, asset) { - return amount.toFixed(3) + ' ' + asset; - }, +import get from "lodash/get"; + +module.exports = steemAPI => { + function numberWithCommas(x) { + return x.replace(/\B(?=(\d{3})+(?!\d))/g, ","); + } + + function vestingSteem(account, gprops) { + const vests = parseFloat(account.vesting_shares.split(" ")[0]); + const total_vests = parseFloat(gprops.total_vesting_shares.split(" ")[0]); + const total_vest_steem = parseFloat( + gprops.total_vesting_fund_steem.split(" ")[0] + ); + const vesting_steemf = total_vest_steem * (vests / total_vests); + return vesting_steemf; + } + + function processOrders(open_orders, assetPrecision) { + const sbdOrders = !open_orders + ? 0 + : open_orders.reduce((o, order) => { + if (order.sell_price.base.indexOf("SBD") !== -1) { + o += order.for_sale; + } + return o; + }, 0) / assetPrecision; + + const steemOrders = !open_orders + ? 0 + : open_orders.reduce((o, order) => { + if (order.sell_price.base.indexOf("STEEM") !== -1) { + o += order.for_sale; + } + return o; + }, 0) / assetPrecision; + + return { steemOrders, sbdOrders }; + } + + function calculateSaving(savings_withdraws) { + let savings_pending = 0; + let savings_sbd_pending = 0; + savings_withdraws.forEach(withdraw => { + const [amount, asset] = withdraw.amount.split(" "); + if (asset === "STEEM") savings_pending += parseFloat(amount); + else { + if (asset === "SBD") savings_sbd_pending += parseFloat(amount); + } + }); + return { savings_pending, savings_sbd_pending }; + } + + return { + reputation: function(reputation) { + if (reputation == null) return reputation; + reputation = parseInt(reputation); + let rep = String(reputation); + const neg = rep.charAt(0) === "-"; + rep = neg ? rep.substring(1) : rep; + const str = rep; + const leadingDigits = parseInt(str.substring(0, 4)); + const log = Math.log(leadingDigits) / Math.log(10); + const n = str.length - 1; + let out = n + (log - parseInt(log)); + if (isNaN(out)) out = 0; + out = Math.max(out - 9, 0); + out = (neg ? -1 : 1) * out; + out = out * 9 + 25; + out = parseInt(out); + return out; + }, + + vestToSteem: function( + vestingShares, + totalVestingShares, + totalVestingFundSteem + ) { + return ( + parseFloat(totalVestingFundSteem) * + (parseFloat(vestingShares) / parseFloat(totalVestingShares)) + ); + }, + + commentPermlink: function(parentAuthor, parentPermlink) { + const timeStr = new Date() + .toISOString() + .replace(/[^a-zA-Z0-9]+/g, "") + .toLowerCase(); + parentPermlink = parentPermlink.replace(/(-\d{8}t\d{9}z)/g, ""); + return "re-" + parentAuthor + "-" + parentPermlink + "-" + timeStr; + }, + + amount: function(amount, asset) { + return amount.toFixed(3) + " " + asset; + }, + numberWithCommas, + vestingSteem, + estimateAccountValue: function estimateAccountValue( + account, + { gprops, feed_price, open_orders, savings_withdraws, vesting_steem } = {} + ) { + const promises = []; + const username = account.name; + const assetPrecision = 1000; + let orders, savings; + + if (!vesting_steem || !feed_price) { + if (!gprops || !feed_price) { + promises.push( + steemAPI.getStateAsync(`/@{username}`).then(data => { + gprops = data.props; + feed_price = data.feed_price; + vesting_steem = vestingSteem(account, gprops); + }) + ); + } else { + vesting_steem = vestingSteem(account, gprops); + } + } + + if (!open_orders) { + promises.push( + steemAPI.getOpenOrdersAsync(username).then(open_orders => { + orders = processOrders(open_orders, assetPrecision); + }) + ); + } else { + orders = processOrders(open_orders, assetPrecision); + } + + if (!savings_withdraws) { + promises.push( + steemAPI + .getSavingsWithdrawFromAsync(username) + .then(savings_withdraws => { + savings = calculateSaving(savings_withdraws); + }) + ); + } else { + savings = calculateSaving(savings_withdraws); + } + + return Promise.all(promises).then(() => { + let price_per_steem = undefined; + const { base, quote } = feed_price; + if (/ SBD$/.test(base) && / STEEM$/.test(quote)) + price_per_steem = parseFloat(base.split(" ")[0]); + const savings_balance = account.savings_balance; + const savings_sbd_balance = account.savings_sbd_balance; + const balance_steem = parseFloat(account.balance.split(" ")[0]); + const saving_balance_steem = parseFloat(savings_balance.split(" ")[0]); + const sbd_balance = parseFloat(account.sbd_balance); + const sbd_balance_savings = parseFloat( + savings_sbd_balance.split(" ")[0] + ); + + let conversionValue = 0; + const currentTime = new Date().getTime(); + (account.other_history || []).reduce((out, item) => { + if (get(item, [1, "op", 0], "") !== "convert") return out; + + const timestamp = new Date(get(item, [1, "timestamp"])).getTime(); + const finishTime = timestamp + 86400000 * 3.5; // add 3.5day conversion delay + if (finishTime < currentTime) return out; + + const amount = parseFloat( + get(item, [1, "op", 1, "amount"]).replace(" SBD", "") + ); + conversionValue += amount; + }, []); + + const total_sbd = + sbd_balance + + sbd_balance_savings + + savings.savings_sbd_pending + + orders.sbdOrders + + conversionValue; + + const total_steem = + vesting_steem + + balance_steem + + saving_balance_steem + + savings.savings_pending + + orders.steemOrders; + + return (total_steem * price_per_steem + total_sbd).toFixed(2); + }); + } + }; }; diff --git a/test/broadcast.test.js b/test/broadcast.test.js index eb3b7935..f95cde30 100644 --- a/test/broadcast.test.js +++ b/test/broadcast.test.js @@ -2,7 +2,6 @@ import Promise from 'bluebird'; import should from 'should'; import steemAuth from '../src/auth'; import steemBroadcast from '../src/broadcast'; -import steemFormatter from '../src/formatter'; import packageJson from '../package.json'; const username = process.env.STEEM_USERNAME || 'guest123';