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();
});
}
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();
}
}
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();
}
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;
}
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) {
;
}
}
}
}
Aggregations