diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..a49b1bef --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,31 @@ +name: run-test-unit + +on: + push: + branches: + - 'master' + pull_request: + types: [opened, reopened, synchronize] + workflow_dispatch: + +jobs: + node6: + runs-on: ubuntu-latest + steps: + - + name: Checkout + uses: actions/checkout@v4 + - + name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - + name: Build to run test unit + uses: docker/build-push-action@v4 + with: + context: . + file: node-6.dockerfile + push: false + tags: test diff --git a/README.md b/README.md index 818ca843..d444b67e 100644 --- a/README.md +++ b/README.md @@ -42,9 +42,9 @@ steem.api.getAccounts(['ned', 'dan'], function(err, response){ ``` ## CDN -https://cdn.steemjs.com/lib/latest/steem.min.js
+https://cdn.jsdelivr.net/npm/steem/dist/steem.min.js
```html - + ``` ## Webpack @@ -58,8 +58,6 @@ $ npm install steem --save ## RPC Servers https://api.steemit.com By Default
-https://node.steem.ws
-https://this.piston.rocks
## Examples ### Broadcast Vote @@ -92,8 +90,22 @@ var reputation = steem.formatter.reputation(user.reputation); console.log(reputation); ``` +### Steem Testnet +Steem-js requires some configuration to work on the public Steem testnet. + +You need to set two Steem API options, `address_prefix` and `chain_id`. +```js +steem.api.setOptions({ + address_prefix: 'TST', + chain_id: '46d82ab7d8db682eb1959aed0ada039a6d49afa1602491f93dde9cac3e8e6c32', + useTestNet: true, +}); +``` + +The Chain ID could change. If it does, it may not be reflected here, but will be documented on any testnet launch announcements. + ## Contributions -Patches are welcome! Contributors are listed in the package.json file. Please run the tests before opening a pull request and make sure that you are passing all of them. If you would like to contribute, but don't know what to work on, check the issues list or on Steemit Chat channel #steemjs https://steemit.chat/channel/steemjs. +Patches are welcome! Contributors are listed in the package.json file. Please run the tests before opening a pull request and make sure that you are passing all of them. If you would like to contribute, but don't know what to work on, check the issues list. ## Issues When you find issues, please report them! diff --git a/doc/README.md b/doc/README.md index e7d267fa..c1350c84 100644 --- a/doc/README.md +++ b/doc/README.md @@ -23,784 +23,2245 @@ - [Auth](#auth) - [Formatter](#formatter) +- - - - - - - - - - - - - - - - - - +- - - - - - - - - - - - - - - - - - # Install -``` +```sh $ npm install steem --save ``` +- - - - - - - - - - - - - - - - - - +- - - - - - - - - - - - - - - - - - # Browser ```html ``` - +- - - - - - - - - - - - - - - - - - ## Config -Default config should work with steem. however you can change it to work with golos -as +Default config should work with steem. however you can change it to work with golos by ```js -steem.api.setOptions({ url: 'wss://ws.golos.io' }); // assuming websocket is work at ws.golos.io +steem.api.setOptions({ url: 'wss://ws.golos.io' }); // assuming websocket is working at ws.golos.io steem.config.set('address_prefix','GLS'); steem.config.set('chain_id','782a3039b478c839e4cb0c941ff4eaeb7df40bdd68bd441afd444b9da763de12'); ``` +- - - - - - - - - - - - - - - - - - ### set -``` +```js steem.config.set('address_prefix','STM'); ``` +- - - - - - - - - - - - - - - - - - ### get -``` +```js steem.config.get('chain_id'); ``` - +- - - - - - - - - - - - - - - - - - ## JSON-RPC Here is how to activate JSON-RPC transport: ```js steem.api.setOptions({ url: 'https://api.steemit.com' }); ``` +- - - - - - - - - - - - - - - - - - +- - - - - - - - - - - - - - - - - - # API - +- - - - - - - - - - - - - - - - - - ## Subscriptions - +- - - - - - - - - - - - - - - - - - ### Set Subscribe Callback -``` +```js steem.api.setSubscribeCallback(callback, clearFilter, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Set Pending Transaction Callback -``` +```js steem.api.setPendingTransactionCallback(cb, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Set Block Applied Callback -``` +```js steem.api.setBlockAppliedCallback(cb, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Cancel All Subscriptions -``` +```js steem.api.cancelAllSubscriptions(function(err, result) { console.log(err, result); }); ``` - +- - - - - - - - - - - - - - - - - - ## Tags - +- - - - - - - - - - - - - - - - - - ### Get Trending Tags -``` +Returns a list of the currently trending tags in descending order by value. +```js steem.api.getTrendingTags(afterTag, limit, function(err, result) { console.log(err, result); }); ``` -### Get Discussions By Trending + +|Parameter|Description|Datatype|Notes| +|---|---|---|---| +|afterTag|The name of the last tag to begin from|String|Use the empty string `''` to start the list. Subsequent calls can use the last tag name| +|limit|The maximum number of tags to return|Integer|| +|function()|Your callback|function|Tip: use `console.log(err, result)` to see the result| + + +Call Example: +```js +steem.api.getTrendingTags('', 2, function(err, result) { + console.log(err, result); +}); +``` + +Return Example: +```js +[ { name: '', total_payouts: '37610793.383 SBD', net_votes: 4211122, top_posts: 411832, comments: 1344461, trending: '5549490701' }, + { name: 'life', total_payouts: '8722947.658 SBD', net_votes: 1498401, top_posts: 127103, comments: 54049, trending: '570954588' } ] ``` -steem.api.getDiscussionsByTrending(query, function(err, result) { + +Using the Result: +```js +// Extract tags from the result into an array of tag name strings +var f = result.map(function(item) { return item.name; }); +console.log(f); + +// Get the last tag for subsequent calls to `getTrendingTags` +// or use: f[f.length - 1] if you used the extraction code above. +var lastKnownTag = result[result.length - 1].name; + +// Use the last known tag to get the next group of tags +steem.api.TrendingTags(lastKnownTag, 2, function(err, result) { console.log(err, result); }); ``` -### Get Discussions By Created + +See also: [getTrendingCategories](#get-trending-categories) +- - - - - - - - - - - - - - - - - - +### Get Blog +Gets the last `limit` number of posts of `account` before the post with index `entryId` + +```js +steem.api.getBlog(account, entryId, limit, callback); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|account|string|a steem username| +|entryId|number|a positive number - the index from which to start counting (the index is zero based)| +|limit|number|a positive number - the max count of posts to be returned| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +steem.api.getBlog("username", 10, 3, function(err, data) { + console.log(err, data); +}); + +// In this case we have a call to get [3] posts, the newest of which is the one with index [10] +// (that's the 11-th post, because the post indexes are zero based) +// That means that the results will be posts [10, 9 and 8] ``` + +Return Example: +```js +[ { + blog:"username" + comment: { /* Omited for simplicity */ } + entry_id: 10 + reblog_on:"1970-01-01T00:00:00" + }, + { + blog:"username" + comment: { /* Omited for simplicity */ } + entry_id: 9 + reblog_on:"1970-01-01T00:00:00" + }, + { + blog:"username" + comment: { /* Omited for simplicity */ } + entry_id: 8 + reblog_on:"1970-01-01T00:00:00" + } ] +``` +- - - - - - - - - - - - - - - - - - +### Get Blog Authors +Gets a list of all people who wrote in someones blog, along with how many times they wrote in that blog. + +```js +steem.api.getBlogAuthors(blogAccount, callback); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|blogAccount|string|a steem username| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +steem.api.getBlogAuthors("username", function(err, data) { + console.log(err, data); +}); +``` + +Return Example: +```js +[ [ 'username1', 1 ], + [ 'username2', 1 ], + [ 'username3', 3 ], + [ 'username4', 2 ], + [ 'username5', 1 ] ] +``` +- - - - - - - - - - - - - - - - - - +### Get Blog Entries +Gets the last `limit` number of posts of `account` before the post with index `entryId` +Very similar to steem.api.getBlog but with much simpler result objects + +```js +steem.api.getBlogEntries(account, entryId, limit, callback); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|account|string|a steem username| +|entryId|number|a positive number - the index from which to start counting (the index is zero based)| +|limit|number|a positive number - the max count of posts to be returned| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +steem.api.getBlogEntries("username", 10, 3, function(err, data) { + console.log(err, data); +}); + +// In this case we have a call to get [3] posts, the newest of which is the one with index [10] +// (that's the 11-th post, because the post indexes are zero based) +// That means that the results will be posts [10, 9 and 8] +``` + +Return Example: +```js +[ { author: 'username', + permlink: 'post-permlink-10', + blog: 'username', + reblog_on: '1970-01-01T00:00:00', + entry_id: 10 }, + { author: 'username', + permlink: 'post-permlink-9', + blog: 'username', + reblog_on: '1970-01-01T00:00:00', + entry_id: 9 }, + { author: 'username', + permlink: 'post-permlink-8', + blog: 'username', + reblog_on: '1970-01-01T00:00:00', + entry_id: 8 } ] +``` +- - - - - - - - - - - - - - - - - - +### Get Discussions By Trending +Gets the steem posts as they would be shown in the trending tab of steemit.com. + +```js +steem.api.getDiscussionsByTrending30(query, callback); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|query|object|an object containing different options for querying, like 'limit' and 'tag'| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +var query = { limit : 3, tag : "steem" }; +steem.api.getDiscussionsByTrending30(query, function(err, data) { + console.log(err, data); +}); + +// NOTE! The default limit is 0. Not setting a limit will get you an empty result. +``` + +Return Example: +```js +// the result is an array of big objects representing the comments + + [ { /* ommited for simplicity */ }, + { /* ommited for simplicity */ }, + { /* ommited for simplicity */ } ] +``` +- - - - - - - - - - - - - - - - - - +### Get Discussions By Created +```js steem.api.getDiscussionsByCreated(query, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Discussions By Active -``` +```js steem.api.getDiscussionsByActive(query, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Discussions By Cashout -``` +```js steem.api.getDiscussionsByCashout(query, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Discussions By Payout -``` +```js steem.api.getDiscussionsByPayout(query, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Discussions By Votes -``` +```js steem.api.getDiscussionsByVotes(query, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Discussions By Children -``` +```js steem.api.getDiscussionsByChildren(query, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Discussions By Hot -``` +```js steem.api.getDiscussionsByHot(query, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Discussions By Feed -``` +```js steem.api.getDiscussionsByFeed(query, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Discussions By Blog -``` +```js steem.api.getDiscussionsByBlog(query, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Discussions By Comments -``` +```js steem.api.getDiscussionsByComments(query, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - +### Get Discussions By Promoted +Gets the recent posts ordered by how much was spent to promote them -## Blocks and transactions +```js +steem.api.getDiscussionsByPromoted(query, callback); +``` -### Get Block Header +|Parameter|Datatype|Description| +|---------|--------|-----------| +|query|object|an object containing different options for querying, like 'limit' and 'tag'| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +var query = { limit : 3, tag : "steem" }; +steem.api.getDiscussionsByPromoted(query, function(err, data) { + console.log(err, data); +}); + +// NOTE! The default limit is 0. Not setting a limit will get you an empty result. +``` + +Return Example: +```js +// the result is an array of big objects representing the comments + + [ { /* ommited for simplicity */ }, + { /* ommited for simplicity */ }, + { /* ommited for simplicity */ } ] +``` +- - - - - - - - - - - - - - - - - - +### Get Comment Discussions By Payout +Gets the recent comments (not posts) ordered by their pending payout. + +```js +steem.api.getCommentDiscussionsByPayout(query, callback); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|query|object|an object containing different options for querying, like 'limit' and 'tag'| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +var query = { limit : 3, tag : "steem" }; +steem.api.getCommentDiscussionsByPayout(query, function(err, data) { + console.log(err, data); +}); + +// NOTE! The default limit is 0. Not setting a limit will get you an empty result. +``` + +Return Example: +```js +// the result is an array of big objects representing the comments + + [ { /* ommited for simplicity */ }, + { /* ommited for simplicity */ }, + { /* ommited for simplicity */ } ] +``` +- - - - - - - - - - - - - - - - - - +### Get Post Discussions By Payout +Gets the recent posts ordered by their pending payout. + +```js +steem.api.getPostDiscussionsByPayout(query, callback); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|query|object|an object containing different options for querying, like 'limit' and 'tag'| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +var query = { limit : 3, tag : "collorchallenge" }; +steem.api.getPostDiscussionsByPayout(query, function(err, data) { + console.log(err, data); +}); + +// NOTE! The default limit is 0. Not setting a limit will get you an empty result. ``` + +Return Example: +```js +// the result is an array of big objects representing the comments + + [ { /* ommited for simplicity */ }, + { /* ommited for simplicity */ }, + { /* ommited for simplicity */ } ] +``` +- - - - - - - - - - - - - - - - - - +## Blocks and transactions +- - - - - - - - - - - - - - - - - - +### Get Block Header +```js steem.api.getBlockHeader(blockNum, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Block -``` +```js steem.api.getBlock(blockNum, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - +### Get Ops In Block +Gets all operations in a given block + +```js +steem.api.getOpsInBlock(blockNum, onlyVirtual, callback); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|blockNum|number|A positive number| +|onlyVirtual|bool|'false' to get all operations. 'true' to only get virtual operations| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +steem.api.getOpsInBlock(10000001, false, function(err, data) { + console.log(err, data); +}); +``` + +Return Example: +```js +[ { trx_id: '4b688c13940fd5b4bb11356286ef12061f71976c', + block: 10000001, + trx_in_block: 0, + op_in_trx: 0, + virtual_op: 0, + timestamp: '2017-03-08T17:34:24', + op: [ 'vote', [Object] ] }, + { trx_id: 'a450debc8332c3b27935b3307891dfc509669edc', + block: 10000001, + trx_in_block: 2, + op_in_trx: 0, + virtual_op: 0, + timestamp: '2017-03-08T17:34:24', + op: [ 'vote', [Object] ] } ] + +``` +- - - - - - - - - - - - - - - - - - ### Get State +Gets a lot of information about the state of `path` + +```js +steem.api.getStateWith(path, callback); ``` -steem.api.getState(path, function(err, result) { - console.log(err, result); + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|path|string| like "/@username". This is the extension from the Steem URL. It can be used on users, posts, comments, comments-by-user, replies-to-user and so on| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +steem.api.getState("/@username", function(err, data) { + console.log(err, data); }); + +// Here are some valid calls: + +steem.api.getState("/@username", function(err, data) { console.log(data); }); + +steem.api.getState("/@username/permlink-of-post", function(err, data) { console.log(data); }); + +steem.api.getState("/@username/comments", function(err, data) { console.log(data); }); + +steem.api.getState("/@username/recent-replies", function(err, data) { console.log(data); }); + +steem.api.getState("/trending", function(err, data) { console.log(data); }); + +steem.api.getState("/trending/collorchallenge", function(err, data) { console.log(data); }); + +// and others.... ``` -### Get Trending Categories + +Return Example: +```js +// The result is huge, and can have many variations depending on what you are getting the state of. It can't be documented briefly. Here is some basic information: +{ accounts: {username: {...}} + content: { + username/permlink1: {...}, + username/permlink2: {...}, + username/permlink3: {...} …} + current_route:"/@username" + discussion_idx: {...} + error:"" + feed_price: {base: "3.889 SBD", quote: "1.000 STEEM"} + pow_queue: [] + props: {...} + tag_idx: { trending: [...] } + tags:{...} + witness_schedule: {...} + witnesses: {...} } +``` +- - - - - - - - - - - - - - - - - - +### Get State With Options + +```js +steem.api.getStateWith(options, callback); ``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|options|object|like { path : "/@username"} where the path is an extension from a Steem URL. It can be used on users, posts, comments, comments-by-user, replies-to-user and so on| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +steem.api.getStateWith({ path : "/@username" }, function(err, data) { + console.log(err, data); +}); +``` +See `steem.api.getState` for more examples... +- - - - - - - - - - - - - - - - - - +### Get Trending Categories +```js steem.api.getTrendingCategories(after, limit, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Best Categories -``` +```js steem.api.getBestCategories(after, limit, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Active Categories -``` +```js steem.api.getActiveCategories(after, limit, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Recent Categories -``` +```js steem.api.getRecentCategories(after, limit, function(err, result) { console.log(err, result); }); ``` - +- - - - - - - - - - - - - - - - - - ## Globals - +- - - - - - - - - - - - - - - - - - ### Get Config -``` +```js steem.api.getConfig(function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Dynamic Global Properties -``` +```js steem.api.getDynamicGlobalProperties(function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Chain Properties -``` +```js steem.api.getChainProperties(function(err, result) { console.log(err, result); }); ``` -### Get Feed History +- - - - - - - - - - - - - - - - - - +### Get Feed Entries +Gets the posts in the feed of a user. +The feed displays posts of followed users, as well as what they resteemed. + +```js +steem.api.getFeedEntries(account, entryId, limit, callback); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|account|string|a steem username| +|entryId|number|the post id from which to start counting. Write '0' to start from newest post| +|limit|number|a positive number| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +steem.api.getFeedEntries("username", 0, 2, function(err, data) { + console.log(err, data); +}); ``` + +Return Example: +```js +[ { author: 'otherusername', + permlink: 'permlink', + reblog_by: [ 'resteembot' ], //full when post is in feed because it's resteemed + reblog_on: '2018-02-11T18:42:54', + entry_id: 10260 }, + { author: 'otherusername', + permlink: 'permlink', + reblog_by: [ ], // false when post is in feed because user follows it's author + reblog_on: '2018-02-11T18:39:24', + entry_id: 10259 } ] +``` +- - - - - - - - - - - - - - - - - - +### Get Feed History +```js steem.api.getFeedHistory(function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Current Median History Price -``` +```js steem.api.getCurrentMedianHistoryPrice(function(err, result) { console.log(err, result); }); ``` -### Get Hardfork Version +- - - - - - - - - - - - - - - - - - +### Get Ticker +Gets the lates summorized data from the steem market. + +```js +steem.api.getTicker(callback); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +steem.api.getTicker(function(err, data) { + console.log(err, data); +}); +``` + +Return Example: +```js +{ latest: '0.89732142857142860', + lowest_ask: '0.89684014869888484', + highest_bid: '0.89600000000000002', + percent_change: '-14.56712923228768730', + steem_volume: '7397.697 STEEM', + sbd_volume: '6662.316 SBD' } +``` +- - - - - - - - - - - - - - - - - - +### Get Trade History +Gets the trade history for a given period between a `start` date and an `end` date + +```js +steem.api.getTradeHistory(start, end, limit, callback); ``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|start|string|Datetime string in the format "2018-01-01T00:00:00"| +|end|string|Datetime string in the format "2018-01-01T00:00:00"| +|limit|number|a positive number| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +var start = "2018-01-01T00:00:00"; +var end = "2018-01-02T00:00:00"; + +steem.api.getTradeHistory(start, end, 5, function(err, data) { + console.log(err, data); +}); +``` + +Return Example: +```js + [ { date: '2018-01-01T00:00:09', + current_pays: '10.192 SBD', + open_pays: '25.650 STEEM' }, + { date: '2018-01-01T00:00:09', + current_pays: '2.000 SBD', + open_pays: '5.033 STEEM' }, + { date: '2018-01-01T00:00:12', + current_pays: '13.560 SBD', + open_pays: '34.128 STEEM' }, + { date: '2018-01-01T00:00:12', + current_pays: '3.057 SBD', + open_pays: '7.690 STEEM' }, + { date: '2018-01-01T00:00:12', + current_pays: '6.908 SBD', + open_pays: '17.375 STEEM' } ] +``` +- - - - - - - - - - - - - - - - - - +### Get Version +Gets the version of the Steem blockchain you are connected to. + +```js +steem.api.getVersion(callback); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +steem.api.getVersion(function(err, data) { + console.log(err, data); +}); +``` + +Return Example: +```js +{ blockchain_version: '0.19.2', + steem_revision: '07be64314ce9d277eb7da921b459c993c2e2412c', + fc_revision: '8dd1fd1ec0906509eb722fa7c8d280d59bcca23d' } +``` +- - - - - - - - - - - - - - - - - - +### Get Volume +Gets the Steem and Steem Dollar volumes + +```js +steem.api.getVolume(callback); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +steem.api.getVolume(function(err, data) { + console.log(err, data); +}); +``` + +Return Example: +```js +{ steem_volume: '8101.888 STEEM', + sbd_volume: '7287.268 SBD' } +``` +- - - - - - - - - - - - - - - - - - +### Get Hardfork Version +Gets the current hardfork version of the STEEM blockchain. +```js steem.api.getHardforkVersion(function(err, result) { console.log(err, result); }); ``` -### Get Next Scheduled Hardfork + +Return Example: +```js +'0.19.0' ``` +This returns a string and not JSON. + +See also: [getNextScheduledHardfork](#get-next-scheduled-hardfork), [getConfig](#get-config) + +- - - - - - - - - - - - - - - - - - +### Get Next Scheduled Hardfork +```js steem.api.getNextScheduledHardfork(function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Reward Fund -``` +```js steem.api.getRewardFund(name, function(err, result) { console.log(err, result); }); ``` -### Get Vesting Delegations +- - - - - - - - - - - - - - - - - - +### Claim Reward Balance +Claims pending rewards, be they Steem, SBD or Vests. + +```js +steem.broadcast.claimRewardBalance(wif, account, reward_steem, reward_sbd, reward_vests, callback); ``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|wif|string|Use steem.auth.toWif(user, pass, type)| +|account|string|a steem username| +|reward_steem|string|balance like "0.000 STEEM"| +|reward_sbd|string|balance like "0.000 SBD"| +|reward_vests|string|balance like "0.000006 VESTS"| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +steem.broadcast.claimRewardBalance("5Hupd....pp7vGY", "username", "0.000 STEEM", "0.000 SBD", "0.000006 VESTS", function(err, data) { + console.log(err, data); +}); +``` + +Return Example: +```js +{ id: '052f.......c6c2f', + block_num: 19756287, + trx_num: 40, + expired: false, + ref_block_num: 29928, + ref_block_prefix: 808836877, + expiration: '2018-02-10T20:12:15', + operations: [ [ 'claim_reward_balance', [Object] ] ], + extensions: [], + signatures: [ '205......614e' ] } +``` +- - - - - - - - - - - - - - - - - - +### Claim Reward Balance With Options +Claims pending rewards, be they Steem, SBD or Vests. + +```js +steem.broadcast.claimRewardBalanceWith(wif, options, callback); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|wif|string|Use < steem.auth.toWif(user, pass, type) >| +|options|object|an object containing the calim parameters. Look at the example below.| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +var options = { + account:"username", + reward_sbd:"0.000 SBD", + reward_steem:"0.000 STEEM", + reward_vests:"0.000006 VESTS" +} +steem.broadcast.claimRewardBalanceWith("5Hupd....pp7vGY", options, function(err, data) { + console.log(err, data); +}); +``` + +Return Example: +```js + { id: '4b7b........034c7', + block_num: 19756322, + trx_num: 3, + expired: false, + ref_block_num: 29965, + ref_block_prefix: 4245658614, + expiration: '2018-02-10T20:14:00', + operations: [ [ 'claim_reward_balance', [Object] ] ], + extensions: [], + signatures: [ '1f61a..........4f3d7' ] } +``` +- - - - - - - - - - - - - - - - - - +### Get Vesting Delegations +Returns a list of delegations made from one `account`. Denominated in VESTS. +```js steem.api.getVestingDelegations(account, from, limit, function(err, result) { console.log(err, result); }); ``` -## Keys +|Parameter|Description|Datatype|Notes| +|---|---|---|---| +|account|Account who is making the delegations|String|| +|from|The name of the last account to begin from|String|Use the empty string `''` to start the list. Subsequent calls can use the last delegatee's account name| +|limit|The maximum number of delegation records to return|Integer|| +|function()|Your callback|function|Tip: use `console.log(err, result)` to see the result| -### Get Key References + +Call Example: +```js +steem.api.getVestingDelegations('ned', '', 2, function(err, result) { + console.log(err, result); +}); ``` -steem.api.getKeyReferences(key, function(err, result) { + +Return Example: +```js +[ { id: 498422, delegator: 'ned', delegatee: 'spaminator', vesting_shares: '409517519.233783 VESTS', min_delegation_time: '2018-01-16T19:30:36' }, + { id: 181809, delegator: 'ned', delegatee: 'surpassinggoogle', vesting_shares: '1029059275.000000 VESTS', min_delegation_time: '2017-08-08T15:25:15' } ] +``` + +Using the Result: +```js +// Extract delegatee names from the result into an array of account name strings +var f = result.map(function(item) { return item.delegatee; }); +console.log(f); + +// Get the last tag for subsequent calls to `getVestingDelegations` +// or use: f[f.length - 1] if you used the extraction code above. +var lastKnownDelegatee = result[result.length - 1].delegatee; + +// Use the last known delegatee to get the next group of delegatees +steem.api.TrendingTags('ned', lastKnownDelegatee, 2, function(err, result) { console.log(err, result); }); ``` -## Accounts +See also: [accountCreateWithDelegation](#account-create-with-delegation), [delegateVestingShares](#delegate-vesting-shares) -### Get Accounts +- - - - - - - - - - - - - - - - - - +## Keys +- - - - - - - - - - - - - - - - - - +### Get Key References +```js +steem.api.getKeyReferences(key, function(err, result) { + console.log(err, result); +}); ``` +- - - - - - - - - - - - - - - - - - +## Accounts +- - - - - - - - - - - - - - - - - - +### Get Accounts +```js steem.api.getAccounts(names, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Account References -``` +```js steem.api.getAccountReferences(accountId, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Lookup Account Names -``` +```js steem.api.lookupAccountNames(accountNames, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Lookup Accounts -``` +```js steem.api.lookupAccounts(lowerBoundName, limit, function(err, result) { console.log(err, result); }); ``` -### Get Account Count +- - - - - - - - - - - - - - - - - - +### Get Account Count +```js +steem.api.getAccountCount(function(err, result) { + console.log(err, result); +}); +``` +- - - - - - - - - - - - - - - - - - +### Get Conversion Requests +```js +steem.api.getConversionRequests(accountName, function(err, result) { + console.log(err, result); +}); +``` +- - - - - - - - - - - - - - - - - - +### Get Account History +```js +steem.api.getAccountHistory(account, from, limit, function(err, result) { + console.log(err, result); +}); +``` +- - - - - - - - - - - - - - - - - - +### Get Owner History +```js +steem.api.getOwnerHistory(account, function(err, result) { + console.log(err, result); +}); +``` +- - - - - - - - - - - - - - - - - - +### Get Recovery Request +```js +steem.api.getRecoveryRequest(account, function(err, result) { + console.log(err, result); +}); +``` +- - - - - - - - - - - - - - - - - - +### Get Account Bandwidth +Get the bandwidth of the `account`. +The bandwidth is the limit of data that can be uploaded to the blockchain. +To have bigger bandwidth - power up your steem. + +```js +steem.api.getAccountBandwidth(account, bandwidthType, callback); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|account|string|a steem username| +|bandwidthType|number|This is a value from an enumeration of predefined values. '1' is for the "Forum" bandwidth, and '2' is for "Market" bandwidth| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +const forumBandwidthType = 1; +const marketBandwidthType = 2; + +steem.api.getAccountBandwidth("username", forumBandwidthType, function(err, data) { + console.log(err, data); +}); +``` + +Return Example: +```js +{ id: 23638, + account: 'username', + type: 'forum', + average_bandwidth: 260815714, + lifetime_bandwidth: '125742000000', + last_bandwidth_update: '2018-02-07T22:30:42' } +``` +- - - - - - - - - - - - - - - - - - +### Get Account Bandwidth With Options +Get the bandwidth of the user specified in the options. + +```js +steem.api.getAccountBandwidthWith(options, callback); ``` -steem.api.getAccountCount(function(err, result) { - console.log(err, result); + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|options|object|like { account: "username", bandwidthType: 1 } where bandwidthType is the value of an enumeration. 1 is "forum" and 2 is "market". They represent the bandwidths for posting and trading respectively| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +var options = { + account: "username", + bandwidthType: 2 +} +steem.api.getAccountBandwidthWith(options, function(err, data) { + console.log(err, data); }); ``` -### Get Conversion Requests + +Return Example: +```js +{ id: 23675, + account: 'username', + type: 'market', + average_bandwidth: 2608157142, + lifetime_bandwidth: '94940000000', + last_bandwidth_update: '2018-02-07T22:30:42' } +``` +- - - - - - - - - - - - - - - - - - +### Get Account Reputations +Gets the reputation points of `limit` accounts with names most similar to `lowerBoundName`. + +```js +steem.api.getAccountReputations(lowerBoundName, limit, callback); ``` -steem.api.getConversionRequests(accountName, function(err, result) { - console.log(err, result); + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|lowerBoundName|string|a steem username query| +|limit|number|a positive number| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +steem.api.getAccountReputations("username", 2, function(err, data) { + console.log(err, data); }); ``` -### Get Account History + +Return Example: +```js + [ { account: 'username', reputation: '26727073581' }, + { account: 'username-taken', reputation: 0 } ] ``` -steem.api.getAccountHistory(account, from, limit, function(err, result) { - console.log(err, result); +- - - - - - - - - - - - - - - - - - +## Recovery Account Change Requests +Get the change requests of recovery account for multiple accounts. + +```js +steem.api.findChangeRecoveryAccountRequests(['justyy222', 'ety001', 'justyy'], function(err, data) { + console.log(err, data); }); ``` -### Get Owner History -``` -steem.api.getOwnerHistory(account, function(err, result) { + +Return Example: + +```js +{"requests": + [ + { + "id":2238, + "account_to_recover":"justyy222", + "recovery_account":"happyukgo", + "effective_on":"2024-09-24T06:15:33" + } + ] +} +``` +- - - - - - - - - - - - - - - - - - +## Market +- - - - - - - - - - - - - - - - - - +### Get Order Book +```js +steem.api.getOrderBook(limit, function(err, result) { console.log(err, result); }); ``` -### Get Recovery Request +- - - - - - - - - - - - - - - - - - +### Get Market Order Book +Takes the top-most `limit` entries in the market order book for both buy and sell orders. + +```js +steem.api.getMarketOrderBook(limit, callback); ``` -steem.api.getRecoveryRequest(account, function(err, result) { - console.log(err, result); + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|limit|number|a positive number| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +steem.api.getMarketOrderBook(2, function(err, data) { + console.log(err, data); }); ``` -## Market +Return Example: +```js + { bids: + [ { price: '0.91116173120728938', steem: 2195, sbd: 2000 }, + { price: '0.91089965397923878', steem: 1156, sbd: 1053 } ], + asks: + [ { price: '0.91145625249700357', steem: 9053, sbd: 8251 }, + { price: '0.91159226975214813', steem: 16184, sbd: 14753 } ] } +``` +- - - - - - - - - - - - - - - - - - +### Get Market Order Book With Options +Takes the top-most `limit` entries in the market order book for both buy and sell orders. -### Get Order Book +```js +steem.api.getMarketOrderBookWith(options, callback); ``` -steem.api.getOrderBook(limit, function(err, result) { - console.log(err, result); + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|options|object|like { limit:number }| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +steem.api.getMarketOrderBookWith({ limit: 3 }, function(err, data) { + console.log(err, data); }); ``` + +Return Example: +```js + { bids: + [ { price: '0.90160333845815954', steem: 9106, sbd: 8210 }, + { price: '0.90152855993563952', steem: 12430, sbd: 11206 }, + { price: '0.89992800575953924', steem: 5556, sbd: 5000 } ], + asks: + [ { price: '0.91004578507945044', steem: 5055, sbd: 4600 }, + { price: '0.91103965702036438', steem: 15853, sbd: 14442 }, + { price: '0.91112433075550281', steem: 5874, sbd: 5351 } ] } +``` +- - - - - - - - - - - - - - - - - - ### Get Open Orders -``` +```js steem.api.getOpenOrders(owner, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Liquidity Queue -``` +```js steem.api.getLiquidityQueue(startAccount, limit, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - +### Get Market History Buckets -## Authority / validation +```js +steem.api.getMarketHistoryBuckets(callback); +``` -### Get Transaction Hex +|Parameter|Datatype|Description| +|---------|--------|-----------| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +steem.api.getMarketHistoryBuckets(function(err, data) { + console.log(err, data); +}); ``` + +Return Example: +```js + [ 15, 60, 300, 3600, 86400 ] +``` +- - - - - - - - - - - - - - - - - - +## Authority / validation +- - - - - - - - - - - - - - - - - - +### Get Transaction Hex +```js steem.api.getTransactionHex(trx, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Transaction -``` +```js steem.api.getTransaction(trxId, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Required Signatures -``` +```js steem.api.getRequiredSignatures(trx, availableKeys, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Potential Signatures -``` +```js steem.api.getPotentialSignatures(trx, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Verify Authority -``` +```js steem.api.verifyAuthority(trx, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Verify Account Authority -``` +```js steem.api.verifyAccountAuthority(nameOrId, signers, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - +### Get Tags Used By Author +Gets tags used by a steem user. Most users have no tags yet, but some do. -## Votes +```js +steem.api.getTagsUsedByAuthor(author, callback); +``` -### Get Active Votes +|Parameter|Datatype|Description| +|---------|--------|-----------| +|author|string|a steem username| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +steem.api.getTagsUsedByAuthor("good-karma", function(err, data) { + console.log(err, data); +}); ``` + +Return Example: +```js + [ [ 'challenge', 0 ] ] +``` +- - - - - - - - - - - - - - - - - - +## Votes +- - - - - - - - - - - - - - - - - - +### Get Active Votes +```js steem.api.getActiveVotes(author, permlink, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Account Votes -``` +```js steem.api.getAccountVotes(voter, function(err, result) { console.log(err, result); }); ``` - +- - - - - - - - - - - - - - - - - - ## Content - - +- - - - - - - - - - - - - - - - - - ### Get Content -``` +```js steem.api.getContent(author, permlink, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Content Replies -``` +```js steem.api.getContentReplies(author, permlink, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Discussions By Author Before Date -``` +```js steem.api.getDiscussionsByAuthorBeforeDate(author, startPermlink, beforeDate, limit, function(err, result) { console.log(err, result); }); ``` -### Get Replies By Last Update +- - - - - - - - - - - - - - - - - - +### Get Reblogged By +Gives a list of the users that reblogged (resteemed) a given post + +```js +steem.api.getRebloggedBy(author, permlink, callback); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|author|string|a steem username| +|permlink|string|a permalink of comment or post| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +steem.api.getRebloggedBy("author", "example-permlink", function(err, data) { + console.log(err, data); +}); +``` + +Return Example: +```js + [ 'author', + 'user1', + 'user2', + 'user3', + 'user4' ] ``` +- - - - - - - - - - - - - - - - - - +### Get Replies By Last Update +```js steem.api.getRepliesByLastUpdate(startAuthor, startPermlink, limit, function(err, result) { console.log(err, result); }); ``` - +- - - - - - - - - - - - - - - - - - ## Witnesses - - +- - - - - - - - - - - - - - - - - - ### Get Witnesses -``` +```js steem.api.getWitnesses(witnessIds, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Witness By Account -``` +Returns information about a witness with the given `accountName`. +```js steem.api.getWitnessByAccount(accountName, function(err, result) { console.log(err, result); }); ``` -### Get Witnesses By Vote +|Parameter|Description|Datatype|Notes| +|---|---|---|---| +|accountName|The account name of the witness to query|String|| +|function()|Your callback|function|Tip: use `console.log(err, result)` to see the result| + +Call Example: +```js +steem.api.getVestingDelegations('sircork', '', 2, function(err, result) { + console.log(err, result); +}); ``` + +See also: +- - - - - - - - - - - - - - - - - - +### Get Witnesses By Vote +```js steem.api.getWitnessesByVote(from, limit, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Lookup Witness Accounts -``` +```js steem.api.lookupWitnessAccounts(lowerBoundName, limit, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Witness Count -``` +```js steem.api.getWitnessCount(function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Get Active Witnesses -``` +```js steem.api.getActiveWitnesses(function(err, result) { console.log(err, result); }); + ``` -### Get Miner Queue +- - - - - - - - - - - - - - - - - - +### Get Witness Schedule +Gets some general information about the witnesses. + +```js +steem.api.getWitnessSchedule(callback); ``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +steem.api.getWitnessSchedule(function(err, data) { + console.log(err,data); +} +``` + +Return Example: +```js +{ id: 0, + current_virtual_time: '292589412128104496649868821', + next_shuffle_block_num: 19756485, + current_shuffled_witnesses: '31797..................00000000', + num_scheduled_witnesses: 21, + top19_weight: 1, + timeshare_weight: 5, + miner_weight: 1, + witness_pay_normalization_factor: 25, + median_props: + { account_creation_fee: '0.100 STEEM', + maximum_block_size: 65536, + sbd_interest_rate: 0 }, + majority_version: '0.19.2', + max_voted_witnesses: 20, + max_miner_witnesses: 0, + max_runner_witnesses: 1, + hardfork_required_witnesses: 17 } +``` +- - - - - - - - - - - - - - - - - - +### Get Miner Queue +```js steem.api.getMinerQueue(function(err, result) { console.log(err, result); }); ``` - +- - - - - - - - - - - - - - - - - - ## Login API - +- - - - - - - - - - - - - - - - - - ### Login -/!\ It's **not safe** to use this method with your username and password. This method always return `true` and is only used in intern with empty values to enable broadcast. +/!\ It's **not safe** to use this method with your username and password. This method always return `true` and is only used internally with empty values to enable broadcast. -``` +```js steem.api.login('', '', function(err, result) { console.log(err, result); }); ``` - +- - - - - - - - - - - - - - - - - - ### Get Api By Name -``` +```js steem.api.getApiByName(apiName, function(err, result) { console.log(err, result); }); ``` - +- - - - - - - - - - - - - - - - - - ## Follow API +The follower API queries information about follow relationships between accounts. The API is read-only and does not create changes on the blockchain. +- - - - - - - - - - - - - - - - - - ### Get Followers -``` +Returns an alphabetical ordered array of the accounts that are following a particular account. + +```js steem.api.getFollowers(following, startFollower, followType, limit, function(err, result) { console.log(err, result); }); ``` -### Get Following + +|Parameter|Description|Datatype|Notes| +|---|---|---|---| +|following|The followers of which account|String|No leading @ symbol| +|startFollower|Start the list from which follower?|String|No leading @symbol. Use the empty string `''` to start the list. Subsequent calls can use the name of the last follower| +|followType|??|??|Set to 0 or 'blog' - either works| +|limit|The maximum number of followers to return|Integer|| +|function()|Your callback|function|Tip: use `console.log(err, result)` to see the result| + + +Call Example: +```js +steem.api.getFollowers('ned', '', 'blog', 2, function(err, result) { + console.log(err, result); +}); +``` + +Return Example: +```js +[ { follower: 'a-0-0', following: 'ned', what: [ 'blog' ] }, + { follower: 'a-0-0-0-1abokina', following: 'ned', what: [ 'blog' ] } ] +``` + +Using the Result: +```js +// Extract followers from the result into an array of account name strings +var f = result.map(function(item) { return item.follower; }); +console.log(f); + +// Get the last follower for subsequent calls to getFollowers +// or use: f[f.length - 1] if you used the extraction code above. +var lastKnownFollower = result[result.length - 1].follower; + +// Use the last known follower to get the next group of followers +steem.api.getFollowers('ned', lastKnownFollower, 'blog', 2, function(err, result) { + console.log(err, result); +}); ``` + +See also: [getFollowing](#get-following), [getFollowCount](#get-follow-count) + + +- - - - - - - - - - - - - - - - - - +### Get Following +Returns an alphabetical ordered Array of the accounts that are followed by a particular account. +```js steem.api.getFollowing(follower, startFollowing, followType, limit, function(err, result) { console.log(err, result); }); ``` -### Get Follow Count + +|Parameter|Description|Datatype|Notes| +|---|---|---|---| +|follower|The account to get the following for|String|No leading @ symbol| +|startFollowing|Start the list at which followed account?|String|No leading @symbol. Use the empty string `''` to start the list| +|followType|??|??|Set to 0 or 'blog' - either works| +|limit|The maximum number of items to return|Integer|| +|function()|Your callback|function|Tip: use `console.log(err, result)` to see the result| + + +Call Example: +```js +steem.api.getFollowing('dan', '', 'blog', 2, function(err, result) { + console.log(err, result); +}); +``` + +Return Example: +```js +[ { follower: 'dan', following: 'dantheman', what: [ 'blog' ] }, + { follower: 'dan', following: 'krnel', what: [ 'blog' ] } ] ``` + +Using the Result: +```js +// Extract followed accounts from the result into an array of account name strings +var f = result.map(function(item) { return item.following; }); +``` +See the usage examples for [getFollowers](#get-followers) because the behaviour is very similar. + + +See also: [getFollowers](#get-followers), [getFollowCount](#get-follow-count) + + +- - - - - - - - - - - - - - - - - - +### Get Follow Count +```js steem.api.getFollowCount(account, function(err, result) { console.log(err, result); }); ``` +|Parameter|Description|Datatype|Notes| +|---|---|---|---| +|account|The name for get the follow ccount for|String|No leading @ symbol| +|function()|Your callback|function|Tip: use `console.log(err, result)` to see the result| + + +Call Example: +```js +steem.api.getFollowCount('ned', function(err, result) { + console.log(err, result); +}); +``` + +Return Example: +```js +{ account: 'ned', follower_count: 16790, following_count: 913 } +``` + + +See also: [getFollowers](#get-followers), [getFollowing](#get-following) + + +- - - - - - - - - - - - - - - - - - ## Broadcast API +- - - - - - - - - - - - - - - - - - +### Broadcast Block With Options +Broadcast a new block on the steem blockchain. -### Broadcast Transaction Synchronous +```js +steem.api.broadcastBlockWith(options, callback); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|options|object|like { b: blockObject } where blockObject contains the information on the block you are trying to broadcast| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +var options = { + b: { + previous:"0000000000000000000000000000000000000000", + timestamp:"1970-01-01T00:00:00", + witness:"", + transaction_merkle_root:"0000000000000000000000000000000000000000", + extensions:[], + witness_signature: + "00000000000000000000000000000000000000000000000000000000000000000"+ + "00000000000000000000000000000000000000000000000000000000000000000", + transactions: [] + } +}; + +steem.api.broadcastBlockWith(options, function(err, data) { + console.log(err, data); +}); ``` +- - - - - - - - - - - - - - - - - - +### Broadcast Transaction Synchronous +```js steem.api.broadcastTransactionSynchronous(trx, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Broadcast Block -``` +```js steem.api.broadcastBlock(b, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - +- - - - - - - - - - - - - - - - - - # Broadcast - +The `steem.broadcast` methods cause permanent changes on the blockchain. +- - - - - - - - - - - - - - - - - - ### Account Create -``` +```js steem.broadcast.accountCreate(wif, fee, creator, newAccountName, owner, active, posting, memoKey, jsonMetadata, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Account Create With Delegation -``` +```js steem.broadcast.accountCreateWithDelegation(wif, fee, delegation, creator, newAccountName, owner, active, posting, memoKey, jsonMetadata, extensions, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Delegate Vesting Shares -``` +Delegates STEEM POWER, denominated in VESTS, from a `delegator` to the `delegatee`. Requires the `delegator`'s private WIF key. Set the delegation to 0 to undelegate. +```js steem.broadcast.delegateVestingShares(wif, delegator, delegatee, vesting_shares, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Account Update -``` +```js steem.broadcast.accountUpdate(wif, account, owner, active, posting, memoKey, jsonMetadata, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Account Witness Proxy -``` +```js steem.broadcast.accountWitnessProxy(wif, account, proxy, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Account Witness Vote -``` +```js steem.broadcast.accountWitnessVote(wif, account, witness, approve, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Change Recovery Account -``` +```js steem.broadcast.changeRecoveryAccount(wif, accountToRecover, newRecoveryAccount, extensions, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Comment -``` +```js steem.broadcast.comment(wif, parentAuthor, parentPermlink, author, permlink, title, body, jsonMetadata, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Comment Options -``` +```js steem.broadcast.commentOptions(wif, author, permlink, maxAcceptedPayout, percentSteemDollars, allowVotes, allowCurationRewards, extensions, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Comment Payout -``` +```js steem.broadcast.commentPayout(wif, author, permlink, payout, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Convert -``` +```js steem.broadcast.convert(wif, owner, requestid, amount, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Custom -``` +```js steem.broadcast.custom(wif, requiredAuths, id, data, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Custom Binary -``` +```js steem.broadcast.customBinary(wif, id, data, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Custom Json -``` +```js steem.broadcast.customJson(wif, requiredAuths, requiredPostingAuths, id, json, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Delete Comment -``` +```js steem.broadcast.deleteComment(wif, author, permlink, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Escrow Dispute -``` +```js steem.broadcast.escrowDispute(wif, from, to, agent, who, escrowId, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Escrow Release -``` +```js steem.broadcast.escrowRelease(wif, from, to, agent, who, receiver, escrowId, sbdAmount, steemAmount, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Escrow Transfer -``` +```js steem.broadcast.escrowTransfer(wif, from, to, agent, escrowId, sbdAmount, steemAmount, fee, ratificationDeadline, escrowExpiration, jsonMeta, function(err, result) { console.log(err, result); }); ``` -### Feed Publish +- - - - - - - - - - - - - - - - - - +### Get Escrow +```js +steem.api.getEscrow(from, escrowId, callback); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|from|string|a steem username| +|escrowId|number|id of the specific escrow transfer| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +steem.api.getEscrow("username", 23456789, function(err, data) { + console.log(err, data); +}); ``` +- - - - - - - - - - - - - - - - - - +### Feed Publish +```js steem.broadcast.feedPublish(wif, publisher, exchangeRate, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Fill Convert Request -``` +```js steem.broadcast.fillConvertRequest(wif, owner, requestid, amountIn, amountOut, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Fill Order -``` +```js steem.broadcast.fillOrder(wif, currentOwner, currentOrderid, currentPays, openOwner, openOrderid, openPays, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Fill Vesting Withdraw -``` +```js steem.broadcast.fillVestingWithdraw(wif, fromAccount, toAccount, withdrawn, deposited, function(err, result) { console.log(err, result); }); ``` -### Interest +- - - - - - - - - - - - - - - - - - +### Get Withdraw Routes +Gets withdraw routes (steem power withdraws). + +```js +steem.api.getWithdrawRoutes(account, withdrawRouteType, callback); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|account|string|a steem username| +|withdrawRouteType|number|a number representing a value from an enumeration. Must be 0, 1 or 2| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +steem.api.getWithdrawRoutes("username", 1, function(err, data) { + console.log(err, data); +}); +``` + +Return Example: +```js +[ { from_account: 'username', + to_account: 'receiver', + percent: 10000, + auto_vest: false } ] ``` +- - - - - - - - - - - - - - - - - - +### Interest +```js steem.broadcast.interest(wif, owner, interest, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Limit Order Cancel -``` +Cancels an open limit order on the [internal market](http://steemit.com/market). Be aware that the order might be filled, or partially filled, before this call completes. + +```js steem.broadcast.limitOrderCancel(wif, owner, orderid, function(err, result) { console.log(err, result); }); ``` + +|Parameter|Description|Datatype|Notes| +|---|---|---|---| +|wif|Active private key|String|| +|owner|Account name|String|No leading @ symbol| +|orderid|User defined ordernumber|Integer|The `orderid` used when the order was created| +|function()|Your callback|function|| + + +See also: [getOpenOrders](#get-open-orders), [limitOrderCancel](#limit-order-cancel), [limitOrderCreate2](#limit-order-create2) + + +- - - - - - - - - - - - - - - - - - ### Limit Order Create -``` +Creates a limit order on the [internal market](http://steemit.com/market) to trade one asset for another using a specified minimum. Orders can be set attempt to fill immediately and or to go to the orderbook. Orders in the order book remain until filled or the expiration time is reached. + +```js steem.broadcast.limitOrderCreate(wif, owner, orderid, amountToSell, minToReceive, fillOrKill, expiration, function(err, result) { console.log(err, result); }); ``` + +|Parameter|Description|Datatype|Notes| +|---|---|---|---| +|wif|Active private key|String|| +|owner|Account name|String|No leading @ symbol| +|orderid|User defined ordernumber|Integer|Used to cancel orders| +|amountToSell|Amount to sell|String|"X.XXX ASSET" must have 3 decimal places. e.g. "25.100 SBD"| +|minToReceive|Amount desired|String|"X.XXX ASSET" must have 3 decimal places. e.g. "20.120 STEEM"| +|fillOrKill|Fill order from current order book or kill the order|Boolean|`false` places the order into the Order Book until either cancelled, filled, or the expiration time is reached| +|expiration|Time when order expires|Integer|Unit milliseconds. Zero is UNIX epoch| +|function()|Your callback|function|| + +Tip: `expiration` time must always be in the future even if `fillOrKill` is set to `true`. + +Risky tip: The Internal Market seems to always try and get the best price from the current orderbook so, to place an at market order, then use the `minToReceive` as `0.001` and `fillOrKill` as `true` (use at own risk). + + +See also: [getOrderBook](#get-order-book), [getOpenOrders](#get-open-orders), [limitOrderCancel](#limit-order-cancel), [limitOrderCreate2](#limit-order-create2) + + +- - - - - - - - - - - - - - - - - - ### Limit Order Create2 -``` +Creates a limit order on the [internal market](http://steemit.com/market) to trade one asset for another using an exchange rate. Orders can be set attempt to fill immediately and or to go to the orderbook. Orders in the order book remain until filled or the expiration time is reached. + +```js steem.broadcast.limitOrderCreate2(wif, owner, orderid, amountToSell, exchangeRate, fillOrKill, expiration, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Recover Account -``` +```js steem.broadcast.recoverAccount(wif, accountToRecover, newOwnerAuthority, recentOwnerAuthority, extensions, function(err, result) { console.log(err, result); }); ``` -### Report Over Production +- - - - - - - - - - - - - - - - - - +### Set Reset Account +Changes the `current_reset_account` of the `account` to a new `reset_account` + +```js +steem.broadcast.setResetAccount(wif, account, current_reset_account, reset_account, callback); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|wif|string|Use < steem.auth.toWif(user, pass, type) >| +|account|string|a steem username| +|current_reset_account|string|a steem username| +|reset_account|string|a steem username| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +steem.broadcast.setResetAccount(wif, "username", "oldresetaccount", "newresetaccount", function(err, data) { + console.log(err, data); +}); +``` + +Return Example: +```js + AssertException + `false: Set Reset Account Operation is currently disabled.` ``` +- - - - - - - - - - - - - - - - - - +### Report Over Production +```js steem.broadcast.reportOverProduction(wif, reporter, firstBlock, secondBlock, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Request Account Recovery -``` +```js steem.broadcast.requestAccountRecovery(wif, recoveryAccount, accountToRecover, newOwnerAuthority, extensions, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Escrow Approve -``` +```js steem.broadcast.escrowApprove(wif, from, to, agent, who, escrowId, approve, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Set Withdraw Vesting Route -``` +```js steem.broadcast.setWithdrawVestingRoute(wif, fromAccount, toAccount, percent, autoVest, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Transfer -``` +Transfers assets, such as STEEM or SBD, from one account to another. +```js steem.broadcast.transfer(wif, from, to, amount, memo, function(err, result) { console.log(err, result); }); ``` +|Parameter|Description|Datatype|Notes| +|---|---|---|---| +|wif|Active private key for the `from` account|String|| +|from|Account name to take asset from|String|No leading @ symbol| +|to|Account name to place asset into|String|No leading @ symbol| +|amount|Amount of asset to transfer|String|"X.XXX ASSET" must have 3 decimal places. e.g. "5.150 SBD"| +|function()|Your callback|function|| + +See also: [transferToVesting](#transfer-to-vesting) +- - - - - - - - - - - - - - - - - - ### Transfer To Vesting -``` +Vests STEEM into STEEM POWER. This method supports powering up one account from another. +```js steem.broadcast.transferToVesting(wif, from, to, amount, function(err, result) { console.log(err, result); }); ``` + +|Parameter|Description|Datatype|Notes| +|---|---|---|---| +|wif|Active private key for the `from` account|String|| +|from|Account name to take STEEM from|String|No leading @ symbol| +|to|Account name to vest STEEM POWER into|String|No leading @ symbol. Can be the same account as `to`| +|amount|Amount of STEEM to vest/power up|String|"X.XXX STEEM" must have 3 decimal places. e.g. "25.100 STEEM". Must be denominated in STEEM| +|function()|Your callback|function|| + +See also: [transfer](#transfer) +- - - - - - - - - - - - - - - - - - ### Vote -``` +```js steem.broadcast.vote(wif, voter, author, permlink, weight, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Withdraw Vesting -``` +```js steem.broadcast.withdrawVesting(wif, account, vestingShares, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Witness Update -``` +```js steem.broadcast.witnessUpdate(wif, owner, url, blockSigningKey, props, fee, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Fill Vesting Withdraw -``` +```js steem.broadcast.fillVestingWithdraw(wif, fromAccount, toAccount, withdrawn, deposited, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Fill Order -``` +```js steem.broadcast.fillOrder(wif, currentOwner, currentOrderid, currentPays, openOwner, openOrderid, openPays, function(err, result) { console.log(err, result); }); ``` -### Fill Transfer From Savings +- - - - - - - - - - - - - - - - - - +### Get Recent Trades +Gets a list of the last `limit` trades from the market. + +```js +steem.api.getRecentTrades(limit, callback); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|limit|number|a positive number| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +steem.api.getRecentTrades(2, function(err, data) { + console.log(err, data); +}); ``` + +Return Example: +```js + [ { date: '2018-02-10T20:38:39', + current_pays: '0.306 SBD', + open_pays: '0.340 STEEM' }, + { date: '2018-02-10T20:36:48', + current_pays: '8.982 SBD', + open_pays: '9.995 STEEM' } ] +``` +- - - - - - - - - - - - - - - - - - +### Fill Transfer From Savings +```js steem.broadcast.fillTransferFromSavings(wif, from, to, amount, requestId, memo, function(err, result) { console.log(err, result); }); ``` -### Comment Payout +- - - - - - - - - - - - - - - - - - +### Get Savings Withdraw From +Gets a list of savings withdraws from `account`. + +```js +steem.api.getSavingsWithdrawFrom(account, callback); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|account|string|a steem username| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +steem.api.getSavingsWithdrawFrom("username", function(err, data) { + console.log(err, data); +}); +``` + +Return Example: +```js + [ /* list of withdraws from savings */ ] +``` +- - - - - - - - - - - - - - - - - - +### Get Savings Withdraw To +Gets a list of savings withdraws from `account`. + +```js +steem.api.getSavingsWithdrawTo(account, callback); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|account|string|a steem username| +|callback|function|function(err, data) {/*code*/}| + + +Call Example: +```js +steem.api.getSavingsWithdrawTo("username", function(err, data) { + console.log(err, data); +}); ``` + +Return Example: +```js + [ /* list of withdraws from savings */ ] +``` +- - - - - - - - - - - - - - - - - - +### Comment Payout +```js steem.broadcast.commentPayout(wif, author, permlink, payout, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Transfer To Savings -``` +```js steem.broadcast.transferToSavings(wif, from, to, amount, memo, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Transfer From Savings -``` +```js steem.broadcast.transferFromSavings(wif, from, requestId, to, amount, memo, function(err, result) { console.log(err, result); }); ``` +- - - - - - - - - - - - - - - - - - ### Cancel Transfer From Savings -``` +```js steem.broadcast.cancelTransferFromSavings(wif, from, requestId, function(err, result) { console.log(err, result); }); ``` - +- - - - - - - - - - - - - - - - - - ### Multisig You can use multisignature to broadcast an operation. -``` +```js steem.broadcast.send({ extensions: [], operations: [ @@ -815,88 +2276,196 @@ steem.broadcast.send({ }); ``` +- - - - - - - - - - - - - - - - - - +- - - - - - - - - - - - - - - - - - # Auth - +- - - - - - - - - - - - - - - - - - ### Verify -``` +```js steem.auth.verify(name, password, auths); ``` - +- - - - - - - - - - - - - - - - - - ### Generate Keys -``` +```js steem.auth.generateKeys(name, password, roles); ``` - +- - - - - - - - - - - - - - - - - - ### Get Private Keys -``` +```js steem.auth.getPrivateKeys(name, password, roles); ``` - +- - - - - - - - - - - - - - - - - - ### Is Wif -``` +```js steem.auth.isWif(privWif); ``` - +- - - - - - - - - - - - - - - - - - ### To Wif -``` +```js steem.auth.toWif(name, password, role); ``` - +- - - - - - - - - - - - - - - - - - ### Wif Is Valid -``` +```js steem.auth.wifIsValid(privWif, pubWif); ``` - +- - - - - - - - - - - - - - - - - - ### Wif To Public -``` +```js steem.auth.wifToPublic(privWif); ``` - +- - - - - - - - - - - - - - - - - - ### Sign Transaction -``` +```js steem.auth.signTransaction(trx, keys); ``` +- - - - - - - - - - - - - - - - - - +- - - - - - - - - - - - - - - - - - # Formatter +- - - - - - - - - - - - - - - - - - +### Amount +Formats number and currency to the valid way for sending (for example - it trims the number's floating point remainer to 3 digits only). -### Create Suggested Password +```js +steem.formatter.amount(_amount, asset); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|_amount|number|A positive number| +|asset|string|The name of a steem asset (steem, sbd)| + + +Call Example: +```js +steem.formatter.amount(53.442346, "STEEM"); +``` + +Return Example: +```js + "53.442 STEEM" ``` +- - - - - - - - - - - - - - - - - - +### Vesting Steem +Converts the vests of `account` into the number of Steem they represent. + +```js +steem.formatter.vestingSteem(account, gprops, callback); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|account|object|a steem user object| +|groups|object|the properties object of the state of "/@username"| + + +Call Example: +```js +steem.api.getAccounts(["username"], function(e1, accounts) { + steem.api.getState("/@username", function (e2, state) { + var vestingSteem = steem.formatter.vestingSteem(accounts[0], state.props); + }); +}); +``` + +Return Example: +```js + 7.42431235 +``` +- - - - - - - - - - - - - - - - - - +### Number With Commas +Formats a big number, by adding a comma on every 3 digits. +Attention - only works on strings. No numbers can be passed directly. + +```js +steem.formatter.numberWithCommas(x); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|x|string|Number to format as string| + + +Call Example: +```js +steem.formatter.numberWithCommas(53304432342.432.toString()); +// or +steem.formatter.numberWithCommas("53304432342.432"); +``` + +Return Example: +```js + "53,304,432,342.432" +``` +- - - - - - - - - - - - - - - - - - +### Estimate Account Value +Gets the estimated dollar value of the assets of `account` + +```js +steem.formatter.estimateAccountValue(account); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|account|object|a steem user object| + + +Call Example: +```js +steem.api.getAccounts(["username"], function(e1, accounts) { + var accountValueInUSD = steem.formatter.estimateAccountValue(accounts[0]) + .catch(function (err) { console.log(err); }) + .then(function (data) { console.log(data); }); +}); +``` + +Return Example: +```js + // The method returns a promise object, that later returns a number as result + 32.25 +``` +- - - - - - - - - - - - - - - - - - +### Create Suggested Password +```js var password = steem.formatter.createSuggestedPassword(); console.log(password); // => 'GAz3GYFvvQvgm7t2fQmwMDuXEzDqTzn9' ``` - +- - - - - - - - - - - - - - - - - - ### Comment Permlink -``` +```js var parentAuthor = 'ned'; var parentPermlink = 'a-selfie'; var commentPermlink = steem.formatter.commentPermlink(parentAuthor, parentPermlink); console.log(commentPermlink); // => 're-ned-a-selfie-20170621t080403765z' ``` - +- - - - - - - - - - - - - - - - - - ### Estimate Account Value -``` +```js var steemPower = steem.formatter.estimateAccountValue(account); ``` - +- - - - - - - - - - - - - - - - - - ### Reputation -``` +```js var reputation = steem.formatter.reputation(3512485230915); console.log(reputation); // => 56 ``` - +- - - - - - - - - - - - - - - - - - ### Vest To Steem -``` +```js var steemPower = steem.formatter.vestToSteem(vestingShares, totalVestingShares, totalVestingFundSteem); console.log(steemPower); ``` +- - - - - - - - - - - - - - - - - - +- - - - - - - - - - - - - - - - - - # Utils - +- - - - - - - - - - - - - - - - - - ### Validate Username -``` +```js var isValidUsername = steem.utils.validateAccountName('test1234'); console.log(isValidUsername); // => 'null' @@ -905,3 +2474,25 @@ var isValidUsername = steem.utils.validateAccountName('a1'); console.log(isValidUsername); // => 'Account name should be longer.' ``` +- - - - - - - - - - - - - - - - - - +### Camel Case +Formats a string with '_' characters to follow the CamelCase notation instead. + +```js +steem.utils.camelCase(str); +``` + +|Parameter|Datatype|Description| +|---------|--------|-----------| +|str|string|the string will be converted to camelCase like "exampleString"| + + +Call Example: +```js +steem.utils.camelCase("example_string"); +``` + +Return Example: +```js +"exampleString" +``` diff --git a/examples/webpack-example/README.md b/examples/webpack-example/README.md index b2a6ba49..95f87ed9 100644 --- a/examples/webpack-example/README.md +++ b/examples/webpack-example/README.md @@ -1,5 +1,5 @@ # `steem-js` webpack configuration example -This is a demo of `steem-js` and webpack usage targetting both the Web and +This is a demo of `steem-js` and webpack usage targeting both the Web and Node.js platforms. ## Compiling the example diff --git a/package.json b/package.json index 83e34c12..dc3f99a8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@steemit/steem-js", - "version": "0.7.1", + "version": "0.7.11", "description": "Steem.js the JavaScript API for Steem blockchain", "main": "lib/index.js", "scripts": { @@ -32,7 +32,7 @@ }, "homepage": "https://github.com/steemit/steem-js#readme", "dependencies": { - "@steemit/rpc-auth": "^1.1.0", + "@steemit/rpc-auth": "^1.1.1", "bigi": "^1.4.2", "bluebird": "^3.4.6", "browserify-aes": "^1.0.6", @@ -42,13 +42,14 @@ "create-hash": "^1.1.2", "create-hmac": "^1.1.4", "cross-env": "^5.0.0", - "cross-fetch": "^1.1.1", + "cross-fetch": "^3.1.5", "debug": "^2.6.8", "detect-node": "^2.0.3", "ecurve": "^1.0.5", "lodash": "^4.16.4", - "secure-random": "^1.1.1", - "ws": "^3.3.2" + "retry": "^0.12.0", + "secure-random": "^1.1.2", + "ws": "^5.2.4" }, "devDependencies": { "babel-cli": "^6.16.0", diff --git a/src/api/index.js b/src/api/index.js index 54e3e4ae..3f1a4652 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -31,9 +31,15 @@ class Steem extends EventEmitter { const methodParams = method.params || []; this[`${methodName}With`] = (options, callback) => { + let params; + if (!method.is_object) { + params = methodParams.map(param => options[param]); + } else { + params = options; + } return this.send(method.api, { method: method.method, - params: methodParams.map(param => options[param]) + params: params }, callback); }; @@ -46,7 +52,7 @@ class Steem extends EventEmitter { return this[`${methodName}With`](options, callback); }; - this[`${methodName}WithAsync`] = Promise.promisify(this[`${methodName}With`]); + this[`${methodName}WithAsync`] = Promise.promisify(this[`${methodName}With`]); this[`${methodName}Async`] = Promise.promisify(this[methodName]); }); this.callAsync = Promise.promisify(this.call); @@ -181,6 +187,10 @@ class Steem extends EventEmitter { this._setLogger(options); this._setTransport(options); this.transport.setOptions(options); + if( options.hasOwnProperty('useTestNet') ) + { + config.set( 'address_prefix', options.useTestNet ? 'TST' : 'STM' ) + } } setWebSocket(url) { diff --git a/src/api/methods.js b/src/api/methods.js index fa2b4252..a0dbd04b 100644 --- a/src/api/methods.js +++ b/src/api/methods.js @@ -398,8 +398,7 @@ export default [ { "api": "follow_api", "method": "get_feed_entries", - "params": ["account", "entryId", "limit" - ] + "params": ["account", "entryId", "limit"] }, { "api": "follow_api", @@ -485,11 +484,48 @@ export default [ { "api": "market_history_api", "method": "get_market_history", - "params": ["bucket_seconds" , "start", "end"] + "params": ["bucket_seconds", "start", "end"] }, { "api": "market_history_api", "method": "get_market_history_buckets", "params": [] + }, + { + "api": "condenser_api", + "method": "find_proposals", + "params": ["id_set"] + }, + { + "api": "condenser_api", + "method": "list_proposals", + "params": ["start", "limit", "order_by", "order_direction", "status"] + }, + { + "api": "condenser_api", + "method": "list_proposal_votes", + "params": ["start", "limit", "order_by", "order_direction", "status"] + }, + { + "api": "condenser_api", + "method": "get_nai_pool", + "params": [] + }, + { + "api": "rc_api", + "method": "find_rc_accounts", + "params": ["accounts"], + "is_object": true + }, + { + "api": "condenser_api", + "method": "get_expiring_vesting_delegations", + "params": ["account", "start", "limit"], + }, + { + "api": "database_api", + "method": "find_change_recovery_account_requests", + "params": ["account"], + "is_object": true } ]; diff --git a/src/api/transports/base.js b/src/api/transports/base.js index 860c2e9a..15bb7afb 100644 --- a/src/api/transports/base.js +++ b/src/api/transports/base.js @@ -27,7 +27,6 @@ export default class Transport extends EventEmitter { send() {} start() {} stop() {} - } Promise.promisifyAll(Transport.prototype); diff --git a/src/api/transports/http.js b/src/api/transports/http.js index 70c9139d..4853daa9 100644 --- a/src/api/transports/http.js +++ b/src/api/transports/http.js @@ -1,5 +1,6 @@ import fetch from 'cross-fetch'; import newDebug from 'debug'; +import retry from 'retry'; import Transport from './base'; const debug = newDebug('steem:http'); @@ -13,9 +14,20 @@ class RPCError extends Error { } } -export function jsonRpc(uri, {method, id, params}) { +/** + * Makes a JSON-RPC request using `fetch` or a user-provided `fetchMethod`. + * + * @param {string} uri - The URI to the JSON-RPC endpoint. + * @param {string} options.method - The remote JSON-RPC method to call. + * @param {string} options.id - ID for the request, for matching to a response. + * @param {*} options.params - The params for the remote method. + * @param {function} [options.fetchMethod=fetch] - A function with the same + * signature as `fetch`, which can be used to make the network request, or for + * stubbing in tests. + */ +export function jsonRpc(uri, {method, id, params, fetchMethod=fetch}) { const payload = {id, jsonrpc: '2.0', method, params}; - return fetch(uri, { + return fetchMethod(uri, { body: JSON.stringify(payload), method: 'post', mode: 'cors', @@ -42,12 +54,56 @@ export function jsonRpc(uri, {method, id, params}) { export default class HttpTransport extends Transport { send(api, data, callback) { if (this.options.useAppbaseApi) { - api = 'condenser_api'; + api = 'condenser_api'; } debug('Steem::send', api, data); const id = data.id || this.id++; const params = [api, data.method, data.params]; - jsonRpc(this.options.uri, {method: 'call', id, params}) - .then(res => { callback(null, res) }, err => { callback(err) }) + const retriable = this.retriable(api, data); + const fetchMethod = this.options.fetchMethod; + if (retriable) { + retriable.attempt((currentAttempt) => { + jsonRpc(this.options.uri, { method: 'call', id, params, fetchMethod }).then( + res => { callback(null, res); }, + err => { + if (retriable.retry(err)) { + return; + } + callback(retriable.mainError()); + } + ); + }); + } else { + jsonRpc(this.options.uri, { method: 'call', id, params, fetchMethod }).then( + res => { callback(null, res); }, + err => { callback(err); } + ); + } + } + + get nonRetriableOperations() { + return this.options.nonRetriableOperations || [ + 'broadcast_transaction', + 'broadcast_transaction_with_callback', + 'broadcast_transaction_synchronous', + 'broadcast_block', + ]; + } + + // An object which can be used to track retries. + retriable(api, data) { + if (this.nonRetriableOperations.some((o) => o === data.method)) { + // Do not retry if the operation is non-retriable. + return null; + } else if (Object(this.options.retry) === this.options.retry) { + // If `this.options.retry` is a map of options, pass those to operation. + return retry.operation(this.options.retry); + } else if (this.options.retry) { + // If `this.options.retry` is `true`, use default options. + return retry.operation(); + } else { + // Otherwise, don't retry. + return null; + } } } diff --git a/src/api/transports/ws.js b/src/api/transports/ws.js index 863ec4f5..1475a941 100644 --- a/src/api/transports/ws.js +++ b/src/api/transports/ws.js @@ -29,12 +29,12 @@ export default class WsTransport extends Transport { if (this.startPromise) { return this.startPromise; } - + this.startPromise = new Promise((resolve, reject) => { this.ws = new WebSocket(this.options.websocket); this.ws.onerror = (err) => { this.startPromise = null; - reject(err); + reject(err); }; this.ws.onopen = () => { this.isOpen = true; @@ -43,7 +43,7 @@ export default class WsTransport extends Transport { this.ws.onclose = this.onClose.bind(this); resolve(); }; - }); + }); return this.startPromise; } @@ -87,7 +87,7 @@ export default class WsTransport extends Transport { id: data.id || this.id++, method: 'call', jsonrpc: '2.0', - params: [api, data.method, data.params] + params: [api, data.method, data.params] } }; this.inFlight++; diff --git a/src/auth/ecc/src/aes.js b/src/auth/ecc/src/aes.js index 20a0f21e..99f4d02c 100644 --- a/src/auth/ecc/src/aes.js +++ b/src/auth/ecc/src/aes.js @@ -12,7 +12,7 @@ const Long = ByteBuffer.Long; Spec: http://localhost:3002/steem/@dantheman/how-to-encrypt-a-memo-when-transferring-steem @throws {Error|TypeError} - "Invalid Key, ..." @arg {PrivateKey} private_key - required and used for decryption - @arg {PublicKey} public_key - required and used to calcualte the shared secret + @arg {PublicKey} public_key - required and used to calculate the shared secret @arg {string} [nonce = uniqueNonce()] - assigned a random unique uint64 @return {object} @@ -27,7 +27,7 @@ export function encrypt(private_key, public_key, message, nonce = uniqueNonce()) /** Spec: http://localhost:3002/steem/@dantheman/how-to-encrypt-a-memo-when-transferring-steem @arg {PrivateKey} private_key - required and used for decryption - @arg {PublicKey} public_key - required and used to calcualte the shared secret + @arg {PublicKey} public_key - required and used to calculate the shared secret @arg {string} nonce - random or unique uint64, provides entropy when re-using the same private/public keys. @arg {Buffer} message - Encrypted or plain text message @arg {number} checksum - shared secret checksum diff --git a/src/auth/ecc/src/key_private.js b/src/auth/ecc/src/key_private.js index 200fe186..b03085cd 100644 --- a/src/auth/ecc/src/key_private.js +++ b/src/auth/ecc/src/key_private.js @@ -20,7 +20,7 @@ class PrivateKey { static fromBuffer(buf) { if (!Buffer.isBuffer(buf)) { - throw new Error("Expecting paramter to be a Buffer type"); + throw new Error("Expecting parameter to be a Buffer type"); } if (32 !== buf.length) { console.log(`WARN: Expecting 32 bytes, instead got ${buf.length}, stack trace:`, new Error().stack); diff --git a/src/auth/ecc/src/signature.js b/src/auth/ecc/src/signature.js index abc7a2a2..c8b8b366 100644 --- a/src/auth/ecc/src/signature.js +++ b/src/auth/ecc/src/signature.js @@ -71,7 +71,7 @@ class Signature { */ static signBufferSha256(buf_sha256, private_key) { if( buf_sha256.length !== 32 || ! Buffer.isBuffer(buf_sha256) ) - throw new Error("buf_sha256: 32 byte buffer requred") + throw new Error("buf_sha256: 32 byte buffer required") private_key = toPrivateObj(private_key) assert(private_key, 'private_key required') diff --git a/src/auth/serializer/src/ChainTypes.js b/src/auth/serializer/src/ChainTypes.js index ca49e2a6..4bb77066 100644 --- a/src/auth/serializer/src/ChainTypes.js +++ b/src/auth/serializer/src/ChainTypes.js @@ -31,8 +31,8 @@ ChainTypes.operations= { comment_options: 19, set_withdraw_vesting_route: 20, limit_order_create2: 21, - challenge_authority: 22, - prove_authority: 23, + claim_account: 22, + create_claimed_account: 23, request_account_recovery: 24, recover_account: 25, change_recovery_account: 26, @@ -51,20 +51,34 @@ ChainTypes.operations= { claim_reward_balance: 39, delegate_vesting_shares: 40, account_create_with_delegation: 41, - fill_convert_request: 42, - author_reward: 43, - curation_reward: 44, - comment_reward: 45, - liquidity_reward: 46, - interest: 47, - fill_vesting_withdraw: 48, - fill_order: 49, - shutdown_witness: 50, - fill_transfer_from_savings: 51, - hardfork: 52, - comment_payout_update: 53, - return_vesting_delegation: 54, - comment_benefactor_reward: 55 + witness_set_properties: 42, + account_update2: 43, + create_proposal: 44, + update_proposal_votes: 45, + remove_proposal: 46, + claim_reward_balance2: 47, + vote2: 48, + smt_setup: 49, + smt_setup_emissions: 50, + smt_setup_ico_tier: 51, + smt_set_setup_parameters: 52, + smt_set_runtime_parameters: 53, + smt_create: 54, + smt_contribute: 55, + fill_convert_request: 56, + author_reward: 57, + curation_reward: 58, + comment_reward: 59, + liquidity_reward: 60, + interest: 61, + fill_vesting_withdraw: 62, + fill_order: 63, + shutdown_witness: 64, + fill_transfer_from_savings: 65, + hardfork: 66, + comment_payout_update: 67, + return_vesting_delegation: 68, + comment_benefactor_reward: 69 }; //types.hpp diff --git a/src/auth/serializer/src/operations.js b/src/auth/serializer/src/operations.js index b34d9fad..b6573e06 100644 --- a/src/auth/serializer/src/operations.js +++ b/src/auth/serializer/src/operations.js @@ -37,7 +37,7 @@ import SerializerImpl from "./serializer" const { //id_type, //varint32, uint8, int64, fixed_array, object_id_type, vote_id, address, - uint16, uint32, int16, uint64, + uint8, uint16, int16, uint32, uint64, int64, uint128, string, string_binary, bytes, bool, array, // protocol_id_type, static_variant, map, set, @@ -45,11 +45,14 @@ const { time_point_sec, optional, asset, + asset_symbol } = types const future_extensions = types.void const hardfork_version_vote = types.void const version = types.void +const required_automated_actions = types.void +const optional_automated_actions = types.void // Place-holder, their are dependencies on "operation" .. The final list of // operations is not avialble until the very end of the generated code. @@ -72,6 +75,58 @@ const comment_payout_beneficiaries = new Serializer(0, { beneficiaries: set(beneficiaries) }); +const votable_asset_options = new Serializer( + "votable_asset_options", { + max_accepted_payout: int64, + allow_curation_rewards: bool, + beneficiaries: comment_payout_beneficiaries +}); + +const allowed_vote_assets = new Serializer(1, { + votable_assets: map((asset_symbol), (votable_asset_options)) +}); + +const smt_generation_unit = new Serializer( + "smt_generation_unit", { + steem_unit: map((string), (uint16)), + token_unit: map((string), (uint16)) +}); + +const smt_capped_generation_policy = new Serializer(0, { + generation_unit: smt_generation_unit, + extensions: set(future_extensions) +}); + +const smt_emissions_unit = new Serializer( + "smt_emissions_unit", { + token_unit: map((string), (uint16)) +}); + +const smt_param_allow_voting = new Serializer(0, { + value: bool +}); + +const smt_param_windows_v1 = new Serializer(0, { + cashout_window_seconds: uint32, + reverse_auction_window_seconds: uint32 +}); + +const smt_param_vote_regeneration_period_seconds_v1 = new Serializer(1, { + vote_regeneration_period_seconds: uint32, + votes_per_regeneration_period: uint32 +}); + +const smt_param_rewards_v1 = new Serializer(2, { + content_constant: uint128, + percent_curation_rewards: uint16, + author_reward_curve: int64, + curation_reward_curve: int64 +}); + +const smt_param_allow_downvotes = new Serializer(3, { + value: bool +}); + // Custom-types after Generated code // ## Generated code follows @@ -82,12 +137,12 @@ Replace: var operation = static_variant([ with: operation.st_operations = [ Delete (these are custom types instead): -let public_key = new Serializer( +let public_key = new Serializer( "public_key", {key_data: bytes(33)} ); -let asset = new Serializer( +let asset = new Serializer( "asset", {amount: int64, symbol: uint64} @@ -96,7 +151,7 @@ let asset = new Serializer( Replace: authority.prototype.account_authority_map With: map((string), (uint16)) */ -let signed_transaction = new Serializer( +let signed_transaction = new Serializer( "signed_transaction", { ref_block_num: uint16, ref_block_prefix: uint32, @@ -107,52 +162,56 @@ let signed_transaction = new Serializer( } ); -let signed_block = new Serializer( +let signed_block = new Serializer( "signed_block", { previous: bytes(20), timestamp: time_point_sec, witness: string, transaction_merkle_root: bytes(20), extensions: set(static_variant([ - future_extensions, - version, - hardfork_version_vote + future_extensions, + version, + hardfork_version_vote, + required_automated_actions, + optional_automated_actions ])), witness_signature: bytes(65), transactions: array(signed_transaction) } ); -let block_header = new Serializer( +let block_header = new Serializer( "block_header", { previous: bytes(20), timestamp: time_point_sec, witness: string, transaction_merkle_root: bytes(20), extensions: set(static_variant([ - future_extensions, - version, + future_extensions, + version, hardfork_version_vote ])) } ); -let signed_block_header = new Serializer( +let signed_block_header = new Serializer( "signed_block_header", { previous: bytes(20), timestamp: time_point_sec, witness: string, transaction_merkle_root: bytes(20), extensions: set(static_variant([ - future_extensions, - version, - hardfork_version_vote + future_extensions, + version, + hardfork_version_vote, + required_automated_actions, + optional_automated_actions ])), witness_signature: bytes(65) } ); -let vote = new Serializer( +let vote = new Serializer( "vote", { voter: string, author: string, @@ -161,7 +220,7 @@ let vote = new Serializer( } ); -let comment = new Serializer( +let comment = new Serializer( "comment", { parent_author: string, parent_permlink: string, @@ -173,7 +232,7 @@ let comment = new Serializer( } ); -let transfer = new Serializer( +let transfer = new Serializer( "transfer", { from: string, to: string, @@ -182,7 +241,7 @@ let transfer = new Serializer( } ); -let transfer_to_vesting = new Serializer( +let transfer_to_vesting = new Serializer( "transfer_to_vesting", { from: string, to: string, @@ -190,14 +249,14 @@ let transfer_to_vesting = new Serializer( } ); -let withdraw_vesting = new Serializer( +let withdraw_vesting = new Serializer( "withdraw_vesting", { account: string, vesting_shares: asset } ); -let limit_order_create = new Serializer( +let limit_order_create = new Serializer( "limit_order_create", { owner: string, orderid: uint32, @@ -208,28 +267,28 @@ let limit_order_create = new Serializer( } ); -let limit_order_cancel = new Serializer( +let limit_order_cancel = new Serializer( "limit_order_cancel", { owner: string, orderid: uint32 } ); -let price = new Serializer( +let price = new Serializer( "price", { base: asset, quote: asset } ); -let feed_publish = new Serializer( +let feed_publish = new Serializer( "feed_publish", { publisher: string, exchange_rate: price } ); -let convert = new Serializer( +let convert = new Serializer( "convert", { owner: string, requestid: uint32, @@ -237,7 +296,7 @@ let convert = new Serializer( } ); -var authority = new Serializer( +var authority = new Serializer( "authority", { weight_threshold: uint32, account_auths: map((string), (uint16)), @@ -245,7 +304,7 @@ var authority = new Serializer( } ); -let account_create = new Serializer( +let account_create = new Serializer( "account_create", { fee: asset, creator: string, @@ -258,7 +317,7 @@ let account_create = new Serializer( } ); -let account_update = new Serializer( +let account_update = new Serializer( "account_update", { account: string, owner: optional(authority), @@ -269,7 +328,7 @@ let account_update = new Serializer( } ); -let chain_properties = new Serializer( +let chain_properties = new Serializer( "chain_properties", { account_creation_fee: asset, maximum_block_size: uint32, @@ -277,7 +336,7 @@ let chain_properties = new Serializer( } ); -let witness_update = new Serializer( +let witness_update = new Serializer( "witness_update", { owner: string, url: string, @@ -287,7 +346,7 @@ let witness_update = new Serializer( } ); -let account_witness_vote = new Serializer( +let account_witness_vote = new Serializer( "account_witness_vote", { account: string, witness: string, @@ -295,14 +354,14 @@ let account_witness_vote = new Serializer( } ); -let account_witness_proxy = new Serializer( +let account_witness_proxy = new Serializer( "account_witness_proxy", { account: string, proxy: string } ); -let pow = new Serializer( +let pow = new Serializer( "pow", { worker: public_key, input: bytes(32), @@ -311,7 +370,7 @@ let pow = new Serializer( } ); -let custom = new Serializer( +let custom = new Serializer( "custom", { required_auths: set(string), id: uint16, @@ -319,7 +378,7 @@ let custom = new Serializer( } ); -let report_over_production = new Serializer( +let report_over_production = new Serializer( "report_over_production", { reporter: string, first_block: signed_block_header, @@ -327,14 +386,14 @@ let report_over_production = new Serializer( } ); -let delete_comment = new Serializer( +let delete_comment = new Serializer( "delete_comment", { author: string, permlink: string } ); -let custom_json = new Serializer( +let custom_json = new Serializer( "custom_json", { required_auths: set(string), required_posting_auths: set(string), @@ -343,7 +402,7 @@ let custom_json = new Serializer( } ); -let comment_options = new Serializer( +let comment_options = new Serializer( "comment_options", { author: string, permlink: string, @@ -352,12 +411,13 @@ let comment_options = new Serializer( allow_votes: bool, allow_curation_rewards: bool, extensions: set(static_variant([ - comment_payout_beneficiaries + comment_payout_beneficiaries, + allowed_vote_assets ])) } ); -let set_withdraw_vesting_route = new Serializer( +let set_withdraw_vesting_route = new Serializer( "set_withdraw_vesting_route", { from_account: string, to_account: string, @@ -366,7 +426,7 @@ let set_withdraw_vesting_route = new Serializer( } ); -let limit_order_create2 = new Serializer( +let limit_order_create2 = new Serializer( "limit_order_create2", { owner: string, orderid: uint32, @@ -377,22 +437,28 @@ let limit_order_create2 = new Serializer( } ); -let challenge_authority = new Serializer( - "challenge_authority", { - challenger: string, - challenged: string, - require_owner: bool +let claim_account = new Serializer( + "claim_account", { + creator: string, + fee: asset, + extensions: set(future_extensions) } ); -let prove_authority = new Serializer( - "prove_authority", { - challenged: string, - require_owner: bool +let create_claimed_account = new Serializer( + "create_claimed_account", { + creator: string, + new_account_name: string, + owner: authority, + active: authority, + posting: authority, + memo_key: public_key, + json_metadata: string, + extensions: set(future_extensions) } ); -let request_account_recovery = new Serializer( +let request_account_recovery = new Serializer( "request_account_recovery", { recovery_account: string, account_to_recover: string, @@ -410,7 +476,7 @@ let recover_account = new Serializer( } ); -let change_recovery_account = new Serializer( +let change_recovery_account = new Serializer( "change_recovery_account", { account_to_recover: string, new_recovery_account: string, @@ -418,7 +484,7 @@ let change_recovery_account = new Serializer( } ); -let escrow_transfer = new Serializer( +let escrow_transfer = new Serializer( "escrow_transfer", { from: string, to: string, @@ -433,7 +499,7 @@ let escrow_transfer = new Serializer( } ); -let escrow_dispute = new Serializer( +let escrow_dispute = new Serializer( "escrow_dispute", { from: string, to: string, @@ -443,7 +509,7 @@ let escrow_dispute = new Serializer( } ); -let escrow_release = new Serializer( +let escrow_release = new Serializer( "escrow_release", { from: string, to: string, @@ -456,7 +522,7 @@ let escrow_release = new Serializer( } ); -let pow2_input = new Serializer( +let pow2_input = new Serializer( "pow2_input", { worker_account: string, prev_block: bytes(20), @@ -464,14 +530,14 @@ let pow2_input = new Serializer( } ); -let pow2 = new Serializer( +let pow2 = new Serializer( "pow2", { input: pow2_input, pow_summary: uint32 } ); -let equihash_proof = new Serializer( +let equihash_proof = new Serializer( "equihash_proof", { n: uint32, k: uint32, @@ -480,7 +546,7 @@ let equihash_proof = new Serializer( } ); -let equihash_pow = new Serializer( +let equihash_pow = new Serializer( "equihash_pow", { input: pow2_input, proof: equihash_proof, @@ -489,7 +555,7 @@ let equihash_pow = new Serializer( } ); -let escrow_approve = new Serializer( +let escrow_approve = new Serializer( "escrow_approve", { from: string, to: string, @@ -500,7 +566,7 @@ let escrow_approve = new Serializer( } ); -let transfer_to_savings = new Serializer( +let transfer_to_savings = new Serializer( "transfer_to_savings", { from: string, to: string, @@ -509,7 +575,7 @@ let transfer_to_savings = new Serializer( } ); -let transfer_from_savings = new Serializer( +let transfer_from_savings = new Serializer( "transfer_from_savings", { from: string, request_id: uint32, @@ -519,14 +585,14 @@ let transfer_from_savings = new Serializer( } ); -let cancel_transfer_from_savings = new Serializer( +let cancel_transfer_from_savings = new Serializer( "cancel_transfer_from_savings", { from: string, request_id: uint32 } ); -let custom_binary = new Serializer( +let custom_binary = new Serializer( "custom_binary", { required_owner_auths: set(string), required_active_auths: set(string), @@ -537,14 +603,14 @@ let custom_binary = new Serializer( } ); -let decline_voting_rights = new Serializer( +let decline_voting_rights = new Serializer( "decline_voting_rights", { account: string, decline: bool } ); -let reset_account = new Serializer( +let reset_account = new Serializer( "reset_account", { reset_account: string, account_to_reset: string, @@ -552,7 +618,7 @@ let reset_account = new Serializer( } ); -let set_reset_account = new Serializer( +let set_reset_account = new Serializer( "set_reset_account", { account: string, current_reset_account: string, @@ -560,7 +626,7 @@ let set_reset_account = new Serializer( } ); -let claim_reward_balance = new Serializer( +let claim_reward_balance = new Serializer( "claim_reward_balance", { account: string, reward_steem: asset, @@ -569,7 +635,7 @@ let claim_reward_balance = new Serializer( } ); -let delegate_vesting_shares = new Serializer( +let delegate_vesting_shares = new Serializer( "delegate_vesting_shares", { delegator: string, delegatee: string, @@ -577,7 +643,7 @@ let delegate_vesting_shares = new Serializer( } ); -let account_create_with_delegation = new Serializer( +let account_create_with_delegation = new Serializer( "account_create_with_delegation", { fee: asset, delegation: asset, @@ -592,7 +658,170 @@ let account_create_with_delegation = new Serializer( } ); -let fill_convert_request = new Serializer( +let witness_set_properties = new Serializer( + "witness_set_properties", { + owner: string, + props: string, + extensions: set(future_extensions) +} +); + +let account_update2 = new Serializer( + "account_update2", { + account: string, + owner: optional(authority), + active: optional(authority), + posting: optional(authority), + memo_key: optional(public_key), + json_metadata: string, + posting_json_metadata: string, + extensions: set(future_extensions) +} +); + +let create_proposal = new Serializer( + "create_proposal", { + creator: string, + receiver: string, + start_date: time_point_sec, + end_date: time_point_sec, + daily_pay: asset, + subject: string, + permlink: string, + extensions: set(future_extensions) +} +); + +let update_proposal_votes = new Serializer( + "update_proposal_votes", { + voter: string, + proposal_ids: array(uint64), + approve: bool, + extensions: set(future_extensions) +} +); + +let remove_proposal = new Serializer( + "remove_proposal", { + proposal_owner: string, + proposal_ids: array(uint64), + extensions: set(future_extensions) +} +); + +let claim_reward_balance2 = new Serializer( + "claim_reward_balance2", { + account: string, + reward_tokens: array(asset), + extensions: set(future_extensions) +} +); + +let vote2 = new Serializer( + "vote2", { + voter: string, + author: string, + permlink: string, + rshares: map((asset_symbol), (int64)), + extensions: set(future_extensions) +} +); + +let smt_create = new Serializer( + "smt_create", { + control_account: string, + symbol: asset_symbol, + smt_creation_fee: asset, + precision: uint8, + extensions: set(future_extensions) +} +); + +let smt_setup = new Serializer( + "smt_setup", { + control_account: string, + symbol: asset_symbol, + max_supply: int64, + contribution_begin_time: time_point_sec, + contribution_end_time: time_point_sec, + launch_time: time_point_sec, + steem_units_min: int64, + min_unit_ratio: uint32, + max_unit_ratio: uint32, + extensions: set(future_extensions) +} +); + +let smt_setup_emissions = new Serializer( + "smt_setup_emissions", { + control_account: string, + symbol: asset_symbol, + schedule_time: time_point_sec, + emissions_unit: smt_emissions_unit, + interval_seconds: uint32, + emission_count: uint32, + lep_time: time_point_sec, + rep_time: time_point_sec, + lep_abs_amount: int64, + rep_abs_amount: int64, + lep_rel_amount_numerator: uint32, + rep_rel_amount_numerator: uint32, + rel_amount_denom_bits: uint8, + remove: bool, + floor_emissions: bool, + extensions: set(future_extensions) +} +); + +let smt_setup_ico_tier = new Serializer( + "smt_setup_ico_tier", { + control_account: string, + symbol: asset_symbol, + steem_units_cap: int64, + generation_policy: static_variant([ + smt_capped_generation_policy + ]), + remove: bool, + extensions: set(future_extensions) + } + ); + +let smt_set_setup_parameters = new Serializer( + "smt_set_setup_parameters", { + control_account: string, + symbol: asset_symbol, + setup_parameters: set(static_variant([ + smt_param_allow_voting + ])), + extensions: set(future_extensions) +} +); + +let smt_set_runtime_parameters = new Serializer( + "smt_set_runtime_parameters", { + control_account: string, + symbol: asset_symbol, + runtime_parameters: set(static_variant([ + smt_param_windows_v1, + smt_param_vote_regeneration_period_seconds_v1, + smt_param_rewards_v1, + smt_param_allow_downvotes + ])), + extensions: set(future_extensions) +} +); + +let smt_contribute = new Serializer( + "smt_contribute", { + contributor: string, + symbol: asset_symbol, + contribution_id: uint32, + contribution: asset, + extensions: set(future_extensions) +} +); + +let fill_convert_request = new Serializer( "fill_convert_request", { owner: string, requestid: uint32, @@ -601,7 +830,7 @@ let fill_convert_request = new Serializer( } ); -let author_reward = new Serializer( +let author_reward = new Serializer( "author_reward", { author: string, permlink: string, @@ -611,7 +840,7 @@ let author_reward = new Serializer( } ); -let curation_reward = new Serializer( +let curation_reward = new Serializer( "curation_reward", { curator: string, reward: asset, @@ -620,7 +849,7 @@ let curation_reward = new Serializer( } ); -let comment_reward = new Serializer( +let comment_reward = new Serializer( "comment_reward", { author: string, permlink: string, @@ -628,21 +857,21 @@ let comment_reward = new Serializer( } ); -let liquidity_reward = new Serializer( +let liquidity_reward = new Serializer( "liquidity_reward", { owner: string, payout: asset } ); -let interest = new Serializer( +let interest = new Serializer( "interest", { owner: string, interest: asset } ); -let fill_vesting_withdraw = new Serializer( +let fill_vesting_withdraw = new Serializer( "fill_vesting_withdraw", { from_account: string, to_account: string, @@ -651,7 +880,7 @@ let fill_vesting_withdraw = new Serializer( } ); -let fill_order = new Serializer( +let fill_order = new Serializer( "fill_order", { current_owner: string, current_orderid: uint32, @@ -662,12 +891,12 @@ let fill_order = new Serializer( } ); -let shutdown_witness = new Serializer( +let shutdown_witness = new Serializer( "shutdown_witness", {owner: string} ); -let fill_transfer_from_savings = new Serializer( +let fill_transfer_from_savings = new Serializer( "fill_transfer_from_savings", { from: string, to: string, @@ -677,26 +906,26 @@ let fill_transfer_from_savings = new Serializer( } ); -let hardfork = new Serializer( +let hardfork = new Serializer( "hardfork", {hardfork_id: uint32} ); -let comment_payout_update = new Serializer( +let comment_payout_update = new Serializer( "comment_payout_update", { author: string, permlink: string } ); -let return_vesting_delegation = new Serializer( +let return_vesting_delegation = new Serializer( "return_vesting_delegation", { account: string, vesting_shares: asset } ); -let comment_benefactor_reward = new Serializer( +let comment_benefactor_reward = new Serializer( "comment_benefactor_reward", { benefactor: string, author: string, @@ -706,65 +935,79 @@ let comment_benefactor_reward = new Serializer( ); operation.st_operations = [ - vote, - comment, - transfer, - transfer_to_vesting, - withdraw_vesting, - limit_order_create, - limit_order_cancel, - feed_publish, - convert, - account_create, - account_update, - witness_update, - account_witness_vote, - account_witness_proxy, - pow, - custom, - report_over_production, - delete_comment, - custom_json, - comment_options, - set_withdraw_vesting_route, - limit_order_create2, - challenge_authority, - prove_authority, - request_account_recovery, - recover_account, - change_recovery_account, - escrow_transfer, - escrow_dispute, - escrow_release, - pow2, - escrow_approve, - transfer_to_savings, - transfer_from_savings, - cancel_transfer_from_savings, - custom_binary, - decline_voting_rights, - reset_account, - set_reset_account, - claim_reward_balance, - delegate_vesting_shares, - account_create_with_delegation, - fill_convert_request, - author_reward, - curation_reward, - comment_reward, - liquidity_reward, - interest, - fill_vesting_withdraw, - fill_order, - shutdown_witness, - fill_transfer_from_savings, - hardfork, - comment_payout_update, - return_vesting_delegation, + vote, + comment, + transfer, + transfer_to_vesting, + withdraw_vesting, + limit_order_create, + limit_order_cancel, + feed_publish, + convert, + account_create, + account_update, + witness_update, + account_witness_vote, + account_witness_proxy, + pow, + custom, + report_over_production, + delete_comment, + custom_json, + comment_options, + set_withdraw_vesting_route, + limit_order_create2, + claim_account, + create_claimed_account, + request_account_recovery, + recover_account, + change_recovery_account, + escrow_transfer, + escrow_dispute, + escrow_release, + pow2, + escrow_approve, + transfer_to_savings, + transfer_from_savings, + cancel_transfer_from_savings, + custom_binary, + decline_voting_rights, + reset_account, + set_reset_account, + claim_reward_balance, + delegate_vesting_shares, + account_create_with_delegation, + witness_set_properties, + account_update2, + create_proposal, + update_proposal_votes, + remove_proposal, + claim_reward_balance2, + vote2, + smt_setup, + smt_setup_emissions, + smt_setup_ico_tier, + smt_set_setup_parameters, + smt_set_runtime_parameters, + smt_create, + smt_contribute, + fill_convert_request, + author_reward, + curation_reward, + comment_reward, + liquidity_reward, + interest, + fill_vesting_withdraw, + fill_order, + shutdown_witness, + fill_transfer_from_savings, + hardfork, + comment_payout_update, + return_vesting_delegation, comment_benefactor_reward ]; -let transaction = new Serializer( +let transaction = new Serializer( "transaction", { ref_block_num: uint16, ref_block_prefix: uint32, diff --git a/src/auth/serializer/src/types.js b/src/auth/serializer/src/types.js index 4551a09d..397b85d8 100644 --- a/src/auth/serializer/src/types.js +++ b/src/auth/serializer/src/types.js @@ -6,15 +6,63 @@ const v = require('./validation'); const ObjectId = require('./object_id') const fp = require('./fast_parser'); const chain_types = require('./ChainTypes') +//const BigInt = require('BigInt') import { PublicKey, Address, ecc_config } from "../../ecc" import { fromImpliedDecimal } from "./number_utils" +import Config from "../../../config.js" const Types = {} module.exports = Types const HEX_DUMP = process.env.npm_config__graphene_serializer_hex_dump +// Highly optimized implementation of Damm algorithm +// https://en.wikipedia.org/wiki/Damm_algorithm +function damm_checksum_8digit( value ) { + if( value >= 100000000 ) + throw new Error("Expected value less than 100000000, instead got " + value ) + + const t = [ + 0, 30, 10, 70, 50, 90, 80, 60, 40, 20, + 70, 0, 90, 20, 10, 50, 40, 80, 60, 30, + 40, 20, 0, 60, 80, 70, 10, 30, 50, 90, + 10, 70, 50, 0, 90, 80, 30, 40, 20, 60, + 60, 10, 20, 30, 0, 40, 50, 90, 70, 80, + 30, 60, 70, 40, 20, 0, 90, 50, 80, 10, + 50, 80, 60, 90, 70, 20, 0, 10, 30, 40, + 80, 90, 40, 50, 30, 60, 20, 0, 10, 70, + 90, 40, 30, 80, 60, 10, 70, 20, 0, 50, + 20, 50, 80, 10, 40, 30, 60, 70, 90, 0 + ]; + + let q0 = value/10 + let d0 = value%10 + let q1 = q0/10 + let d1 = q0%10 + let q2 = q1/10 + let d2 = q1%10 + let q3 = q2/10 + let d3 = q2%10 + let q4 = q3/10 + let d4 = q3%10 + let q5 = q4/10 + let d5 = q4%10 + let d6 = q5%10 + let d7 = q5/10 + + let x = t[d7] + x = t[x+d6] + x = t[x+d5] + x = t[x+d4] + x = t[x+d3] + x = t[x+d2] + x = t[x+d1] + x = t[x+d0] + + return x/10 +} + /** * Asset symbols contain the following information * @@ -25,34 +73,120 @@ const HEX_DUMP = process.env.npm_config__graphene_serializer_hex_dump * * It is treated as a uint64_t for all internal operations, but * is easily converted to something that can be displayed. +* +* Legacy serialization of assets +* 0000pppp aaaaaaaa bbbbbbbb cccccccc dddddddd eeeeeeee ffffffff 00000000 +* Symbol = abcdef +* +* NAI serialization of assets +* aaa1pppp bbbbbbbb cccccccc dddddddd +* NAI = (MSB to LSB) dddddddd cccccccc bbbbbbbb aaa +* +* NAI internal storage of legacy assets */ Types.asset = { fromByteBuffer(b){ let amount = b.readInt64() let precision = b.readUint8() - let b_copy = b.copy(b.offset, b.offset + 7) - let symbol = new Buffer(b_copy.toBinary(), "binary").toString().replace(/\x00/g, "") - b.skip(7); - // "1.000 STEEM" always written with full precision - let amount_string = fromImpliedDecimal(amount, precision) + let amount_string = "" + let symbol = "" + + if(precision >= 16) + { + // NAI Case + let b_copy = b.copy(b.offset - 1, b.offset + 3) + let nai = new Buffer(b_copy.toBinary(), "binary").readInt32() + nai = nai / 32 + symbol = "@@" + nai.toString().padStart(8, '0') + damm_checksum_8digit(nai).to_String() + precision = precision % 16 + b.skip(3) + amount_string = fromImpliedDecimal(amount,precision) + } + else + { + // Legacy Case + let b_copy = b.copy(b.offset, b.offset + 7) + symbol = new Buffer(b_copy.toBinary(), "binary").toString().replace(/\x00/g, "") + b.skip(7) + // "1.000 STEEM" always written with full precision + amount_string = fromImpliedDecimal(amount, precision) + } + return amount_string + " " + symbol }, appendByteBuffer(b, object){ - object = object.trim() - if( ! /^[0-9]+\.?[0-9]* [A-Za-z0-9]+$/.test(object)) - throw new Error("Expecting amount like '99.000 SYMBOL', instead got '" + object + "'") - - let [ amount, symbol ] = object.split(" ") - if(symbol.length > 6) - throw new Error("Symbols are not longer than 6 characters " + symbol + "-"+ symbol.length) - - b.writeInt64(v.to_long(amount.replace(".", ""))) - let dot = amount.indexOf(".") // 0.000 - let precision = dot === -1 ? 0 : amount.length - dot - 1 - b.writeUint8(precision) - b.append(symbol.toUpperCase(), 'binary') - for(let i = 0; i < 7 - symbol.length; i++) - b.writeUint8(0) + let amount = "" + let symbol = "" + let nai = 0 + let precision = 0 + + if(object["nai"]) + { + symbol = object["nai"] + nai = parseInt(symbol.slice(2)) + let checksum = nai % 10 + nai = Math.floor(nai / 10); + let expected_checksum = damm_checksum_8digit(nai) + + switch(object["nai"]) + { + case "@@000000021": + precision = 3 + symbol = Config.get( "address_prefix" ) == "STM" ? "STEEM" : "TESTS" + break + case "@@000000013": + precision = 3 + symbol = Config.get( "address_prefix" ) == "STM" ? "SBD" : "TBD" + break + case "@@000000037": + precision = 6 + symbol = "VESTS" + break + } + + precision = parseInt(object["precision"]) + b.writeInt64(v.to_long(parseInt(object["amount"]))) + } + else + { + object = object.trim() + if( ! /^[0-9]+\.?[0-9]* [A-Za-z0-9@]+$/.test(object)) + throw new Error("Expecting amount like '99.000 SYMBOL', instead got '" + object + "'") + + let res = object.split(" ") + amount = res[0] + symbol = res[1] + + if(symbol.startsWith("@@")) + { + // NAI Case + nai = parseInt(symbol.slice(2)) + let checksum = nai % 10 + nai = Math.floor(nai / 10); + let expected_checksum = damm_checksum_8digit(nai) + } + else if(symbol.length > 6) + throw new Error("Symbols are not longer than 6 characters " + symbol + "-"+ symbol.length) + + b.writeInt64(v.to_long(amount.replace(".", ""))) + let dot = amount.indexOf(".") // 0.000 + precision = dot === -1 ? 0 : amount.length - dot - 1 + } + + + if(symbol.startsWith("@@")) + { + nai = (nai << 5) + 16 + precision + b.writeUint32(nai) + } + else + { + b.writeUint8(precision) + b.append(symbol.toUpperCase(), 'binary') + for(let i = 0; i < 7 - symbol.length; i++) + b.writeUint8(0) + } + return }, fromObject(object){ @@ -64,6 +198,94 @@ Types.asset = { } } +Types.asset_symbol = { + fromByteBuffer(b){ + let precision = b.readUint8() + let amount_string = "" + let nai_string = "" + + if(precision >= 16) + { + // NAI Case + let b_copy = b.copy(b.offset - 1, b.offset + 3) + let nai = new Buffer(b_copy.toBinary(), "binary").readInt32() + nai = nai / 32 + nai_string = "@@" + nai.toString().padStart(8, '0') + damm_checksum_8digit(nai).to_String() + precision = precision % 16 + b.skip(3) + } + else + { + // Legacy Case + let b_copy = b.copy(b.offset, b.offset + 7) + let symbol = new Buffer(b_copy.toBinary(), "binary").toString().replace(/\x00/g, "") + if(symbol == "STEEM" || symbol == "TESTS") + nai_string = "@@000000021" + else if(symbol == "SBD" || symbol == "TBD") + nai_string = "@@000000013" + else if(symbol == "VESTS") + nai_string = "@@000000037" + else + throw new Error("Expecting non-smt core asset symbol, instead got '" + symbol + "'") + b.skip(7) + } + + return {"nai" : nai_string, "precision" : precision} + }, + appendByteBuffer(b, object){ + + let nai = 0 + if(!object["nai"].startsWith("@@")) + throw new Error("Asset Symbols NAIs must be prefixed with '@@'. Was " + object["nai"]) + + nai = parseInt(object["nai"].slice(2)) + let checksum = nai % 10 + nai = Math.floor(nai / 10); + let expected_checksum = damm_checksum_8digit(nai) + + let precision = 0; + let symbol = ""; + switch(object["nai"]) + { + case "@@000000021": + precision = 3 + symbol = Config.get( "address_prefix" ) == "STM" ? "STEEM" : "TESTS" + break + case "@@000000013": + precision = 3 + symbol = Config.get( "address_prefix" ) == "STM" ? "SBD" : "TBD" + break + case "@@000000037": + precision = 6 + symbol = "VESTS" + break + } + + if( precision > 0 ) + { + //Core Symbol Case + b.writeUint8(precision) + b.append(symbol, 'binary') + for(let i = 0; i < 7 - symbol.length; i++) + b.writeUint8(0) + } + else + { + nai = (nai << 5) + 16 + object["precision"] + b.writeUint32(nai) + } + + return + }, + fromObject(object){ + return object + }, + toObject(object, debug = {}){ + if (debug.use_default && object === undefined) { return "STEEM"; } + return object + } +} + Types.uint8 = { fromByteBuffer(b){ @@ -217,6 +439,25 @@ Types.uint64 = } }; +Types.uint128 = + {fromByteBuffer(b){ + b.readBigInt64(); + return b.readBigInt64(); + }, + appendByteBuffer(b, object){ + b.writeUint64(v.to_long(v.unsigned(0))); + b.writeUint64(v.to_long(v.unsigned(object))); + return; + }, + fromObject(object){ + return v.to_long(v.unsigned(object)); + }, + toObject(object, debug = {}){ + if (debug.use_default && object === undefined) { return "0"; } + return v.to_long(object).toString(); + } + }; + Types.string = {fromByteBuffer(b){ return new Buffer(b.readVString(), 'utf8'); diff --git a/src/broadcast/index.js b/src/broadcast/index.js index 81ecfe22..3890ff2d 100644 --- a/src/broadcast/index.js +++ b/src/broadcast/index.js @@ -54,8 +54,8 @@ steemBroadcast._prepareTransaction = function steemBroadcast$_prepareTransaction // Set defaults on the transaction const chainDate = new Date(properties.time + 'Z'); const refBlockNum = (properties.last_irreversible_block_num - 1) & 0xFFFF; - return steemApi.getBlockAsync(properties.last_irreversible_block_num).then((block) => { - const headBlockId = block.previous; + return steemApi.getBlockHeaderAsync(properties.last_irreversible_block_num).then((block) => { + const headBlockId = block ? block.previous : '0000000000000000000000000000000000000000'; return Object.assign({ ref_block_num: refBlockNum, ref_block_prefix: new Buffer(headBlockId, 'hex').readUInt32LE(4), @@ -76,7 +76,7 @@ operations.forEach((operation) => { const operationParams = operation.params || []; const useCommentPermlink = - operationParams.indexOf('parent_permlink') !== -1 && + operationParams.indexOf('parent_author') !== -1 && operationParams.indexOf('parent_permlink') !== -1; steemBroadcast[`${operationName}With`] = diff --git a/src/broadcast/operations.js b/src/broadcast/operations.js index 0834f98b..21501805 100644 --- a/src/broadcast/operations.js +++ b/src/broadcast/operations.js @@ -221,20 +221,26 @@ module.exports = [ ] }, { - "roles": ["posting", "active", "owner"], - "operation": "challenge_authority", + "roles": ["active", "owner"], + "operation": "claim_account", "params": [ - "challenger", - "challenged", - "require_owner" + "creator", + "fee", + "extensions" ] }, { "roles": ["active", "owner"], - "operation": "prove_authority", + "operation": "create_claimed_account", "params": [ - "challenged", - "require_owner" + "creator", + "new_account_name", + "owner", + "active", + "posting", + "memo_key", + "json_metadata", + "extensions" ] }, { @@ -425,6 +431,174 @@ module.exports = [ "extensions" ] }, + { + "roles": ["active", "owner"], + "operation": "witness_set_properties", + "params": [ + "owner", + "props", + "extensions" + ] + }, + { + "roles": ["posting", "active", "owner"], + "operation": "account_update2", + "params": [ + "account", + "owner", + "active", + "posting", + "memo_key", + "json_metadata", + "posting_json_metadata", + "extensions" + ] + }, + { + "roles": ["active", "owner"], + "operation": "create_proposal", + "params": [ + "creator", + "receiver", + "start_date", + "end_date", + "daily_pay", + "subject", + "permlink", + "extensions" + ] + }, + { + "roles": ["active", "owner"], + "operation": "update_proposal_votes", + "params": [ + "voter", + "proposal_ids", + "approve", + "extensions" + ] + }, + { + "roles": ["active", "owner"], + "operation": "remove_proposal", + "params": [ + "proposal_owner", + "proposal_ids", + "extensions" + ] + }, + { + "roles": ["posting", "active", "owner"], + "operation": "claim_reward_balance2", + "params": [ + "account", + "reward_tokens", + "extensions" + ] + }, + { + "roles": ["posting", "active", "owner"], + "operation": "vote2", + "params": [ + "voter", + "author", + "permlink", + "rshares", + "extensions" + ] + }, + { + "roles": ["active", "owner"], + "operation": "smt_create", + "params": [ + "control_account", + "symbol", + "smt_creation_fee", + "precision", + "extensions" + ] + }, + { + "roles": ["active", "owner"], + "operation": "smt_setup", + "params": [ + "control_account", + "symbol", + "max_supply", + "contribution_begin_time", + "contribution_end_time", + "launch_time", + "steem_units_min", + "min_unit_ratio", + "max_unit_ratio", + "extensions" + ] + }, + { + "roles": ["active", "owner"], + "operation": "smt_setup_emissions", + "params": [ + "control_account", + "symbol", + "schedule_time", + "emissions_unit", + "interval_seconds", + "interval_coount", + "lep_time", + "rep_time", + "lep_abs_amount", + "rep_abs_amount", + "lep_rel_amount_numerator", + "rep_rel_amount_numerator", + "rel_amount_denom_bits", + "remove", + "floor_emissions", + "extensions" + ] + }, + { + "roles": ["active", "owner"], + "operation": "smt_setup_ico_tier", + "params": [ + "control_account", + "symbol", + "steem_units_cap", + "generation_policy", + "remove", + "extensions" + ] + }, + { + "roles": ["active", "owner"], + "operation": "smt_set_setup_parameters", + "params": [ + "control_account", + "symbol", + "setup_parameters", + "extensions" + ] + }, + { + "roles": ["active", "owner"], + "operation": "smt_set_runtime_parameters", + "params": [ + "control_account", + "symbol", + "runtime_parameters", + "extensions" + ] + }, + { + "roles": ["active", "owner"], + "operation": "smt_contribute", + "params": [ + "contributor", + "symbol", + "contribution_id", + "contribution", + "extensions" + ] + }, { "roles": ["active", "owner"], "operation": "fill_convert_request", diff --git a/src/browser.js b/src/browser.js index b3640595..9a948e79 100644 --- a/src/browser.js +++ b/src/browser.js @@ -1,5 +1,6 @@ const api = require("./api"); const auth = require("./auth"); +const memo = require("./auth/memo"); const broadcast = require("./broadcast"); const config = require("./config"); const formatter = require("./formatter")(api); @@ -8,6 +9,7 @@ const utils = require("./utils"); const steem = { api, auth, + memo, broadcast, config, formatter, diff --git a/src/formatter.js b/src/formatter.js old mode 100644 new mode 100755 index b794afd1..d9e8bf24 --- a/src/formatter.js +++ b/src/formatter.js @@ -51,6 +51,15 @@ module.exports = steemAPI => { return { savings_pending, savings_sbd_pending }; } + function pricePerSteem(feed_price) { + let price_per_steem = undefined; + const { base, quote } = feed_price; + if (/ SBD$/.test(base) && / STEEM$/.test(quote)) { + price_per_steem = parseFloat(base.split(" ")[0]) / parseFloat(quote.split(" ")[0]); + } + return price_per_steem; + } + function estimateAccountValue( account, { gprops, feed_price, open_orders, savings_withdraws, vesting_steem } = {} @@ -63,7 +72,7 @@ module.exports = steemAPI => { if (!vesting_steem || !feed_price) { if (!gprops || !feed_price) { promises.push( - steemAPI.getStateAsync(`/@{username}`).then(data => { + steemAPI.getStateAsync(`/@${username}`).then(data => { gprops = data.props; feed_price = data.feed_price; vesting_steem = vestingSteem(account, gprops); @@ -97,10 +106,8 @@ module.exports = steemAPI => { } 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]); + let price_per_steem = pricePerSteem(feed_price); + const savings_balance = account.savings_balance; const savings_sbd_balance = account.savings_sbd_balance; const balance_steem = parseFloat(account.balance.split(" ")[0]); @@ -149,22 +156,14 @@ module.exports = steemAPI => { return { reputation: function(reputation) { - if (reputation == null) return reputation; - reputation = parseInt(reputation); + if (reputation == 0) return 25; + if (!reputation) return reputation; + let neg = reputation < 0; 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; + let v = (Math.log10((rep > 0 ? rep : -rep) - 10) - 9); + v = neg ? -v : v; + return parseInt(v * 9 + 25); }, vestToSteem: function( @@ -193,6 +192,7 @@ module.exports = steemAPI => { numberWithCommas, vestingSteem, estimateAccountValue, - createSuggestedPassword + createSuggestedPassword, + pricePerSteem }; }; diff --git a/test/Crypto.js b/test/Crypto.js index 05280781..d35c6ee2 100644 --- a/test/Crypto.js +++ b/test/Crypto.js @@ -1,3 +1,4 @@ +import config from "../src/config" import { Aes, PrivateKey, PublicKey, Signature } from "../src/auth/ecc" import assert from "assert" @@ -28,8 +29,9 @@ describe("steem.auth: Crypto", function() { describe("steem.auth: derives", ()=> { + let prefix = config.get("address_prefix") let one_time_private = PrivateKey.fromHex("8fdfdde486f696fd7c6313325e14d3ff0c34b6e2c390d1944cbfe150f4457168") - let to_public = PublicKey.fromStringOrThrow("STM7vbxtK1WaZqXsiCHPcjVFBewVj8HFRd5Z5XZDpN6Pvb2dZcMqK") + let to_public = PublicKey.fromStringOrThrow(prefix + "7vbxtK1WaZqXsiCHPcjVFBewVj8HFRd5Z5XZDpN6Pvb2dZcMqK") let secret = one_time_private.get_shared_secret( to_public ) let child = hash.sha256( secret ) diff --git a/test/KeyFormats.js b/test/KeyFormats.js index a96b7d97..11fbf674 100644 --- a/test/KeyFormats.js +++ b/test/KeyFormats.js @@ -4,7 +4,7 @@ import assert from "assert" var test = function(key) { describe("steem.auth: key_formats", function() { - it("Calcualtes public key from private key", function() { + it("Calculates public key from private key", function() { var private_key = PrivateKey.fromHex(key.private_key); var public_key = private_key.toPublicKey(); assert.equal(key.public_key, public_key.toPublicKeyString()); diff --git a/test/api.test.js b/test/api.test.js index fad95fe0..b2f15011 100644 --- a/test/api.test.js +++ b/test/api.test.js @@ -3,13 +3,16 @@ import assert from 'assert'; import should from 'should'; import testPost from './test-post.json'; import steem from '../src'; +import api from '../src/api'; describe('steem.api:', function () { this.timeout(30 * 1000); describe('setOptions', () => { it('works', () => { - steem.api.setOptions({ url: steem.config.get('websocket') }); + let url = steem.config.get('uri'); + if(! url) url = steem.config.get('websocket'); + steem.api.setOptions({ url: url, useAppbaseApi: true }); }); }); @@ -148,4 +151,213 @@ describe('steem.api:', function () { }); }); + describe('with retry', () => { + let steemApi; + beforeEach(() => { + steemApi = new api.Steem({}); + }); + + it('works by default', async function() { + let attempts = 0; + steemApi.setOptions({ + url: 'https://api.steemit.com', + fetchMethod: (uri, req) => new Promise((res, rej) => { + const data = JSON.parse(req.body); + res({ + ok: true, + json: () => Promise.resolve({ + jsonrpc: '2.0', + id: data.id, + result: ['ned'], + }), + }); + attempts++; + }), + }); + const result = await steemApi.getFollowersAsync('ned', 0, 'blog', 5) + assert.equal(attempts, 1); + assert.deepEqual(result, ['ned']); + }); + + it('does not retry by default', async() => { + let attempts = 0; + steemApi.setOptions({ + url: 'https://api.steemit.com', + fetchMethod: (uri, req) => new Promise((res, rej) => { + rej(new Error('Bad request')); + attempts++; + }), + }); + + let result; + let errored = false; + try { + result = await steemApi.getFollowersAsync('ned', 0, 'blog', 5) + } catch (e) { + errored = true; + } + assert.equal(attempts, 1); + assert.equal(errored, true); + }); + + it('works with retry passed as a boolean', async() => { + let attempts = 0; + steemApi.setOptions({ + url: 'https://api.steemit.com', + fetchMethod: (uri, req) => new Promise((res, rej) => { + const data = JSON.parse(req.body); + res({ + ok: true, + json: () => Promise.resolve({ + jsonrpc: '2.0', + id: data.id, + result: ['ned'], + }), + }); + attempts++; + }), + }); + + const result = await steemApi.getFollowersAsync('ned', 0, 'blog', 5) + assert.equal(attempts, 1); + assert.deepEqual(result, ['ned']); + }); + + it('retries with retry passed as a boolean', async() => { + let attempts = 0; + steemApi.setOptions({ + url: 'https://api.steemit.com', + retry: true, + fetchMethod: (uri, req) => new Promise((res, rej) => { + if (attempts < 1) { + rej(new Error('Bad request')); + } else { + const data = JSON.parse(req.body); + res({ + ok: true, + json: () => Promise.resolve({ + jsonrpc: '2.0', + id: data.id, + result: ['ned'], + }), + }); + } + attempts++; + }), + }); + + let result; + let errored = false; + try { + result = await steemApi.getFollowersAsync('ned', 0, 'blog', 5); + } catch (e) { + errored = true; + } + assert.equal(attempts, 2); + assert.equal(errored, false); + assert.deepEqual(result, ['ned']); + }); + + it('works with retry passed as an object', async() => { + steemApi.setOptions({ + url: 'https://api.steemit.com', + retry: { + retries: 3, + minTimeout: 1, // 1ms + }, + fetchMethod: (uri, req) => new Promise((res, rej) => { + const data = JSON.parse(req.body); + res({ + ok: 'true', + json: () => Promise.resolve({ + jsonrpc: '2.0', + id: data.id, + result: ['ned'], + }), + }); + }), + }); + + const result = await steemApi.getFollowersAsync('ned', 0, 'blog', 5); + assert.deepEqual(result, ['ned']); + }); + + it('retries with retry passed as an object', async() => { + let attempts = 0; + steemApi.setOptions({ + url: 'https://api.steemit.com', + retry: { + retries: 3, + minTimeout: 1, + }, + fetchMethod: (uri, req) => new Promise((res, rej) => { + if (attempts < 1) { + rej(new Error('Bad request')); + } else { + const data = JSON.parse(req.body); + res({ + ok: true, + json: () => Promise.resolve({ + jsonrpc: '2.0', + id: data.id, + result: ['ned'], + }), + }); + } + attempts++; + }), + }); + + let result; + let errored = false; + try { + result = await steemApi.getFollowersAsync('ned', 0, 'blog', 5); + } catch (e) { + errored = true; + } + assert.equal(attempts, 2); + assert.equal(errored, false); + assert.deepEqual(result, ['ned']); + }); + + it('does not retry non-retriable operations'); + }); + + describe('getRC', () => { + describe('getting a RC of an account', () => { + it('works', async () => { + const result = await steem.api.findRcAccountsAsync(["justinsunsteemit"]); + result.should.have.properties("rc_accounts"); + result["rc_accounts"][0].should.have.properties("rc_manabar"); + }); + it('clears listeners', async () => { + steem.api.listeners('message').should.have.lengthOf(0); + }); + }); + }); + + describe('getExpiringDelegations', () => { + describe('getting expired delegation of an account', () => { + it('works', async () => { + const result = await steem.api.getExpiringVestingDelegationsAsync("justyy", "2004-01-02T00:11:22", 100); + result.should.have.properties("length"); + }); + it('clears listeners', async () => { + steem.api.listeners('message').should.have.lengthOf(0); + }); + }); + }); + + describe('Account Recovery', () => { + describe('findChangeRecoveryAccountRequests', () => { + it('works', async () => { + const result = await steem.api.findChangeRecoveryAccountRequestsAsync(["justyy", "ety001"]); + result.should.have.properties("requests"); + result.requests.should.have.properties("length"); + }); + it('clears listeners', async () => { + steem.api.listeners('message').should.have.lengthOf(0); + }); + }); + }); }); diff --git a/test/broadcast.test.js b/test/broadcast.test.js index 7fe02325..ebf4dc2e 100644 --- a/test/broadcast.test.js +++ b/test/broadcast.test.js @@ -51,6 +51,67 @@ describe('steem.broadcast:', () => { }); }); + describe('no blocks on chain', () => { + it('works', async () => { + const newAccountName = username + '-' + Math.floor(Math.random() * 10000); + const keys = steem.auth.generateKeys( + username, password, ['posting', 'active', 'owner', 'memo']); + + const oldGetDynamicGlobalProperties = steem.api.getDynamicGlobalPropertiesAsync; + steem.api.getDynamicGlobalPropertiesAsync = () => Promise.resolve({ + time: '2019-04-14T21:30:56', + last_irreversible_block_num: 32047459, + }); + + // If the block returned is `null`, then no blocks are on the chain yet. + const oldGetBlockAsync = steem.api.getBlockAsync; + steem.api.getBlockAsync = () => Promise.resolve(null); + + try { + const tx = await steem.broadcast._prepareTransaction({ + extensions: [], + operations: [[ + 'account_create', + { + fee: '0.000 STEEM', + creator: username, + new_account_name: newAccountName, + owner: { + weight_threshold: 1, + account_auths: [], + key_auths: [[keys.owner, 1]], + }, + active: { + weight_threshold: 1, + account_auths: [], + key_auths: [[keys.active, 1]], + }, + posting: { + weight_threshold: 1, + account_auths: [], + key_auths: [[keys.posting, 1]], + }, + memo_key: keys.memo, + json_metadata: '', + extensions: [], + } + ]], + }); + + tx.should.have.properties([ + 'expiration', + 'ref_block_num', + 'ref_block_prefix', + 'extensions', + 'operations', + ]); + } finally { + steem.api.getDynamicGlobalPropertiesAsync = oldGetDynamicGlobalProperties; + steem.api.getBlockAsync = oldGetBlockAsync; + } + }); + }); + describe('downvoting', () => { it('works', async () => { const tx = await steem.broadcast.voteAsync( @@ -149,7 +210,7 @@ describe('steem.broadcast:', () => { ]); }); }); - + describe('writeOperations', () => { it('receives a properly formatted error response', () => { const wif = steem.auth.toWif('username', 'password', 'posting'); diff --git a/test/hf20-accounts.test.js b/test/hf20-accounts.test.js new file mode 100644 index 00000000..4a66acad --- /dev/null +++ b/test/hf20-accounts.test.js @@ -0,0 +1,76 @@ +import Promise from 'bluebird'; +import should from 'should'; +import steem from '../src'; + +const username = process.env.STEEM_USERNAME || 'guest123'; +const password = process.env.STEEM_PASSWORD; +const activeWif = steem.auth.toWif(username, password, 'active'); + +describe('steem.hf20-accounts:', () => { + it('has generated methods', () => { + should.exist(steem.broadcast.claimAccount); + should.exist(steem.broadcast.createClaimedAccount); + }); + + it('has promise methods', () => { + should.exist(steem.broadcast.claimAccountAsync); + should.exist(steem.broadcast.createClaimedAccountAsync); + }); + + + describe('claimAccount', () => { + +/* Skip these tests. Steem-js test infrastructure not set up for testing active auths + Blocked by Steem issue #3546 + it('signs and verifies auth', function(done) { + let tx = { + 'operations': [[ + 'claim_account', { + 'creator': username, + 'fee': '0.000 STEEM'}]] + } + + steem.api.callAsync('condenser_api.get_version', []).then((result) => { + if(result['blockchain_version'] < '0.22.0') return done(); + + steem.broadcast._prepareTransaction(tx).then(function(tx){ + tx = steem.auth.signTransaction(tx, [activeWif]); + steem.api.verifyAuthorityAsync(tx).then( + (result) => {result.should.equal(true); done();}, + (err) => {done(err);} + ); + }); + }); + + }); + + it('claims and creates account', function(done) { + this.skip(); // (!) need test account with enough RC + + steem.api.callAsync('condenser_api.get_version', []).then((result) => { + if(result['blockchain_version'] < '0.22.0') return done(); + + steem.broadcast.claimAccountAsync(activeWif, username, '0.000 STEEM', []).then((result) => { + let newAccountName = username + '-' + Math.floor(Math.random() * 10000); + let keys = steem.auth.generateKeys( + username, password, ['posting', 'active', 'owner', 'memo']); + + steem.broadcast.createClaimedAccountAsync( + activeWif, + username, + newAccountName, + keys['owner'], + keys['active'], + keys['posting'], + keys['memo'], + {}, [] + ).then((result) => { + should.exist(result); + done(); + }, (err) => {done(err)}); + }, (err) => {done(err)}); + }); + }); +*/ + }); +}); diff --git a/test/hf21-sps.test.js b/test/hf21-sps.test.js new file mode 100644 index 00000000..bb628ab3 --- /dev/null +++ b/test/hf21-sps.test.js @@ -0,0 +1,78 @@ +import assert from "assert" +import Promise from 'bluebird'; +import should from 'should'; +import steem from '../src'; + +const username = process.env.STEEM_USERNAME || 'guest123'; +const password = process.env.STEEM_PASSWORD; +const activeWif = steem.auth.toWif(username, password, 'active'); + +describe('steem.hf21-accounts:', () => { + it('has generated methods', () => { + should.exist(steem.broadcast.createProposal); + should.exist(steem.broadcast.updateProposalVotes); + should.exist(steem.broadcast.removeProposal); + }); + + it('has promise methods', () => { + should.exist(steem.broadcast.createProposalAsync); + should.exist(steem.broadcast.updateProposalVotesAsync); + should.exist(steem.broadcast.removeProposalAsync); + }); + + describe('create proposal ops', () => { +/* Skip these tests. Steem-js test infrastructure not set up for testing active auths + Blocked by Steem issue #3546 + it('signs and verifies create_proposal', function(done) { + let permlink = 'test'; + + let tx = { + 'operations': [[ + 'create_proposal', { + 'creator': username, + 'receiver': username, + 'start_date': '2019-09-01T00:00:00', + 'end_date': '2019-10-01T00:00:00', + 'daily_pay': '1.000 SBD', + 'subject': 'testing', + 'permlink': permlink + }]] + } + + steem.api.callAsync('condenser_api.get_version', []).then((result) => { + if(result['blockchain_version'] < '0.22.0') return done(); + result.should.have.property('blockchain_version'); + + steem.broadcast._prepareTransaction(tx).then(function(tx){ + tx = steem.auth.signTransaction(tx, [activeWif]); + steem.api.verifyAuthorityAsync(tx).then( + (result) => {result.should.equal(true); done();}, + (err) => {done(err);} + ); + }); + }); + }) + + it('signs and verifies update_proposal_votes', function(done) { + let tx = { + 'operations': [[ + 'update_proposal_votes', { + 'voter': username, + 'proposal_ids': [7], + 'approve': true + }]] + } + + return done(); + + steem.broadcast._prepareTransaction(tx).then(function(tx){ + tx = steem.auth.signTransaction(tx, [activeWif]); + steem.api.verifyAuthorityAsync(tx).then( + (result) => {result.should.equal(true); done();}, + (err) => {done(err);} + ); + }); + }) +*/ + }); +}); diff --git a/test/reputation.test.js b/test/reputation.test.js new file mode 100644 index 00000000..244a9aad --- /dev/null +++ b/test/reputation.test.js @@ -0,0 +1,36 @@ +import assert from 'assert'; +import steem from '../src'; + +describe('steem.format.reputation', ()=> { + const reputation = steem.formatter.reputation; + it('rep 0 => 25', () => { + assert.equal(reputation(0), 25); + }); + it('rep 95832978796820 => 69', () => { + assert.equal(reputation(95832978796820), 69); + }); + it('rep 10004392664120 => 61', () => { + assert.equal(reputation(10004392664120), 61); + }); + it('rep 30999525306309 => 65', () => { + assert.equal(reputation(30999525306309), 65); + }); + it('rep -37765258368568 => -16', () => { + assert.equal(reputation(-37765258368568), -16); + }); + it('rep 334486135407077 => 74', () => { + assert.equal(reputation(334486135407077), 74); + }); + it('rep null => null', () => { + assert.equal(reputation(null), null); + }); + it('rep undefined => undefined', () => { + assert.equal(reputation(undefined), undefined); + }); + it('rep -1234123412342234 => -29', () => { + assert.equal(reputation(-1234123412342234), -29); + }); + it('rep -22233344455 => 12', () => { + assert.equal(reputation(-22233344455), 12); + }); +}) diff --git a/test/smt.test.js b/test/smt.test.js new file mode 100644 index 00000000..29cd2be1 --- /dev/null +++ b/test/smt.test.js @@ -0,0 +1,347 @@ +import assert from 'assert' +import Promise from 'bluebird'; +import should from 'should'; +import steem from '../src'; + +const username = process.env.STEEM_USERNAME || 'guest123'; +const password = process.env.STEEM_PASSWORD; +const activeWif = steem.auth.toWif(username, password, 'active'); + +describe('steem.smt:', () => { + + describe('smt creation ops', () => { + it('signs and verifies smt_create', function(done) { + let url = steem.config.get('uri'); + steem.api.setOptions({ url: url, useAppbaseApi: true }); + + let tx = { + 'operations': [[ + 'smt_create', { + 'control_account': username, + 'symbol': {'nai':'@@631672482','precision':3}, + 'smt_creation_fee': {'amount':'10000','precision':3,'nai':'@@000000013'}, + 'precision': 3, + }]] + } + + steem.api.callAsync('condenser_api.get_version', []).then((result) => { + if(result['blockchain_version'] < '0.24.0') return done(); /* SKIP AS THIS WILL ONLY PASS ON A TESTNET CURRENTLY */ + result.should.have.property('blockchain_version'); + + steem.broadcast._prepareTransaction(tx).then(function(tx){ + tx = steem.auth.signTransaction(tx, [activeWif]); + steem.api.verifyAuthorityAsync(tx).then( + (result) => {result.should.equal(true); done();}, + (err) => {done(err);} + ); + }); + }); + }) + + it('signs and verifies smt_setup', function(done) { + let tx = { + 'operations': [[ + 'smt_setup', { + 'control_account' : username, + 'symbol' : {'nai':'@@631672482','precision':3}, + 'max_supply' : '1000000000000000', + 'contribution_begin_time' : '2020-12-21T00:00:00', + 'contribution_end_time' : '2021-12-21T00:00:00', + 'launch_time' : '2021-12-22T00:00:00', + 'steem_units_min' : 0, + 'min_unit_ratio' : 50, + 'max_unit_ratio' : 100, + 'extensions':[] + } + ]] + } + + steem.api.callAsync('condenser_api.get_version', []).then((result) => { + if(result['blockchain_version'] < '0.24.0') return done(); /* SKIP AS THIS WILL ONLY PASS ON A TESTNET CURRENTLY */ + result.should.have.property('blockchain_version'); + + steem.broadcast._prepareTransaction(tx).then(function(tx){ + tx = steem.auth.signTransaction(tx, [activeWif]); + steem.api.verifyAuthorityAsync(tx).then( + (result) => {result.should.equal(true); done();}, + (err) => {done(err);} + ); + }); + }); + }) + + it('signs and verifies smt_setup_ico_tier', function(done) { + let tx = { + 'operations': [[ + 'smt_setup_ico_tier', { + 'control_account' : username, + 'symbol' : {'nai':'@@631672482','precision':3}, + 'steem_units_cap' : 10000, + 'generation_policy' : [ + 0, + { + 'generation_unit' : { + 'steem_unit' : [ + ['$!alice.vesting',2], + ['$market_maker',2], + ['alice',2] + ], + 'token_unit' : [ + ['$!alice.vesting',2], + ['$from',2], + ['$from.vesting',2], + ['$market_maker',2], + ['$rewards',2], + ['alice',2] + ] + }, + 'extensions':[] + } + ], + 'remove' : false, + 'extensions':[] + }]] + } + + steem.api.callAsync('condenser_api.get_version', []).then((result) => { + if(result['blockchain_version'] < '0.24.0') return done(); /* SKIP AS THIS WILL ONLY PASS ON A TESTNET CURRENTLY */ + result.should.have.property('blockchain_version'); + + steem.broadcast._prepareTransaction(tx).then(function(tx){ + tx = steem.auth.signTransaction(tx, [activeWif]); + steem.api.verifyAuthorityAsync(tx).then( + (result) => {result.should.equal(true); done();}, + (err) => {done(err);} + ); + }); + }); + }) + + it('signs and verifies smt_setup_emissions', function(done) { + let tx = { + 'operations': [[ + 'smt_setup_emissions', { + 'control_account' : username, + 'symbol' : {'nai':'@@631672482','precision':3}, + 'schedule_time' : '2019-10-16T19:47:05', + 'emissions_unit' : { + 'token_unit' : [ + ['$market_maker',1], + ['$rewards',1], + ['$vesting',1] + ] + }, + 'interval_seconds' : 21600, + 'emission_count' : 1, + 'lep_time' : '1970-01-01T00:00:00', + 'rep_time' : '1970-01-01T00:00:00', + 'lep_abs_amount' : 0, + 'rep_abs_amount': 0, + 'lep_rel_amount_numerator' : 1, + 'rep_rel_amount_numerator' : 0, + 'rel_amount_denom_bits' : 0, + 'remove' : false, + 'floor_emissions' : false, + 'extensions':[] + }]] + } + + steem.api.callAsync('condenser_api.get_version', []).then((result) => { + if(result['blockchain_version'] < '0.24.0') return done(); /* SKIP AS THIS WILL ONLY PASS ON A TESTNET CURRENTLY */ + result.should.have.property('blockchain_version'); + + steem.broadcast._prepareTransaction(tx).then(function(tx){ + tx = steem.auth.signTransaction(tx, [activeWif]); + steem.api.verifyAuthorityAsync(tx).then( + (result) => {result.should.equal(true); done();}, + (err) => {done(err);} + ); + }); + }); + }) + + it('signs and verifies smt_set_setup_parameters', function(done) { + let tx = { + 'operations': [[ + 'smt_set_setup_parameters', { + 'control_account' : username, + 'symbol' : {'nai':'@@631672482','precision':3}, + 'setup_parameters' : [[ + 0, { + 'value':false + }]], + 'extensions':[] + }]] + } + + steem.api.callAsync('condenser_api.get_version', []).then((result) => { + if(result['blockchain_version'] < '0.24.0') return done(); /* SKIP AS THIS WILL ONLY PASS ON A TESTNET CURRENTLY */ + result.should.have.property('blockchain_version'); + + steem.broadcast._prepareTransaction(tx).then(function(tx){ + tx = steem.auth.signTransaction(tx, [activeWif]); + steem.api.verifyAuthorityAsync(tx).then( + (result) => {result.should.equal(true); done();}, + (err) => {done(err);} + ); + }); + }); + }) + + it('signs and verifies smt_set_runtime_parameters', function(done) { + let tx = { + 'operations': [[ + 'smt_set_runtime_parameters', { + 'control_account' : username, + 'symbol' : {'nai':'@@631672482','precision':3}, + 'runtime_parameters' : [[ + 1, { + 'vote_regeneration_period_seconds' : 604800, + 'votes_per_regeneration_period' : 6999 + }]], + 'extensions':[] + }]] + } + + steem.api.callAsync('condenser_api.get_version', []).then((result) => { + if(result['blockchain_version'] < '0.24.0') return done(); /* SKIP AS THIS WILL ONLY PASS ON A TESTNET CURRENTLY */ + result.should.have.property('blockchain_version'); + + steem.broadcast._prepareTransaction(tx).then(function(tx){ + tx = steem.auth.signTransaction(tx, [activeWif]); + steem.api.verifyAuthorityAsync(tx).then( + (result) => {result.should.equal(true); done();}, + (err) => {done(err);} + ); + }); + }); + }) + + it('signs and verifies smt_contribute', function(done) { + let tx = { + 'operations': [[ + 'smt_contribute', { + 'contributor' : username, + 'symbol' : {'nai':'@@631672482','precision':3}, + 'contribution_id' : 1, + 'contribution': {'amount':'1000','precision':3,'nai':'@@000000013'}, + 'extensions':[] + }]] + } + + steem.api.callAsync('condenser_api.get_version', []).then((result) => { + if(result['blockchain_version'] < '0.24.0') return done(); /* SKIP AS THIS WILL ONLY PASS ON A TESTNET CURRENTLY */ + result.should.have.property('blockchain_version'); + + steem.broadcast._prepareTransaction(tx).then(function(tx){ + tx = steem.auth.signTransaction(tx, [activeWif]); + steem.api.verifyAuthorityAsync(tx).then( + (result) => {result.should.equal(true); done();}, + (err) => {done(err);} + ); + }); + }); + }) + }); + + describe('smt extended ops', () => { + let permlink = 'test'; + + it('signs and verifies claim_rewards_balance2', function(done) { + let tx = { + 'operations': [[ + 'claim_reward_balance2', { + 'account' : username, + 'reward_tokens' : [ + {'amount':'1000','precision':3,'nai':'@@000000013'}, + {'amount':'1000','precision':3,'nai':'@@000000021'}, + {'amount':'1000000','precision':6,'nai':'@@000000037'}, + {'amount':'1','precision':1,'nai':'@@631672482'}, + {'amount':'1','precision':0,'nai':'@@642246725'}, + {'amount':'1','precision':1,'nai':'@@678264426'} + ], + 'extensions':[] + }]] + } + + steem.api.callAsync('condenser_api.get_version', []).then((result) => { + if(result['blockchain_version'] < '0.24.0') return done(); /* SKIP AS THIS WILL ONLY PASS ON A TESTNET CURRENTLY */ + result.should.have.property('blockchain_version'); + + steem.broadcast._prepareTransaction(tx).then(function(tx){ + tx = steem.auth.signTransaction(tx, [activeWif]); + steem.api.verifyAuthorityAsync(tx).then( + (result) => {result.should.equal(true); done();}, + (err) => {done(err);} + ); + }); + }); + }) + + it('signs and verifies comment_options', function(done) { + let tx = { + 'operations': [[ + 'comment_options', { + 'author' : username, + 'permlink' : permlink, + 'max_accepted_payout' : '1000000.000 TESTS', + 'percent_steem_dollars' : 10000, + 'allow_votes' : true, + 'allow_curation_rewards' : true, + 'extensions' : [[ + 1, { + 'votable_assets':[[ + {'nai':'@@631672482','precision':3}, { + 'max_accepted_payout' : 10, + 'allow_curation_rewards' : true, + 'beneficiaries' : { + 'beneficiaries' : [ + { 'account' : 'alice', 'weight' : 100 }, + { 'account': 'bob' , 'weight' : 100 } + ]}}]]}]]}]] + } + + steem.api.callAsync('condenser_api.get_version', []).then((result) => { + if(result['blockchain_version'] < '0.24.0') return done(); /* SKIP AS THIS WILL ONLY PASS ON A TESTNET CURRENTLY */ + result.should.have.property('blockchain_version'); + + steem.broadcast._prepareTransaction(tx).then(function(tx){ + tx = steem.auth.signTransaction(tx, [activeWif]); + steem.api.verifyAuthorityAsync(tx).then( + (result) => {result.should.equal(true); done();}, + (err) => {done(err);} + ); + }); + }); + }) + + it('signs and verifies vote2', function(done) { + let tx = { + 'operations': [[ + 'vote2', { + 'voter' : username, + 'author' : username, + 'permlink' : permlink, + 'rshares': [ + [{'nai':'@@631672482','precision':3},2000000000], + [{'nai':'@@000000013','precision':3},81502331182] + ], + 'extensions':[] + }]] + } + + steem.api.callAsync('condenser_api.get_version', []).then((result) => { + if(result['blockchain_version'] < '0.24.0') return done(); /* SKIP AS THIS WILL ONLY PASS ON A TESTNET CURRENTLY */ + result.should.have.property('blockchain_version'); + + steem.broadcast._prepareTransaction(tx).then(function(tx){ + tx = steem.auth.signTransaction(tx, [activeWif]); + steem.api.verifyAuthorityAsync(tx).then( + (result) => {result.should.equal(true); done();}, + (err) => {done(err);} + ); + }); + }); + }) + }); +}); diff --git a/yarn.lock b/yarn.lock index 26d01555..683e4ca2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6,9 +6,10 @@ version "1.0.1" resolved "https://registry.yarnpkg.com/@steemit/libcrypto/-/libcrypto-1.0.1.tgz#c31ab3e5deb667628169b3d54d746b015de31a79" -"@steemit/rpc-auth@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@steemit/rpc-auth/-/rpc-auth-1.1.0.tgz#4170c04d928ef37af5bdbde3f517ef74909480bd" +"@steemit/rpc-auth@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@steemit/rpc-auth/-/rpc-auth-1.1.1.tgz#8f6239e89783d2b251b49e9e1b9486b5d167f944" + integrity sha512-Eb8BW3O1y4+/+Dbf+LqGVmgXYqyfHxP9mBlmzkpjXiIepTpxoK90NIGrneqcnEGq0TR2nSt4BVv9Ur9c+hxoig== dependencies: "@steemit/libcrypto" "^1.0.1" @@ -133,8 +134,11 @@ asap@~2.0.3: resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" asn1@~0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + dependencies: + safer-buffer "~2.1.0" assert-plus@1.0.0, assert-plus@^1.0.0: version "1.0.0" @@ -667,6 +671,7 @@ babylon@^6.17.0, babylon@^6.18.0: balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= base-x@^3.0.2: version "3.0.3" @@ -683,8 +688,9 @@ base64-js@^1.0.2: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886" bcrypt-pbkdf@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= dependencies: tweetnacl "^0.14.3" @@ -703,6 +709,7 @@ binary-extensions@^1.0.0: block-stream@*: version "0.0.9" resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= dependencies: inherits "~2.0.0" @@ -717,8 +724,9 @@ boom@2.x.x: hoek "2.x.x" brace-expansion@^1.1.7: - version "1.1.8" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" @@ -925,6 +933,7 @@ commoner@^0.10.1: concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= concat-stream@^1.5.2: version "1.6.0" @@ -995,12 +1004,12 @@ cross-env@^5.0.0: cross-spawn "^5.1.0" is-windows "^1.0.0" -cross-fetch@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-1.1.1.tgz#dede6865ae30f37eae62ac90ebb7bdac002b05a0" +cross-fetch@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" + integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== dependencies: - node-fetch "1.7.3" - whatwg-fetch "2.0.3" + node-fetch "2.6.7" cross-spawn@^5.1.0: version "5.1.0" @@ -1035,6 +1044,14 @@ d@1: dependencies: es5-ext "^0.10.9" +d@^1.0.1, d@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.2.tgz#2aefd554b81981e7dccf72d6842ae725cb17e5de" + integrity sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw== + dependencies: + es5-ext "^0.10.64" + type "^2.7.2" + damerau-levenshtein@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz#03191c432cb6eea168bb77f3a55ffdccb8978514" @@ -1042,6 +1059,7 @@ damerau-levenshtein@^1.0.0: dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= dependencies: assert-plus "^1.0.0" @@ -1147,10 +1165,12 @@ domain-browser@^1.1.1: resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" ecc-jsbn@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= dependencies: jsbn "~0.1.0" + safer-buffer "^2.1.0" ecurve@^1.0.5: version "1.0.6" @@ -1163,12 +1183,6 @@ emojis-list@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" -encoding@^0.1.11: - version "0.1.12" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" - dependencies: - iconv-lite "~0.4.13" - enhanced-resolve@~0.9.0: version "0.9.1" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz#4d6e689b3725f86090927ccc86cd9f1635b89e2e" @@ -1208,14 +1222,17 @@ es-to-primitive@^1.1.1: is-date-object "^1.0.1" is-symbol "^1.0.1" -es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.37" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.37.tgz#0ee741d148b80069ba27d020393756af257defc3" +es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.62, es5-ext@^0.10.64, es5-ext@^0.10.9, es5-ext@~0.10.14: + version "0.10.64" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.64.tgz#12e4ffb48f1ba2ea777f1fcdd1918ef73ea21714" + integrity sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg== dependencies: - es6-iterator "~2.0.1" - es6-symbol "~3.1.1" + es6-iterator "^2.0.3" + es6-symbol "^3.1.3" + esniff "^2.0.1" + next-tick "^1.1.0" -es6-iterator@^2.0.1, es6-iterator@~2.0.1: +es6-iterator@^2.0.1, es6-iterator@^2.0.3, es6-iterator@~2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" dependencies: @@ -1251,6 +1268,14 @@ es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: d "1" es5-ext "~0.10.14" +es6-symbol@^3.1.3: + version "3.1.4" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.4.tgz#f4e7d28013770b4208ecbf3e0bf14d3bcb557b8c" + integrity sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg== + dependencies: + d "^1.0.2" + ext "^1.7.0" + es6-weak-map@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" @@ -1360,6 +1385,16 @@ eslint@^3.5.0: text-table "~0.2.0" user-home "^2.0.0" +esniff@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/esniff/-/esniff-2.0.1.tgz#a4d4b43a5c71c7ec51c51098c1d8a29081f9b308" + integrity sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg== + dependencies: + d "^1.0.1" + es5-ext "^0.10.62" + event-emitter "^0.3.5" + type "^2.7.2" + espree@^3.4.0: version "3.5.2" resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.2.tgz#756ada8b979e9dcfcdb30aad8d1a9304a905e1ca" @@ -1400,7 +1435,7 @@ esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" -event-emitter@~0.3.5: +event-emitter@^0.3.5, event-emitter@~0.3.5: version "0.3.5" resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" dependencies: @@ -1434,9 +1469,17 @@ expand-range@^1.8.1: dependencies: fill-range "^2.1.0" +ext@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/ext/-/ext-1.7.0.tgz#0ea4383c0103d60e70be99e9a7f11027a33c4f5f" + integrity sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw== + dependencies: + type "^2.7.2" + extend@~3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== extglob@^0.3.1: version "0.3.2" @@ -1553,6 +1596,7 @@ fs-readdir-recursive@^1.0.0: fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= fsevents@^1.0.0: version "1.1.3" @@ -1569,9 +1613,10 @@ fstream-ignore@^1.0.5: inherits "2" minimatch "^3.0.0" -fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: - version "1.0.11" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" +fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" + integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== dependencies: graceful-fs "^4.1.2" inherits "~2.0.0" @@ -1608,6 +1653,7 @@ generate-object-property@^1.1.0: getpass@^0.1.1: version "0.1.7" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= dependencies: assert-plus "^1.0.0" @@ -1656,6 +1702,18 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.2: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^7.1.3: + version "7.1.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.5.tgz#6714c69bee20f3c3e64c4dd905553e532b40cdc0" + integrity sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + globals@^9.14.0, globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -1671,7 +1729,12 @@ globby@^5.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" -graceful-fs@^4.1.2, graceful-fs@^4.1.4: +graceful-fs@^4.1.2: + version "4.2.3" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" + integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== + +graceful-fs@^4.1.4: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" @@ -1763,7 +1826,7 @@ https-browserify@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82" -iconv-lite@^0.4.5, iconv-lite@~0.4.13: +iconv-lite@^0.4.5: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" @@ -1786,21 +1849,24 @@ indexof@0.0.1: inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= dependencies: once "^1.3.0" wrappy "1" inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== inherits@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" ini@~1.3.0: - version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + version "1.3.7" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84" + integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ== inquirer@^0.12.0: version "0.12.0" @@ -1951,10 +2017,6 @@ is-resolvable@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.1.tgz#acca1cd36dbe44b974b924321555a70ba03b1cf4" -is-stream@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - is-symbol@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" @@ -1999,6 +2061,7 @@ js-yaml@^3.5.1: jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= jsesc@^1.3.0: version "1.3.0" @@ -2161,8 +2224,9 @@ lodash.keys@^3.0.0: lodash.isarray "^3.0.0" lodash@^4.0.0, lodash@^4.16.4, lodash@^4.17.4, lodash@^4.3.0: - version "4.17.4" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== lolex@1.3.2: version "1.3.2" @@ -2238,12 +2302,14 @@ mime-types@^2.1.12, mime-types@~2.1.7: "minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== dependencies: brace-expansion "^1.1.7" minimist@0.0.8, minimist@~0.0.1: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= minimist@^1.2.0: version "1.2.0" @@ -2294,12 +2360,17 @@ natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" -node-fetch@1.7.3: - version "1.7.3" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" +next-tick@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" + integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== + +node-fetch@2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== dependencies: - encoding "^0.1.11" - is-stream "^1.0.1" + whatwg-url "^5.0.0" node-libs-browser@^0.7.0: version "0.7.0" @@ -2405,6 +2476,7 @@ object.omit@^2.0.0: once@^1.3.0, once@^1.3.3: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= dependencies: wrappy "1" @@ -2489,8 +2561,9 @@ path-is-inside@^1.0.1: resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" path-parse@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== pbkdf2-compat@2.0.1: version "2.0.1" @@ -2581,8 +2654,9 @@ q@^1.1.2: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" qs@~6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" + version "6.4.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.1.tgz#2bad97710a5b661c366b378b1e3a44a592ff45e6" + integrity sha512-LQy1Q1fcva/UsnP/6Iaa4lVeM49WiOitu2T4hZCyA/elLKu37L99qcBJk4VCCk+rdLvnMzfKyiN3SZTqdAZGSQ== querystring-es3@^0.2.0: version "0.2.1" @@ -2776,13 +2850,25 @@ restore-cursor@^1.0.1: exit-hook "^1.0.0" onetime "^1.0.0" +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= + right-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" dependencies: align-text "^0.1.1" -rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.6.1: +rimraf@2: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.6.1: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" dependencies: @@ -2813,13 +2899,19 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" +safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + samsam@1.1.2, samsam@~1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.1.2.tgz#bec11fdc83a9fda063401210e40176c3024d1567" -secure-random@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/secure-random/-/secure-random-1.1.1.tgz#0880f2d8c5185f4bcb4684058c836b4ddb07145a" +secure-random@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/secure-random/-/secure-random-1.1.2.tgz#ed103b460a851632d420d46448b2a900a41e7f7c" + integrity sha512-H2bdSKERKdBV1SwoqYm6C0y+9EA94v6SUBOWO8kDndc4NoUih7Dv6Tsgma7zO1lv27wIvjlD0ZpMQk7um5dheQ== semver@^5.3.0: version "5.4.1" @@ -2956,17 +3048,18 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" sshpk@^1.7.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" + version "1.16.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" - dashdash "^1.12.0" - getpass "^0.1.1" - optionalDependencies: bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" ecc-jsbn "~0.1.1" + getpass "^0.1.1" jsbn "~0.1.0" + safer-buffer "^2.0.2" tweetnacl "~0.14.0" stream-browserify@^2.0.1: @@ -3074,11 +3167,12 @@ tar-pack@^3.4.0: uid-number "^0.0.6" tar@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + version "2.2.2" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.2.tgz#0ca8848562c7299b8b446ff6a4d60cdbb23edc40" + integrity sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA== dependencies: block-stream "*" - fstream "^1.0.2" + fstream "^1.0.12" inherits "2" text-table@~0.2.0: @@ -3109,6 +3203,11 @@ tough-cookie@~2.3.0: dependencies: punycode "^1.4.1" +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= + trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" @@ -3126,6 +3225,7 @@ tunnel-agent@^0.6.0: tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= type-check@~0.3.2: version "0.3.2" @@ -3133,13 +3233,19 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" +type@^2.7.2: + version "2.7.3" + resolved "https://registry.yarnpkg.com/type/-/type-2.7.3.tgz#436981652129285cc3ba94f392886c2637ea0486" + integrity sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ== + typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" ua-parser-js@^0.7.9: - version "0.7.17" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" + version "0.7.28" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.28.tgz#8ba04e653f35ce210239c64661685bf9121dec31" + integrity sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g== uglify-js@~2.7.3: version "2.7.5" @@ -3158,10 +3264,6 @@ uid-number@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" -ultron@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" - url@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" @@ -3221,6 +3323,11 @@ watchpack@^0.2.1: chokidar "^1.0.0" graceful-fs "^4.1.2" +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= + webpack-core@~0.6.9: version "0.6.9" resolved "https://registry.yarnpkg.com/webpack-core/-/webpack-core-0.6.9.tgz#fc571588c8558da77be9efb6debdc5a3b172bdc2" @@ -3257,14 +3364,18 @@ webpack@^1.13.2: watchpack "^0.2.1" webpack-core "~0.6.9" -whatwg-fetch@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84" - whatwg-fetch@^0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-0.9.0.tgz#0e3684c6cb9995b43efc9df03e4c365d95fd9cc0" +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + which@^1.2.9: version "1.3.0" resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" @@ -3296,6 +3407,7 @@ wordwrap@~1.0.0: wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= write@^0.2.1: version "0.2.1" @@ -3303,13 +3415,12 @@ write@^0.2.1: dependencies: mkdirp "^0.5.1" -ws@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.2.tgz#96c1d08b3fefda1d5c1e33700d3bfaa9be2d5608" +ws@^5.2.4: + version "5.2.4" + resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.4.tgz#c7bea9f1cfb5f410de50e70e82662e562113f9a7" + integrity sha512-fFCejsuC8f9kOSu9FYaOw8CdO68O3h5v0lg4p74o8JqWpwTf9tniOD+nOB78aWoVSS6WptVUmDrp/KPsMVBWFQ== dependencies: async-limiter "~1.0.0" - safe-buffer "~5.1.0" - ultron "~1.1.0" xtend@^4.0.0: version "4.0.1"