Search in sources :

Example 11 with PaymentCode

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

the class PayNymDetailsActivity method doNotifTx.

private void doNotifTx() {
    // 
    // get wallet balance
    // 
    long balance = 0L;
    try {
        balance = APIFactory.getInstance(PayNymDetailsActivity.this).getXpubAmounts().get(HD_WalletFactory.getInstance(PayNymDetailsActivity.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();
    // 
    // add Samourai Wallet fee to total amount
    // 
    amount += SendNotifTxFactory._bSWFee.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().getAllP2SH_P2WPKH().values());
    } else {
        utxos = APIFactory.getInstance(PayNymDetailsActivity.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("PayNymDetailsActivity", "single output");
            Log.d("PayNymDetailsActivity", "value selected:" + u.getValue());
            Log.d("PayNymDetailsActivity", "total value selected:" + totalValueSelected);
            Log.d("PayNymDetailsActivity", "nb inputs:" + u.getOutpoints().size());
            break;
        }
    }
    // 
    // use normal fee settings
    // 
    SuggestedFee suggestedFee = FeeUtil.getInstance().getSuggestedFee();
    long lo = FeeUtil.getInstance().getLowFee().getDefaultPerKB().longValue() / 1000L;
    long mi = FeeUtil.getInstance().getNormalFee().getDefaultPerKB().longValue() / 1000L;
    long hi = FeeUtil.getInstance().getHighFee().getDefaultPerKB().longValue() / 1000L;
    if (lo == mi && mi == hi) {
        SuggestedFee hi_sf = new SuggestedFee();
        hi_sf.setDefaultPerKB(BigInteger.valueOf((long) (hi * 1.15 * 1000.0)));
        FeeUtil.getInstance().setSuggestedFee(hi_sf);
    } else if (lo == mi) {
        FeeUtil.getInstance().setSuggestedFee(FeeUtil.getInstance().getHighFee());
    } else {
        FeeUtil.getInstance().setSuggestedFee(FeeUtil.getInstance().getNormalFee());
    }
    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("PayNymDetailsActivity", "multiple outputs");
                Log.d("PayNymDetailsActivity", "total value selected:" + totalValueSelected);
                Log.d("PayNymDetailsActivity", "nb inputs:" + u.getOutpoints().size());
                break;
            }
        }
        // fee = FeeUtil.getInstance().estimatedFee(selected, 4);
        fee = FeeUtil.getInstance().estimatedFee(selected, 7);
    } else {
        // fee = FeeUtil.getInstance().estimatedFee(1, 4);
        fee = FeeUtil.getInstance().estimatedFee(1, 7);
    }
    // 
    // 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(PayNymDetailsActivity.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(PayNymDetailsActivity.this, R.string.bip47_cannot_identify_outpoint, Toast.LENGTH_SHORT).show();
        return;
    }
    byte[] op_return = null;
    // 
    try {
        // Script inputScript = new Script(outPoint.getConnectedPubKeyScript());
        byte[] scriptBytes = outPoint.getConnectedPubKeyScript();
        String address = null;
        if (Bech32Util.getInstance().isBech32Script(Hex.toHexString(scriptBytes))) {
            address = Bech32Util.getInstance().getAddressFromScript(Hex.toHexString(scriptBytes));
        } else {
            address = new Script(scriptBytes).getToAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString();
        }
        // String address = inputScript.getToAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString();
        ECKey ecKey = SendFactory.getPrivKey(address, 0);
        if (ecKey == null || !ecKey.hasPrivKey()) {
            Toast.makeText(PayNymDetailsActivity.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(SamouraiWallet.getInstance().getCurrentNetworkParams()).getPubKey();
        byte[] outpoint = outPoint.bitcoinSerialize();
        // Log.i("PayNymDetailsActivity", "outpoint:" + Hex.toHexString(outpoint));
        // Log.i("PayNymDetailsActivity", "payer shared secret:" + Hex.toHexString(new SecretPoint(privkey, pubkey).ECDHSecretAsBytes()));
        byte[] mask = PaymentCode.getMask(new SecretPoint(privkey, pubkey).ECDHSecretAsBytes(), outpoint);
        // Log.i("PayNymDetailsActivity", "mask:" + Hex.toHexString(mask));
        // Log.i("PayNymDetailsActivity", "mask length:" + mask.length);
        // Log.i("PayNymDetailsActivity", "payload0:" + Hex.toHexString(BIP47Util.getInstance(context).getPaymentCode().getPayload()));
        op_return = PaymentCode.blind(BIP47Util.getInstance(PayNymDetailsActivity.this).getPaymentCode().getPayload(), mask);
    // Log.i("PayNymDetailsActivity", "payload1:" + Hex.toHexString(op_return));
    } catch (InvalidKeyException ike) {
        Toast.makeText(PayNymDetailsActivity.this, ike.getMessage(), Toast.LENGTH_SHORT).show();
        return;
    } catch (InvalidKeySpecException ikse) {
        Toast.makeText(PayNymDetailsActivity.this, ikse.getMessage(), Toast.LENGTH_SHORT).show();
        return;
    } catch (NoSuchAlgorithmException nsae) {
        Toast.makeText(PayNymDetailsActivity.this, nsae.getMessage(), Toast.LENGTH_SHORT).show();
        return;
    } catch (NoSuchProviderException nspe) {
        Toast.makeText(PayNymDetailsActivity.this, nspe.getMessage(), Toast.LENGTH_SHORT).show();
        return;
    } catch (Exception e) {
        Toast.makeText(PayNymDetailsActivity.this, e.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(SamouraiWallet.getInstance().getCurrentNetworkParams()).getAddressString(), SendNotifTxFactory._bNotifTxValue);
    receivers.put(SamouraiWallet.getInstance().isTestNet() ? SendNotifTxFactory.TESTNET_SAMOURAI_NOTIF_TX_FEE_ADDRESS : SendNotifTxFactory.SAMOURAI_NOTIF_TX_FEE_ADDRESS, SendNotifTxFactory._bSWFee);
    final long change = totalValueSelected - (amount + fee.longValue());
    if (change > 0L) {
        String change_address = BIP84Util.getInstance(PayNymDetailsActivity.this).getAddressAt(AddressFactory.CHANGE_CHAIN, BIP84Util.getInstance(PayNymDetailsActivity.this).getWallet().getAccount(0).getChange().getAddrIdx()).getBech32AsString();
        receivers.put(change_address, BigInteger.valueOf(change));
    }
    Log.d("PayNymDetailsActivity", "outpoints:" + outpoints.size());
    Log.d("PayNymDetailsActivity", "totalValueSelected:" + BigInteger.valueOf(totalValueSelected).toString());
    Log.d("PayNymDetailsActivity", "amount:" + BigInteger.valueOf(amount).toString());
    Log.d("PayNymDetailsActivity", "change:" + BigInteger.valueOf(change).toString());
    Log.d("PayNymDetailsActivity", "fee:" + fee.toString());
    if (change < 0L) {
        Toast.makeText(PayNymDetailsActivity.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);
    showFollowAlert(strAmount, view -> {
        new Thread(new Runnable() {

            @Override
            public void run() {
                Looper.prepare();
                Transaction tx = SendFactory.getInstance(PayNymDetailsActivity.this).makeTransaction(0, outpoints, receivers);
                if (tx != null) {
                    String input0hash = tx.getInput(0L).getOutpoint().getHash().toString();
                    Log.d("PayNymDetailsActivity", "input0 hash:" + input0hash);
                    Log.d("PayNymDetailsActivity", "_outPoint hash:" + _outPoint.getTxHash().toString());
                    int input0index = (int) tx.getInput(0L).getOutpoint().getIndex();
                    Log.d("PayNymDetailsActivity", "input0 index:" + input0index);
                    Log.d("PayNymDetailsActivity", "_outPoint index:" + _outPoint.getTxOutputN());
                    if (!input0hash.equals(_outPoint.getTxHash().toString()) || input0index != _outPoint.getTxOutputN()) {
                        Toast.makeText(PayNymDetailsActivity.this, R.string.bip47_cannot_compose_notif_tx, Toast.LENGTH_SHORT).show();
                        return;
                    }
                    tx = SendFactory.getInstance(PayNymDetailsActivity.this).signTransaction(tx, 0);
                    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(PayNymDetailsActivity.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(PayNymDetailsActivity.this, R.string.pushtx_returns_null, Toast.LENGTH_SHORT).show();
                            return;
                        }
                        if (isOK) {
                            Toast.makeText(PayNymDetailsActivity.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(PayNymDetailsActivity.this).getWallet().getAccount(0).getChange().incAddrIdx();
                            }
                            savePayLoad();
                        } else {
                            Toast.makeText(PayNymDetailsActivity.this, R.string.tx_failed, Toast.LENGTH_SHORT).show();
                        }
                        runOnUiThread(() -> {
                            setPayNym();
                        });
                    } catch (JSONException je) {
                        Toast.makeText(PayNymDetailsActivity.this, "pushTx:" + je.getMessage(), Toast.LENGTH_SHORT).show();
                        return;
                    } catch (MnemonicException.MnemonicLengthException mle) {
                        Toast.makeText(PayNymDetailsActivity.this, "pushTx:" + mle.getMessage(), Toast.LENGTH_SHORT).show();
                        return;
                    } catch (DecoderException de) {
                        Toast.makeText(PayNymDetailsActivity.this, "pushTx:" + de.getMessage(), Toast.LENGTH_SHORT).show();
                        return;
                    } catch (IOException ioe) {
                        Toast.makeText(PayNymDetailsActivity.this, "pushTx:" + ioe.getMessage(), Toast.LENGTH_SHORT).show();
                        return;
                    } catch (DecryptionException de) {
                        Toast.makeText(PayNymDetailsActivity.this, "pushTx:" + de.getMessage(), Toast.LENGTH_SHORT).show();
                        return;
                    }
                }
                Looper.loop();
            }
        }).start();
    });
}
Also used : AlertDialog(android.app.AlertDialog) 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) JSONException(org.json.JSONException) DecoderException(org.bouncycastle.util.encoders.DecoderException) 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) 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 12 with PaymentCode

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

