用bsv.js和MatterCloud实现可以收发比特币BSV的极简钱包
这篇文章教大家如何自己编写一个极简的BSV钱包,可以生成私钥、地址,并发送交易。
准备工作
语言:JavaScript
环境:Node.js
操作系统:Win、Mac、Linux
推荐IDE:VSCode
首先,确保计算机上安装了Node.js并配置了环境变量,如果没有安装Node.js,可以到官网(https://nodejs.org/zh-cn/)下载安装。
新建一个工程文件夹,名字任意,例如SimplestWallet。用命令行打开这个文件夹。
依次输入如下命令安装所需的依赖包:
npm install bsv
npm install mattercloudjs
如果看到如下log,说明依赖包安装成功(版本号不一样没关系)。
...
+ aaa@qq.com
...
+ aaa@qq.com
...
其中,bsv库(https://docs.moneybutton.com/docs/bsv-overview.html)是用于比特币BSV的事务数据操作方法的库。
mattercloudjs库(https://www.mattercloud.net)封装了和比特币运营节点MatterCloud通信的网络API。
然后,我们需要申请一下MatterCloud的免费API权限。到官网(https://www.mattercloud.net)点击 `Get API Key` 按钮,
再点击Generate,即可得到Key。
生成私钥和地址
在制作钱包之前,我们先随机生成一个私钥。我们当然可以手动打入随机数,但正常做法是用随机算法生成,这样可以保证编码正确。
创建一个random-key.js文件,代码如下
const BSV = require('bsv') //引用bsv库
let priKey = BSV.PrivateKey.fromRandom() //随机生成私钥
console.log(priKey.toHex()) //输出Hex格式私钥
console.log(priKey.toAddress()) //输出地址
保存后,在命令行里用如下node命令运行该代码
node .\random-key.js
随即输出一个私钥和对应的地址,例如
79f5876834b1e179de0112fd150e3170259fc2863328bb39a3f6f07403686158
1F9929pRu1TETjzd69Yf3znzG5baywqFva
记录好私钥,但千万不要公开。这个地址就可以用来收款。
可以在https://cli.im自行制作地址的二维码,方便手机钱包扫码付款。
转入少量BSV
为了测试我们的钱包,需要一定的币,你也可以在写完代码后再转币。
在此列举几个获取少量币的方法。
https://sv.cafe/buy 小额人民币快速买BSV,下限1元。
https://if.cash/bsv/faucet BSV水龙头,免费领取币,但可能失败。
https://www.freebsv.com BSV水龙头,未测试。
如果你想知道当前地址的余额,可以在区块链浏览器查询到,如
https://satomoto.com/bitcoin-sv
编写转账功能
在工程文件夹里新建文件send-money.js,粘贴如下代码
const BSV = require('bsv') //引用bsv库
const MatterCloud = require('mattercloudjs') //引用MatterCloud库
const MatterCloudAPIKey = "CeJg9E1uuVJueBoJg6fkD5f5u7jBv4k7jj4cr6mmo8UTMzuqbq8Muzp3aXYTZ6bTh" //MatterCloud API Key
const matterAPI = MatterCloud.instance({
api_key: MatterCloudAPIKey,
})
let priKeyHex = "79f5876834b1e179de0112fd150e3170259fc2863328bb39a3f6f07403686158" //钱包私钥
let receiverAddresss = "1FjdJzaGXiUKQjnPBiTXqbuTPZMwypfoPC" //收款地址
let value = 1000 //收款金额(单位:Sat)
async function main() {
let priKey = BSV.PrivateKey.fromHex(priKeyHex) //组装私钥
let address = priKey.toAddress() //获取自己钱包的地址
//获取锁定在钱包地址上的所有UTXO
await matterAPI.getUtxos(address).then(async utxos => {
let newTx = new BSV.Transaction() //创建一个transaction
newTx.feePerKb(600) //设置手续费率为 0.6 Sat/Byte。 FIXME: 最终得到的tx的手续费和这里设置的不一致,原因不明
//不同服务商的费率不同,经测试MatterCloud的广播API至少要 0.5 Sat/Byte。
//将所有UTXO全部填入transaction的输入端(这是一种无脑做法,优秀的钱包应该智能地选择UTXO)
let inputs = []
utxos.forEach(utxo => {
inputs.push(utxo)
});
newTx.from(inputs)
//将收款地址对应的P2PKH输出添加到transaction的输出端
let output = BSV.Transaction.Output({
satoshis: value,
script: BSV.Script.fromAddress(receiverAddresss)
})
newTx.addOutput(output)
newTx.change(address) //将自己的地址设置为找零地址
newTx.sign(priKey) //用私钥给transaction签署
//生成16进制的transaction原数据,并输出,你可以用其他服务商来广播transaction
let rawTx = newTx.toBuffer().toString('hex')
console.log('RawTx:')
console.log(rawTx)
//用MatterCloud服务商广播transaction
await matterAPI.sendRawTx(rawTx).then(res => {
console.log('发送transaction成功:')
console.log(res) //输出广播transaction的结果,包含txid
}).catch(e => {
console.error(e)
})
})
}
main()
如果你的钱包地址上已经有币,就可以转账了。
注意修改代码中的几个变量:
- MatterCloudAPIKey。这是之前在MatterCloud免费获得的API Key。以后无需修改。
- priKeyHex。这是你自己的钱包私钥,也就是刚刚生成的那个。以后很少修改。
- receiverAddresss。本次转账的目标地址,每次转账时注意修改。
- value。本次转账的金额,以Sat为单位,每次转账也应该修改。
用node命令运行脚本:
node .\send-money.js
如果发送成功,则输出如下
RawTx:
0100000002616f4ed2d6f9ad733e0e79fc12ea25e5022b99ce028edc7fdce7c3cbebf3a482010000008b483045022100faf05e98a313f9272af265e4685ad101ff670d0a34f82b1fe880d3275f32f948022046b3e6ed50de5ef5847f1d96a2b48fe9ae5aaa5d4667bb43724092acbed45e594141048da20227dc514bc19ba554caa81d373fe2714828fed99e6dec0ca05503da6e2ea1f631deb355502b77d3ce4cde5584e3810fd7d25777878d1b3a1dc6a89bd76bffffffff631540441b4dd04f7dc970b0059cdbd76a008186d675d050c1e737c254a53366010000008a473044022028dfe3e8243513847995cb97060b9eab0042fb718382ebc71bb52fb7055de77502204aaf50c30daefd46da76291bed5bf5288ac6fbc172afd8c0898e46419069159a4141048da20227dc514bc19ba554caa81d373fe2714828fed99e6dec0ca05503da6e2ea1f631deb355502b77d3ce4cde5584e3810fd7d25777878d1b3a1dc6a89bd76bffffffff02e8030000000000001976a914a1a18aa70fe9c31c041c23eb6ee57f18c7cda25888aceb250000000000001976a9149b1bc88717b3d068d55a12519f4fd7fcc31f5ab588ac00000000
发送transaction成功:
{ txid: '7467a9782d56230d3eefd857fbc3b57a6bf77a5e5034c2ce679ba334ae803d69' }
最后得到的txid,就是transaction的hash,可以用来在区块链浏览器上查到刚刚发送的transaction。
回顾
log里输出的rawTx是16进制表示的transaction原数据。可以用https://whatsonchain.com/decode解码tx。如果广播不成功,还可以用https://whatsonchain.com/broadcast直接广播transaction原数据。
本案例里用到了两个库。
其中,bsv库用来处理比特币的数据结构、底层协议相关的东西,如生成私钥、地址,组装和签署transaction。
MatterCloud是一个数据服务商,让我们可以通过远程API查询链上数据,或者广播transaction。我们可以把MatterCloud换成其他数据服务商(区块链浏览器也会提供数据服务),如
https://developers.whatsonchain.com