在开发喵星时重新应用了下hivejs的各个功能,把一些常用的应用场景都趟了一遍,也算有些心得。总结总结,给Hive社区的小伙伴们做些参考。
Hive dev
- 下载与资源
- 公共节点
- 安装与使用
- dhive
- Auth权限
- 获取帐户数据
- Hive登录逻辑
- 发布文章
- json_metadata
- 一篇文章的结构
- 点赞某篇文章
- 获取粉丝列表
- 获取关注列表
- 获取文章的函数们
- 获取作者的最近文章列表
- 获取所有文章并保存在本地
- 获取用户关注作者的文章列表
- 获取某篇文章的回复
- 获取某篇文章的所有回复
- 获取作者对别人的留言
- 获取对作者的评论
- 转帐HIVE或HBD
- 获取某位作者某篇文章的点赞
- 创建新用户
- HP代理
- 查询代理
下载与资源
公共节点
https://api.hive.blog @blocktrades
https://api.openhive.network @gtg
https://rpc.mahdiyari.info @mahdiyari
https://techcoderx.com @techcoderx
https://api.deathwing.me @deathwing
https://hive-api.arcange.eu @arcange
安装与使用
yarn add @hiveio/hive-js //^2.0.8
// npm install @hiveio/hive-js --save
//
import hive from '@hiveio/hive-js'
//初始化hive节点
const hiveConNode = 'https://api.openhive.network'
// const hiveConNode = 'https://api.hive.blog'
hive.api.setOptions({ url: hiveConNode})
dhive
npm install @hiveio/dhive --save
var dhive = require("@hiveio/dhive")
var client = new dhive.Client(["https://api.hive.blog", "https://api.hivekings.com", "https://api.openhive.network"])
var key = dhive.PrivateKey.fromLogin("username", "password", "posting")
Auth权限
//认证
hive.auth.verify(name, password, auths)
eg:
let username = 'epexa'
let password = 'P5...' // 用户密码
let auths = {
posting: [['STM6...']],
}
hive.auth.verify(username, password, auths) //return true or false
// Generate Keys 生成公钥对
hive.auth.generateKeys(name, password, roles)
let publicKeys = hive.auth.generateKeys(newAccountName, newAccountPassword, ['owner', 'active', 'posting', 'memo'])
//返回数据
{
owner: 'STM5sxKw1uEdryNmCj3xAxxxxxx',
active: 'STM5iEkPwjNPw6WecgeDxxxxx',
posting: 'STM7dKMMke2aiPTCnExxxx',
memo: 'STM8KxMKW5t9QkweXBogdxxxxxx'
}
// Get Private Keys 从用户名和密码得到对应的公私钥
hive.auth.getPrivateKeys(name, password, roles)
let roles = ['owner', 'active', 'posting', 'memo']
let res = hive.auth.getPrivateKeys(name, password, roles)
//返回数据
{
owner: '5JDZPwykhCb6ZmmvSUFcTsxxxxxxxx',
ownerPubkey: 'STM5sxKw1uEdryNmCxxxxxx',
active: '5JSxdtFeCNGSRt18u7WDxxxxxxxx',
activePubkey: 'STM5iEkPwjNPw6Wecxxxxx',
posting: '5KE3ET6DD6X47VWDUCXxxxxxxxx',
postingPubkey: 'STM7dKMMke2aixxxxxxxx',
memo: '5JgW5NNxT7VJAQMxjtCbDmFxxxxxxxx',
memoPubkey: 'STM8KxMKW5t9QkweXBoxxxxxx'
}
// Is Wif //判断是否是私钥,返回 true 或 false
hive.auth.isWif(privWif)
let privWif = "5JfxkpNEBFDxxxvxxxxxxxx"
let res = hive.auth.isWif(privWif) //true
// To Wif 从用户名和密码得到对应的私钥
hive.toWif(name, password, role)
let role = ["active"]
let res = hive.auth.toWif(name, password, role)
//返回数据
"5Jv9NHkL8TrdvJNue2EKZHQDbxxxxxxx"
// Wif Is Valid 验证公私钥对是否匹配,返回true 或 false
hive.auth.wifIsValid(privWif, pubWif)
let privWif = "5Jv9NHkL8TrdvJNubXxxxxxx"
let pubWif = "STM5f2H2rbSmVoEzrPxxxxxxxx"
let res = hive.auth.wifIsValid(privWif, pubWif) //true
// Wif To Public 从私钥得到对应的公钥
hive.auth.wifToPublic(privWif)
let privWif = "5Jv9NHkL8TrdvJNue2qxxxxxxx"
let res = hive.auth.wifToPublic(privWif)
// Sign Transaction
hive.auth.signTransaction(trx, keys)
获取帐户数据
帐户数据几乎都在这里了,包括创建的时间,余额,点赞能量等等。
let result = await hive.api.getAccountsAsync([account])
console.log(256, result, result.length === 0) //length为0表示帐户不存在
Hive登录逻辑
let account = "lucky"
let privWif = "5tikkkxxxxxx"
let result = await hive.api.getAccountsAsync([account])
if(result.length === 0){
return ('用户不存在!')
}
//判断是否私钥
let hiveres = hive.auth.isWif(privWif)
let postWif = privWif
if(hiveres !== true){
//获取发贴私钥(从密码)
let role = ["posting"]
postWif = hive.auth.toWif(account, privWif, role)
}
//公私钥是否配对
let pubWif = result[0].posting.key_auths[0][0]
let isvalid3 = hive.auth.wifIsValid(postWif, pubWif)
if(isvalid3 === true){
return ({
username: account,
wif: postWif,
avatar: `https://images.hive.blog/u/${account}/avatar`
})
} else {
return ('密钥错误!')
}
发布文章
发贴或评论都是用的同一个函数,只是发帖的parent_author为空。
hive.broadcast.comment(wif, parentAuthor, parentPermlink, author, permlink, title, body, jsonMetadata, function(err, result) {
console.log(err, result)
}) //commentAsync
//函数讲解
hive.broadcast.comment (
wif, //发帖密钥
parentAuthor, // 如果是发帖则为空,如果是评论则为父帖作者
parentPermlink, // 如果是发帖则为主标签,如果是评论则为父帖地址
author, // 作者
permlink, // URL地址
title, // 标题 ,如果是评论则为空
body, // 内容
jsonMetadata // json
)
eg:
let wif = '5pfffff'
let parentAuthor = ''
let parentPermlink = 'cn'
let author = 'lemooljiang'
let permlink = 'kdk54gf'
let title = '这是标题'
let body = '这是正文'
let tags = ['cn', 'miao', 'bitcoin']
let jsonMetadata = {"tags": tags, "dapp": "miao", "format": "markdown"}
hive.broadcast.comment(wif, parentAuthor, parentPermlink, author, permlink, title, body, jsonMetadata, function(err, result) {
console.log(1234, err, result)
})
// 另一种Async写法:
let res = await hive.broadcast.commentAsync(wif, parentAuthor, parentPermlink, author, permlink, title, body, jsonMetadata)
console.log(126, res)
/*
{ id: '1bea63265fd12d5bf725e1d1e7083eecb6444ff5', 22:17:06
ref_block_num: 4735,
ref_block_prefix: 588181965,
expiration: '2025-08-04T14:27:06',
operations: [ [ 'comment', [Object] ] ],
extensions: [],
signatures:
[ '2076f2e87b1d976804eexxxxxxxx' ] }
*/
json_metadata
post.json_metadata还可以按需求写入其它的数据,有点类似MongoDB。这样的话易于对文章进行过滤,也可保存一些特殊的数据。
json_metadata: "{"tags":["cn","network-institute","markdown","html"],"app":"miao","format":"markdown"}"
eg:
let jsonMetadata = {"tags": tags, "dapp": "miao", "format": "markdown", "cover": hash, "text": text}
JSON.stringify(jsonMetadata)
一篇文章的结构
{
author: 'lemooljiang',
permlink: 'tfdhqbvp',
category: 'hive-105017',
title: '洞庭南路离奇车祸,数人伤亡',
body: '昨晚的车祸由于发生在身边,不由感到阵阵后怕。车祸也是让人感到匪夷所思......',
json_metadata: '{"tags":["cn","cn-reader","yueyang","caraccident"],"dapp":"larkBlog","format":"markdown"}',
created: '2025-08-07T04:13:57',
last_update: '2025-08-07T04:13:57',
depth: 0,
children: 0,
last_payout: '1969-12-31T23:59:59',
cashout_time: '2025-08-14T04:13:57',
total_payout_value: '0.000 HBD',
curator_payout_value: '0.000 HBD',
pending_payout_value: '4.143 HBD',
promoted: '0.000 HBD',
replies: [],
body_length: 403,
author_reputation: 439510683431084,
parent_author: '',
parent_permlink: 'hive-105017',
url: '/hive-105017/@lemooljiang/tfdhqbvp',
root_title: '洞庭南路离奇车祸,数人伤亡',
beneficiaries: [],
max_accepted_payout: '1000000.000 HBD',
percent_hbd: 10000,
id: 144763251,
author_rewards: 0,
max_cashout_time: '1969-12-31T23:59:59',
reward_weight: 10000,
root_author: 'lemooljiang',
root_permlink: 'tfdhqbvp',
allow_replies: true,
allow_votes: true,
allow_curation_rewards: true,
reblogged_by: [],
net_votes: 37,
children_abs_rshares: 0,
total_pending_payout_value: '0.000 HBD',
total_vote_weight: 13801670934098,
vote_rshares: 13801670934098,
net_rshares: 13801670934098,
abs_rshares: 13801670934098,
active_votes: [{
percent: 7000,
reputation: 3100979937647200,
rshares: 5785001502757,
time: '2025-08-07T04:17:45',
voter: 'deanliu',
weight: 5785001502757
},......]
}
点赞某篇文章
hive.broadcast.vote(wif, voter, author, permlink, weight, function(err, result) {
console.log(err, result)
})
//函数讲解
hive.broadcast.vote (
wif, //发帖密钥
voter, //点赞人
author, //作者
permlink, // URL地址
weight //点赞比重,100*100
)
eg:
hive.broadcast.vote(
"5KRSmEMffffff",
"lemooljiang",
"starnote",
'6ekczn-2019',
10000,
function(err, result) {
console.log(8888, err, result)
})
获取粉丝列表
hive.api.getFollowers('lemooljiang', '', 'blog', 10, function(err, result) {
console.log(111, err, result)
})
获取关注列表
hive.api.getFollowing('lemooljiang', '', 'blog', 10, function(err, result) {
console.log(222, err, result)
})
获取文章的函数们
getDiscussionsByXXX
//query的参数结构
string tag;
uint32_t limit = 0;
set filter_tags;
set select_authors;
set select_tags;
uint32_t truncate_body = 0;
optional start_author;
optional start_permlink;
optional parent_author;
optional parent_permlink;
// 获取热门文章
hive.api.getDiscussionsByHot(query, function(err, result) {
console.log(err, result)
})
eg:
hive.api.getDiscussionsByHot({tag: 'photography', limit: 1}, function(err, result) {
console.log(err, result)
})
//获取某标签的趁势热贴(只有7天的)
hive.api.getDiscussionsByTrending({tag: 'photography', limit: 1}, function(err, result) {
console.log(err, result)
});
eg:
getTrending(){
let query = { tag: "cn", limit : 20 }
hive.api.getDiscussionsByTrending(query, function(err, data) {
//取到最后一篇文章的author和Permlink,做为下一次查询的起始点
author.value = data[data.length - 1].author
permlink.value = data[data.length - 1].permlink
})
}
//获取新帖(所有日期的)
hive.api.getDiscussionsByCreated({tag: 'photography', limit: 1}, function(err, result) {
console.log(err, result)
})
获取作者的最近文章列表
//获取最新文章
hive.api.getDiscussionsByAuthorBeforeDate(author, startPermlink, beforeDate, limit, function(err, result) {
console.log(err, result)
})
let author = username
let beforeDate = new Date().toISOString().split('.')[0]
let startPermlink = null
let result = await hive.api.getDiscussionsByAuthorBeforeDateAsync(author, startPermlink, beforeDate, 10)
// console.log(655,result) 一次最多能取100篇
获取所有文章并保存在本地
import hive from '@hiveio/hive-js'
import fs from "fs"
//初始化hive节点
const hiveConNode = 'https://api.openhive.network'
// const hiveConNode = 'https://api.hive.blog'
hive.api.setOptions({ url: hiveConNode})
const waiting = async() => {
return new Promise(resolve => {
setTimeout(resolve, 6000) //6秒
})
}
async function getArticles(author, startPermlink, beforeDate, limit){
let posts = []
while(true){
let result = await hive.api.getDiscussionsByAuthorBeforeDateAsync(author, startPermlink, beforeDate, limit)
console.log(655,"result:",result.length)
//如果查询数组为空,则已查询完,可以终止查询了 result: 0
if(result.length == 0){
console.log(8888, posts.length) //从新到旧的数组
break
}
//做一次遍历去掉重复的文章
result.forEach(post => {
if (post.permlink != startPermlink) {
//把数据规整
let newPost = {
"title": post.title,
"author": post.author,
"category": post.parent_permlink,
"permlink": post.permlink,
"body": post.body,
"created": post.created,
"tags": JSON.parse(post.json_metadata).tags //"tags":["cn-reader","cn"]
}
// posts.push(post)
posts.push(newPost)
}
})
//取到最后一篇文章的Permlink,做为下一次查询的起始点
startPermlink = result[result.length - 1].permlink
await waiting() //主要是因为节点的限制
}
console.log(5598, "posts", posts.length, posts[posts.length - 1].title, posts[posts.length - 1].created)
//保存为md文件
let path = './2025.md'
fs.writeFileSync(path, JSON.stringify(posts))
console.log(666, "save ok!")
return posts
}
let author = 'lemooljiang' //改成自己的名字
let beforeDate = new Date().toISOString().split('.')[0]
getArticles(author, null, beforeDate, 80) //传入要查询的作者名,初始标签,初始时间,一次查询的条数(最多是100)
获取用户关注作者的文章列表
let query = {tag: body.tag, limit: body.limit, start_author: body.author, start_permlink: body.permlink}
let result = await hive.api.getDiscussionsByFeedAsync(query)
eg:
let query = {tag: "lemooljiang", limit: 10, start_author: "nie", start_permlink: "sskxiik"}
let result = await hive.api.getDiscussionsByFeedAsync(query)
获取某篇文章的回复
hive.api.getContentReplies(author, permlink, function(err, result) {
console.log(err, result)
})
eg:
hive.api.getContentReplies('lemooljiang', 'hivejs-41', function(err, result) {
console.log(err, result)
})
获取某篇文章的所有回复
使用递归的方法获取
async function getAllReplies(author, permlink, res=[]) {
let replies = await hive.api.getContentRepliesAsync(author, permlink)
let children = []
replies.forEach(item => {
res.push(item)
if(item.children > 0){
//把得到的子数据塞进 .child 中
children.push(getAllReplies(item.author, item.permlink, item.child=[]))
}
})
await Promise.all(children)
return res
}
获取作者对别人的留言
let author = "lucky"
let query = { limit : 30, start_author: author, start_permlink: ""}
hive.api.getDiscussionsByComments(query, function(err, result) {
console.log(265, err, result)
}
获取对作者的评论
从帐户历史中遍历获取
async function getToAuthorReplies(author, limit){
//获取对作者的最新评论
let replies = []
let res = await hive.api.getAccountHistoryAsync(author, -1, limit)
res.forEach(item => {
if(item[1].op[0] == "comment" & item[1].op[1].parent_author == author){
replies.push(item)
}
})
return replies
}
转帐HIVE或HBD
hive.broadcast.transfer(wif, from, to, amount, memo, function(err, result) {
console.log(err, result)
})
// wif, from, to, amount, memo
// 转账私钥,发起转帐地址,转给谁, 金额, 备注
transfer("wif", "lemool", "lucky", "0.001 HBD", "You are awesome ! take some tokens")
eg:
async hiveTransfer(){
let from = "lemooljiang"
let to = "lucky"
let wif = "5KNxxxxxxxxxxxxxxxx"
// let ss = parseFloat(hivevalue).toFixed(3)
// let amount = ss+' HIVE'
let amount = "100.200 HIVE" //必须是3位小数且带上单位的格式,
let memo = "测试"
await hive.broadcast.transferAsync(wif, from, to, amount, memo)
}
获取某位作者某篇文章的点赞
let author = "lemooljiang"
let permlink = "pvw4dotxg"
let res = await hive.api.getActiveVotesAsync(author, permlink)
console.log(566, res)
创建新用户
hive.auth.generateKeys 用于生成4组密钥(owner, active, posting, memo), hvie.broadcast.accountCreate 用于创建账号
register() {
let newAccountName = "betty" //新帐户
let newAccountPassword = "FDDjjjRxxxxxxxx" //新帐户密码
let publicKeys = this.steem.auth.generateKeys(newAccountName, newAccountPassword, ['owner', 'active', 'posting', 'memo'])
let owner = { weight_threshold: 1, account_auths: [], key_auths: [[publicKeys.owner, 1]] }
let active = { weight_threshold: 1, account_auths: [], key_auths: [[publicKeys.active, 1]] }
let posting = { weight_threshold: 1, account_auths: [], key_auths: [[publicKeys.posting, 1]] }
let memoKey = publicKeys.memo
let creator = "lemooljiang" //创建者
let creatorWif = "5Jbfffxxxxx" //创建者的资金密钥
let fee = "3.000 HIVE" //费用
let jsonMetadata = ""
hvie.broadcast.accountCreate(
creatorWif,
fee,
creator,
newAccountName,
owner,
active,
posting,
memoKey,
jsonMetadata,
(err, result) => {
if(err){
console.log(444, '创建失败!', err)
}else{
console.log(666, '创建成功!', result)
}
})
}
HP代理
HP代理是以VESTS来计算的
hive.broadcast.delegateVestingShares(wif, delegator, delegatee, vesting_shares, function(err, result) {
console.log(err, result)
})
wif - 资金私钥
delegator - 代理人
delegatee - 被代理人
vesting_shares - hp要转换成vests
//VESTS和HP换算关系
async function main() {
let s = await hive.api.getDynamicGlobalPropertiesAsync()
console.log(11, s)
console.log(12, s.total_vesting_shares)
console.log(13, s.total_vesting_fund_hive)
console.log(14, "hp_to_vests", parseFloat(s.total_vesting_shares) / parseFloat(s.total_vesting_fund_hive))
}
main()
//
12 313254970159.720284 VESTS
13 188674228.477 HIVE
当前 1 HP = 1660.295487 VESTS
eg:
async delegate(){
let wif = '5KNxxxxxxxxxxxxxxx'
let delegator = 'lemool'
let delegatee = "lucky"
let a = await hive.api.getDynamicGlobalPropertiesAsync()
let hp_to_vests = parseFloat(a.total_vesting_shares) / parseFloat(a.total_vesting_fund_hive)
let b = '1.8' * hp_to_vests //代理1.8个HP
let c = b.toFixed(6) //6位小数
let vests = c+' VESTS' //换算成VESTS
await hive.broadcast.delegateVestingSharesAsync(wif, delegator, delegatee, vests)
}
////执行结果:
operations: Array(1)
0: Array(2)
0: "delegate_vesting_shares"
1:
delegatee: "tsteem.test"
delegator: "timool"
vesting_shares: "3483.359523 VESTS"
__proto__: Object
length: 2
注意: 最小代理量不能小于1HP,要取消代理直接把代理量设为0即可,取消代理要有7天才能回到原有帐户。
查询代理
hive.api.getVestingDelegations('ned', '', 2, function(err, result) {
console.log(err, result)
}) //null []
eg:
async getDelegateHP(){
let user = 'lemooljiang'
let res = await hive.api.getVestingDelegationsAsync(user, '', 2)
if(res.length == 0){
return 0
} else{
return parseFloat(res[0].vesting_shares)
}
}