Search in sources :

Example 1 with PaymentCode

use of com.samourai.wallet.bip47.rpc.PaymentCode in project samourai-wallet-android by Samourai-Wallet.

the class BIP47Activity method doNotifTx.

private void doNotifTx(final String pcode) {
    // 
    // get wallet balance
    // 
    long balance = 0L;
    try {
        balance = APIFactory.getInstance(BIP47Activity.this).getXpubAmounts().get(HD_WalletFactory.getInstance(BIP47Activity.this).get().getAccount(0).xpubstr());
    } catch (IOException ioe) {
        balance = 0L;
    } catch (MnemonicException.MnemonicLengthException mle) {
        balance = 0L;
    } catch (java.lang.NullPointerException npe) {
        balance = 0L;
    }
    final List<UTXO> selectedUTXO = new ArrayList<UTXO>();
    long totalValueSelected = 0L;
    // long change = 0L;
    BigInteger fee = null;
    // 
    // spend dust threshold amount to notification address
    // 
    long amount = SendNotifTxFactory._bNotifTxValue.longValue();
    // 
    // calc btc fee from USD Samourai fee
    // 
    double btc_fx = ExchangeRateFactory.getInstance(BIP47Activity.this).getBitfinexPrice("USD");
    BigInteger currentSWFee = BigInteger.valueOf((long) ((btc_fx / SendNotifTxFactory._dSWFeeUSD) * 1e8));
    if (currentSWFee.longValue() < SendNotifTxFactory._bSWFee.longValue() || currentSWFee.longValue() > SendNotifTxFactory._bSWCeilingFee.longValue()) {
        currentSWFee = SendNotifTxFactory._bSWFee;
    }
    // 
    // add Samourai Wallet fee to total amount
    // 
    amount += currentSWFee.longValue();
    // 
    // get unspents
    // 
    List<UTXO> utxos = null;
    if (UTXOFactory.getInstance().getTotalP2SH_P2WPKH() > amount + FeeUtil.getInstance().estimatedFeeSegwit(0, 1, 4).longValue()) {
        utxos = new ArrayList<UTXO>();
        utxos.addAll(UTXOFactory.getInstance().getP2SH_P2WPKH().values());
    } else {
        utxos = APIFactory.getInstance(BIP47Activity.this).getUtxos(true);
    }
    // sort in ascending order by value
    final List<UTXO> _utxos = utxos;
    Collections.sort(_utxos, new UTXO.UTXOComparator());
    Collections.reverse(_utxos);
    // 
    for (UTXO u : _utxos) {
        if (u.getValue() >= (amount + SamouraiWallet.bDust.longValue() + FeeUtil.getInstance().estimatedFee(1, 4).longValue())) {
            selectedUTXO.add(u);
            totalValueSelected += u.getValue();
            Log.d("BIP47Activity", "single output");
            Log.d("BIP47Activity", "value selected:" + u.getValue());
            Log.d("BIP47Activity", "total value selected:" + totalValueSelected);
            Log.d("BIP47Activity", "nb inputs:" + u.getOutpoints().size());
            break;
        }
    }
    // 
    // use low fee settings
    // 
    SuggestedFee suggestedFee = FeeUtil.getInstance().getSuggestedFee();
    FeeUtil.getInstance().setSuggestedFee(FeeUtil.getInstance().getLowFee());
    if (selectedUTXO.size() == 0) {
        // sort in descending order by value
        Collections.sort(_utxos, new UTXO.UTXOComparator());
        int selected = 0;
        // get largest UTXOs > than spend + fee + dust
        for (UTXO u : _utxos) {
            selectedUTXO.add(u);
            totalValueSelected += u.getValue();
            selected += u.getOutpoints().size();
            if (totalValueSelected >= (amount + SamouraiWallet.bDust.longValue() + FeeUtil.getInstance().estimatedFee(selected, 4).longValue())) {
                Log.d("BIP47Activity", "multiple outputs");
                Log.d("BIP47Activity", "total value selected:" + totalValueSelected);
                Log.d("BIP47Activity", "nb inputs:" + u.getOutpoints().size());
                break;
            }
        }
        fee = FeeUtil.getInstance().estimatedFee(selected, 4);
    } else {
        fee = FeeUtil.getInstance().estimatedFee(1, 4);
    }
    // 
    // reset fee to previous setting
    // 
    FeeUtil.getInstance().setSuggestedFee(suggestedFee);
    // 
    if ((amount + fee.longValue()) >= balance) {
        String message = getText(R.string.bip47_notif_tx_insufficient_funds_1) + " ";
        BigInteger biAmount = SendNotifTxFactory._bSWFee.add(SendNotifTxFactory._bNotifTxValue.add(FeeUtil.getInstance().estimatedFee(1, 4, FeeUtil.getInstance().getLowFee().getDefaultPerKB())));
        String strAmount = MonetaryUtil.getInstance().getBTCFormat().format(((double) biAmount.longValue()) / 1e8) + " BTC ";
        message += strAmount;
        message += " " + getText(R.string.bip47_notif_tx_insufficient_funds_2);
        AlertDialog.Builder dlg = new AlertDialog.Builder(BIP47Activity.this).setTitle(R.string.app_name).setMessage(message).setCancelable(false).setPositiveButton(R.string.help, new DialogInterface.OnClickListener() {

            public void onClick(DialogInterface dialog, int whichButton) {
                Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://support.samourai.io/article/58-connecting-to-a-paynym-contact"));
                startActivity(browserIntent);
            }
        }).setNegativeButton(R.string.close, new DialogInterface.OnClickListener() {

            public void onClick(DialogInterface dialog, int whichButton) {
                dialog.dismiss();
            }
        });
        if (!isFinishing()) {
            dlg.show();
        }
        return;
    }
    // 
    // payment code to be notified
    // 
    PaymentCode payment_code;
    try {
        payment_code = new PaymentCode(pcode);
    } catch (AddressFormatException afe) {
        payment_code = null;
    }
    if (payment_code == null) {
        return;
    }
    // 
    // create outpoints for spend later
    // 
    final List<MyTransactionOutPoint> outpoints = new ArrayList<MyTransactionOutPoint>();
    for (UTXO u : selectedUTXO) {
        outpoints.addAll(u.getOutpoints());
    }
    // 
    // create inputs from outpoints
    // 
    List<MyTransactionInput> inputs = new ArrayList<MyTransactionInput>();
    for (MyTransactionOutPoint o : outpoints) {
        Script script = new Script(o.getScriptBytes());
        if (script.getScriptType() == Script.ScriptType.NO_TYPE) {
            continue;
        }
        MyTransactionInput input = new MyTransactionInput(SamouraiWallet.getInstance().getCurrentNetworkParams(), null, new byte[0], o, o.getTxHash().toString(), o.getTxOutputN());
        inputs.add(input);
    }
    // 
    // sort inputs
    // 
    Collections.sort(inputs, new SendFactory.BIP69InputComparator());
    // 
    // find outpoint that corresponds to 0th input
    // 
    MyTransactionOutPoint outPoint = null;
    for (MyTransactionOutPoint o : outpoints) {
        if (o.getTxHash().toString().equals(inputs.get(0).getTxHash()) && o.getTxOutputN() == inputs.get(0).getTxPos()) {
            outPoint = o;
            break;
        }
    }
    if (outPoint == null) {
        Toast.makeText(BIP47Activity.this, R.string.bip47_cannot_identify_outpoint, Toast.LENGTH_SHORT).show();
        return;
    }
    byte[] op_return = null;
    // 
    try {
        Script inputScript = new Script(outPoint.getConnectedPubKeyScript());
        String address = inputScript.getToAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString();
        ECKey ecKey = SendFactory.getPrivKey(address);
        if (ecKey == null || !ecKey.hasPrivKey()) {
            Toast.makeText(BIP47Activity.this, R.string.bip47_cannot_compose_notif_tx, Toast.LENGTH_SHORT).show();
            return;
        }
        // 
        // use outpoint for payload masking
        // 
        byte[] privkey = ecKey.getPrivKeyBytes();
        byte[] pubkey = payment_code.notificationAddress().getPubKey();
        byte[] outpoint = outPoint.bitcoinSerialize();
        // Log.i("BIP47Activity", "outpoint:" + Hex.toHexString(outpoint));
        // Log.i("BIP47Activity", "payer shared secret:" + Hex.toHexString(new SecretPoint(privkey, pubkey).ECDHSecretAsBytes()));
        byte[] mask = PaymentCode.getMask(new SecretPoint(privkey, pubkey).ECDHSecretAsBytes(), outpoint);
        // Log.i("BIP47Activity", "mask:" + Hex.toHexString(mask));
        // Log.i("BIP47Activity", "mask length:" + mask.length);
        // Log.i("BIP47Activity", "payload0:" + Hex.toHexString(BIP47Util.getInstance(context).getPaymentCode().getPayload()));
        op_return = PaymentCode.blind(BIP47Util.getInstance(BIP47Activity.this).getPaymentCode().getPayload(), mask);
    // Log.i("BIP47Activity", "payload1:" + Hex.toHexString(op_return));
    } catch (InvalidKeyException ike) {
        Toast.makeText(BIP47Activity.this, ike.getMessage(), Toast.LENGTH_SHORT).show();
        return;
    } catch (InvalidKeySpecException ikse) {
        Toast.makeText(BIP47Activity.this, ikse.getMessage(), Toast.LENGTH_SHORT).show();
        return;
    } catch (NoSuchAlgorithmException nsae) {
        Toast.makeText(BIP47Activity.this, nsae.getMessage(), Toast.LENGTH_SHORT).show();
        return;
    } catch (NoSuchProviderException nspe) {
        Toast.makeText(BIP47Activity.this, nspe.getMessage(), Toast.LENGTH_SHORT).show();
        return;
    }
    final HashMap<String, BigInteger> receivers = new HashMap<String, BigInteger>();
    receivers.put(Hex.toHexString(op_return), BigInteger.ZERO);
    receivers.put(payment_code.notificationAddress().getAddressString(), SendNotifTxFactory._bNotifTxValue);
    receivers.put(SamouraiWallet.getInstance().isTestNet() ? SendNotifTxFactory.TESTNET_SAMOURAI_NOTIF_TX_FEE_ADDRESS : SendNotifTxFactory.SAMOURAI_NOTIF_TX_FEE_ADDRESS, currentSWFee);
    final long change = totalValueSelected - (amount + fee.longValue());
    if (change > 0L) {
        String change_address = BIP49Util.getInstance(BIP47Activity.this).getAddressAt(AddressFactory.CHANGE_CHAIN, BIP49Util.getInstance(BIP47Activity.this).getWallet().getAccount(0).getChange().getAddrIdx()).getAddressAsString();
        receivers.put(change_address, BigInteger.valueOf(change));
    }
    Log.d("BIP47Activity", "outpoints:" + outpoints.size());
    Log.d("BIP47Activity", "totalValueSelected:" + BigInteger.valueOf(totalValueSelected).toString());
    Log.d("BIP47Activity", "amount:" + BigInteger.valueOf(amount).toString());
    Log.d("BIP47Activity", "change:" + BigInteger.valueOf(change).toString());
    Log.d("BIP47Activity", "fee:" + fee.toString());
    if (change < 0L) {
        Toast.makeText(BIP47Activity.this, R.string.bip47_cannot_compose_notif_tx, Toast.LENGTH_SHORT).show();
        return;
    }
    final MyTransactionOutPoint _outPoint = outPoint;
    String strNotifTxMsg = getText(R.string.bip47_setup4_text1) + " ";
    long notifAmount = amount;
    String strAmount = MonetaryUtil.getInstance().getBTCFormat().format(((double) notifAmount + fee.longValue()) / 1e8) + " BTC ";
    strNotifTxMsg += strAmount + getText(R.string.bip47_setup4_text2);
    AlertDialog.Builder dlg = new AlertDialog.Builder(BIP47Activity.this).setTitle(R.string.bip47_setup4_title).setMessage(strNotifTxMsg).setPositiveButton(R.string.confirm, new DialogInterface.OnClickListener() {

        public void onClick(DialogInterface dialog, int whichButton) {
            new Thread(new Runnable() {

                @Override
                public void run() {
                    Looper.prepare();
                    Transaction tx = SendFactory.getInstance(BIP47Activity.this).makeTransaction(0, outpoints, receivers);
                    if (tx != null) {
                        String input0hash = tx.getInput(0L).getOutpoint().getHash().toString();
                        Log.d("BIP47Activity", "input0 hash:" + input0hash);
                        Log.d("BIP47Activity", "_outPoint hash:" + _outPoint.getTxHash().toString());
                        int input0index = (int) tx.getInput(0L).getOutpoint().getIndex();
                        Log.d("BIP47Activity", "input0 index:" + input0index);
                        Log.d("BIP47Activity", "_outPoint index:" + _outPoint.getTxOutputN());
                        if (!input0hash.equals(_outPoint.getTxHash().toString()) || input0index != _outPoint.getTxOutputN()) {
                            Toast.makeText(BIP47Activity.this, R.string.bip47_cannot_compose_notif_tx, Toast.LENGTH_SHORT).show();
                            return;
                        }
                        tx = SendFactory.getInstance(BIP47Activity.this).signTransaction(tx);
                        final String hexTx = new String(org.bouncycastle.util.encoders.Hex.encode(tx.bitcoinSerialize()));
                        Log.d("SendActivity", tx.getHashAsString());
                        Log.d("SendActivity", hexTx);
                        boolean isOK = false;
                        String response = null;
                        try {
                            response = PushTx.getInstance(BIP47Activity.this).samourai(hexTx);
                            Log.d("SendActivity", "pushTx:" + response);
                            if (response != null) {
                                org.json.JSONObject jsonObject = new org.json.JSONObject(response);
                                if (jsonObject.has("status")) {
                                    if (jsonObject.getString("status").equals("ok")) {
                                        isOK = true;
                                    }
                                }
                            } else {
                                Toast.makeText(BIP47Activity.this, R.string.pushtx_returns_null, Toast.LENGTH_SHORT).show();
                                return;
                            }
                            if (isOK) {
                                Toast.makeText(BIP47Activity.this, R.string.payment_channel_init, Toast.LENGTH_SHORT).show();
                                // 
                                // set outgoing index for payment code to 0
                                // 
                                BIP47Meta.getInstance().setOutgoingIdx(pcode, 0);
                                // Log.i("SendNotifTxFactory", "tx hash:" + tx.getHashAsString());
                                // 
                                // status to NO_CFM
                                // 
                                BIP47Meta.getInstance().setOutgoingStatus(pcode, tx.getHashAsString(), BIP47Meta.STATUS_SENT_NO_CFM);
                                // 
                                if (change > 0L) {
                                    BIP49Util.getInstance(BIP47Activity.this).getWallet().getAccount(0).getChange().incAddrIdx();
                                }
                                PayloadUtil.getInstance(BIP47Activity.this).saveWalletToJSON(new CharSequenceX(AccessFactory.getInstance(BIP47Activity.this).getGUID() + AccessFactory.getInstance(BIP47Activity.this).getPIN()));
                            } else {
                                Toast.makeText(BIP47Activity.this, R.string.tx_failed, Toast.LENGTH_SHORT).show();
                            }
                        } catch (JSONException je) {
                            Toast.makeText(BIP47Activity.this, "pushTx:" + je.getMessage(), Toast.LENGTH_SHORT).show();
                            return;
                        } catch (MnemonicException.MnemonicLengthException mle) {
                            Toast.makeText(BIP47Activity.this, "pushTx:" + mle.getMessage(), Toast.LENGTH_SHORT).show();
                            return;
                        } catch (DecoderException de) {
                            Toast.makeText(BIP47Activity.this, "pushTx:" + de.getMessage(), Toast.LENGTH_SHORT).show();
                            return;
                        } catch (IOException ioe) {
                            Toast.makeText(BIP47Activity.this, "pushTx:" + ioe.getMessage(), Toast.LENGTH_SHORT).show();
                            return;
                        } catch (DecryptionException de) {
                            Toast.makeText(BIP47Activity.this, "pushTx:" + de.getMessage(), Toast.LENGTH_SHORT).show();
                            return;
                        }
                    }
                    Looper.loop();
                }
            }).start();
        }
    }).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {

        public void onClick(DialogInterface dialog, int whichButton) {
            ;
        }
    });
    dlg.show();
}
Also used : AlertDialog(android.app.AlertDialog) CharSequenceX(com.samourai.wallet.util.CharSequenceX) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) MyTransactionOutPoint(com.samourai.wallet.send.MyTransactionOutPoint) ECKey(org.bitcoinj.core.ECKey) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) JSONObject(org.json.JSONObject) InvalidKeySpecException(java.security.spec.InvalidKeySpecException) SecretPoint(com.samourai.wallet.bip47.rpc.SecretPoint) AddressFormatException(org.bitcoinj.core.AddressFormatException) Script(org.bitcoinj.script.Script) SuggestedFee(com.samourai.wallet.send.SuggestedFee) Transaction(org.bitcoinj.core.Transaction) JSONObject(org.json.JSONObject) BigInteger(java.math.BigInteger) DialogInterface(android.content.DialogInterface) MnemonicException(org.bitcoinj.crypto.MnemonicException) PaymentCode(com.samourai.wallet.bip47.rpc.PaymentCode) SendFactory(com.samourai.wallet.send.SendFactory) JSONException(org.json.JSONException) Intent(android.content.Intent) IOException(java.io.IOException) InvalidKeyException(java.security.InvalidKeyException) MyTransactionOutPoint(com.samourai.wallet.send.MyTransactionOutPoint) SecretPoint(com.samourai.wallet.bip47.rpc.SecretPoint) Point(android.graphics.Point) UTXO(com.samourai.wallet.send.UTXO) DecoderException(org.bouncycastle.util.encoders.DecoderException) MyTransactionInput(com.samourai.wallet.send.MyTransactionInput) NoSuchProviderException(java.security.NoSuchProviderException) DecryptionException(com.samourai.wallet.crypto.DecryptionException)

