Search in sources :

Example 6 with PaymentAddress

use of com.samourai.wallet.bip47.rpc.PaymentAddress 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 7 with PaymentAddress

use of com.samourai.wallet.bip47.rpc.PaymentAddress 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 8 with PaymentAddress

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

the class RBFTask method signTx.

private Transaction signTx(Transaction tx) {
    HashMap<String, ECKey> keyBag = new HashMap<String, ECKey>();
    HashMap<String, ECKey> keyBag49 = new HashMap<String, ECKey>();
    HashMap<String, ECKey> keyBag84 = new HashMap<String, ECKey>();
    HashMap<String, String> keys = rbf.getKeyBag();
    for (String outpoint : keys.keySet()) {
        ECKey ecKey = null;
        String[] s = keys.get(outpoint).split("/");
        Log.i("RBF", "path length:" + s.length);
        if (s.length == 4) {
            if (s[3].equals("84")) {
                HD_Address addr = BIP84Util.getInstance(activity).getWallet().getAccount(0).getChain(Integer.parseInt(s[1])).getAddressAt(Integer.parseInt(s[2]));
                ecKey = addr.getECKey();
            } else {
                HD_Address addr = BIP49Util.getInstance(activity).getWallet().getAccount(0).getChain(Integer.parseInt(s[1])).getAddressAt(Integer.parseInt(s[2]));
                ecKey = addr.getECKey();
            }
        } else if (s.length == 3) {
            HD_Address hd_address = AddressFactory.getInstance(activity).get(0, 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 if (s.length == 2) {
            try {
                PaymentAddress address = BIP47Util.getInstance(activity).getReceiveAddress(new PaymentCode(s[0]), Integer.parseInt(s[1]));
                ecKey = address.getReceiveECKey();
            } catch (Exception e) {
                ;
            }
        } else {
            ;
        }
        Log.i("RBF", "outpoint:" + outpoint);
        Log.i("RBF", "path:" + keys.get(outpoint));
        if (ecKey != null) {
            if (s.length == 4) {
                if (s[3].equals("84")) {
                    keyBag84.put(outpoint, ecKey);
                } else {
                    keyBag49.put(outpoint, ecKey);
                }
            } else {
                keyBag.put(outpoint, ecKey);
            }
        } else {
            throw new RuntimeException("ECKey error: cannot process private key");
        // Log.i("ECKey error", "cannot process private key");
        }
    }
    List<TransactionInput> inputs = tx.getInputs();
    for (int i = 0; i < inputs.size(); i++) {
        ECKey ecKey = null;
        String address = null;
        if (inputs.get(i).getValue() != null || keyBag49.containsKey(inputs.get(i).getOutpoint().toString()) || keyBag84.containsKey(inputs.get(i).getOutpoint().toString())) {
            if (keyBag84.containsKey(inputs.get(i).getOutpoint().toString())) {
                ecKey = keyBag84.get(inputs.get(i).getOutpoint().toString());
                SegwitAddress segwitAddress = new SegwitAddress(ecKey.getPubKey(), SamouraiWallet.getInstance().getCurrentNetworkParams());
                address = segwitAddress.getBech32AsString();
            } else {
                ecKey = keyBag49.get(inputs.get(i).getOutpoint().toString());
                SegwitAddress segwitAddress = new SegwitAddress(ecKey.getPubKey(), SamouraiWallet.getInstance().getCurrentNetworkParams());
                address = segwitAddress.getAddressAsString();
            }
        } else {
            ecKey = keyBag.get(inputs.get(i).getOutpoint().toString());
            address = ecKey.toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString();
        }
        Log.d("RBF", "pubKey:" + Hex.toHexString(ecKey.getPubKey()));
        Log.d("RBF", "address:" + address);
        if (inputs.get(i).getValue() != null || keyBag49.containsKey(inputs.get(i).getOutpoint().toString()) || keyBag84.containsKey(inputs.get(i).getOutpoint().toString())) {
            final SegwitAddress segwitAddress = new SegwitAddress(ecKey.getPubKey(), SamouraiWallet.getInstance().getCurrentNetworkParams());
            Script scriptPubKey = segwitAddress.segWitOutputScript();
            final Script redeemScript = segwitAddress.segWitRedeemScript();
            System.out.println("redeem script:" + Hex.toHexString(redeemScript.getProgram()));
            final Script scriptCode = redeemScript.scriptCode();
            System.out.println("script code:" + Hex.toHexString(scriptCode.getProgram()));
            TransactionSignature sig = tx.calculateWitnessSignature(i, ecKey, scriptCode, Coin.valueOf(input_values.get(inputs.get(i).getOutpoint().toString())), Transaction.SigHash.ALL, false);
            final TransactionWitness witness = new TransactionWitness(2);
            witness.setPush(0, sig.encodeToBitcoin());
            witness.setPush(1, ecKey.getPubKey());
            tx.setWitness(i, witness);
            if (!FormatsUtil.getInstance().isValidBech32(address) && Address.fromBase58(SamouraiWallet.getInstance().getCurrentNetworkParams(), address).isP2SHAddress()) {
                final ScriptBuilder sigScript = new ScriptBuilder();
                sigScript.data(redeemScript.getProgram());
                tx.getInput(i).setScriptSig(sigScript.build());
                tx.getInput(i).getScriptSig().correctlySpends(tx, i, scriptPubKey, Coin.valueOf(input_values.get(inputs.get(i).getOutpoint().toString())), Script.ALL_VERIFY_FLAGS);
            }
        } else {
            Log.i("RBF", "sign outpoint:" + inputs.get(i).getOutpoint().toString());
            Log.i("RBF", "ECKey address from keyBag:" + ecKey.toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString());
            Log.i("RBF", "script:" + ScriptBuilder.createOutputScript(ecKey.toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams())));
            Log.i("RBF", "script:" + Hex.toHexString(ScriptBuilder.createOutputScript(ecKey.toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams())).getProgram()));
            TransactionSignature sig = tx.calculateSignature(i, ecKey, ScriptBuilder.createOutputScript(ecKey.toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams())).getProgram(), Transaction.SigHash.ALL, false);
            tx.getInput(i).setScriptSig(ScriptBuilder.createInputScript(sig, ecKey));
        }
    }
    return tx;
}
Also used : Script(org.bitcoinj.script.Script) PaymentCode(com.samourai.wallet.bip47.rpc.PaymentCode) TransactionWitness(org.bitcoinj.core.TransactionWitness) HD_Address(com.samourai.wallet.hd.HD_Address) HashMap(java.util.HashMap) SegwitAddress(com.samourai.wallet.segwit.SegwitAddress) ECKey(org.bitcoinj.core.ECKey) TransactionSignature(org.bitcoinj.crypto.TransactionSignature) ScriptBuilder(org.bitcoinj.script.ScriptBuilder) PaymentAddress(com.samourai.wallet.bip47.rpc.PaymentAddress) JSONException(org.json.JSONException) DecoderException(org.bouncycastle.util.encoders.DecoderException) MnemonicException(org.bitcoinj.crypto.MnemonicException) IOException(java.io.IOException) MyTransactionInput(com.samourai.wallet.send.MyTransactionInput) TransactionInput(org.bitcoinj.core.TransactionInput) MyTransactionOutPoint(com.samourai.wallet.send.MyTransactionOutPoint) DumpedPrivateKey(org.bitcoinj.core.DumpedPrivateKey)

