OmniTool.NET开发包 - 用C#高效开发Omni/USDT区块链应用
OmniTool.Net开发包适用于为.Net/C#应用快速增加对Omni Layer/USDT数字资产的支持能力,即支持使用自有Omni Layer节点的应用场景,也支持基于第三方API服务和离线裸交易的轻量级部署场景。OmniTool.Net开发包官方下载地址:http://sc.hubwiz.com/codebag/omni-dotnet-lib/。
1、开发包概述
OmniTool.Net开发包主要包含以下特性:
- 完善的Omni Layer节点RPC API封装
- 支持利用自有节点或第三方服务获取指定地址的比特币utxo集合
- 支持离线生成omni代币转账裸交易
- 支持利用自有节点或第三方服务广播裸交易
OmniTool.Net支持本地部署的Omnicored节点,也支持第三方服务提供的开放API,要增加新的第三方服务也非常简单,只需要参考代码实现如下接口:
- IUtxoCollector:utxo收集器
- IBroadcaster:裸交易广播器
OmniTool.Net软件包当前版本1.0.0,主要类/接口及关系如下图所示:
OmniTool.Net软件包主要代码文件清单如下:
代码文件 | 说明 |
---|---|
OmniTool.sln | OmniTool.Net解决方案文件 |
OmniTool/OmniTool.csproj | OmniTool.Net开发库项目文件 |
OmniTool/OmniClient.cs | OmniLayer/Bitcoin RPC API客户端 |
OmniTool/RpcModule.cs | RPC API模块实现类 |
OmniTool/ToolKit.cs | 开发库入口类 |
OmniTool/IKeyStore.cs | 密钥存储接口 |
OmniTool/IUtxoCollector.cs | UTXO采集器接口 |
OmniTool/IUtxoSelector.cs | UTXO选择器接口 |
OmniTool/IBroadcaster.cs | 裸交易广播器接口 |
OmniTool/KeyStoreMemory.cs | 内存密钥存储库实现类 |
OmniTool/KeyStoreSqlite.cs | SQLite密钥存储库实现类 |
OmniTool/UtxoCollectorRpc.cs | 基于RPC API的UTXO采集器实现类 |
OmniTool/UtxoCollectorSmartbit.cs | 基于云端第三方API的UTXO采集器实现类 |
OmniTool/UtxoSelectorDefault.cs | UTXO选择器接口的默认策略实现类 |
OmniTool/BroadcasterRpc.cs | 基于RPC API的裸交易广播器实现类 |
OmniTool/BroadcasterSmartbit.cs | 基于云端第三方API的裸交易广播器实现类 |
OmniTool/UtxoBag.cs | UTXO集合类 |
OmniTool/Utxo.cs | UTXO模型类 |
OmniTool/KeyStoreItem.cs | 密钥存储记录类 |
OmniTool/Utils.cs | 辅助工具类 |
Demo/Demo.csproj | OmniTool.Net演示应用项目文件 |
Demo/Program.cs | 演示应用入口代码 |
Demo/RpcClientDemo.cs | Omni/Btc RPC API客户端使用方法演示代码 |
Demo/MemoryKeyStoreDemo.csproj | 内存密钥库使用方法演示代码 |
Demo/SqliteKeyStoreDemo.csproj | Sqlite密钥库使用方法演示代码 |
Demo/BtcTxRpcDemo.cs | 比特币转账交易演示代码,基于RPC API |
Demo/BtcTxCloudDemo.cs | 比特币转账交易演示代码,基于第三方服务API |
Demo/OmniTxRpcDemo.cs | Omni/USDT代币转账交易演示代码,基于RPC API |
Demo/OmniTxCloudDemo.cs | Omni/USDT代币转账交易演示代码,基于第三方服务API |
2、OmniClient类使用说明
OmniClient类封装了比特币以及Omni Layer的RPC API接口协议。创建OmniClient对象时,需要传入
包含有效身份信息的节点RPC URL。例如,假设安装在本机的omnicored节点软件接入主网,其配置如下:
- rpcuser:user
- rpcpassword:123456
- rpcport:8332
那么可以使用如下的代码来实例化OmniClient:
//using OmniTool; OmniClient client = new OmniClient( "http://user:123456@127.0.0.1:8332", /*节点RPC API的URL*/ "main" /*接入的Bitcoin网络*/ );
OmniCore节点在Bitcoin原有的RPC接口之外,扩充了额外的接口用来操作Omni层的数据,这些扩展的RPC接口采用omni_
前缀以区隔于Bitcoin的原有RPC接口。为了便于区隔这两层的RPC调用,OmniClient引入了协议子模块的概念,将Bitcoin的原始RPC接口和Omni的扩展RPC接口分别挂接到Btc
子模块和Omni
子模块。
例如,获取某个地址的USDT代币余额需要使用Omni层的omni_getbalance调用,这个RPC调用对应于RpcClient实例的omni
子模块的getBalance()
方法。下面的代码获取地址1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P
的USDT(资产ID:31)余额:
var ret = client.Omni.GetBalance( "1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P", /*账户地址*/ 31 /*Omni资产ID:USDT=31*/ ); Console.WriteLine(ret); /*返回JToken对象*/
类似的,可以使用omni_send调用来执行简单的USDT转账,这个调用对应于OmniClient实例的Omni
子模块的send()
方法。例如,下面的代码从地址3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY
向地址37FaKponF7zqoMLUjEiko25pDiuVH5YLEa
转入100.0个USDT代币:
var ret = client.Omni.Send( "3M9qvHKtgARhqcMtM5cRT9VaiDJ5PSfQGY", /*代币转出地址*/ "37FaKponF7zqoMLUjEiko25pDiuVH5YLEa", /*代币转入地址*/ 31, /*代币ID:USDT*/ "100.00" /*转移的代币数量*/ );
原有的Bitoin层的RPC接口则可以通过OmniClient的Btc
子模块来访问。例如,使用listunspent调用来获取本地节点中指定地址的utxo:
var ret = client.Btc.ListUnspent( 6, /*最小确认数*/ 999999, /*最大确认数*/ new String[]{"mgnucj8nYqdrPFh2JfZSB1NmUThUGnmsqe"} /*地址清单*/ );
开发包中的Demo/RpcClientDemo.cs
示例代码使用OmniClient完整演示了在Omni层的代币发行与转账功能,如果你计划搭建自己的Omni Core节点,相信这个示例会有很大帮助。
3、ToolKit类使用说明
如果不愿意搭建自己的Omni Core节点,而是希望基于第三方API为自己的.NET/C#应用增加对Omni Layer/USDT的支持,那么最简单的方法是使用离线交易的入口类ToolKit。
ToolKit类的主要作用是根据创建并广播Omni代币转账裸交易或比特币转账裸交易,它的基本使用步骤如下:
- 创建一个ToolKit实例
- 使用
AddKey()
方法将必要的私钥加入该ToolKit实例,例如转出地址的私钥,因为ToolKit需要利用私钥对裸交易进行签名 - 使用
SendOmnicoin()
方法生成并广播Omni代币转账裸交易,或者使用SendBitcoin()
方法生成并广播比特币转账裸交易
3.1 Omni/USDT代币转账
使用ToolKit实现的Omni/USDT代币转账示例代码如下,说明见注释:
//using OmniTool; String network = "main"; ToolKit kit = new ToolKit( network, /*接入的网络*/ new KeyStoreMemory(), /*使用内存密钥库*/ new UtxoCollectorSmartbit(network), /*使用云端Utxo采集器*/ new UtxoSelectorDefault(), /*使用默认策略Utxo选择器*/ new BroadcasterSmartbit(network) /*使用云端裸交易广播器*/ ); String privHex = "4aec8e45106....00d5c5a05b"; /*私钥:16进制字符串*/ kit.addKey(privHex); /*将私钥加入ToolKit*/ String from = kit.KeyStore.GetByKey(privHex).Address; /*私钥对应的地址作为发起账号*/ String to = "1GxX5tQR1C.....x2zbdj4mMuDcWR"; /*接收地址*/ String txid = kit.SendOmnicoin( from, /*发送方地址,私钥必须已经加入钱包*/ to, /*接收方地址*/ 31, /*转账代币ID,USDT=31*/ 10000 /*转账代币数量,调整为最小单位计量的整数*/ ); Console.WriteLine($"txid => {txid}"); /*打印交易哈希*/
注意:
- ToolKit实例利用钱包中的私钥生成地址列表,并利用这些地址从第三方服务获取utxo信息。 因此需要钱包中
的私钥对应地址在链上有utxo存在,ToolKit对象才能够成功构造并签名裸交易。 - 转账目标地址应当与创建Toolkit对象时指定的网络一致,例如主网的
p2pkh
地址,前缀应当为1
。
3.2 指定Omni交易的手续费支付地址
在Omni协议层不需要支付交易手续费,但是Omni交易所嵌入的比特币交易依然需要支付手续费。默认情况下SendOmnicoin()
方法使用发送方地址支付比特币交易手续费,但可以传入额外的参数来指定其他地址支付交易手续费,当你的.Net/C#应用需要实现多账户归集功能时,使用统一的手续费支付地址会更容易管理一些。
例如,下面的代码使用地址35stX1w6LKHj7hGHz6GVNzXZCdUhAeqDb6
支付Omni交易的手续费:
String txid = kit.SendOmnicoin( from, /*发送方地址,私钥必须已加入ToolKit*/ to, /*接收方地址*/ 31, /*转账OMNI代币ID,2:TOMN*/ 10000, /*转账OMNI代币数量*/ fundAddr: "35stX1w6LKH...CdUhAeqDb6" /*交易手续费支付地址,私钥必须已加入ToolKit*/ );
注意:
- 即使指定了余额充足的手续费支付地址,Omni交易的发送方依然必须有微量的比特币 余额(546 SATOSHI),因为Omni协议需要交易发送方至少有一个可用UTXO。- 手续费支付地址同时也是找零地址,多余的比特币将返回至该地址。
3.3 指定Omni交易的比特币转账数量
由于Omni交易要求发送方必须有可用的UTXO,因此为了便于接收Omni代币的地址可以继续流通所持有的Omni代币,SendOmnicoin()
方法在默认情况下将向接收方地址转入微量的比特币(546 SATOSHI),可以在调用该方法时修改这个默认数值。
例如,下面的代码转入接收方1000个SATOSHI:
String txid = kit.SendOmnicoin( from, /*发送方地址,私钥必须已加入ToolKit*/ to, /*接收方地址*/ 31, /*转账OMNI代币ID,2:TOMN*/ 10000, /*转账OMNI代币数量*/ fundAddr: "35stX1w6LKH...CdUhAeqDb6" /*交易手续费支付地址,私钥必须已加入ToolKit*/ refer: 1000 /*转账比特币数量,单位:SATOSHI*/ );
3.4 指定Omni交易的手续费
SendOmnicoin()
方法的默认手续费为10000 SATOSHI
,可以使用命名参数fee
来修改这一默认设定,例如设置为3000 SATOSHI
:
String txid = kit.SendOmnicoin( from, /*发送方地址,私钥必须已加入ToolKit*/ to, /*接收方地址*/ 31, /*转账OMNI代币ID,2:TOMN*/ 10000, /*转账OMNI代币数量*/ fee: 3000 /*交易手续费,单位:SATOSHI*/ );
3.5 仅生成Omni裸交易但不广播
有时可能只需要生成Omni转账裸交易但并不需要广播出去,可以使用SendOmnicoin()
方法的命名参数broadcast
来取消广播,这时将返回生成的裸交易。例如:
String rawtx = kit.SendOmnicoin( from, /*发送方地址,私钥必须已加入ToolKit*/ to, /*接收方地址*/ 31, /*转账OMNI代币ID,2:TOMN*/ 10000, /*转账OMNI代币数量*/ broadcast: false /*不广播*/ ); Console.WriteLine(rawtx); /*打印裸交易内容*/
3.6 比特币转账
OmniTool.Net也支持比特币转账裸交易的生成与广播。
例如,下面的代码从ToolKit的某个地址向其他地址转10000 SATOSHI
:
String privHex = "4aec8e45106....00d5c5a05b"; /*私钥:16进制字符串*/ kit.addKey(privHex); /*将私钥加入ToolKit*/ String from = kit.KeyStore.GetByKey(privHex).Address; /*私钥对应的地址作为发起账号*/ String to = "1GxX5tQR1C.....x2zbdj4mMuDcWR"; /*接收地址*/ String txid = kit.SendBitcoin( from, /*发送方地址*/ to, /*接收方地址*/ 10000 /*转账比特币数量,单位:SATOSHI*/ );
默认情况下,SendBitcoin()
方法使用发送方地址作为找零地址,也可以使用命名参数changeAddr
在调用时指定其他找零地址,例如,下面的代码创建一个新地址接收找零:
String changeAddr = kit.NewAddress(); /*创建新地址*/ String txid = kit.SendBitcoin( from, /*发送方地址*/ to, /*接收方地址*/ 10000, /*转账比特币数量,单位:SATOSHI*/ fee: 1500, /*手续费,单位:SATOSHI*/ changeAddr: changeAddr /*找零地址*/ );
类似的,当只需要生成裸交易而不希望广播时,可以使用broadcast
命名参数:
String rawtx = kit.SendBitcoin( from, /*发送方地址*/ to, /*接收方地址*/ 10000, /*转账比特币数量,单位:SATOSHI*/ broadcast: false /*找零地址*/ );
4、UTXO采集器
OmniTool.Net使用接口IUtxoCollector
来约定UTXO的采集功能。该接口的实现需要支持获取指定地址的候选UTXO集合,可指定多个地址。
接口方法:
UtxoBag Collect(String[] addresses); /*提取并返回候选UTXO集合*/
参数addresses
用来声明要收集UTXO的地址清单。
当前实现类:
- UtxoCollectorSmartbit:基于云端第三方API实现的Utxo采集器
- UtxoCollectorRpc:基于omnicored节点RPC API实现的Utxo采集器
例如,下面的代码使用UtxoCollectorSmartbit获取测试链某个指定地址的UTXO:
IUtxoCollector collector = new UtxoCollectorSmartbit( "testnet" /*测试链*/ ); String[] addresses = new String[]{"1C3TZ...brS2xHM"}; UtxoBag collected = collector.Collect( addresses /*地址清单*/ );
5、UTXO选择器
OmniTool.Net使用IUtxoSelector
来约定UTXO的筛选策略。该接口的实现需要根据目标金额从候选UTXO中选择可用UTXO,并返回新的UtxoBag实例。
接口方法:
UtxoBag Select(long target,UtxoBag collected); /*选择可消费UTXO,返回UtxoBag对象*/
参数target
声明要达成的最低金额目标,单位:SATOSHI。
参数collected
是候选的utxo集合,通常是IUtxoCollector的Collect()
调用返回的结果。
当前实现类:
- UtxoSelectorDefault:选择不少于6个确认的未消费UTXO
例如下面的代码使用UtxoSelectorDefault
实例从候选UTXO中删选出至少100000 SATOSHI
的UTXO:
//collected表示候选UTXO集合,来自Utxo采集器的Collect()调用结果 IUtxoSelector selector = new UtxoSelectorDefault(); UtxoBag selected = selector.Select( 100000, /*最低目标金额*/ collected /*候选UTXO集合*/ ); Console.WriteLine($"Total => {selected.Total}"); /*打印输出选中utxo总额*/
考虑到UTXO的不可分割性,筛选出的若干UTXO的总和,有可能超过目标金额。可以使用UtxoBag实例的Total
属性查看集合中的UTXO总额,如上。
6、裸交易广播器
OmniTool.Net使用IBroadcaster
接口约定裸交易广播的功能规格。该接口的实现应当将裸交易广播到Omni/Btc网络中。
接口方法:
String Broadcast(String rawtx); /*广播裸交易*/
参数rawtx
用来声明要广播的裸交易,类型为16进制字符串。
当前实现类:
- BroadcasterSmartbit
- BroadcasterRpc
例如,下面的代码使用BroadcasterSmartbit
将裸交易码流广播到Omni/Btc网络中:
IBroadcaster broadcaster = new BroadcasterSmartbit( "testnet" /*测试链*/ ); String txid = broadcaster.Broadcast( "01000000011da9283b4...59f58488ac00000000" /*裸交易*/ );
7、密钥存储接口
OmniTool.Net使用IKeyStore
约定密钥存储的功能规格。
接口方法:
bool Add(KeyStoreItem item); /*存入密钥*/ KeyStoreItem[] List(); /*浏览全部密钥*/ KeyStoreItem GetByKey(); /*查询指定16进制私钥对应的密钥信息*/ KeyStoreItem GetByWif(); /*查询指定WIF格式私钥对应的密钥信息*/ KeyStoreItem GetByAddress(); /*查询指定地址对应的密钥信息*/ KeyStoreItem GetByScript(); /*查询指定公钥脚本对应的密钥信息*/
IKeyStore
当前实现类有两个:
- KeyStoreMemory:基于内存字典实现,没有持久化能力,适合调试- KeyStoreSqlite:基于Sqlite数据库实现,适合作为生产环境密钥存储的参考实现。
密钥存储实例的主要功能就是为ToolKit提供密钥存储和查询能力。下面的代码使用KeyStoreSqlite来启动ToolKit,生成几个不同类型的地址,导入16进制私钥和WIF私钥,然后进行查询:
ToolKit kit = new ToolKit( "testnet", keyStore: new KeyStoreSqlite("./testnet.wallet") ); String addr1 = kit.NewAddress("SEGWIT-P2SH"); /*生成隔离见证p2sh地址*/ String addr2 = kit.NewAddress("SEGWIT"); /*生成隔离见证地址*/ String addr3 = kit.NewAddress("P2PKH"); /*生成P2PKH地址,默认选项*/ String addr4 = kit.AddKey( /*导入16进制私钥*/ "4aec8e45106....00d5c5a05b", "SEGWIT-P2SH" /*使用该私钥的SEGWIT-P2SH地址*/ ); String addr5 = kit.AddWif( /*导入WIF格式的私钥*/ "cNJFgo1driF...SkdcF6JXXwHMm" ); /*默认使用私钥的P2PKH地址*/ KeyStoreItem[] items = kit.List(); /*返回全部密钥记录*/ foreach(var item in items) { Console.WriteLine($"key => {item.Key}"); Console.WriteLine($"wif => {item.Wif}"); Console.WriteLine($"address => {item.Address}"); Console.WriteLine($"script => {item.Script}"); } KeyStoreItem item = Kit.GetByAddress(addr1); /*查询指定地址的密钥记录*/ Console.WriteLine($"key => {item.Key}");
OmniTool.NET下载地址:http://sc.hubwiz.com/codebag/omni-dotnet-lib/

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Python中lambda的使用,与它的三个好基友介绍!
匿名函数lambda 除了def语句,python还提供了一种生成函数对象的表达式形式。由于它与LISP语言中的一个工具类似,所以称为lambda。 就像def一样,这个表达式创建了一个之后能够调用的函数,但是它返回一个函数而不是将这个函数赋值给一个变量。这些就是lambda叫做匿名函数的原因。实际上,他常常以一种行内进行函数定义的方式使用,或者用作推迟执行一些代码。 lambda的一般形式是关键字lambda之后跟着一个或多个参数(与一个def头部内用括号括起来的参数列表类似),紧跟着是一个冒号,之后是表达式 lambda arg1,arg2,argn:expression using arguments 由lambda表达式所返回的函数对象与由def创建并复制后的函数对象工作起来是完全一致的,但lambda有一些不同之处,让其扮演特定的角色时更有用: lambda是一个表达式,而不是一个语句 因为这一点,lambda可以出现在python语法不允许def出现的地方。此外,作为一个表达式,lambda返回一个值(一个新的函数),可以选择性的赋值给一个变量相反,def语句总是得在头部将...
- 下一篇
Java描述设计模式(24):备忘录模式
本文源码:GitHub·点这里 || GitEE·点这里 一、生活场景 1、场景描述 常见的视频播放软件都具备这样一个功能:假设在播放视频西游记,如果这时候切换播放视频红楼梦,当再次切回播放西游记时,视频会从上次切走的时间点继续播放。下面基于备忘录设计模式来描述该场景流程。 2、场景图解 3、代码实现 public class C01_InScene { public static void main(String[] args) { Record record = new Record() ; Player player = new Player() ; PlayData pd1 = new PlayData("西游记","19:19") ; PlayData pd2 = new PlayData("红楼梦","29:19") ; player.setPlayData(pd1); player.saveProgress() ; System.out.println("正在播放:"+ player.getPlayData().getVideoName()+":"+ player.get...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS关闭SELinux安全模块
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- SpringBoot2整合Redis,开启缓存,提高访问速度
- CentOS7设置SWAP分区,小内存服务器的救世主
- CentOS7,8上快速安装Gitea,搭建Git服务器