the class SendActivity method processPCode.

private void processPCode(String pcode, String meta) {
    if (FormatsUtil.getInstance().isValidPaymentCode(pcode)) {
        if (BIP47Meta.getInstance().getOutgoingStatus(pcode) == BIP47Meta.STATUS_SENT_CFM) {
            try {
                PaymentCode _pcode = new PaymentCode(pcode);
                PaymentAddress paymentAddress = BIP47Util.getInstance(SendActivity.this).getSendAddress(_pcode, BIP47Meta.getInstance().getOutgoingIdx(pcode));
                strDestinationBTCAddress = paymentAddress.getSendECKey().toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString();
                strPCode = _pcode.toString();
                edAddress.setText(BIP47Meta.getInstance().getDisplayLabel(strPCode));
                edAddress.setEnabled(false);
            } catch (Exception e) {
                Toast.makeText(SendActivity.this, R.string.error_payment_code, Toast.LENGTH_SHORT).show();
            }
        } else {
            if (meta != null && meta.startsWith("?") && meta.length() > 1) {
                meta = meta.substring(1);
            }
            Intent intent = new Intent(SendActivity.this, BIP47Activity.class);
            intent.putExtra("pcode", pcode);
            if (meta != null && meta.length() > 0) {
                intent.putExtra("meta", meta);
            }
            startActivity(intent);
        }
    } else {
        Toast.makeText(SendActivity.this, R.string.invalid_payment_code, Toast.LENGTH_SHORT).show();
    }
}
Also used : PaymentCode(com.samourai.wallet.bip47.rpc.PaymentCode) Intent(android.content.Intent) PaymentAddress(com.samourai.wallet.bip47.rpc.PaymentAddress) JSONException(org.json.JSONException) IOException(java.io.IOException) WriterException(com.google.zxing.WriterException) ParseException(java.text.ParseException) DecoderException(org.bouncycastle.util.encoders.DecoderException) FileNotFoundException(java.io.FileNotFoundException) MnemonicException(org.bitcoinj.crypto.MnemonicException)

