Search in sources :

Example 21 with SegwitAddress

use of com.samourai.wallet.segwit.SegwitAddress 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 22 with SegwitAddress

use of com.samourai.wallet.segwit.SegwitAddress 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 23 with SegwitAddress

use of com.samourai.wallet.segwit.SegwitAddress 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 24 with SegwitAddress

use of com.samourai.wallet.segwit.SegwitAddress 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)

Example 25 with SegwitAddress

use of com.samourai.wallet.segwit.SegwitAddress in project samourai-wallet-android by Samourai-Wallet.

the class Stowaway method doStep1.

// 
// receiver
// 
public boolean doStep1(HashMap<_TransactionOutPoint, Triple<byte[], byte[], String>> inputs, HashMap<_TransactionOutput, Triple<byte[], byte[], String>> outputs) throws Exception {
    if (this.getStep() != 0 || this.getSpendAmount() == 0L) {
        return false;
    }
    if (this.getType() == Cahoots.CAHOOTS_STONEWALLx2 && outputs == null) {
        return false;
    }
    Transaction transaction = new Transaction(params);
    for (_TransactionOutPoint outpoint : inputs.keySet()) {
        TransactionInput input = new TransactionInput(params, null, new byte[0], outpoint, outpoint.getValue());
        Log.d("Stowaway", "input value:" + input.getValue().longValue());
        transaction.addInput(input);
        outpoints.put(outpoint.getTxHash().toString() + "-" + outpoint.getTxOutputN(), outpoint.getValue().longValue());
    }
    for (_TransactionOutput output : outputs.keySet()) {
        transaction.addOutput(output);
    }
    PSBT psbt = new PSBT(transaction);
    for (_TransactionOutPoint outpoint : inputs.keySet()) {
        Triple triple = inputs.get(outpoint);
        // input type 1
        SegwitAddress segwitAddress = new SegwitAddress((byte[]) triple.getLeft(), params);
        psbt.addInput(PSBT.PSBT_IN_WITNESS_UTXO, null, PSBT.writeSegwitInputUTXO(outpoint.getValue().longValue(), segwitAddress.segWitRedeemScript().getProgram()));
        // input type 6
        String[] s = ((String) triple.getRight()).split("/");
        psbt.addInput(PSBT.PSBT_IN_BIP32_DERIVATION, (byte[]) triple.getLeft(), PSBT.writeBIP32Derivation((byte[]) triple.getMiddle(), 84, params instanceof TestNet3Params ? 1 : 0, account, Integer.valueOf(s[1]), Integer.valueOf(s[2])));
    }
    for (_TransactionOutput output : outputs.keySet()) {
        Triple triple = outputs.get(output);
        // output type 2
        String[] s = ((String) triple.getRight()).split("/");
        psbt.addOutput(PSBT.PSBT_OUT_BIP32_DERIVATION, (byte[]) triple.getLeft(), PSBT.writeBIP32Derivation((byte[]) triple.getMiddle(), 84, params instanceof TestNet3Params ? 1 : 0, account, Integer.valueOf(s[1]), Integer.valueOf(s[2])));
    }
    this.psbt = psbt;
    Log.d("Stowaway", "input value:" + psbt.getTransaction().getInputs().get(0).getValue().longValue());
    this.setStep(1);
    return true;
}
Also used : PSBT(com.samourai.wallet.cahoots.psbt.PSBT) Triple(org.apache.commons.lang3.tuple.Triple) TestNet3Params(org.bitcoinj.params.TestNet3Params) SegwitAddress(com.samourai.wallet.segwit.SegwitAddress)

Aggregations

SegwitAddress (com.samourai.wallet.segwit.SegwitAddress)30 ECKey (org.bitcoinj.core.ECKey)17 HashMap (java.util.HashMap)12 JSONException (org.json.JSONException)12 MyTransactionOutPoint (com.samourai.wallet.send.MyTransactionOutPoint)11 HD_Address (com.samourai.wallet.hd.HD_Address)10 IOException (java.io.IOException)10 MnemonicException (org.bitcoinj.crypto.MnemonicException)10 JSONObject (org.json.JSONObject)9 Triple (org.apache.commons.lang3.tuple.Triple)8 Script (org.bitcoinj.script.Script)8 ArrayList (java.util.ArrayList)7 TransactionOutPoint (org.bitcoinj.core.TransactionOutPoint)7 AlertDialog (android.app.AlertDialog)6 DialogInterface (android.content.DialogInterface)5 WriterException (com.google.zxing.WriterException)5 PaymentAddress (com.samourai.wallet.bip47.rpc.PaymentAddress)5 PaymentCode (com.samourai.wallet.bip47.rpc.PaymentCode)5 UTXO (com.samourai.wallet.send.UTXO)5 TransactionSignature (org.bitcoinj.crypto.TransactionSignature)5