USDT离线签名

你的名字 2020-11-17 10:39 847阅读 0赞

本篇文章仍然使用bitcoinj开源项目来解决UDST的离线签名。

1.上代码:

  1. /**
  2. * usdt 离线签名
  3. *
  4. * @param privateKey:私钥
  5. * @param toAddress:接收地址
  6. * @param amount:转账金额
  7. * @return
  8. */
  9. public String omniSign(String fromAddress, String toAddress, String privateKey, Long amount, Long fee, Integer propertyid, List<UTXO> utxos) throws Exception {
  10. NetworkParameters networkParameters = isMainNet ? MainNetParams.get() : TestNet3Params.get();
  11. Transaction tran = new Transaction(networkParameters);
  12. if(utxos==null||utxos.size()==0){
  13. throw new Exception("utxo为空");
  14. }
  15. //这是比特币的限制最小转账金额,所以很多usdt转账会收到一笔0.00000546的btc
  16. Long miniBtc = 546L;
  17. tran.addOutput(Coin.valueOf(miniBtc), Address.fromBase58(networkParameters, toAddress));
  18. //构建usdt的输出脚本 注意这里的金额是要乘10的8次方
  19. String usdtHex = "6a146f6d6e69" + String.format("%016x", propertyid) + String.format("%016x", amount);
  20. tran.addOutput(Coin.valueOf(0L), new Script(Utils.HEX.decode(usdtHex)));
  21. //如果有找零就添加找零
  22. String changeAddress = fromAddress;
  23. Long changeAmount = 0L;
  24. Long utxoAmount = 0L;
  25. List<UTXO> needUtxo = new ArrayList<>();
  26. for (UTXO utxo : utxos) {
  27. if (utxoAmount > (fee + miniBtc)) {
  28. break;
  29. } else {
  30. needUtxo.add(utxo);
  31. utxoAmount += utxo.getValue().value;
  32. }
  33. }
  34. changeAmount = utxoAmount - (fee + miniBtc);
  35. //余额判断
  36. if (changeAmount < 0) {
  37. throw new Exception("utxo余额不足");
  38. }
  39. if (changeAmount > 0) {
  40. tran.addOutput(Coin.valueOf(changeAmount), Address.fromBase58(networkParameters, changeAddress));
  41. }
  42. //先添加未签名的输入,也就是utxo
  43. for (UTXO utxo : needUtxo) {
  44. tran.addInput(utxo.getHash(), utxo.getIndex(), utxo.getScript()).setSequenceNumber(TransactionInput.NO_SEQUENCE - 2);
  45. }
  46. //下面就是签名
  47. for (int i = 0; i < needUtxo.size(); i++) {
  48. ECKey ecKey = DumpedPrivateKey.fromBase58(networkParameters, privateKey).getKey();
  49. TransactionInput transactionInput = tran.getInput(i);
  50. Script scriptPubKey = ScriptBuilder.createOutputScript(Address.fromBase58(networkParameters, fromAddress));
  51. Sha256Hash hash = tran.hashForSignature(i, scriptPubKey, Transaction.SigHash.ALL, false);
  52. ECKey.ECDSASignature ecSig = ecKey.sign(hash);
  53. TransactionSignature txSig = new TransactionSignature(ecSig, Transaction.SigHash.ALL, false);
  54. transactionInput.setScriptSig(ScriptBuilder.createInputScript(txSig, ecKey));
  55. }
  56. //这是签名之后的原始交易,直接去广播就行了
  57. String signedHex = Hex.toHexString(tran.bitcoinSerialize());
  58. //这是交易的hash
  59. String txHash = Hex.toHexString(Utils.reverseBytes(Sha256Hash.hash(Sha256Hash.hash(tran.bitcoinSerialize()))));
  60. logger.info("fee:{},utxoAmount:{},changeAmount:{}", fee, utxoAmount, changeAmount);
  61. return signedHex;
  62. }
  63. /**
  64. * 获取矿工费用
  65. * @param utxos
  66. * @return
  67. */
  68. public Long getOmniFee(List<UTXO> utxos) {
  69. Long miniBtc = 546L;
  70. Long feeRate = getFeeRate();
  71. Long utxoAmount = 0L;
  72. Long fee = 0L;
  73. Long utxoSize = 0L;
  74. for (UTXO output : utxos) {
  75. utxoSize++;
  76. if (utxoAmount > (fee + miniBtc)) {
  77. break;
  78. } else {
  79. utxoAmount += output.getValue().value;
  80. fee = (utxoSize * 148 * 34 * 3 + 10) * feeRate;
  81. }
  82. }
  83. return fee;
  84. }
  85. /***
  86. * 获取未消费列表
  87. * @param address :地址
  88. * @return
  89. */
  90. public List<UTXO> getUnspent(String address) {
  91. List<UTXO> utxos = Lists.newArrayList();
  92. String host = this.isMainNet ? "blockchain.info" : "testnet.blockchain.info";
  93. String url = "https://" + host + "/zh-cn/unspent?active=" + address;
  94. try {
  95. String httpGet = HttpUtil.sendGet(url, null);//TODO;联网
  96. if (StringUtils.equals("No free outputs to spend", httpGet)) {
  97. return utxos;
  98. }
  99. JSONObject jsonObject = JSON.parseObject(httpGet);
  100. JSONArray unspentOutputs = jsonObject.getJSONArray("unspent_outputs");
  101. List<Map> outputs = JSONObject.parseArray(unspentOutputs.toJSONString(), Map.class);
  102. if (outputs == null || outputs.size() == 0) {
  103. System.out.println("交易异常,余额不足");
  104. }
  105. for (int i = 0; i < outputs.size(); i++) {
  106. Map outputsMap = outputs.get(i);
  107. String tx_hash = outputsMap.get("tx_hash").toString();
  108. String tx_hash_big_endian = outputsMap.get("tx_hash_big_endian").toString();
  109. String tx_index = outputsMap.get("tx_index").toString();
  110. String tx_output_n = outputsMap.get("tx_output_n").toString();
  111. String script = outputsMap.get("script").toString();
  112. String value = outputsMap.get("value").toString();
  113. String value_hex = outputsMap.get("value_hex").toString();
  114. String confirmations = outputsMap.get("confirmations").toString();
  115. UTXO utxo = new UTXO(Sha256Hash.wrap(tx_hash_big_endian), Long.valueOf(tx_output_n), Coin.valueOf(Long.valueOf(value)),
  116. 0, false, new Script(Hex.decode(script)));
  117. utxos.add(utxo);
  118. }
  119. return utxos;
  120. } catch (Exception e) {
  121. logger.error("【BTC获取未消费列表】失败,", e);
  122. return null;
  123. }
  124. }
  125. /**
  126. * 获取btc费率
  127. *
  128. * @return
  129. */
  130. public Long getFeeRate() {
  131. try {
  132. String httpGet1 = HttpUtil.sendGet("https://bitcoinfees.earn.com/api/v1/fees/recommended", null);
  133. Map map = JSON.parseObject(httpGet1, Map.class);
  134. Long fastestFee = Long.valueOf(map.get("fastestFee").toString());
  135. return fastestFee;
  136. } catch (Exception e) {
  137. e.printStackTrace();
  138. return 0L;
  139. }
  140. }