Example 13 with PaymentCode

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

the class BIP47Activity method doSync.

private void doSync(final String pcode) {
    progress = new ProgressDialog(BIP47Activity.this);
    progress.setCancelable(false);
    progress.setTitle(R.string.app_name);
    progress.setMessage(getString(R.string.please_wait));
    progress.show();
    new Thread(new Runnable() {

        @Override
        public void run() {
            try {
                PaymentCode payment_code = new PaymentCode(pcode);
                int idx = 0;
                boolean loop = true;
                ArrayList<String> addrs = new ArrayList<String>();
                while (loop) {
                    addrs.clear();
                    for (int i = idx; i < (idx + 20); i++) {
                        PaymentAddress receiveAddress = BIP47Util.getInstance(BIP47Activity.this).getReceiveAddress(payment_code, i);
                        // Log.i("BIP47Activity", "sync receive from " + i + ":" + receiveAddress.getReceiveECKey().toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString());
                        BIP47Meta.getInstance().setIncomingIdx(payment_code.toString(), i, receiveAddress.getReceiveECKey().toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString());
                        BIP47Meta.getInstance().getIdx4AddrLookup().put(receiveAddress.getReceiveECKey().toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString(), i);
                        BIP47Meta.getInstance().getPCode4AddrLookup().put(receiveAddress.getReceiveECKey().toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString(), payment_code.toString());
                        addrs.add(receiveAddress.getReceiveECKey().toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString());
                    }
                    String[] s = addrs.toArray(new String[addrs.size()]);
                    int nb = APIFactory.getInstance(BIP47Activity.this).syncBIP47Incoming(s);
                    // Log.i("BIP47Activity", "sync receive idx:" + idx + ", nb == " + nb);
                    if (nb == 0) {
                        loop = false;
                    }
                    idx += 20;
                }
                idx = 0;
                loop = true;
                BIP47Meta.getInstance().setOutgoingIdx(pcode, 0);
                while (loop) {
                    addrs.clear();
                    for (int i = idx; i < (idx + 20); i++) {
                        PaymentAddress sendAddress = BIP47Util.getInstance(BIP47Activity.this).getSendAddress(payment_code, i);
                        // Log.i("BIP47Activity", "sync send to " + i + ":" + sendAddress.getSendECKey().toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString());
                        // BIP47Meta.getInstance().setOutgoingIdx(payment_code.toString(), i);
                        BIP47Meta.getInstance().getIdx4AddrLookup().put(sendAddress.getSendECKey().toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString(), i);
                        BIP47Meta.getInstance().getPCode4AddrLookup().put(sendAddress.getSendECKey().toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString(), payment_code.toString());
                        addrs.add(sendAddress.getSendECKey().toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString());
                    }
                    String[] s = addrs.toArray(new String[addrs.size()]);
                    int nb = APIFactory.getInstance(BIP47Activity.this).syncBIP47Outgoing(s);
                    // Log.i("BIP47Activity", "sync send idx:" + idx + ", nb == " + nb);
                    if (nb == 0) {
                        loop = false;
                    }
                    idx += 20;
                }
                BIP47Meta.getInstance().pruneIncoming();
                PayloadUtil.getInstance(BIP47Activity.this).saveWalletToJSON(new CharSequenceX(AccessFactory.getInstance(BIP47Activity.this).getGUID() + AccessFactory.getInstance(BIP47Activity.this).getPIN()));
                Intent intent = new Intent("com.samourai.wallet.BalanceFragment.REFRESH");
                LocalBroadcastManager.getInstance(BIP47Activity.this).sendBroadcast(intent);
            } catch (IOException ioe) {
                ;
            } catch (JSONException je) {
                ;
            } catch (DecryptionException de) {
                ;
            } catch (NotSecp256k1Exception nse) {
                ;
            } catch (InvalidKeySpecException ikse) {
                ;
            } catch (InvalidKeyException ike) {
                ;
            } catch (NoSuchAlgorithmException nsae) {
                ;
            } catch (NoSuchProviderException nspe) {
                ;
            } catch (MnemonicException.MnemonicLengthException mle) {
                ;
            }
            if (progress != null && progress.isShowing()) {
                progress.dismiss();
                progress = null;
            }
            runOnUiThread(new Runnable() {

                @Override
                public void run() {
                    new Thread(new Runnable() {

                        @Override
                        public void run() {
                            if (refreshDisplay()) {
                                handler.post(new Runnable() {

                                    @Override
                                    public void run() {
                                        refreshList();
                                        adapter.notifyDataSetChanged();
                                    }
                                });
                            }
                        }
                    }).start();
                }
            });
        }
    }).start();
}
Also used : PaymentCode(com.samourai.wallet.bip47.rpc.PaymentCode) CharSequenceX(com.samourai.wallet.util.CharSequenceX) ArrayList(java.util.ArrayList) JSONException(org.json.JSONException) Intent(android.content.Intent) PaymentAddress(com.samourai.wallet.bip47.rpc.PaymentAddress) IOException(java.io.IOException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) ProgressDialog(android.app.ProgressDialog) InvalidKeyException(java.security.InvalidKeyException) NotSecp256k1Exception(com.samourai.wallet.bip47.rpc.NotSecp256k1Exception) MyTransactionOutPoint(com.samourai.wallet.send.MyTransactionOutPoint) SecretPoint(com.samourai.wallet.bip47.rpc.SecretPoint) Point(android.graphics.Point) MnemonicException(org.bitcoinj.crypto.MnemonicException) InvalidKeySpecException(java.security.spec.InvalidKeySpecException) NoSuchProviderException(java.security.NoSuchProviderException) DecryptionException(com.samourai.wallet.crypto.DecryptionException)

