USDT离线签名

落日映苍穹つ 2022-04-23 06:36 303阅读 0赞
  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.测试:
@Test
public void tranaction() throws Exception {
api.setIsMainNet(false);
String fromAddress = “mm26iTQBLEga8zJxvqURo81xuKE7y4m3hB”;
String toAddress = “mjsmd3HGE7erguBCqCef2jG98TZrFLX6LY”;
String privateKey = “xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx”;
List utxos = api.getUnspent(fromAddress);
Long amount = 10000L;
Integer propertyid = 1;
Long fee = api.getOmniFee(utxos);
String sign = api.omniSign(fromAddress, toAddress, privateKey, amount,fee, propertyid,utxos);
String txid = api.publishTx(sign);//广播交易
System.out.println(txid);
}

发表评论

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

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

相关阅读

    相关 USDT API

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

    相关 以太坊线签名交易

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

    相关 EOS JAVA 调用(线签名)

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

    相关 XRP-线签名

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