Search in sources :

Example 26 with MyTransactionOutPoint

use of com.samourai.wallet.send.MyTransactionOutPoint in project samourai-wallet-android by Samourai-Wallet.

the class CahootsUtil method doSTONEWALLx2_2.

// 
// sender
// 
public Cahoots doSTONEWALLx2_2(STONEWALLx2 stonewall1) throws Exception {
    Transaction transaction = stonewall1.getTransaction();
    debug("CahootsUtil", "step2 tx:" + org.spongycastle.util.encoders.Hex.toHexString(transaction.bitcoinSerialize()));
    int nbIncomingInputs = transaction.getInputs().size();
    List<UTXO> utxos = getCahootsUTXO(stonewall1.getAccount());
    Collections.shuffle(utxos);
    debug("CahootsUtil", "BIP84 utxos:" + utxos.size());
    List<String> seenTxs = new ArrayList<String>();
    for (TransactionInput input : transaction.getInputs()) {
        if (!seenTxs.contains(input.getOutpoint().getHash().toString())) {
            seenTxs.add(input.getOutpoint().getHash().toString());
        }
    }
    List<UTXO> selectedUTXO = new ArrayList<UTXO>();
    long totalSelectedAmount = 0L;
    int nbTotalSelectedOutPoints = 0;
    for (int step = 0; step < 3; step++) {
        if (stonewall1.getCounterpartyAccount() == 0) {
            step = 2;
        }
        List<String> _seenTxs = seenTxs;
        selectedUTXO = new ArrayList<UTXO>();
        nbTotalSelectedOutPoints = 0;
        for (UTXO utxo : utxos) {
            switch(step) {
                case 0:
                    if (utxo.getPath() != null && utxo.getPath().length() > 3 && utxo.getPath().charAt(2) != '0') {
                        continue;
                    }
                    break;
                case 1:
                    if (utxo.getPath() != null && utxo.getPath().length() > 3 && utxo.getPath().charAt(2) != '1') {
                        continue;
                    }
                    break;
                default:
                    break;
            }
            UTXO _utxo = new UTXO();
            for (MyTransactionOutPoint outpoint : utxo.getOutpoints()) {
                if (!_seenTxs.contains(outpoint.getTxHash().toString())) {
                    _utxo.getOutpoints().add(outpoint);
                    _seenTxs.add(outpoint.getTxHash().toString());
                }
            }
            if (_utxo.getOutpoints().size() > 0) {
                selectedUTXO.add(_utxo);
                totalSelectedAmount += _utxo.getValue();
                nbTotalSelectedOutPoints += _utxo.getOutpoints().size();
                debug("CahootsUtil", "BIP84 selected utxo:" + _utxo.getValue());
            }
            if (totalSelectedAmount > FeeUtil.getInstance().estimatedFeeSegwit(0, 0, nbTotalSelectedOutPoints + nbIncomingInputs, 4).longValue() + stonewall1.getSpendAmount() + SamouraiWallet.bDust.longValue()) {
                break;
            }
        }
        if (totalSelectedAmount > FeeUtil.getInstance().estimatedFeeSegwit(0, 0, nbTotalSelectedOutPoints + nbIncomingInputs, 4).longValue() + stonewall1.getSpendAmount() + SamouraiWallet.bDust.longValue()) {
            break;
        }
    }
    if (!(totalSelectedAmount > FeeUtil.getInstance().estimatedFeeSegwit(0, 0, nbTotalSelectedOutPoints + nbIncomingInputs, 4).longValue() + stonewall1.getSpendAmount() + SamouraiWallet.bDust.longValue())) {
        return null;
    }
    debug("CahootsUtil", "BIP84 selected utxos:" + selectedUTXO.size());
    long fee = FeeUtil.getInstance().estimatedFeeSegwit(0, 0, nbTotalSelectedOutPoints + nbIncomingInputs, 4).longValue();
    debug("CahootsUtil", "fee:" + fee);
    if (fee % 2L != 0) {
        fee++;
    }
    debug("CahootsUtil", "fee pair:" + fee);
    stonewall1.setFeeAmount(fee);
    debug("CahootsUtil", "destination:" + stonewall1.getDestination());
    if (transaction.getOutputs() != null && transaction.getOutputs().size() == 2) {
        int idx = -1;
        for (int i = 0; i < 2; i++) {
            byte[] buf = transaction.getOutputs().get(i).getScriptBytes();
            byte[] script = new byte[buf.length];
            script[0] = 0x00;
            System.arraycopy(buf, 1, script, 1, script.length - 1);
            debug("CahootsUtil", "script:" + new Script(script).toString());
            debug("CahootsUtil", "script hex:" + Hex.toHexString(script));
            debug("CahootsUtil", "address from script:" + Bech32Util.getInstance().getAddressFromScript(new Script(script)));
            if (Bech32Util.getInstance().getAddressFromScript(new Script(script)).equalsIgnoreCase(stonewall1.getCollabChange())) {
                idx = i;
                break;
            }
        }
        if (idx == 0 || idx == 1) {
            Coin value = transaction.getOutputs().get(idx).getValue();
            Coin _value = Coin.valueOf(value.longValue() - (fee / 2L));
            debug("CahootsUtil", "output value post fee:" + _value);
            transaction.getOutputs().get(idx).setValue(_value);
            stonewall1.getPSBT().setTransaction(transaction);
        } else {
            return null;
        }
    } else {
        return null;
    }
    NetworkParameters params = stonewall1.getParams();
    // 
    // 
    // step2: B verif, utxos -> A (take smallest that cover amount)
    // 
    // 
    String zpub = BIP84Util.getInstance(context).getWallet().getAccountAt(stonewall1.getAccount()).zpubstr();
    HashMap<_TransactionOutPoint, Triple<byte[], byte[], String>> inputsB = new HashMap<_TransactionOutPoint, Triple<byte[], byte[], String>>();
    for (UTXO utxo : selectedUTXO) {
        for (MyTransactionOutPoint outpoint : utxo.getOutpoints()) {
            _TransactionOutPoint _outpoint = new _TransactionOutPoint(outpoint);
            ECKey eckey = SendFactory.getPrivKey(_outpoint.getAddress(), stonewall1.getAccount());
            String path = APIFactory.getInstance(context).getUnspentPaths().get(_outpoint.getAddress());
            inputsB.put(_outpoint, Triple.of(eckey.getPubKey(), FormatsUtil.getInstance().getFingerprintFromXPUB(zpub), path));
        }
    }
    // spender change output
    HashMap<_TransactionOutput, Triple<byte[], byte[], String>> outputsB = new HashMap<_TransactionOutput, Triple<byte[], byte[], String>>();
    if (stonewall1.getAccount() == WhirlpoolMeta.getInstance(context).getWhirlpoolPostmix()) {
        int idx = AddressFactory.getInstance(context).getHighestPostChangeIdx();
        SegwitAddress segwitAddress = BIP84Util.getInstance(context).getAddressAt(stonewall1.getAccount(), 1, idx);
        Pair<Byte, byte[]> pair0 = Bech32Segwit.decode(SamouraiWallet.getInstance().isTestNet() ? "tb" : "bc", segwitAddress.getBech32AsString());
        byte[] scriptPubKey_B0 = Bech32Segwit.getScriptPubkey(pair0.getLeft(), pair0.getRight());
        _TransactionOutput output_B0 = new _TransactionOutput(params, null, Coin.valueOf((totalSelectedAmount - stonewall1.getSpendAmount()) - (fee / 2L)), scriptPubKey_B0);
        outputsB.put(output_B0, Triple.of(segwitAddress.getECKey().getPubKey(), stonewall1.getFingerprint(), "M/1/" + idx));
    } else {
        int idx = BIP84Util.getInstance(context).getWallet().getAccount(0).getChange().getAddrIdx();
        SegwitAddress segwitAddress = BIP84Util.getInstance(context).getAddressAt(0, 1, idx);
        Pair<Byte, byte[]> pair0 = Bech32Segwit.decode(SamouraiWallet.getInstance().isTestNet() ? "tb" : "bc", segwitAddress.getBech32AsString());
        byte[] scriptPubKey_B0 = Bech32Segwit.getScriptPubkey(pair0.getLeft(), pair0.getRight());
        _TransactionOutput output_B0 = new _TransactionOutput(params, null, Coin.valueOf((totalSelectedAmount - stonewall1.getSpendAmount()) - (fee / 2L)), scriptPubKey_B0);
        outputsB.put(output_B0, Triple.of(segwitAddress.getECKey().getPubKey(), stonewall1.getFingerprint(), "M/1/" + idx));
    }
    STONEWALLx2 stonewall2 = new STONEWALLx2(stonewall1);
    stonewall2.inc(inputsB, outputsB, null);
    return stonewall2;
}
Also used : HashMap(java.util.HashMap) SegwitAddress(com.samourai.wallet.segwit.SegwitAddress) ArrayList(java.util.ArrayList) MyTransactionOutPoint(com.samourai.wallet.send.MyTransactionOutPoint) ECKey(org.bitcoinj.core.ECKey) TransactionInput(org.bitcoinj.core.TransactionInput) Coin(org.bitcoinj.core.Coin) Script(org.bitcoinj.script.Script) NetworkParameters(org.bitcoinj.core.NetworkParameters) MyTransactionOutPoint(com.samourai.wallet.send.MyTransactionOutPoint) TransactionOutPoint(org.bitcoinj.core.TransactionOutPoint) Triple(org.apache.commons.lang3.tuple.Triple) UTXO(com.samourai.wallet.send.UTXO) Transaction(org.bitcoinj.core.Transaction)