Example 14 with PaymentCode

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

the class BIP47Activity method refreshDisplay.

public boolean refreshDisplay() {
    boolean changed = false;
    // 
    // check for incoming payment code notification tx
    // 
    int before = BIP47Meta.getInstance().getLabels().size();
    try {
        PaymentCode pcode = BIP47Util.getInstance(BIP47Activity.this).getPaymentCode();
        APIFactory.getInstance(BIP47Activity.this).getNotifAddress(pcode.notificationAddress().getAddressString());
    } catch (AddressFormatException afe) {
        afe.printStackTrace();
        Toast.makeText(BIP47Activity.this, "HD wallet error", Toast.LENGTH_SHORT).show();
    }
    int after = BIP47Meta.getInstance().getLabels().size();
    if (before != after) {
        changed = true;
    }
    // 
    // check on outgoing payment code notification tx
    // 
    List<org.apache.commons.lang3.tuple.Pair<String, String>> outgoingUnconfirmed = BIP47Meta.getInstance().getOutgoingUnconfirmed();
    for (org.apache.commons.lang3.tuple.Pair<String, String> pair : outgoingUnconfirmed) {
        // Log.i("BalanceFragment", "outgoing payment code:" + pair.getLeft());
        // Log.i("BalanceFragment", "outgoing payment code tx:" + pair.getRight());
        int confirmations = APIFactory.getInstance(BIP47Activity.this).getNotifTxConfirmations(pair.getRight());
        if (confirmations > 0) {
            BIP47Meta.getInstance().setOutgoingStatus(pair.getLeft(), BIP47Meta.STATUS_SENT_CFM);
            changed = true;
        }
        if (confirmations == -1) {
            BIP47Meta.getInstance().setOutgoingStatus(pair.getLeft(), BIP47Meta.STATUS_NOT_SENT);
        }
    }
    return changed;
}
Also used : AddressFormatException(org.bitcoinj.core.AddressFormatException) PaymentCode(com.samourai.wallet.bip47.rpc.PaymentCode) MyTransactionOutPoint(com.samourai.wallet.send.MyTransactionOutPoint) SecretPoint(com.samourai.wallet.bip47.rpc.SecretPoint) Point(android.graphics.Point)

