BTC创建钱包,查询余额,查询交易记录 转账

用到的库

implementation’org.bitcoinj:bitcoinj-core:0.15.2’
implementation(‘com.alibaba:fastjson:1.2.51’)

创建钱包(由于和eth共有助记词就用助记词创建)


fun importByWords(words: String): ECKey {
    val wordsList = words.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray().toList()
    val deterministicSeed = DeterministicSeed(wordsList, null, "", 0L)
    val deterministicKeyChain = DeterministicKeyChain.builder().seed(deterministicSeed).build()
    // //如果是调试模式, 第二个字符串应该填1' M/44H/0H/0H/0/0
    val privKeyBTC = deterministicKeyChain.getKeyByPath(parsePath("M/44H/0H/0H"), true).privKey
    //拿到私钥就可以创建钱包了
    return ECKey.fromPrivate(privKeyBTC)
}

拿到钱包信息(上面获取到的)

获取地址

LegacyAddress.fromKey(params, key).toBase58()

获取私钥

key.getPrivateKeyEncoded(params).toBase58()

查询余额和交易记录

https://blockchain.info/rawaddr/1HMrjkcrqV6ZewxnNcCc7WgNa4T8zWRpu1

获取手续费(可用可不用,转账的时候可以写死手续费)

  /**
     * 获取矿工费用
     *
     * @param amount
     * @param utxos
     * @return
     */
    public static Long getFee(long amount, List<UTXO> utxos) {
        Long feeRate = getFeeRate();//获取费率
        Long utxoAmount = 0L;
        Long fee = 0L;
        Long utxoSize = 0L;
        for (UTXO us : utxos) {
            utxoSize++;
            if (utxoAmount >= (amount + fee)) {
                break;
            } else {
                utxoAmount += us.getValue().value;
                //其实34乘以几都行,加10也可以不要,无非就是手续费低点,打包确认慢点
                // fee = (utxoSize * 148 * 34 * 3 + 10) * feeRate;
                fee = (utxoSize * 148 * 34 * 3 + 10) * feeRate;

            }
        }
        return fee;
    }

    /**
     * 获取btc费率
     *
     * @return
     */
    public static Long getFeeRate() {
        try {
            String httpGet1 = get("https://bitcoinfees.earn.com/api/v1/fees/recommended");
            Map map = JSON.parseObject(httpGet1, Map.class);
            Long fastestFee = Long.valueOf(map.get("hourFee").toString());
            return fastestFee;
        } catch (Exception e) {
            e.printStackTrace();
            return 0L;
        }
    }

获取未消费列表(自己的钞票面值不可分割)

举例说明不可分割,你手里面有4张5元的,你买东西花了12 ,你需要给3张5元的,找回3元
https://blockchain.info/unspent?active=1HMrjkcrqV6ZewxnNcCc7WgNa4T8zWRpu1
https://api-r.bitcoinchain.com/v1/address/utxo/1Ccb4vrC5atJHHdj3hHhYwJmYxtVZLZXWc

计算

1.算出自己需要转出去的值 自己的几个面值刚好大于sendAmount+fee
2.需要找回的钱 减去sendAmount和fee

组合交易信息

1.添加转出金额
2.添加找回金额
3.输入未消费列表项(签名)
4.序列化并且十六进制

发送 签名数据 到链上

https://blockchain.info/pushtx post请求 参数tx