Example 27 with MyTransactionOutPoint

use of com.samourai.wallet.send.MyTransactionOutPoint in project samourai-wallet-android by Samourai-Wallet.

the class CahootsUtil method doStowaway4.

// 
// sender
// 
public Cahoots doStowaway4(Stowaway stowaway3) throws Exception {
    debug("CahootsUtil", "sender account (4):" + stowaway3.getAccount());
    HashMap<String, String> utxo2Address = new HashMap<String, String>();
    List<UTXO> utxos = null;
    if (stowaway3.getAccount() == WhirlpoolMeta.getInstance(context).getWhirlpoolPostmix()) {
        utxos = APIFactory.getInstance(context).getUtxosPostMix(true);
    } else {
        utxos = APIFactory.getInstance(context).getUtxos(true);
    }
    for (UTXO utxo : utxos) {
        for (MyTransactionOutPoint outpoint : utxo.getOutpoints()) {
            utxo2Address.put(outpoint.getTxHash().toString() + "-" + outpoint.getTxOutputN(), outpoint.getAddress());
            debug("CahootsUtil", "outpoint address:" + outpoint.getTxHash().toString() + "-" + outpoint.getTxOutputN() + "," + outpoint.getAddress());
        }
    }
    Transaction transaction = stowaway3.getPSBT().getTransaction();
    HashMap<String, ECKey> keyBag_B = new HashMap<String, ECKey>();
    for (TransactionInput input : transaction.getInputs()) {
        TransactionOutPoint outpoint = input.getOutpoint();
        String key = outpoint.getHash().toString() + "-" + outpoint.getIndex();
        if (utxo2Address.containsKey(key)) {
            String address = utxo2Address.get(key);
            ECKey eckey = SendFactory.getPrivKey(address, stowaway3.getAccount());
            keyBag_B.put(outpoint.toString(), eckey);
        }
    }
    // 
    // 
    // step4: B verif, sig, broadcast
    // 
    // 
    Stowaway stowaway4 = new Stowaway(stowaway3);
    stowaway4.inc(null, null, keyBag_B);
    return stowaway4;
}
Also used : UTXO(com.samourai.wallet.send.UTXO) Transaction(org.bitcoinj.core.Transaction) HashMap(java.util.HashMap) MyTransactionOutPoint(com.samourai.wallet.send.MyTransactionOutPoint) ECKey(org.bitcoinj.core.ECKey) TransactionInput(org.bitcoinj.core.TransactionInput) MyTransactionOutPoint(com.samourai.wallet.send.MyTransactionOutPoint) TransactionOutPoint(org.bitcoinj.core.TransactionOutPoint)