Example 15 with PaymentCode

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

the class APIFactory method parseNotifTx.

public void parseNotifTx(JSONObject jsonObject, String addr, String hash) throws JSONException {
    info("APIFactory", "notif address:" + addr);
    info("APIFactory", "hash:" + hash);
    if (jsonObject != null) {
        byte[] mask = null;
        byte[] payload = null;
        PaymentCode pcode = null;
        if (jsonObject.has("inputs")) {
            JSONArray inArray = (JSONArray) jsonObject.get("inputs");
            if (inArray.length() > 0) {
                JSONObject objInput = (JSONObject) inArray.get(0);
                byte[] pubkey = null;
                String strScript = objInput.getString("sig");
                info("APIFactory", "scriptsig:" + strScript);
                if ((strScript == null || strScript.length() == 0 || strScript.startsWith("160014")) && objInput.has("witness")) {
                    JSONArray witnessArray = (JSONArray) objInput.get("witness");
                    if (witnessArray.length() == 2) {
                        pubkey = Hex.decode((String) witnessArray.get(1));
                    }
                } else {
                    Script script = new Script(Hex.decode(strScript));
                    info("APIFactory", "pubkey from script:" + Hex.toHexString(script.getPubKey()));
                    pubkey = script.getPubKey();
                }
                ECKey pKey = new ECKey(null, pubkey, true);
                info("APIFactory", "address from script:" + pKey.toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString());
                if (((JSONObject) inArray.get(0)).has("outpoint")) {
                    JSONObject received_from = ((JSONObject) inArray.get(0)).getJSONObject("outpoint");
                    String strHash = received_from.getString("txid");
                    int idx = received_from.getInt("vout");
                    byte[] hashBytes = Hex.decode(strHash);
                    Sha256Hash txHash = new Sha256Hash(hashBytes);
                    TransactionOutPoint outPoint = new TransactionOutPoint(SamouraiWallet.getInstance().getCurrentNetworkParams(), idx, txHash);
                    byte[] outpoint = outPoint.bitcoinSerialize();
                    info("APIFactory", "outpoint:" + Hex.toHexString(outpoint));
                    try {
                        mask = BIP47Util.getInstance(context).getIncomingMask(pubkey, outpoint);
                        info("APIFactory", "mask:" + Hex.toHexString(mask));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        if (jsonObject.has("outputs")) {
            JSONArray outArray = (JSONArray) jsonObject.get("outputs");
            JSONObject outObj = null;
            boolean isIncoming = false;
            String _addr = null;
            String script = null;
            String op_return = null;
            for (int j = 0; j < outArray.length(); j++) {
                outObj = (JSONObject) outArray.get(j);
                if (outObj.has("address")) {
                    _addr = outObj.getString("address");
                    if (addr.equals(_addr)) {
                        isIncoming = true;
                    }
                }
                if (outObj.has("scriptpubkey")) {
                    script = outObj.getString("scriptpubkey");
                    if (script.startsWith("6a4c50")) {
                        op_return = script;
                    }
                }
            }
            if (isIncoming && op_return != null && op_return.startsWith("6a4c50")) {
                payload = Hex.decode(op_return.substring(6));
            }
        }
        if (mask != null && payload != null) {
            try {
                byte[] xlat_payload = PaymentCode.blind(payload, mask);
                info("APIFactory", "xlat_payload:" + Hex.toHexString(xlat_payload));
                pcode = new PaymentCode(xlat_payload);
                info("APIFactory", "incoming payment code:" + pcode.toString());
                if (!pcode.toString().equals(BIP47Util.getInstance(context).getPaymentCode().toString()) && pcode.isValid() && !BIP47Meta.getInstance().incomingExists(pcode.toString())) {
                    BIP47Meta.getInstance().setLabel(pcode.toString(), "");
                    BIP47Meta.getInstance().setIncomingStatus(hash);
                }
            } catch (AddressFormatException afe) {
                afe.printStackTrace();
            }
        }
        // 
        if (pcode != null) {
            try {
                // 
                for (int i = 0; i < BIP47Meta.INCOMING_LOOKAHEAD; i++) {
                    info("APIFactory", "receive from " + i + ":" + BIP47Util.getInstance(context).getReceivePubKey(pcode, i));
                    BIP47Meta.getInstance().getIdx4AddrLookup().put(BIP47Util.getInstance(context).getReceivePubKey(pcode, i), i);
                    BIP47Meta.getInstance().getPCode4AddrLookup().put(BIP47Util.getInstance(context).getReceivePubKey(pcode, i), pcode.toString());
                }
            } catch (Exception e) {
                ;
            }
        }
    }
}
Also used : Script(org.bitcoinj.script.Script) AddressFormatException(org.bitcoinj.core.AddressFormatException) PaymentCode(com.samourai.wallet.bip47.rpc.PaymentCode) Sha256Hash(org.bitcoinj.core.Sha256Hash) JSONArray(org.json.JSONArray) ECKey(org.bitcoinj.core.ECKey) MyTransactionOutPoint(com.samourai.wallet.send.MyTransactionOutPoint) TransactionOutPoint(org.bitcoinj.core.TransactionOutPoint) 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) JSONObject(org.json.JSONObject) MyTransactionOutPoint(com.samourai.wallet.send.MyTransactionOutPoint) TransactionOutPoint(org.bitcoinj.core.TransactionOutPoint)

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