转账代码

 /**
     * btc交易签名
     *
     * @param toAddress
     * @param amount
     * @return
     * @throws Exception
     */
    public static Pair<Boolean, String> sign(String toAddress, long amount) throws Exception {
        String fromAddress = UserInfoData.Companion.getInstance().getBtcAddress();

        String changeAddress = fromAddress;//找零地址

        List<UTXO> utxos = getUnspent(fromAddress);

        NetworkParameters networkParameters = MainNetParams.get();
        Transaction transaction = new Transaction(networkParameters);
        String privateKey = EthUtilsKt.getDecryptAESPriKey();


        Long changeAmount = 0L;
        Long utxoAmount = 0L;
        //long fee = 8000;
        //long fee = getFee(amount, utxos);
        long fee = 8000L;
        List<UTXO> needUtxos = new ArrayList<>();
        //获取未消费列表
        if (utxos == null || utxos.size() == 0) {
            throw new Exception(getString(R.string.network_tip));
        }
        //遍历未花费列表,组装合适的item
        for (UTXO utxo : utxos) {
            if (utxoAmount >= (amount + fee)) {
                break;
            } else {
                needUtxos.add(utxo);
                utxoAmount += utxo.getValue().value;
            }
        }
        transaction.addOutput(Coin.valueOf(amount), Address.fromString(networkParameters, toAddress));
        //消费列表总金额 - 已经转账的金额 - 手续费 就等于需要返回给自己的金额了
        changeAmount = utxoAmount - (amount + fee);
        //余额判断
        if (changeAmount < 0) {
            throw new Exception(getString(R.string.error_balance_not_enough));
        }
        //输出-转给自己(找零)
        if (changeAmount > 0) {
            transaction.addOutput(Coin.valueOf(changeAmount), Address.fromString(networkParameters, changeAddress));
        }
        //输入未消费列表项
        DumpedPrivateKey dumpedPrivateKey = DumpedPrivateKey.fromBase58(networkParameters, privateKey);
        ECKey ecKey = dumpedPrivateKey.getKey();
        for (UTXO utxo : needUtxos) {
            TransactionOutPoint outPoint = new TransactionOutPoint(networkParameters, utxo.getIndex(), utxo.getHash());
            transaction.addSignedInput(outPoint, utxo.getScript(), ecKey, Transaction.SigHash.ALL, true);
        }
        byte[] bytes = transaction.bitcoinSerialize();
        String hash = Hex.toHexString(transaction.bitcoinSerialize());
        LogUtil.e("fee:{},utxoAmount:{},changeAmount{}", "" + fee + utxoAmount + changeAmount);
        LogUtil.e(hash);
        return new Pair(true, hash);
    }

    /***
     * 获取未消费列表
     * @param address :地址
     * @return
     */
    public static List<UTXO> getUnspent(String address) {
        List<UTXO> utxos = new ArrayList();
        String host = "blockchain.info";
        String url = "https://" + host + "/zh-cn/unspent?active=" + address;
        try {
            String httpGet = get(url);//TODO;联网
            if ("No free outputs to spend".equals(httpGet)) {
                return utxos;
            }
            JSONObject jsonObject = JSON.parseObject(httpGet);
            JSONArray unspentOutputs = jsonObject.getJSONArray("unspent_outputs");
            List<Map> outputs = JSONObject.parseArray(unspentOutputs.toJSONString(), Map.class);
            if (outputs == null || outputs.size() == 0) {
                System.out.println("交易异常,余额不足");
            }
            for (int i = 0; i < outputs.size(); i++) {
                Map outputsMap = outputs.get(i);
                String tx_hash = outputsMap.get("tx_hash").toString();
                String tx_hash_big_endian = outputsMap.get("tx_hash_big_endian").toString();
                String tx_index = outputsMap.get("tx_index").toString();
                String tx_output_n = outputsMap.get("tx_output_n").toString();
                String script = outputsMap.get("script").toString();
                String value = outputsMap.get("value").toString();
                String value_hex = outputsMap.get("value_hex").toString();
                String confirmations = outputsMap.get("confirmations").toString();
                UTXO utxo = new UTXO(Sha256Hash.wrap(tx_hash_big_endian), Long.valueOf(tx_output_n), Coin.valueOf(Long.valueOf(value)),
                        0, false, new Script(Hex.decode(script)));
                utxos.add(utxo);
            }
            return utxos;
        } catch (Exception e) {
            LogUtil.e("【BTC获取未消费列表】失败,", e.getMessage());
            return null;
        }

    }

发布了96 篇原创文章 · 获赞 12 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/yujunlong3919/article/details/100555597