Example 2 with PaymentCode

use of com.samourai.wallet.bip47.rpc.PaymentCode in project samourai-wallet-android by Samourai-Wallet.

the class BIP47Util method getPaymentAddress.

public PaymentAddress getPaymentAddress(PaymentCode pcode, int idx, HD_Address address) throws AddressFormatException, NotSecp256k1Exception {
    DumpedPrivateKey dpk = new DumpedPrivateKey(SamouraiWallet.getInstance().getCurrentNetworkParams(), address.getPrivateKeyString());
    ECKey eckey = dpk.getKey();
    PaymentAddress paymentAddress = new PaymentAddress(pcode, idx, eckey.getPrivKeyBytes());
    return paymentAddress;
}
Also used : ECKey(org.bitcoinj.core.ECKey) PaymentAddress(com.samourai.wallet.bip47.rpc.PaymentAddress) DumpedPrivateKey(org.bitcoinj.core.DumpedPrivateKey)

Example 3 with PaymentCode

use of com.samourai.wallet.bip47.rpc.PaymentCode in project samourai-wallet-android by Samourai-Wallet.

the class SendFactory method getPrivKey.

public static ECKey getPrivKey(String address) {
    ECKey ecKey = null;
    try {
        String path = APIFactory.getInstance(context).getUnspentPaths().get(address);
        // Log.d("APIFactory", "address:" + path);
        if (path != null) {
            String[] s = path.split("/");
            if (Address.fromBase58(SamouraiWallet.getInstance().getCurrentNetworkParams(), address).isP2SHAddress()) {
                // Log.d("APIFactory", "address type:" + "bip49");
                HD_Address addr = BIP49Util.getInstance(context).getWallet().getAccount(0).getChain(Integer.parseInt(s[1])).getAddressAt(Integer.parseInt(s[2]));
                ecKey = addr.getECKey();
            } else {
                // Log.d("APIFactory", "address type:" + "bip44");
                int account_no = APIFactory.getInstance(context).getUnspentAccounts().get(address);
                HD_Address hd_address = AddressFactory.getInstance(context).get(account_no, Integer.parseInt(s[1]), Integer.parseInt(s[2]));
                String strPrivKey = hd_address.getPrivateKeyString();
                DumpedPrivateKey pk = new DumpedPrivateKey(SamouraiWallet.getInstance().getCurrentNetworkParams(), strPrivKey);
                ecKey = pk.getKey();
            }
        } else {
            // Log.d("APIFactory", "address type:" + "bip47");
            String pcode = BIP47Meta.getInstance().getPCode4Addr(address);
            int idx = BIP47Meta.getInstance().getIdx4Addr(address);
            PaymentAddress addr = BIP47Util.getInstance(context).getReceiveAddress(new PaymentCode(pcode), idx);
            ecKey = addr.getReceiveECKey();
        }
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
    return ecKey;
}
Also used : PaymentCode(com.samourai.wallet.bip47.rpc.PaymentCode) HD_Address(com.samourai.wallet.hd.HD_Address) ECKey(org.bitcoinj.core.ECKey) PaymentAddress(com.samourai.wallet.bip47.rpc.PaymentAddress) DumpedPrivateKey(org.bitcoinj.core.DumpedPrivateKey) MnemonicException(org.bitcoinj.crypto.MnemonicException) ScriptException(org.bitcoinj.script.ScriptException) AddressFormatException(org.bitcoinj.core.AddressFormatException) IOException(java.io.IOException)

Example 4 with PaymentCode

use of com.samourai.wallet.bip47.rpc.PaymentCode in project samourai-wallet-android by Samourai-Wallet.

the class APIFactory method initWalletAmounts.

private synchronized void initWalletAmounts() {
    APIFactory.getInstance(context).reset();
    List<String> addressStrings = new ArrayList<String>();
    String[] s = null;
    try {
        if (PrefsUtil.getInstance(context).getValue(PrefsUtil.XPUB44REG, false) == false) {
            registerXPUB(HD_WalletFactory.getInstance(context).get().getAccount(0).xpubstr(), 44, null);
        }
        if (PrefsUtil.getInstance(context).getValue(PrefsUtil.XPUB49REG, false) == false) {
            registerXPUB(BIP49Util.getInstance(context).getWallet().getAccount(0).xpubstr(), 49, null);
        }
        if (PrefsUtil.getInstance(context).getValue(PrefsUtil.XPUB84REG, false) == false) {
            registerXPUB(BIP84Util.getInstance(context).getWallet().getAccount(0).xpubstr(), 84, null);
        }
        if (PrefsUtil.getInstance(context).getValue(PrefsUtil.XPUBPREREG, false) == false) {
            registerXPUB(BIP84Util.getInstance(context).getWallet().getAccountAt(WhirlpoolMeta.getInstance(context).getWhirlpoolPremixAccount()).xpubstr(), 84, PrefsUtil.XPUBPREREG);
        }
        if (PrefsUtil.getInstance(context).getValue(PrefsUtil.XPUBPOSTREG, false) == false) {
            registerXPUB(BIP84Util.getInstance(context).getWallet().getAccountAt(WhirlpoolMeta.getInstance(context).getWhirlpoolPostmix()).xpubstr(), 84, PrefsUtil.XPUBPOSTREG);
        }
        if (PrefsUtil.getInstance(context).getValue(PrefsUtil.XPUBBADBANKREG, false) == false) {
            registerXPUB(BIP84Util.getInstance(context).getWallet().getAccountAt(WhirlpoolMeta.getInstance(context).getWhirlpoolBadBank()).xpubstr(), 84, PrefsUtil.XPUBPOSTREG);
        }
        xpub_txs.put(HD_WalletFactory.getInstance(context).get().getAccount(0).xpubstr(), new ArrayList<Tx>());
        addressStrings.addAll(Arrays.asList(BIP47Meta.getInstance().getIncomingAddresses(false)));
        for (String _s : Arrays.asList(BIP47Meta.getInstance().getIncomingLookAhead(context))) {
            if (!addressStrings.contains(_s)) {
                addressStrings.add(_s);
            }
        }
        for (String pcode : BIP47Meta.getInstance().getUnspentProviders()) {
            for (String addr : BIP47Meta.getInstance().getUnspentAddresses(context, pcode)) {
                if (!addressStrings.contains(addr)) {
                    addressStrings.add(addr);
                }
            }
            List<Integer> idxs = BIP47Meta.getInstance().getUnspent(pcode);
            for (Integer idx : idxs) {
                String receivePubKey = BIP47Util.getInstance(context).getReceivePubKey(new PaymentCode(pcode), idx);
                BIP47Meta.getInstance().getIdx4AddrLookup().put(receivePubKey, idx);
                BIP47Meta.getInstance().getPCode4AddrLookup().put(receivePubKey, pcode.toString());
                if (!addressStrings.contains(receivePubKey)) {
                    addressStrings.add(receivePubKey);
                }
            }
        }
        if (addressStrings.size() > 0) {
            s = addressStrings.toArray(new String[0]);
            // info("APIFactory", addressStrings.toString());
            utxoObj0 = getUnspentOutputs(s);
        }
        debug("APIFactory", "addresses:" + addressStrings.toString());
        HD_Wallet hdw = HD_WalletFactory.getInstance(context).get();
        if (hdw != null && hdw.getXPUBs() != null) {
            String[] all = null;
            if (s != null && s.length > 0) {
                all = new String[hdw.getXPUBs().length + 2 + s.length];
                all[0] = BIP49Util.getInstance(context).getWallet().getAccount(0).xpubstr();
                all[1] = BIP84Util.getInstance(context).getWallet().getAccount(0).xpubstr();
                System.arraycopy(hdw.getXPUBs(), 0, all, 2, hdw.getXPUBs().length);
                System.arraycopy(s, 0, all, hdw.getXPUBs().length + 2, s.length);
            } else {
                all = new String[hdw.getXPUBs().length + 2];
                all[0] = BIP49Util.getInstance(context).getWallet().getAccount(0).xpubstr();
                all[1] = BIP84Util.getInstance(context).getWallet().getAccount(0).xpubstr();
                System.arraycopy(hdw.getXPUBs(), 0, all, 2, hdw.getXPUBs().length);
            }
            APIFactory.getInstance(context).getXPUB(all, true);
            String[] xs = new String[3];
            xs[0] = HD_WalletFactory.getInstance(context).get().getAccount(0).xpubstr();
            xs[1] = BIP49Util.getInstance(context).getWallet().getAccount(0).xpubstr();
            xs[2] = BIP84Util.getInstance(context).getWallet().getAccount(0).xpubstr();
            utxoObj1 = getUnspentOutputs(xs);
            getDynamicFees();
        }
        try {
            List<JSONObject> utxoObjs = new ArrayList<JSONObject>();
            if (utxoObj0 != null) {
                utxoObjs.add(utxoObj0);
            }
            if (utxoObj1 != null) {
                utxoObjs.add(utxoObj1);
            }
            PayloadUtil.getInstance(context).serializeUTXO(utxoObjs);
        } catch (IOException | DecryptionException e) {
            ;
        }
        // 
        // 
        // 
        List<String> seenOutputs = new ArrayList<String>();
        List<UTXO> _utxos = getUtxos(false);
        for (UTXO _u : _utxos) {
            for (MyTransactionOutPoint _o : _u.getOutpoints()) {
                seenOutputs.add(_o.getTxHash().toString() + "-" + _o.getTxOutputN());
            }
        }
        for (String _s : BlockedUTXO.getInstance().getNotDustedUTXO()) {
            // debug("APIFactory", "not dusted:" + _s);
            if (!seenOutputs.contains(_s)) {
                BlockedUTXO.getInstance().removeNotDusted(_s);
            // debug("APIFactory", "not dusted removed:" + _s);
            }
        }
        for (String _s : BlockedUTXO.getInstance().getBlockedUTXO().keySet()) {
            // debug("APIFactory", "blocked:" + _s);
            if (!seenOutputs.contains(_s)) {
                BlockedUTXO.getInstance().remove(_s);
            // debug("APIFactory", "blocked removed:" + _s);
            }
        }
        String strPreMix = BIP84Util.getInstance(context).getWallet().getAccountAt(WhirlpoolMeta.getInstance(context).getWhirlpoolPremixAccount()).xpubstr();
        String strPostMix = BIP84Util.getInstance(context).getWallet().getAccountAt(WhirlpoolMeta.getInstance(context).getWhirlpoolPostmix()).xpubstr();
        String strBadBank = BIP84Util.getInstance(context).getWallet().getAccountAt(WhirlpoolMeta.getInstance(context).getWhirlpoolBadBank()).xpubstr();
        JSONObject preMultiAddrObj = getRawXPUB(new String[] { strPreMix });
        JSONObject preUnspentObj = getRawUnspentOutputs(new String[] { strPreMix });
        debug("APIFactory", "pre-mix multi:" + preMultiAddrObj.toString(2));
        debug("APIFactory", "pre-mix unspent:" + preUnspentObj.toString());
        boolean parsedPreMultiAddr = parseMixXPUB(preMultiAddrObj);
        boolean parsedPreUnspent = parseMixUnspentOutputs(preUnspentObj.toString());
        JSONObject postMultiAddrObj = getRawXPUB(new String[] { strPostMix });
        JSONObject postUnspentObj = getRawUnspentOutputs(new String[] { strPostMix });
        debug("APIFactory", "post-mix multi:" + postMultiAddrObj.toString());
        debug("APIFactory", "post-mix unspent:" + postUnspentObj.toString());
        boolean parsedPostMultiAddr = parseMixXPUB(postMultiAddrObj);
        boolean parsedPostUnspent = parseMixUnspentOutputs(postUnspentObj.toString());
        // debug("APIFactory", "post-mix multi:" + parsedPostMultiAddr);
        // debug("APIFactory", "post-mix unspent:" + parsedPostUnspent);
        // debug("APIFactory", "post-mix multi:" + getXpubPostMixBalance());
        // debug("APIFactory", "post-mix unspent:" + getUtxosPostMix().size());
        JSONObject badbankMultiAddrObj = getRawXPUB(new String[] { strBadBank });
        JSONObject badbankUnspentObj = getRawUnspentOutputs(new String[] { strBadBank });
        debug("APIFactory", "bad bank multi:" + badbankMultiAddrObj.toString());
        debug("APIFactory", "bad bank unspent:" + badbankUnspentObj.toString());
        boolean parsedBadBankMultiAddr = parseMixXPUB(badbankMultiAddrObj);
        boolean parsedBadBanktUnspent = parseMixUnspentOutputs(badbankUnspentObj.toString());
        // 
        // 
        // 
        List<String> seenOutputsPostMix = new ArrayList<String>();
        List<UTXO> _utxosPostMix = getUtxosPostMix(false);
        for (UTXO _u : _utxosPostMix) {
            for (MyTransactionOutPoint _o : _u.getOutpoints()) {
                seenOutputsPostMix.add(_o.getTxHash().toString() + "-" + _o.getTxOutputN());
            }
        }
        for (String _s : UTXOUtil.getInstance().getTags().keySet()) {
            if (!seenOutputsPostMix.contains(_s) && !seenOutputs.contains(_s)) {
                UTXOUtil.getInstance().remove(_s);
                UTXOUtil.getInstance().removeNote(_s);
            }
        }
        List<String> seenOutputsBadBank = new ArrayList<String>();
        List<UTXO> _utxosBadBank = getUtxosBadBank(false);
        for (UTXO _u : _utxosBadBank) {
            for (MyTransactionOutPoint _o : _u.getOutpoints()) {
                seenOutputsBadBank.add(_o.getTxHash().toString() + "-" + _o.getTxOutputN());
            }
        }
        for (String _s : UTXOUtil.getInstance().getTags().keySet()) {
            if (!seenOutputsBadBank.contains(_s) && !seenOutputs.contains(_s)) {
                UTXOUtil.getInstance().remove(_s);
            }
        }
        /*
            for(String _s : BlockedUTXO.getInstance().getNotDustedUTXO())   {
//                debug("APIFactory", "not dusted:" + _s);
                if(!seenOutputsPostMix.contains(_s))    {
                    BlockedUTXO.getInstance().removeNotDusted(_s);
//                    debug("APIFactory", "not dusted removed:" + _s);
                }
            }
            */
        for (String _s : BlockedUTXO.getInstance().getBlockedUTXOPostMix().keySet()) {
            debug("APIFactory", "blocked post-mix:" + _s);
            if (!seenOutputsPostMix.contains(_s)) {
                BlockedUTXO.getInstance().removePostMix(_s);
                debug("APIFactory", "blocked removed:" + _s);
            }
        }
        // refresh Whirlpool utxos
        Optional<WhirlpoolWallet> whirlpoolWalletOpt = AndroidWhirlpoolWalletService.getInstance().getWhirlpoolWallet();
        if (whirlpoolWalletOpt.isPresent()) {
            whirlpoolWalletOpt.get().clearCache(WhirlpoolAccount.DEPOSIT);
            whirlpoolWalletOpt.get().clearCache(WhirlpoolAccount.PREMIX);
            whirlpoolWalletOpt.get().clearCache(WhirlpoolAccount.POSTMIX);
            whirlpoolWalletOpt.get().clearCache(WhirlpoolAccount.BADBANK);
        }
    } catch (IndexOutOfBoundsException ioobe) {
        ioobe.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    }
    walletInit = true;
}
Also used : PaymentCode(com.samourai.wallet.bip47.rpc.PaymentCode) HD_Wallet(com.samourai.wallet.hd.HD_Wallet) ArrayList(java.util.ArrayList) MyTransactionOutPoint(com.samourai.wallet.send.MyTransactionOutPoint) IOException(java.io.IOException) NotSecp256k1Exception(com.samourai.wallet.bip47.rpc.NotSecp256k1Exception) JSONException(org.json.JSONException) AddressFormatException(org.bitcoinj.core.AddressFormatException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) InvalidKeyException(java.security.InvalidKeyException) InvalidKeySpecException(java.security.spec.InvalidKeySpecException) MnemonicException(org.bitcoinj.crypto.MnemonicException) DecryptionException(com.samourai.wallet.crypto.DecryptionException) IOException(java.io.IOException) NoSuchProviderException(java.security.NoSuchProviderException) BigInteger(java.math.BigInteger) UTXO(com.samourai.wallet.send.UTXO) BlockedUTXO(com.samourai.wallet.send.BlockedUTXO) JSONObject(org.json.JSONObject) WhirlpoolWallet(com.samourai.whirlpool.client.wallet.WhirlpoolWallet) DecryptionException(com.samourai.wallet.crypto.DecryptionException)

Example 5 with PaymentCode

use of com.samourai.wallet.bip47.rpc.PaymentCode in project samourai-wallet-android by Samourai-Wallet.

the class PayNymCalcActivity method onCreate.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_paynym_calc);
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    edPayNym = (EditText) findViewById(R.id.paynym);
    edIndex = (EditText) findViewById(R.id.index);
    edPayNym.setOnTouchListener(new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // final int DRAWABLE_LEFT = 0;
            // final int DRAWABLE_TOP = 1;
            final int DRAWABLE_RIGHT = 2;
            if (event.getAction() == MotionEvent.ACTION_UP && event.getRawX() >= (edPayNym.getRight() - edPayNym.getCompoundDrawables()[DRAWABLE_RIGHT].getBounds().width())) {
                final List<String> entries = new ArrayList<String>();
                entries.addAll(BIP47Meta.getInstance().getSortedByLabels(true));
                final ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(PayNymCalcActivity.this, android.R.layout.select_dialog_singlechoice);
                for (int i = 0; i < entries.size(); i++) {
                    arrayAdapter.add(BIP47Meta.getInstance().getDisplayLabel(entries.get(i)));
                }
                AlertDialog.Builder dlg = new AlertDialog.Builder(PayNymCalcActivity.this);
                dlg.setIcon(R.drawable.ic_launcher);
                dlg.setTitle(R.string.app_name);
                dlg.setAdapter(arrayAdapter, new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        edPayNym.setText(entries.get(which));
                    }
                });
                dlg.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                });
                dlg.show();
                return true;
            }
            return false;
        }
    });
    btOK = (Button) findViewById(R.id.ok);
    btOK.setOnClickListener(new View.OnClickListener() {

        public void onClick(View v) {
            String strPayNym = edPayNym.getText().toString();
            String strIndex = edIndex.getText().toString();
            PaymentCode pcode = new PaymentCode(strPayNym);
            if (pcode == null) {
                Toast.makeText(PayNymCalcActivity.this, R.string.invalid_payment_code, Toast.LENGTH_SHORT).show();
                return;
            }
            if (strIndex == null || strIndex.length() < 1) {
                Toast.makeText(PayNymCalcActivity.this, R.string.invalid_index, Toast.LENGTH_SHORT).show();
                return;
            }
            try {
                int index = Integer.parseInt(strIndex);
                String message = strPayNym;
                final ECKey receiveECKey;
                final SegwitAddress receiveSegwit;
                PaymentAddress receiveAddress = BIP47Util.getInstance(PayNymCalcActivity.this).getReceiveAddress(new PaymentCode(strPayNym), index);
                PaymentAddress sendAddress = BIP47Util.getInstance(PayNymCalcActivity.this).getSendAddress(new PaymentCode(strPayNym), index);
                receiveECKey = receiveAddress.getReceiveECKey();
                ECKey sendECKey = sendAddress.getSendECKey();
                receiveSegwit = new SegwitAddress(receiveECKey, SamouraiWallet.getInstance().getCurrentNetworkParams());
                SegwitAddress sendSegwit = new SegwitAddress(sendECKey, SamouraiWallet.getInstance().getCurrentNetworkParams());
                message += "\n";
                message += index + ":";
                message += "\n";
                message += "\n";
                message += PayNymCalcActivity.this.getText(R.string.receive_addresses).toString() + ":";
                message += "\n";
                message += receiveECKey.toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString();
                message += "\n";
                message += receiveSegwit.getAddressAsString();
                message += "\n";
                message += receiveSegwit.getBech32AsString();
                message += "\n";
                message += PayNymCalcActivity.this.getText(R.string.send_addresses).toString() + ":";
                message += "\n";
                message += sendECKey.toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString();
                message += "\n";
                message += sendSegwit.getAddressAsString();
                message += "\n";
                message += sendSegwit.getBech32AsString();
                message += "\n";
                final TextView tvText = new TextView(getApplicationContext());
                tvText.setTextSize(12);
                tvText.setText(message);
                tvText.setTextIsSelectable(true);
                tvText.setPadding(40, 10, 40, 10);
                tvText.setTextColor(0xffffffff);
                AlertDialog.Builder dlg = new AlertDialog.Builder(PayNymCalcActivity.this).setTitle(R.string.app_name).setView(tvText).setCancelable(true).setPositiveButton(R.string.display_receive_redeem, new DialogInterface.OnClickListener() {

                    public void onClick(DialogInterface dialog, int whichButton) {
                        String redeemScript = org.spongycastle.util.encoders.Hex.toHexString(receiveSegwit.segWitRedeemScript().getProgram());
                        TextView showText = new TextView(PayNymCalcActivity.this);
                        showText.setText(redeemScript);
                        showText.setTextIsSelectable(true);
                        showText.setPadding(40, 10, 40, 10);
                        showText.setTextSize(18.0f);
                        new AlertDialog.Builder(PayNymCalcActivity.this).setTitle(R.string.app_name).setView(showText).setCancelable(false).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {

                            public void onClick(DialogInterface dialog, int whichButton) {
                                dialog.dismiss();
                            }
                        }).show();
                    }
                }).setNeutralButton(R.string.close, new DialogInterface.OnClickListener() {

                    public void onClick(DialogInterface dialog, int whichButton) {
                        dialog.dismiss();
                    }
                }).setNegativeButton(R.string.display_receive_privkey, new DialogInterface.OnClickListener() {

                    public void onClick(DialogInterface dialog, int whichButton) {
                        String strPrivKey = receiveECKey.getPrivateKeyAsWiF(SamouraiWallet.getInstance().getCurrentNetworkParams());
                        ImageView showQR = new ImageView(PayNymCalcActivity.this);
                        Bitmap bitmap = null;
                        QRCodeEncoder qrCodeEncoder = new QRCodeEncoder(strPrivKey, null, Contents.Type.TEXT, BarcodeFormat.QR_CODE.toString(), 500);
                        try {
                            bitmap = qrCodeEncoder.encodeAsBitmap();
                        } catch (WriterException e) {
                            e.printStackTrace();
                        }
                        showQR.setImageBitmap(bitmap);
                        TextView showText = new TextView(PayNymCalcActivity.this);
                        showText.setText(strPrivKey);
                        showText.setTextIsSelectable(true);
                        showText.setPadding(40, 10, 40, 10);
                        showText.setTextSize(18.0f);
                        LinearLayout privkeyLayout = new LinearLayout(PayNymCalcActivity.this);
                        privkeyLayout.setOrientation(LinearLayout.VERTICAL);
                        privkeyLayout.addView(showQR);
                        privkeyLayout.addView(showText);
                        new AlertDialog.Builder(PayNymCalcActivity.this).setTitle(R.string.app_name).setView(privkeyLayout).setCancelable(false).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {

                            public void onClick(DialogInterface dialog, int whichButton) {
                                ;
                            }
                        }).show();
                    }
                });
                if (!isFinishing()) {
                    dlg.show();
                }
            } catch (Exception e) {
                Toast.makeText(PayNymCalcActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
            }
        }
    });
    btCancel = (Button) findViewById(R.id.cancel);
    btCancel.setOnClickListener(new View.OnClickListener() {

        public void onClick(View v) {
            finish();
        }
    });
}
Also used : AlertDialog(android.app.AlertDialog) DialogInterface(android.content.DialogInterface) SegwitAddress(com.samourai.wallet.segwit.SegwitAddress) QRCodeEncoder(com.google.zxing.client.android.encode.QRCodeEncoder) ECKey(org.bitcoinj.core.ECKey) Bitmap(android.graphics.Bitmap) ArrayList(java.util.ArrayList) List(java.util.List) TextView(android.widget.TextView) ImageView(android.widget.ImageView) PaymentCode(com.samourai.wallet.bip47.rpc.PaymentCode) PaymentAddress(com.samourai.wallet.bip47.rpc.PaymentAddress) ImageView(android.widget.ImageView) View(android.view.View) TextView(android.widget.TextView) WriterException(com.google.zxing.WriterException) MotionEvent(android.view.MotionEvent) ArrayAdapter(android.widget.ArrayAdapter) WriterException(com.google.zxing.WriterException) LinearLayout(android.widget.LinearLayout)