Example 28 with MyTransactionOutPoint

use of com.samourai.wallet.send.MyTransactionOutPoint in project samourai-wallet-android by Samourai-Wallet.

the class CahootsUtil method doSTONEWALLx2_1.

// 
// counterparty
// 
public Cahoots doSTONEWALLx2_1(STONEWALLx2 stonewall0) throws Exception {
    List<UTXO> utxos = getCahootsUTXO(stonewall0.getCounterpartyAccount());
    Collections.shuffle(utxos);
    debug("CahootsUtil", "BIP84 utxos:" + utxos.size());
    List<UTXO> selectedUTXO = new ArrayList<UTXO>();
    long totalContributedAmount = 0L;
    for (int step = 0; step < 3; step++) {
        if (stonewall0.getCounterpartyAccount() == 0) {
            step = 2;
        }
        List<String> seenTxs = new ArrayList<String>();
        selectedUTXO = new ArrayList<UTXO>();
        totalContributedAmount = 0L;
        for (UTXO utxo : utxos) {
            switch(step) {
                case 0:
                    if (utxo.getPath() != null && utxo.getPath().length() > 3 && utxo.getPath().charAt(2) != '0') {
                        continue;
                    }
                    break;
                case 1:
                    if (utxo.getPath() != null && utxo.getPath().length() > 3 && utxo.getPath().charAt(2) != '1') {
                        continue;
                    }
                    break;
                default:
                    break;
            }
            UTXO _utxo = new UTXO();
            for (MyTransactionOutPoint outpoint : utxo.getOutpoints()) {
                if (!seenTxs.contains(outpoint.getTxHash().toString())) {
                    _utxo.getOutpoints().add(outpoint);
                    seenTxs.add(outpoint.getTxHash().toString());
                }
            }
            if (_utxo.getOutpoints().size() > 0) {
                selectedUTXO.add(_utxo);
                totalContributedAmount += _utxo.getValue();
                debug("CahootsUtil", "BIP84 selected utxo:" + _utxo.getValue());
            }
            if (totalContributedAmount > stonewall0.getSpendAmount() + SamouraiWallet.bDust.longValue()) {
                break;
            }
        }
        if (totalContributedAmount > stonewall0.getSpendAmount() + SamouraiWallet.bDust.longValue()) {
            break;
        }
    }
    if (!(totalContributedAmount > stonewall0.getSpendAmount() + SamouraiWallet.bDust.longValue())) {
        return null;
    }
    debug("CahootsUtil", "BIP84 selected utxos:" + selectedUTXO.size());
    NetworkParameters params = stonewall0.getParams();
    // 
    // 
    // step1: A utxos -> B (take largest that cover amount)
    // 
    // 
    String zpub = BIP84Util.getInstance(context).getWallet().getAccountAt(stonewall0.getCounterpartyAccount()).zpubstr();
    HashMap<_TransactionOutPoint, Triple<byte[], byte[], String>> inputsA = new HashMap<_TransactionOutPoint, Triple<byte[], byte[], String>>();
    for (UTXO utxo : selectedUTXO) {
        for (MyTransactionOutPoint outpoint : utxo.getOutpoints()) {
            _TransactionOutPoint _outpoint = new _TransactionOutPoint(outpoint);
            ECKey eckey = SendFactory.getPrivKey(_outpoint.getAddress(), stonewall0.getCounterpartyAccount());
            String path = APIFactory.getInstance(context).getUnspentPaths().get(_outpoint.getAddress());
            inputsA.put(_outpoint, Triple.of(eckey.getPubKey(), stonewall0.getFingerprintCollab(), path));
        }
    }
    HashMap<_TransactionOutput, Triple<byte[], byte[], String>> outputsA = new HashMap<_TransactionOutput, Triple<byte[], byte[], String>>();
    if (stonewall0.getCounterpartyAccount() == WhirlpoolMeta.getInstance(context).getWhirlpoolPostmix()) {
        // contributor mix output
        int idx = AddressFactory.getInstance(context).getHighestPostChangeIdx();
        SegwitAddress segwitAddress0 = BIP84Util.getInstance(context).getAddressAt(stonewall0.getCounterpartyAccount(), 1, idx);
        Pair<Byte, byte[]> pair0 = Bech32Segwit.decode(SamouraiWallet.getInstance().isTestNet() ? "tb" : "bc", segwitAddress0.getBech32AsString());
        byte[] scriptPubKey_A0 = Bech32Segwit.getScriptPubkey(pair0.getLeft(), pair0.getRight());
        _TransactionOutput output_A0 = new _TransactionOutput(params, null, Coin.valueOf(stonewall0.getSpendAmount()), scriptPubKey_A0);
        outputsA.put(output_A0, Triple.of(segwitAddress0.getECKey().getPubKey(), stonewall0.getFingerprintCollab(), "M/1/" + idx));
        // contributor change output
        ++idx;
        SegwitAddress segwitAddress1 = BIP84Util.getInstance(context).getAddressAt(stonewall0.getCounterpartyAccount(), 1, idx);
        Pair<Byte, byte[]> pair1 = Bech32Segwit.decode(SamouraiWallet.getInstance().isTestNet() ? "tb" : "bc", segwitAddress1.getBech32AsString());
        byte[] scriptPubKey_A1 = Bech32Segwit.getScriptPubkey(pair1.getLeft(), pair1.getRight());
        _TransactionOutput output_A1 = new _TransactionOutput(params, null, Coin.valueOf(totalContributedAmount - stonewall0.getSpendAmount()), scriptPubKey_A1);
        outputsA.put(output_A1, Triple.of(segwitAddress1.getECKey().getPubKey(), stonewall0.getFingerprintCollab(), "M/1/" + idx));
        stonewall0.setCollabChange(segwitAddress1.getBech32AsString());
    } else {
        // contributor mix output
        int idx = BIP84Util.getInstance(context).getWallet().getAccount(0).getReceive().getAddrIdx();
        SegwitAddress segwitAddress0 = BIP84Util.getInstance(context).getAddressAt(0, 0, idx);
        if (segwitAddress0.getBech32AsString().equalsIgnoreCase(stonewall0.getDestination())) {
            segwitAddress0 = BIP84Util.getInstance(context).getAddressAt(0, 0, idx + 1);
        }
        Pair<Byte, byte[]> pair0 = Bech32Segwit.decode(SamouraiWallet.getInstance().isTestNet() ? "tb" : "bc", segwitAddress0.getBech32AsString());
        byte[] scriptPubKey_A0 = Bech32Segwit.getScriptPubkey(pair0.getLeft(), pair0.getRight());
        _TransactionOutput output_A0 = new _TransactionOutput(params, null, Coin.valueOf(stonewall0.getSpendAmount()), scriptPubKey_A0);
        outputsA.put(output_A0, Triple.of(segwitAddress0.getECKey().getPubKey(), stonewall0.getFingerprintCollab(), "M/0/" + idx));
        // contributor change output
        idx = BIP84Util.getInstance(context).getWallet().getAccount(0).getChange().getAddrIdx();
        SegwitAddress segwitAddress1 = BIP84Util.getInstance(context).getAddressAt(0, 1, idx);
        Pair<Byte, byte[]> pair1 = Bech32Segwit.decode(SamouraiWallet.getInstance().isTestNet() ? "tb" : "bc", segwitAddress1.getBech32AsString());
        byte[] scriptPubKey_A1 = Bech32Segwit.getScriptPubkey(pair1.getLeft(), pair1.getRight());
        _TransactionOutput output_A1 = new _TransactionOutput(params, null, Coin.valueOf(totalContributedAmount - stonewall0.getSpendAmount()), scriptPubKey_A1);
        outputsA.put(output_A1, Triple.of(segwitAddress1.getECKey().getPubKey(), stonewall0.getFingerprintCollab(), "M/1/" + idx));
        stonewall0.setCollabChange(segwitAddress1.getBech32AsString());
    }
    STONEWALLx2 stonewall1 = new STONEWALLx2(stonewall0);
    stonewall1.inc(inputsA, outputsA, null);
    return stonewall1;
}
Also used : HashMap(java.util.HashMap) SegwitAddress(com.samourai.wallet.segwit.SegwitAddress) NetworkParameters(org.bitcoinj.core.NetworkParameters) ArrayList(java.util.ArrayList) MyTransactionOutPoint(com.samourai.wallet.send.MyTransactionOutPoint) ECKey(org.bitcoinj.core.ECKey) MyTransactionOutPoint(com.samourai.wallet.send.MyTransactionOutPoint) TransactionOutPoint(org.bitcoinj.core.TransactionOutPoint) Triple(org.apache.commons.lang3.tuple.Triple) UTXO(com.samourai.wallet.send.UTXO)