Example 9 with PaymentAddress

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

the class SendFactory method getPrivKey.

public static ECKey getPrivKey(String address, int account) {
    // debug("SendFactory", "get privkey for:" + address);
    ECKey ecKey = null;
    try {
        String path = APIFactory.getInstance(context).getUnspentPaths().get(address);
        debug("SendFactory", "address path:" + path);
        if (path != null) {
            String[] s = path.split("/");
            if (FormatsUtil.getInstance().isValidBech32(address)) {
                debug("SendFactory", "address type:" + "bip84");
                HD_Address addr = null;
                if (account == 0) {
                    addr = BIP84Util.getInstance(context).getWallet().getAccount(account).getChain(Integer.parseInt(s[1])).getAddressAt(Integer.parseInt(s[2]));
                } else {
                    addr = BIP84Util.getInstance(context).getWallet().getAccountAt(account).getChain(Integer.parseInt(s[1])).getAddressAt(Integer.parseInt(s[2]));
                }
                ecKey = addr.getECKey();
            } else if (Address.fromBase58(SamouraiWallet.getInstance().getCurrentNetworkParams(), address).isP2SHAddress()) {
                debug("SendFactory", "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 {
                debug("SendFactory", "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 {
            debug("SendFactory", "address type:" + "bip47");
            debug("SendFactory", "address:" + address);
            String pcode = BIP47Meta.getInstance().getPCode4Addr(address);
            debug("SendFactory", "pcode:" + pcode);
            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) ScriptException(org.bitcoinj.script.ScriptException) AddressFormatException(org.bitcoinj.core.AddressFormatException) MnemonicException(org.bitcoinj.crypto.MnemonicException) IOException(java.io.IOException)

Example 10 with PaymentAddress

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

the class RicochetMeta method script.

public JSONObject script(long spendAmount, long feePerKBAmount, String strDestination, int nbHops, String strPCode, boolean samouraiFeeViaBIP47, boolean useTimeLock) {
    JSONObject jObj = new JSONObject();
    try {
        BigInteger biSpend = BigInteger.valueOf(spendAmount);
        // default 4 hops min. for base fee, each additional hop 0.001
        BigInteger biSamouraiFee = BigInteger.valueOf(samouraiFeeAmountV2.longValue() * ((nbHops - defaultNbHops) + 1));
        BigInteger biFeePerKB = BigInteger.valueOf(feePerKBAmount);
        long latestBlock = APIFactory.getInstance(context).getLatestBlockHeight();
        long nTimeLock = 0L;
        if (useTimeLock && latestBlock > 0L) {
            nTimeLock = latestBlock;
        }
        jObj.put("ts", System.currentTimeMillis() / 1000L);
        jObj.put("hops", nbHops);
        jObj.put("spend_amount", biSpend.longValue());
        jObj.put("samourai_fee", biSamouraiFee.longValue());
        jObj.put("samourai_fee_via_bip47", samouraiFeeViaBIP47);
        jObj.put("feeKB", biFeePerKB.longValue());
        jObj.put("destination", strDestination);
        if (strPCode != null) {
            jObj.put("pcode", strPCode);
        }
        if (useTimeLock) {
            jObj.put("nTimeLock", nTimeLock);
        }
        JSONObject jHop = new JSONObject();
        JSONArray jHops = new JSONArray();
        int hopSz = 0;
        if (samouraiFeeViaBIP47) {
            hopSz = FeeUtil.getInstance().estimatedSize(1, 2);
        } else {
            hopSz = FeeUtil.getInstance().estimatedSize(1, 1);
        }
        BigInteger biFeePerHop = FeeUtil.getInstance().calculateFee(hopSz, biFeePerKB);
        Pair<List<UTXO>, BigInteger> pair = getHop0UTXO(spendAmount, nbHops, biFeePerHop.longValue(), samouraiFeeViaBIP47);
        List<UTXO> utxos = pair.getLeft();
        long totalValueSelected = 0L;
        for (UTXO u : utxos) {
            totalValueSelected += u.getValue();
        }
        // Log.d("RicochetMeta", "totalValueSelected (return):" + totalValueSelected);
        // hop0 'leaves' wallet, change returned to wallet
        BigInteger hop0 = biSpend.add(biSamouraiFee).add(biFeePerHop.multiply(BigInteger.valueOf((long) nbHops)));
        // BigInteger hop0Fee = FeeUtil.getInstance().calculateFee(hop0sz, biFeePerKB);
        BigInteger hop0Fee = pair.getRight();
        // Log.d("RicochetMeta", "hop0Fee (return):" + hop0Fee.longValue());
        Transaction txHop0 = getHop0Tx(utxos, hop0.longValue(), getDestinationAddress(index), hop0Fee.longValue(), samouraiFeeViaBIP47, nTimeLock);
        if (txHop0 == null) {
            return null;
        }
        // Log.d("RicochetMeta", "searching for:" + getDestinationAddress(index));
        int prevTxN = 0;
        for (int i = 0; i < txHop0.getOutputs().size(); i++) {
            Script script = txHop0.getOutputs().get(i).getScriptPubKey();
            // Log.d("RicochetMeta", "script:" + Hex.toHexString(script.getProgram()));
            String address = null;
            if (Hex.toHexString(script.getProgram()).startsWith("0014")) {
                String hrp = null;
                if (SamouraiWallet.getInstance().getCurrentNetworkParams() instanceof TestNet3Params) {
                    hrp = "tb";
                } else {
                    hrp = "bc";
                }
                try {
                    String _script = Hex.toHexString(script.getProgram());
                    address = Bech32Segwit.encode(hrp, (byte) 0x00, Hex.decode(_script.substring(4).getBytes()));
                } catch (Exception e) {
                    ;
                }
            // Log.d("RicochetMeta", "bech32:" + address);
            } else {
                address = new Script(script.getProgram()).getToAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString();
            // Log.d("RicochetMeta", "address from script:" + address);
            }
            if (address.equals(getDestinationAddress(index))) {
                prevTxN = i;
                // Log.d("RicochetMeta", "tx output n:" + prevTxN);
                break;
            }
        }
        jHop.put("seq", 0);
        jHop.put("spend_amount", hop0.longValue());
        jHop.put("fee", hop0Fee.longValue());
        jHop.put("fee_per_hop", biFeePerHop.longValue());
        jHop.put("index", index);
        jHop.put("destination", getDestinationAddress(index));
        // Log.d("RicochetMeta", "destination:" + getDestinationAddress(index));
        int prevIndex = index;
        index++;
        jHop.put("tx", new String(Hex.encode(txHop0.bitcoinSerialize())));
        jHop.put("hash", txHop0.getHash().toString());
        if (useTimeLock) {
            jHop.put("nTimeLock", nTimeLock);
        }
        jHops.put(jHop);
        List<Pair<String, Long>> samouraiFees = new ArrayList<Pair<String, Long>>();
        if (samouraiFeeViaBIP47) {
            long baseVal = samouraiFeeAmountV2.longValue() / 4L;
            long totalVal = 0L;
            SecureRandom random = new SecureRandom();
            int _outgoingIdx = BIP47Meta.getInstance().getOutgoingIdx(BIP47Meta.strSamouraiDonationPCode);
            for (int i = 0; i < 4; i++) {
                int val = random.nextInt(25000);
                int sign = random.nextInt(1);
                if (sign == 0) {
                    val *= -1L;
                }
                long feeVal = 0L;
                if (i == 3) {
                    feeVal = samouraiFeeAmountV2.longValue() - totalVal;
                } else {
                    feeVal = baseVal + val;
                    totalVal += feeVal;
                }
                // 
                try {
                    PaymentCode pcode = new PaymentCode(BIP47Meta.strSamouraiDonationPCode);
                    PaymentAddress paymentAddress = BIP47Util.getInstance(context).getSendAddress(pcode, _outgoingIdx + i);
                    // String strAddress = paymentAddress.getSendECKey().toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString();
                    // 
                    // derive as bech32
                    // 
                    SegwitAddress segwitAddress = new SegwitAddress(paymentAddress.getSendECKey().getPubKey(), SamouraiWallet.getInstance().getCurrentNetworkParams());
                    String strAddress = segwitAddress.getBech32AsString();
                    samouraiFees.add(Pair.of(strAddress, feeVal));
                // samouraiFees.add(Pair.of(strAddress, 200000L / 4L));
                } catch (Exception e) {
                    samouraiFees.add(Pair.of(SendNotifTxFactory.SAMOURAI_NOTIF_TX_FEE_ADDRESS, feeVal));
                }
            }
        }
        Transaction txHop = null;
        String prevTxHash = txHop0.getHash().toString();
        String prevScriptPubKey = Hex.toHexString(txHop0.getOutput(prevTxN).getScriptPubKey().getProgram());
        BigInteger remainingSamouraiFee = BigInteger.ZERO;
        long prevSpendValue = hop0.longValue();
        if (!samouraiFeeViaBIP47) {
            prevSpendValue -= biSamouraiFee.longValue();
        } else {
            remainingSamouraiFee = samouraiFeeAmountV2;
        }
        int _hop = 0;
        for (int i = (nbHops - 1); i >= 0; i--) {
            _hop++;
            BigInteger hopx = null;
            if (samouraiFeeViaBIP47) {
                remainingSamouraiFee = remainingSamouraiFee.subtract(BigInteger.valueOf(samouraiFees.get(_hop - 1).getRight()));
                hopx = biSpend.add(biFeePerHop.multiply(BigInteger.valueOf((long) i))).add(remainingSamouraiFee);
            } else {
                hopx = biSpend.add(biFeePerHop.multiply(BigInteger.valueOf((long) i)));
            }
            if (useTimeLock && latestBlock > 0L) {
                nTimeLock = latestBlock + _hop;
            }
            // Log.d("RicochetMeta", "doing hop:" + _hop);
            if (samouraiFeeViaBIP47 && ((_hop - 1) < 4)) {
                txHop = getHopTx(prevTxHash, prevTxN, prevIndex, prevSpendValue, hopx.longValue(), _hop < nbHops ? getDestinationAddress(index) : strDestination, samouraiFees.get(_hop - 1), nTimeLock);
            } else {
                txHop = getHopTx(prevTxHash, prevTxN, prevIndex, prevSpendValue, hopx.longValue(), _hop < nbHops ? getDestinationAddress(index) : strDestination, null, nTimeLock);
            }
            if (txHop == null) {
                return null;
            }
            jHop = new JSONObject();
            jHop.put("seq", (nbHops - i));
            jHop.put("spend_amount", hopx.longValue());
            jHop.put("fee", biFeePerHop.longValue());
            jHop.put("prev_tx_hash", prevTxHash);
            jHop.put("prev_tx_n", prevTxN);
            jHop.put("prev_spend_value", prevSpendValue);
            jHop.put("script", prevScriptPubKey);
            jHop.put("tx", new String(Hex.encode(txHop.bitcoinSerialize())));
            jHop.put("hash", txHop.getHash().toString());
            if (useTimeLock) {
                jHop.put("nTimeLock", nTimeLock);
            }
            if (_hop < nbHops) {
                jHop.put("index", index);
                jHop.put("destination", getDestinationAddress(index));
                // Log.d("RicochetMeta", "destination:" + getDestinationAddress(index));
                prevIndex = index;
                index++;
            } else {
                jHop.put("destination", strDestination);
            // Log.d("RicochetMeta", "destination:" + strDestination);
            }
            if (samouraiFeeViaBIP47) {
                jObj.put("samourai_fee_address", samouraiFees.get(_hop - 1).getLeft());
                jObj.put("samourai_fee_amount", samouraiFees.get(_hop - 1).getRight());
            }
            jHops.put(jHop);
            prevTxHash = txHop.getHash().toString();
            prevTxN = 0;
            prevSpendValue = hopx.longValue();
            prevScriptPubKey = Hex.toHexString(txHop.getOutputs().get(0).getScriptPubKey().getProgram());
        }
        jObj.put("hops", jHops);
        BigInteger totalAmount = hop0.add(hop0Fee);
        jObj.put("total_spend", totalAmount.longValue());
    } catch (JSONException je) {
        return null;
    }
    System.out.println("RicochetMeta:" + jObj.toString());
    return jObj;
}
Also used : Script(org.bitcoinj.script.Script) PaymentCode(com.samourai.wallet.bip47.rpc.PaymentCode) SegwitAddress(com.samourai.wallet.segwit.SegwitAddress) JSONArray(org.json.JSONArray) ArrayList(java.util.ArrayList) SecureRandom(java.security.SecureRandom) JSONException(org.json.JSONException) PaymentAddress(com.samourai.wallet.bip47.rpc.PaymentAddress) MyTransactionOutPoint(com.samourai.wallet.send.MyTransactionOutPoint) TransactionOutPoint(org.bitcoinj.core.TransactionOutPoint) JSONException(org.json.JSONException) ScriptException(org.bitcoinj.script.ScriptException) MnemonicException(org.bitcoinj.crypto.MnemonicException) IOException(java.io.IOException) UTXO(com.samourai.wallet.send.UTXO) TestNet3Params(org.bitcoinj.params.TestNet3Params) JSONObject(org.json.JSONObject) Transaction(org.bitcoinj.core.Transaction) BigInteger(java.math.BigInteger) List(java.util.List) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) Pair(org.apache.commons.lang3.tuple.Pair)

Aggregations

PaymentAddress (com.samourai.wallet.bip47.rpc.PaymentAddress)12 PaymentCode (com.samourai.wallet.bip47.rpc.PaymentCode)11 IOException (java.io.IOException)9 MnemonicException (org.bitcoinj.crypto.MnemonicException)9 JSONException (org.json.JSONException)6 SegwitAddress (com.samourai.wallet.segwit.SegwitAddress)5 ArrayList (java.util.ArrayList)5 ECKey (org.bitcoinj.core.ECKey)5 Intent (android.content.Intent)4 DumpedPrivateKey (org.bitcoinj.core.DumpedPrivateKey)4 WriterException (com.google.zxing.WriterException)3 HD_Address (com.samourai.wallet.hd.HD_Address)3 MyTransactionOutPoint (com.samourai.wallet.send.MyTransactionOutPoint)3 CharSequenceX (com.samourai.wallet.util.CharSequenceX)3 UnsupportedEncodingException (java.io.UnsupportedEncodingException)3 ParseException (java.text.ParseException)3 HashMap (java.util.HashMap)3 AddressFormatException (org.bitcoinj.core.AddressFormatException)3 ScriptException (org.bitcoinj.script.ScriptException)3 NotSecp256k1Exception (com.samourai.wallet.bip47.rpc.NotSecp256k1Exception)2