Omni-usdt离线交易

关于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
  }这笔是找零返回的。
原创文章 25 获赞 10 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_42195162/article/details/105529286