Example 29 with MyTransactionOutPoint

use of com.samourai.wallet.send.MyTransactionOutPoint in project samourai-wallet-android by Samourai-Wallet.

the class CahootsUtil method doStowaway2.

// 
// sender
// 
public Cahoots doStowaway2(Stowaway stowaway1) throws Exception {
    debug("CahootsUtil", "sender account (2):" + stowaway1.getAccount());
    Transaction transaction = stowaway1.getTransaction();
    debug("CahootsUtil", "step2 tx:" + org.spongycastle.util.encoders.Hex.toHexString(transaction.bitcoinSerialize()));
    int nbIncomingInputs = transaction.getInputs().size();
    List<UTXO> utxos = getCahootsUTXO(stowaway1.getAccount());
    // sort in ascending order by value
    Collections.sort(utxos, new UTXO.UTXOComparator());
    Collections.reverse(utxos);
    debug("CahootsUtil", "BIP84 utxos:" + utxos.size());
    List<UTXO> selectedUTXO = new ArrayList<UTXO>();
    int nbTotalSelectedOutPoints = 0;
    long totalSelectedAmount = 0L;
    List<UTXO> lowUTXO = new ArrayList<UTXO>();
    for (UTXO utxo : utxos) {
        if (utxo.getValue() < stowaway1.getSpendAmount()) {
            lowUTXO.add(utxo);
        }
    }
    List<List<UTXO>> listOfLists = new ArrayList<List<UTXO>>();
    Collections.shuffle(lowUTXO);
    listOfLists.add(lowUTXO);
    listOfLists.add(utxos);
    for (List<UTXO> list : listOfLists) {
        selectedUTXO.clear();
        totalSelectedAmount = 0L;
        nbTotalSelectedOutPoints = 0;
        for (UTXO utxo : list) {
            selectedUTXO.add(utxo);
            totalSelectedAmount += utxo.getValue();
            debug("BIP84 selected utxo:", "" + utxo.getValue());
            nbTotalSelectedOutPoints += utxo.getOutpoints().size();
            if (totalSelectedAmount > FeeUtil.getInstance().estimatedFeeSegwit(0, 0, nbTotalSelectedOutPoints + nbIncomingInputs, 2).longValue() + stowaway1.getSpendAmount() + SamouraiWallet.bDust.longValue()) {
                // discard "extra" utxo, if any
                List<UTXO> _selectedUTXO = new ArrayList<UTXO>();
                Collections.reverse(selectedUTXO);
                int _nbTotalSelectedOutPoints = 0;
                long _totalSelectedAmount = 0L;
                for (UTXO utxoSel : selectedUTXO) {
                    _selectedUTXO.add(utxoSel);
                    _totalSelectedAmount += utxoSel.getValue();
                    debug("CahootsUtil", "BIP84 post selected utxo:" + utxoSel.getValue());
                    _nbTotalSelectedOutPoints += utxoSel.getOutpoints().size();
                    if (_totalSelectedAmount > FeeUtil.getInstance().estimatedFeeSegwit(0, 0, _nbTotalSelectedOutPoints + nbIncomingInputs, 2).longValue() + stowaway1.getSpendAmount() + SamouraiWallet.bDust.longValue()) {
                        selectedUTXO.clear();
                        selectedUTXO.addAll(_selectedUTXO);
                        totalSelectedAmount = _totalSelectedAmount;
                        nbTotalSelectedOutPoints = _nbTotalSelectedOutPoints;
                        break;
                    }
                }
                break;
            }
        }
        if (totalSelectedAmount > FeeUtil.getInstance().estimatedFeeSegwit(0, 0, nbTotalSelectedOutPoints + nbIncomingInputs, 2).longValue() + stowaway1.getSpendAmount() + SamouraiWallet.bDust.longValue()) {
            break;
        }
    }
    /*
        if(lowUTXO.size() > 0)    {
            Collections.shuffle(lowUTXO);
            for (UTXO utxo : lowUTXO) {
                selectedUTXO.add(utxo);
                totalSelectedAmount += utxo.getValue();
                debug("BIP84 selected utxo:", "" + utxo.getValue());
                nbTotalSelectedOutPoints += utxo.getOutpoints().size();
                if (totalSelectedAmount > FeeUtil.getInstance().estimatedFeeSegwit(0, 0, nbTotalSelectedOutPoints + nbIncomingInputs, 2).longValue() + stowaway1.getSpendAmount() + SamouraiWallet.bDust.longValue()) {

                    // discard "extra" utxo, if any
                    List<UTXO> _selectedUTXO = new ArrayList<UTXO>();
                    Collections.reverse(selectedUTXO);
                    int _nbTotalSelectedOutPoints = 0;
                    long _totalSelectedAmount = 0L;
                    for (UTXO utxoSel : selectedUTXO) {
                        _selectedUTXO.add(utxoSel);
                        _totalSelectedAmount += utxoSel.getValue();
                        debug("CahootsUtil", "BIP84 post selected utxo:" + utxoSel.getValue());
                        _nbTotalSelectedOutPoints += utxoSel.getOutpoints().size();
                        if (_totalSelectedAmount > FeeUtil.getInstance().estimatedFeeSegwit(0, 0, _nbTotalSelectedOutPoints + nbIncomingInputs, 2).longValue() + stowaway1.getSpendAmount() + SamouraiWallet.bDust.longValue()) {
                            selectedUTXO.clear();
                            selectedUTXO.addAll(_selectedUTXO);
                            totalSelectedAmount = _totalSelectedAmount;
                            nbTotalSelectedOutPoints = _nbTotalSelectedOutPoints;
                            break;
                        }
                    }

                    break;
                }
            }

        }
        if (!(totalSelectedAmount > FeeUtil.getInstance().estimatedFeeSegwit(0, 0, nbTotalSelectedOutPoints + nbIncomingInputs, 2).longValue() + stowaway1.getSpendAmount() + SamouraiWallet.bDust.longValue())) {
            selectedUTXO.clear();
            totalSelectedAmount = 0L;
            nbTotalSelectedOutPoints = 0;
            for (UTXO utxo : utxos) {
                selectedUTXO.add(utxo);
                totalSelectedAmount += utxo.getValue();
                debug("BIP84 selected utxo:", "" + utxo.getValue());
                nbTotalSelectedOutPoints += utxo.getOutpoints().size();
                if (totalSelectedAmount > FeeUtil.getInstance().estimatedFeeSegwit(0, 0, nbTotalSelectedOutPoints + nbIncomingInputs, 2).longValue() + stowaway1.getSpendAmount() + SamouraiWallet.bDust.longValue()) {

                    // discard "extra" utxo, if any
                    List<UTXO> _selectedUTXO = new ArrayList<UTXO>();
                    Collections.reverse(selectedUTXO);
                    int _nbTotalSelectedOutPoints = 0;
                    long _totalSelectedAmount = 0L;
                    for (UTXO utxoSel : selectedUTXO) {
                        _selectedUTXO.add(utxoSel);
                        _totalSelectedAmount += utxoSel.getValue();
                        debug("CahootsUtil", "BIP84 post selected utxo:" + utxoSel.getValue());
                        _nbTotalSelectedOutPoints += utxoSel.getOutpoints().size();
                        if (_totalSelectedAmount > FeeUtil.getInstance().estimatedFeeSegwit(0, 0, _nbTotalSelectedOutPoints + nbIncomingInputs, 2).longValue() + stowaway1.getSpendAmount() + SamouraiWallet.bDust.longValue()) {
                            selectedUTXO.clear();
                            selectedUTXO.addAll(_selectedUTXO);
                            totalSelectedAmount = _totalSelectedAmount;
                            nbTotalSelectedOutPoints = _nbTotalSelectedOutPoints;
                            break;
                        }
                    }

                    break;
                }
            }
        }
        */
    if (!(totalSelectedAmount > FeeUtil.getInstance().estimatedFeeSegwit(0, 0, nbTotalSelectedOutPoints + nbIncomingInputs, 2).longValue() + stowaway1.getSpendAmount() + SamouraiWallet.bDust.longValue())) {
        return null;
    }
    debug("CahootsUtil", "BIP84 selected utxos:" + selectedUTXO.size());
    long fee = FeeUtil.getInstance().estimatedFeeSegwit(0, 0, nbTotalSelectedOutPoints + nbIncomingInputs, 2).longValue();
    debug("CahootsUtil", "fee:" + fee);
    NetworkParameters params = stowaway1.getParams();
    // 
    // 
    // step2: B verif, utxos -> A (take smallest that cover amount)
    // 
    // 
    String zpub = BIP84Util.getInstance(context).getWallet().getAccountAt(stowaway1.getAccount()).zpubstr();
    HashMap<_TransactionOutPoint, Triple<byte[], byte[], String>> inputsB = new HashMap<_TransactionOutPoint, Triple<byte[], byte[], String>>();
    for (UTXO utxo : selectedUTXO) {
        for (MyTransactionOutPoint outpoint : utxo.getOutpoints()) {
            _TransactionOutPoint _outpoint = new _TransactionOutPoint(outpoint);
            ECKey eckey = SendFactory.getPrivKey(_outpoint.getAddress(), stowaway1.getAccount());
            String path = APIFactory.getInstance(context).getUnspentPaths().get(_outpoint.getAddress());
            inputsB.put(_outpoint, Triple.of(eckey.getPubKey(), stowaway1.getFingerprint(), path));
        }
    }
    debug("CahootsUtil", "inputsB:" + inputsB.size());
    // change output
    SegwitAddress segwitAddress = null;
    int idx = 0;
    if (stowaway1.getAccount() == WhirlpoolMeta.getInstance(context).getWhirlpoolPostmix()) {
        idx = AddressFactory.getInstance(context).getHighestPostChangeIdx();
        HD_Address addr = BIP84Util.getInstance(context).getWallet().getAccountAt(stowaway1.getAccount()).getChange().getAddressAt(idx);
        segwitAddress = new SegwitAddress(addr.getPubKey(), SamouraiWallet.getInstance().getCurrentNetworkParams());
    } else {
        idx = BIP84Util.getInstance(context).getWallet().getAccount(0).getChange().getAddrIdx();
        segwitAddress = BIP84Util.getInstance(context).getAddressAt(1, idx);
    }
    HashMap<_TransactionOutput, Triple<byte[], byte[], String>> outputsB = new HashMap<_TransactionOutput, Triple<byte[], byte[], String>>();
    Pair<Byte, byte[]> pair = Bech32Segwit.decode(SamouraiWallet.getInstance().isTestNet() ? "tb" : "bc", segwitAddress.getBech32AsString());
    byte[] scriptPubKey_B = Bech32Segwit.getScriptPubkey(pair.getLeft(), pair.getRight());
    _TransactionOutput output_B0 = new _TransactionOutput(params, null, Coin.valueOf((totalSelectedAmount - stowaway1.getSpendAmount()) - fee), scriptPubKey_B);
    outputsB.put(output_B0, Triple.of(segwitAddress.getECKey().getPubKey(), stowaway1.getFingerprint(), "M/1/" + idx));
    debug("CahootsUtil", "outputsB:" + outputsB.size());
    Stowaway stowaway2 = new Stowaway(stowaway1);
    stowaway2.inc(inputsB, outputsB, null);
    stowaway2.setFeeAmount(fee);
    return stowaway2;
}
Also used : HashMap(java.util.HashMap) SegwitAddress(com.samourai.wallet.segwit.SegwitAddress) ArrayList(java.util.ArrayList) MyTransactionOutPoint(com.samourai.wallet.send.MyTransactionOutPoint) ECKey(org.bitcoinj.core.ECKey) ArrayList(java.util.ArrayList) List(java.util.List) HD_Address(com.samourai.wallet.hd.HD_Address) NetworkParameters(org.bitcoinj.core.NetworkParameters) MyTransactionOutPoint(com.samourai.wallet.send.MyTransactionOutPoint) TransactionOutPoint(org.bitcoinj.core.TransactionOutPoint) Triple(org.apache.commons.lang3.tuple.Triple) UTXO(com.samourai.wallet.send.UTXO) Transaction(org.bitcoinj.core.Transaction)