2.测试:

  1. @Test
  2. public void tranaction() throws Exception {
  3. api.setIsMainNet(false);
  4. String fromAddress = "mm26iTQBLEga8zJxvqURo81xuKE7y4m3hB";
  5. String toAddress = "mjsmd3HGE7erguBCqCef2jG98TZrFLX6LY";
  6. String privateKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
  7. List<UTXO> utxos = api.getUnspent(fromAddress);
  8. Long amount = 10000L;
  9. Integer propertyid = 1;
  10. Long fee = api.getOmniFee(utxos);
  11. String sign = api.omniSign(fromAddress, toAddress, privateKey, amount,fee, propertyid,utxos);
  12. String txid = api.publishTx(sign);//广播交易
  13. System.out.println(txid);
  14. }

发表评论

表情:
评论列表 (有 0 条评论,847人围观)

还没有评论,来说两句吧...

相关阅读

    相关 USDT API

    交易创建[Transaction creation][]          用于创建事务的RPC可用于创建和广播Omni Protocol事务。 结果返回广播事务的哈希

    相关 以太坊线签名交易

    1.什么是冷钱包? 冷钱包就是不连网的钱包,也叫离线钱包。热钱包就是保持联网上线的钱包,也就是在线钱包。冷钱包不联网会比热钱包更安全。 由于冷钱包只对交易信息进行签名,在通

    相关 EOS JAVA 调用(线签名)

    前言:  之前一篇文章是用的在线签名,本地启用了keosd服务,来管理用户密钥和数据签名. 本篇文章,直接离线签名,无需自己再启动eos的相关服务.  (上一篇文章[http

    相关 XRP-线签名

    这篇文章使用xrp测试环境实现以下功能: > 1.xrp离线签名交易; > 2.xrp充值; > 3.xrp生成秘钥对(要自己搭建xrp节点,测试网无法调用...