Aggregations

PaymentCode (com.samourai.wallet.bip47.rpc.PaymentCode)21 IOException (java.io.IOException)15 MnemonicException (org.bitcoinj.crypto.MnemonicException)15 JSONException (org.json.JSONException)14 PaymentAddress (com.samourai.wallet.bip47.rpc.PaymentAddress)12 ArrayList (java.util.ArrayList)10 AddressFormatException (org.bitcoinj.core.AddressFormatException)10 MyTransactionOutPoint (com.samourai.wallet.send.MyTransactionOutPoint)9 Intent (android.content.Intent)8 DecryptionException (com.samourai.wallet.crypto.DecryptionException)8 ECKey (org.bitcoinj.core.ECKey)8 InvalidKeyException (java.security.InvalidKeyException)7 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)7 NoSuchProviderException (java.security.NoSuchProviderException)7 InvalidKeySpecException (java.security.spec.InvalidKeySpecException)7 CharSequenceX (com.samourai.wallet.util.CharSequenceX)6 SegwitAddress (com.samourai.wallet.segwit.SegwitAddress)5 Script (org.bitcoinj.script.Script)5 JSONObject (org.json.JSONObject)5 NotSecp256k1Exception (com.samourai.wallet.bip47.rpc.NotSecp256k1Exception)4