關於omni-usdt離線交易:
如果是正式鏈,可以通過下面這個api獲取utxo:
blockchain : https://blockchain.info/unspent?active=你需要用到的地址
拿到未使用的utxo就可以進行離線交易了。
添加的依賴:
<dependency>
<groupId>org.bitcoinj</groupId>
<artifactId>bitcoinj-tools</artifactId>
<version>0.14.7</version>
</dependency>
<dependency>
<groupId>org.bitcoinj</groupId>
<artifactId>bitcoinj-examples</artifactId>
<version>0.14.7</version>
</dependency>
<dependency>
<groupId>org.bitcoinj</groupId>
<artifactId>bitcoinj-core</artifactId>
<version>0.14.7</version>
</dependency>
構建一個實體類:
@Data
public class UnSpentUtxo implements Serializable {
private static final long serialVersionUID = -7417428486644921613L;
private String hash; //未交易hash
private long txN;//vout
private long value;//金額
private int height; //高度
private String script;//簽名
private String address;//錢包地址
}
調用方法:
/**
*
* @param ptivateKey btc私鑰
* @param fromAddress 轉出地址
* @param privateUsdtKey usdt密鑰
* @param recivAddress usdt接收地址
* @param fee 手續費
* @param omniHex usdthex
* @param unBtcUtxo btc utxo --手續費用
* @param unSpentUsdtUtxo usdt utxo --轉賬用
* @return
*/
public String CreateRawTransaction(String ptivateKey,String fromAddress,String privateUsdtKey,String recivAddress,long fee,String omniHex,
List<UnSpentUtxo> unBtcUtxo,List<UnSpentUtxo> unSpentUsdtUtxo){
List<UTXO> btcUtxos = new ArrayList<>();
List<UTXO> usdtUtxos = new ArrayList<>();
try {
if(!unBtcUtxo.isEmpty() && !unSpentUsdtUtxo.isEmpty()){
//find a btc eckey info
DumpedPrivateKey btcPrikey = DumpedPrivateKey.fromBase58(TestNet3Params.get(), ptivateKey);
ECKey btcKey = btcPrikey.getKey();
//find a usdt eckey info
DumpedPrivateKey usdtPrivateKey = DumpedPrivateKey.fromBase58(TestNet3Params.get(), privateUsdtKey);
ECKey usdtKey = usdtPrivateKey.getKey();
//rec 地址
Address receiveAddress = Address.fromBase58(TestNet3Params.get(),recivAddress);
//create a transaction
Transaction tx = new Transaction(TestNet3Params.get());
//odd Address;
Address oddAddress = Address.fromBase58(TestNet3Params.get(), fromAddress);
//如果需要找零 消費列表總額-已經轉賬的金額 -手續費
long valueBtc = unBtcUtxo.stream().mapToLong(UnSpentUtxo::getValue).sum();
long valueUSDT = unSpentUsdtUtxo.stream().mapToLong(UnSpentUtxo::getValue).sum();
//總輸入 - 手續費 - 546 - 546 = 找零金額
long leave = (valueBtc + valueUSDT) - fee - 1092;
if(leave > 0){
tx.addOutput(Coin.valueOf(leave),oddAddress);
}
//usdt transaction
tx.addOutput(Coin.valueOf(546),new Script(Utils.HEX.decode(omniHex)));
//send to address
tx.addOutput(Coin.valueOf(546),receiveAddress);
//btc utxos is an array of inputs from my wallet
for(UnSpentUtxo unUtxo : unBtcUtxo){
btcUtxos.add(new UTXO(Sha256Hash.wrap(unUtxo.getHash()),
unUtxo.getTxN(),
Coin.valueOf(unUtxo.getValue()),
unUtxo.getHeight(),
false,
new Script(Utils.HEX.decode(unUtxo.getScript())),
unUtxo.getAddress()));
}
//usdt utxos is an array of inputs from my wallet
for(UnSpentUtxo unUtxo: unSpentUsdtUtxo){
usdtUtxos.add(new UTXO(Sha256Hash.wrap(unUtxo.getHash()),
unUtxo.getTxN(),
Coin.valueOf(unUtxo.getValue()),
unUtxo.getHeight(),
false,
new Script(Utils.HEX.decode(unUtxo.getScript())),
unUtxo.getAddress()));
}
//create usdt utxo data
for(UTXO utxo : usdtUtxos){
TransactionOutPoint outPoint = new TransactionOutPoint(TestNet3Params.get(), utxo.getIndex(), utxo.getHash());
tx.addSignedInput(outPoint, utxo.getScript(),usdtKey,Transaction.SigHash.ALL,true);
}
//create btc utxo data
for(UTXO utxo : btcUtxos){
TransactionOutPoint outPoint = new TransactionOutPoint(TestNet3Params.get(), utxo.getIndex(), utxo.getHash());
tx.addSignedInput(outPoint, utxo.getScript(),btcKey,Transaction.SigHash.ALL,true);
}
Context context = new Context(TestNet3Params.get());
tx.getConfidence().setSource(TransactionConfidence.Source.NETWORK);
tx.setPurpose(Transaction.Purpose.USER_PAYMENT);
log.info("===============[USDT sign success,hash is {}==========", tx.getHashAsString());
return new String(Hex.encodeHex(tx.bitcoinSerialize()));
}}catch (Exception e){
log.info("========com.bscoin.coldwallet.cointype.usdt.RawTransaction.createRawTransaction(String, String, String, String, String, long, String, List<UnSpentUtxo>, List<UnSpentUtxo>):{} ==="
,e.getMessage(),e);
}
return null;
}
調用:
public static void main(String[] args) {
String mkPrivateKey = "";
String usdtPri = "";
//構造Data前綴
String methodStrart = "6a146f6d6e69";
//幣種唯一標識的16進制---這個是1,我用測試鏈的omni代幣
String coinProperity1 = "0000000000000001";
//幣種唯一標識的16進制---這是31,usdt。
String coinProperity31 = "000000000000001f";
//構造Data的數量16進制數。 需要 基本數量 *10^8再轉,我轉的數量爲5個
String Hex16ToBalance = "000000001dcd6500";
//構造的Data 爲方法前綴+幣唯一標識16進制+轉賬數量的16進制
String omniHex = methodStrart+coinProperity1+Hex16ToBalance;
Map m = new HashMap();
List<UnSpentUtxo> us = new ArrayList<UnSpentUtxo>();
//第一個utxo爲手續費用到的
UnSpentUtxo u = new UnSpentUtxo();
u.setAddress("mkUWwGMQ2nHbRPyRL2czV9HnFGqg6XMqUL");//地址
u.setHash("af2ec076ae16a0e0ea1aac82af35817b8b2ba81edc5a4f7f77597de7a623ece8");//交易hash
u.setHeight(1696973);//確認交易的區塊高度
u.setScript("76a9143662a0fc506262a3c658b46df05183b19b64f8e688ac");//script
u.setTxN(0);//utxo中的vout
u.setValue(1900000);//數量--如果用listunspent的話,需要*10^8
us.add(u);
//第二個爲載體(真正需要轉出去用到的)
List<UnSpentUtxo> us2 = new ArrayList<UnSpentUtxo>();
UnSpentUtxo u3 = new UnSpentUtxo();
u3.setAddress("msCzB99PdAZRfeaFSkrNZjfqBgavWU2Kjs");
u3.setHash("7e3d4fed3c849960758c505b56cf967b6c3b36b6aedbfa39c39b8b3690415732");
u3.setHeight(1612275);
u3.setScript("76a914803b979506bf04579b2a24d3c5fd01895272fac488ac");
u3.setTxN(2);
u3.setValue(546);
us2.add(u3);
m.put("btcUtxo", us);
m.put("usdtUtxo", us2);
m.put("omniHex", methodStrart+coinProperity1+Hex16ToBalance);
System.out.println("傳輸參數:" + JSONObject.toJSONString(m));
/**
* 第一個,手續費的私鑰
* 第二個,手續費地址
* 第三個:要付款的usdt私鑰--(付款了5個數量爲16進制,需要5*10^8 再轉16)
* 第四個:接收地址
* 第五個:手續費費用 需要/10^8纔是真實,例如下面的就是0.0001個btc手續費
* 第五個,構造的data,--爲 固定前綴6a146f6d6e69 + 幣種唯一標識的十六進制 + 轉賬數量 * 10^8 再轉16進制
* 第六個,手續費utxo
* 第七個,轉賬的0.00000546 utxo
*
* 調用了之後,會生成已經簽好名的交易,
* 通過廣播sendrawtransaction接口返回生成的hashId。
*
* 消耗了手續費的utxo、轉賬的utxo
* 接收地址會收到一個新的0.00000546UTXO,
* 手續費會返回一個新的utxo
*/
String c = new UnSpentUtxo().CreateRawTransaction(mkPrivateKey, "mkUWwGMQ2nHbRPyRL2czV9HnFGqg6XMqUL",usdtPri,
"mkUWwGMQ2nHbRPyRL2czV9HnFGqg6XMqUL",10000,omniHex,us,us2);//手續費是0.0001BTC
System.out.println(c);
try {
String txid = rpcUtils.invoke("http://127.0.0.1:8888", "sendrawtransaction","c3czZGY6d2Vyc3ZzZGY=" , new Object[]{c});
System.out.println(txid);
} catch (Exception e) {
log.error("調用失敗:{}", e.getMessage());
}
}
調用結果:
傳輸參數:{"omniHex":"6a146f6d6e690000000000000001000000001dcd6500","usdtUtxo":[{"address":"msCzB99PdAZRfeaFSkrNZjfqBgavWU2Kjs","hash":"7e3d4fed3c849960758c505b56cf967b6c3b36b6aedbfa39c39b8b3690415732","height":1612275,"script":"76a914803b979506bf04579b2a24d3c5fd01895272fac488ac","txN":2,"value":546}],"btcUtxo":[{"address":"mkUWwGMQ2nHbRPyRL2czV9HnFGqg6XMqUL","hash":"af2ec076ae16a0e0ea1aac82af35817b8b2ba81edc5a4f7f77597de7a623ece8","height":1696973,"script":"76a9143662a0fc506262a3c658b46df05183b19b64f8e688ac","txN":0,"value":1900000}]}
四月 15, 2020 9:57:31 上午 org.bitcoin.Secp256k1Context <clinit>
信息: java.lang.UnsatisfiedLinkError: no secp256k1 in java.library.path
四月 15, 2020 9:57:31 上午 org.bitcoinj.core.Context <init>
信息: Creating bitcoinj 0.14.7 context.
四月 15, 2020 9:57:31 上午 com.hlgj.entity.UnSpentUtxo CreateRawTransaction
信息: ===============[USDT sign success,hash is 2549a0c2d058e4f262db57ce498b6fa42e46bc3014420808053fe0bd0b77e9e3==========
010000000232574190368b9bc339fadbaeb6363b6c7b96cf565b508c756099843ced4f3d7e020000006b483045022100f76ab6398dcf01a118c22ff1f9cfc254e0eb7a4f355a0be96835a90b1b0640d7022042f5eff1026fa8ffa58c07084565893fb2844e2fb03466bdb05f8e74673d78308121031b6c481878b001ee6971bc494dbed93f88120844050d81e79481c71576840f39ffffffffe8ec23a6e77d59777f4f5adc1ea82b8b7b8135af82ac1aeae0a016ae76c02eaf000000006a47304402201ed328cdb85468ec850ebff23c9074eef37249a8f91d7bd8778c509648c3855e02202cd74327ea177c3338929e1c0fbc8572ef89ad905881e91a2513fe4581837b96812103de8addf3269ab5a9cfe55e1ba9c7e395dec92a04853f1c5c43a815ae20c4f7e0ffffffff03aed41c00000000001976a9143662a0fc506262a3c658b46df05183b19b64f8e688ac2202000000000000166a146f6d6e690000000000000001000000001dcd650022020000000000001976a9143662a0fc506262a3c658b46df05183b19b64f8e688ac00000000//已經簽名的交易
2549a0c2d058e4f262db57ce498b6fa42e46bc3014420808053fe0bd0b77e9e3//這個是調用之後返回的hash
調用了之後, 會發現:
omni錢包,少掉了兩個utxo,
就是上述填入的u 還有 us3.
但同時手續費地址會收到一筆新的utxo(找零返回的),接收地址也多了一筆0.00000546的utxo:
{
"txid": "2549a0c2d058e4f262db57ce498b6fa42e46bc3014420808053fe0bd0b77e9e3",
"vout": 0,
"address": "mkUWwGMQ2nHbRPyRL2czV9HnFGqg6XMqUL",
"label": "watch-only test",
"scriptPubKey": "xxxxxxxx",
"amount": 0.01889454,
"confirmations": 56,
"spendable": false,
"solvable": false,
"safe": true
}這筆是找零返回的。