Example 30 with MyTransactionOutPoint

use of com.samourai.wallet.send.MyTransactionOutPoint in project samourai-wallet-android by Samourai-Wallet.

the class CahootsUtil method doStowaway1.

// 
// receiver
// 
public Cahoots doStowaway1(Stowaway stowaway0) throws Exception {
    List<UTXO> utxos = getCahootsUTXO(0);
    // sort in descending order by value
    Collections.sort(utxos, new UTXO.UTXOComparator());
    debug("CahootsUtil", "BIP84 utxos:" + utxos.size());
    List<UTXO> selectedUTXO = new ArrayList<UTXO>();
    long totalContributedAmount = 0L;
    List<UTXO> highUTXO = new ArrayList<UTXO>();
    for (UTXO utxo : utxos) {
        if (utxo.getValue() > stowaway0.getSpendAmount() + SamouraiWallet.bDust.longValue()) {
            highUTXO.add(utxo);
        }
    }
    if (highUTXO.size() > 0) {
        SecureRandom random = new SecureRandom();
        UTXO utxo = highUTXO.get(random.nextInt(highUTXO.size()));
        debug("CahootsUtil", "BIP84 selected random utxo:" + utxo.getValue());
        selectedUTXO.add(utxo);
        totalContributedAmount = utxo.getValue();
    }
    if (selectedUTXO.size() == 0) {
        for (UTXO utxo : utxos) {
            selectedUTXO.add(utxo);
            totalContributedAmount += utxo.getValue();
            debug("CahootsUtil", "BIP84 selected utxo:" + utxo.getValue());
            if (totalContributedAmount > stowaway0.getSpendAmount() + SamouraiWallet.bDust.longValue()) {
                break;
            }
        }
    }
    if (!(totalContributedAmount > stowaway0.getSpendAmount() + SamouraiWallet.bDust.longValue())) {
        return null;
    }
    debug("CahootsUtil", "BIP84 selected utxos:" + selectedUTXO.size());
    NetworkParameters params = stowaway0.getParams();
    // 
    // 
    // step1: A utxos -> B (take largest that cover amount)
    // 
    // 
    String zpub = BIP84Util.getInstance(context).getWallet().getAccount(0).zpubstr();
    HashMap<_TransactionOutPoint, Triple<byte[], byte[], String>> inputsA = new HashMap<_TransactionOutPoint, Triple<byte[], byte[], String>>();
    for (UTXO utxo : selectedUTXO) {
        for (MyTransactionOutPoint outpoint : utxo.getOutpoints()) {
            _TransactionOutPoint _outpoint = new _TransactionOutPoint(outpoint);
            ECKey eckey = SendFactory.getPrivKey(_outpoint.getAddress(), 0);
            String path = APIFactory.getInstance(context).getUnspentPaths().get(_outpoint.getAddress());
            inputsA.put(_outpoint, Triple.of(eckey.getPubKey(), stowaway0.getFingerprintCollab(), path));
        }
    }
    // destination output
    int idx = BIP84Util.getInstance(context).getWallet().getAccount(0).getReceive().getAddrIdx();
    SegwitAddress segwitAddress = BIP84Util.getInstance(context).getAddressAt(0, idx);
    HashMap<_TransactionOutput, Triple<byte[], byte[], String>> outputsA = new HashMap<_TransactionOutput, Triple<byte[], byte[], String>>();
    // byte[] scriptPubKey_A = getScriptPubKey("tb1qewwlc2dksuez3zauf38d82m7uqd4ewkf2avdl8", params);
    Pair<Byte, byte[]> pair = Bech32Segwit.decode(SamouraiWallet.getInstance().isTestNet() ? "tb" : "bc", segwitAddress.getBech32AsString());
    byte[] scriptPubKey_A = Bech32Segwit.getScriptPubkey(pair.getLeft(), pair.getRight());
    _TransactionOutput output_A0 = new _TransactionOutput(params, null, Coin.valueOf(stowaway0.getSpendAmount()), scriptPubKey_A);
    outputsA.put(output_A0, Triple.of(segwitAddress.getECKey().getPubKey(), stowaway0.getFingerprintCollab(), "M/0/" + idx));
    stowaway0.setDestination(segwitAddress.getBech32AsString());
    Stowaway stowaway1 = new Stowaway(stowaway0);
    stowaway1.inc(inputsA, outputsA, null);
    return stowaway1;
}
Also used : HashMap(java.util.HashMap) SegwitAddress(com.samourai.wallet.segwit.SegwitAddress) NetworkParameters(org.bitcoinj.core.NetworkParameters) ArrayList(java.util.ArrayList) SecureRandom(java.security.SecureRandom) MyTransactionOutPoint(com.samourai.wallet.send.MyTransactionOutPoint) ECKey(org.bitcoinj.core.ECKey) MyTransactionOutPoint(com.samourai.wallet.send.MyTransactionOutPoint) TransactionOutPoint(org.bitcoinj.core.TransactionOutPoint) Triple(org.apache.commons.lang3.tuple.Triple) UTXO(com.samourai.wallet.send.UTXO)

Aggregations

MyTransactionOutPoint (com.samourai.wallet.send.MyTransactionOutPoint)32 UTXO (com.samourai.wallet.send.UTXO)28 HashMap (java.util.HashMap)19 ArrayList (java.util.ArrayList)18 Transaction (org.bitcoinj.core.Transaction)16 BlockedUTXO (com.samourai.wallet.send.BlockedUTXO)12 IOException (java.io.IOException)12 BigInteger (java.math.BigInteger)12 ECKey (org.bitcoinj.core.ECKey)12 TransactionOutPoint (org.bitcoinj.core.TransactionOutPoint)12 MnemonicException (org.bitcoinj.crypto.MnemonicException)11 JSONException (org.json.JSONException)11 JSONObject (org.json.JSONObject)11 TransactionInput (org.bitcoinj.core.TransactionInput)10 Script (org.bitcoinj.script.Script)9 Intent (android.content.Intent)8 SegwitAddress (com.samourai.wallet.segwit.SegwitAddress)8 AlertDialog (android.app.AlertDialog)7 DecryptionException (com.samourai.wallet.crypto.DecryptionException)7 DialogInterface (android.content.DialogInterface)6