Omni USDT Java版离线签名
前言
大家好,我是凉凉,今天是第一次写博客,如有不足之处,请多多包涵。
从事区块链钱包方向已经快一年了,一直处于研究方向,没时间分享经验,趁着这次机会就分享一下大家比较头疼的基于Omni协议上USDT有坑的地方,以及如何离线签名。
正文
1.转usdt的关键
我们先要知道BTC和USDT之间的关系,omni协议的usdt转账就是基于btc链的,见下图
如图就是一笔usdt转账,和btc转账的区别就是多了一个null_data的输出脚本
我们只要把这一部分构建好了就可以转usdt了
2.usdt的输出脚本的组成
6a146f6d6e69是固定的前缀,测试网络和正式网络都是一样的。
000000000000001f是31的16进制,补零补足16位
0000000000989680是金额*10^8再转16进制,补零补足16位
3.代码如何写
如果做过btc的离线签名,那么这一部分应该可以直接复用,加一个ouput就行了,需要引bitcoinj这个依赖,直接去仓库搜就行了
/**
* usdt 离线签名
* @param privateKey
* @param changeAddress
* @param changeAmount
* @param toAddress
* @param outputs
* @param amount
* @return
*/
public String sign(String privateKey, String changeAddress,Long changeAmount, String toAddress, List<Utxo> outputs,Long amount) {
MainNetParams network = MainNetParams.get();
Transaction tran = new Transaction(MainNetParams.get());
//这是比特币的限制最小转账金额,所以很多usdt转账会收到一笔0.00000546的btc
tran.addOutput(Coin.valueOf(546L), Address.fromBase58(network, toAddress));
//构建usdt的输出脚本 注意这里的金额是要乘10的8次方
String usdtHex = "6a146f6d6e69" + String.format("%016x", 31) + String.format("%016x", amount);
tran.addOutput(Coin.valueOf(0L), new Script(Utils.HEX.decode(usdtHex)));
//如果有找零就添加找零
if (changeAmount.compareTo(0L) > 0) {
tran.addOutput(Coin.valueOf(changeAmount), Address.fromBase58(network, changeAddress));
}
//先添加未签名的输入,也就是utxo
for (Utxo output : outputs) {
tran.addInput(Sha256Hash.wrap(output.getTxHash()), output.getVout(), new Script(HexUtil.decodeHex(output.getScriptPubKey()))).setSequenceNumber(TransactionInput.NO_SEQUENCE - 2);
}
//下面就是签名
for (int i = 0; i < outputs.size(); i++) {
Utxo output = outputs.get(i);
ECKey ecKey = DumpedPrivateKey.fromBase58(network, privateKey).getKey();
TransactionInput transactionInput = tran.getInput(i);
Script scriptPubKey = ScriptBuilder.createOutputScript(Address.fromBase58(network, output.getAddress()));
Sha256Hash hash = tran.hashForSignature(i, scriptPubKey, Transaction.SigHash.ALL, false);
ECKey.ECDSASignature ecSig = ecKey.sign(hash);
TransactionSignature txSig = new TransactionSignature(ecSig, Transaction.SigHash.ALL, false);
transactionInput.setScriptSig(ScriptBuilder.createInputScript(txSig, ecKey));
}
//这是签名之后的原始交易,直接去广播就行了
String signedHex = HexUtil.encodeHexStr(tran.bitcoinSerialize());
//这是交易的hash
String txHash = HexUtil.encodeHexStr(Utils.reverseBytes(Sha256Hash.hash(Sha256Hash.hash(tran.bitcoinSerialize()))));
return signedHex;
}
如果有什么不明白的直接下面留言,或者加我qq:520283995