use of org.bitcoinj.core.TransactionInput in project bisq-core by bisq-network.
the class TradeWalletService method traderSignAndFinalizeDisputedPayoutTx.
/**
* A trader who got the signed tx from the arbitrator finalizes the payout tx
*
* @param depositTxSerialized Serialized deposit tx
* @param arbitratorSignature DER encoded canonical signature of arbitrator
* @param buyerPayoutAmount Payout amount of the buyer
* @param sellerPayoutAmount Payout amount of the seller
* @param buyerAddressString The address of the buyer.
* @param sellerAddressString The address of the seller.
* @param tradersMultiSigKeyPair The keypair for the MultiSig of the trader who calls that method
* @param buyerPubKey The public key of the buyer.
* @param sellerPubKey The public key of the seller.
* @param arbitratorPubKey The public key of the arbitrator.
* @return The completed payout tx
* @throws AddressFormatException
* @throws TransactionVerificationException
* @throws WalletException
*/
public Transaction traderSignAndFinalizeDisputedPayoutTx(byte[] depositTxSerialized, byte[] arbitratorSignature, Coin buyerPayoutAmount, Coin sellerPayoutAmount, String buyerAddressString, String sellerAddressString, DeterministicKey tradersMultiSigKeyPair, byte[] buyerPubKey, byte[] sellerPubKey, byte[] arbitratorPubKey) throws AddressFormatException, TransactionVerificationException, WalletException {
Transaction depositTx = new Transaction(params, depositTxSerialized);
log.trace("signAndFinalizeDisputedPayoutTx called");
log.trace("depositTx " + depositTx);
log.trace("arbitratorSignature r " + ECKey.ECDSASignature.decodeFromDER(arbitratorSignature).r.toString());
log.trace("arbitratorSignature s " + ECKey.ECDSASignature.decodeFromDER(arbitratorSignature).s.toString());
log.trace("buyerPayoutAmount " + buyerPayoutAmount.toFriendlyString());
log.trace("sellerPayoutAmount " + sellerPayoutAmount.toFriendlyString());
log.trace("buyerAddressString " + buyerAddressString);
log.trace("sellerAddressString " + sellerAddressString);
log.trace("tradersMultiSigKeyPair (not displayed for security reasons)");
log.info("buyerPubKey " + ECKey.fromPublicOnly(buyerPubKey).toString());
log.info("sellerPubKey " + ECKey.fromPublicOnly(sellerPubKey).toString());
log.info("arbitratorPubKey " + ECKey.fromPublicOnly(arbitratorPubKey).toString());
TransactionOutput p2SHMultiSigOutput = depositTx.getOutput(0);
Transaction payoutTx = new Transaction(params);
payoutTx.addInput(p2SHMultiSigOutput);
if (buyerPayoutAmount.isGreaterThan(Coin.ZERO))
payoutTx.addOutput(buyerPayoutAmount, Address.fromBase58(params, buyerAddressString));
if (sellerPayoutAmount.isGreaterThan(Coin.ZERO))
payoutTx.addOutput(sellerPayoutAmount, Address.fromBase58(params, sellerAddressString));
// take care of sorting!
Script redeemScript = getMultiSigRedeemScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
Sha256Hash sigHash = payoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
checkNotNull(tradersMultiSigKeyPair, "tradersMultiSigKeyPair must not be null");
if (tradersMultiSigKeyPair.isEncrypted())
checkNotNull(aesKey);
ECKey.ECDSASignature tradersSignature = tradersMultiSigKeyPair.sign(sigHash, aesKey).toCanonicalised();
TransactionSignature tradersTxSig = new TransactionSignature(tradersSignature, Transaction.SigHash.ALL, false);
TransactionSignature arbitratorTxSig = new TransactionSignature(ECKey.ECDSASignature.decodeFromDER(arbitratorSignature), Transaction.SigHash.ALL, false);
// Take care of order of signatures. See comment below at getMultiSigRedeemScript (sort order needed here: arbitrator, seller, buyer)
Script inputScript = ScriptBuilder.createP2SHMultiSigInputScript(ImmutableList.of(arbitratorTxSig, tradersTxSig), redeemScript);
TransactionInput input = payoutTx.getInput(0);
input.setScriptSig(inputScript);
WalletService.printTx("disputed payoutTx", payoutTx);
WalletService.verifyTransaction(payoutTx);
WalletService.checkWalletConsistency(wallet);
WalletService.checkScriptSig(payoutTx, input, 0);
checkNotNull(input.getConnectedOutput(), "input.getConnectedOutput() must not be null");
input.verify(input.getConnectedOutput());
return payoutTx;
}
use of org.bitcoinj.core.TransactionInput in project bisq-core by bisq-network.
the class TradeWalletService method sellerSignsAndFinalizesPayoutTx.
/**
* Buyer creates and signs payout transaction and adds signature of seller to complete the transaction
*
* @param depositTx Deposit transaction
* @param buyerSignature DER encoded canonical signature of seller
* @param buyerPayoutAmount Payout amount for buyer
* @param sellerPayoutAmount Payout amount for seller
* @param buyerPayoutAddressString Address for buyer
* @param sellerPayoutAddressString Address for seller
* @param multiSigKeyPair Buyer's keypair for MultiSig
* @param buyerPubKey The public key of the buyer.
* @param sellerPubKey The public key of the seller.
* @param arbitratorPubKey The public key of the arbitrator.
* @return The payout transaction
* @throws AddressFormatException
* @throws TransactionVerificationException
* @throws WalletException
*/
public Transaction sellerSignsAndFinalizesPayoutTx(Transaction depositTx, byte[] buyerSignature, Coin buyerPayoutAmount, Coin sellerPayoutAmount, String buyerPayoutAddressString, String sellerPayoutAddressString, DeterministicKey multiSigKeyPair, byte[] buyerPubKey, byte[] sellerPubKey, byte[] arbitratorPubKey) throws AddressFormatException, TransactionVerificationException, WalletException {
log.trace("buyerSignsAndFinalizesPayoutTx called");
log.trace("depositTx " + depositTx.toString());
log.trace("buyerSignature r " + ECKey.ECDSASignature.decodeFromDER(buyerSignature).r.toString());
log.trace("buyerSignature s " + ECKey.ECDSASignature.decodeFromDER(buyerSignature).s.toString());
log.trace("buyerPayoutAmount " + buyerPayoutAmount.toFriendlyString());
log.trace("sellerPayoutAmount " + sellerPayoutAmount.toFriendlyString());
log.trace("buyerPayoutAddressString " + buyerPayoutAddressString);
log.trace("sellerPayoutAddressString " + sellerPayoutAddressString);
log.trace("multiSigKeyPair (not displayed for security reasons)");
log.info("buyerPubKey " + ECKey.fromPublicOnly(buyerPubKey).toString());
log.info("sellerPubKey " + ECKey.fromPublicOnly(sellerPubKey).toString());
log.info("arbitratorPubKey " + ECKey.fromPublicOnly(arbitratorPubKey).toString());
Transaction payoutTx = createPayoutTx(depositTx, buyerPayoutAmount, sellerPayoutAmount, buyerPayoutAddressString, sellerPayoutAddressString);
// MS redeemScript
Script redeemScript = getMultiSigRedeemScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
// MS output from prev. tx is index 0
Sha256Hash sigHash = payoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
checkNotNull(multiSigKeyPair, "multiSigKeyPair must not be null");
if (multiSigKeyPair.isEncrypted())
checkNotNull(aesKey);
ECKey.ECDSASignature sellerSignature = multiSigKeyPair.sign(sigHash, aesKey).toCanonicalised();
TransactionSignature buyerTxSig = new TransactionSignature(ECKey.ECDSASignature.decodeFromDER(buyerSignature), Transaction.SigHash.ALL, false);
TransactionSignature sellerTxSig = new TransactionSignature(sellerSignature, Transaction.SigHash.ALL, false);
// Take care of order of signatures. Need to be reversed here. See comment below at getMultiSigRedeemScript (arbitrator, seller, buyer)
Script inputScript = ScriptBuilder.createP2SHMultiSigInputScript(ImmutableList.of(sellerTxSig, buyerTxSig), redeemScript);
TransactionInput input = payoutTx.getInput(0);
input.setScriptSig(inputScript);
WalletService.printTx("payoutTx", payoutTx);
WalletService.verifyTransaction(payoutTx);
WalletService.checkWalletConsistency(wallet);
WalletService.checkScriptSig(payoutTx, input, 0);
checkNotNull(input.getConnectedOutput(), "input.getConnectedOutput() must not be null");
input.verify(input.getConnectedOutput());
return payoutTx;
}
use of org.bitcoinj.core.TransactionInput in project samourai-wallet-android by Samourai-Wallet.
the class BatchSendActivity method doSpend.
private void doSpend() {
HashMap<String, BigInteger> receivers = new HashMap<String, BigInteger>();
long amount = 0L;
for (BatchSendUtil.BatchSend _data : data) {
Log.d("BatchSendActivity", "output:" + _data.amount);
Log.d("BatchSendActivity", "output:" + _data.addr);
Log.d("BatchSendActivity", "output:" + _data.pcode);
amount += _data.amount;
receivers.put(_data.addr, BigInteger.valueOf(_data.amount));
}
Log.d("BatchSendActivity", "amount:" + amount);
List<UTXO> utxos = APIFactory.getInstance(BatchSendActivity.this).getUtxos(true);
Collections.sort(utxos, new UTXO.UTXOComparator());
List<UTXO> selectedUTXO = new ArrayList<UTXO>();
int p2pkh = 0;
int p2wpkh = 0;
long totalValueSelected = 0L;
int totalSelected = 0;
for (UTXO utxo : utxos) {
Log.d("BatchSendActivity", "utxo value:" + utxo.getValue());
selectedUTXO.add(utxo);
totalValueSelected += utxo.getValue();
totalSelected += utxo.getOutpoints().size();
Pair<Integer, Integer> outpointTypes = FeeUtil.getInstance().getOutpointCount(utxo.getOutpoints());
p2pkh += outpointTypes.getLeft();
p2wpkh += outpointTypes.getRight();
if (totalValueSelected >= (amount + SamouraiWallet.bDust.longValue() + FeeUtil.getInstance().estimatedFeeSegwit(p2pkh, p2wpkh, receivers.size() + 1).longValue())) {
break;
}
}
Log.d("BatchSendActivity", "totalSelected:" + totalSelected);
Log.d("BatchSendActivity", "totalValueSelected:" + totalValueSelected);
List<MyTransactionOutPoint> outpoints = new ArrayList<MyTransactionOutPoint>();
for (UTXO utxo : selectedUTXO) {
outpoints.addAll(utxo.getOutpoints());
for (MyTransactionOutPoint out : utxo.getOutpoints()) {
Log.d("BatchSendActivity", "outpoint hash:" + out.getTxHash().toString());
Log.d("BatchSendActivity", "outpoint idx:" + out.getTxOutputN());
Log.d("BatchSendActivity", "outpoint address:" + out.getAddress());
}
}
Pair<Integer, Integer> outpointTypes = FeeUtil.getInstance().getOutpointCount(outpoints);
BigInteger fee = FeeUtil.getInstance().estimatedFeeSegwit(outpointTypes.getLeft(), outpointTypes.getRight(), receivers.size() + 1);
Log.d("BatchSendActivity", "fee:" + fee.longValue());
if (amount + fee.longValue() > balance) {
Toast.makeText(BatchSendActivity.this, R.string.insufficient_funds, Toast.LENGTH_SHORT).show();
return;
}
long changeAmount = totalValueSelected - (amount + fee.longValue());
String change_address = null;
int change_idx = -1;
if (changeAmount > 0L) {
change_idx = BIP49Util.getInstance(BatchSendActivity.this).getWallet().getAccount(0).getChange().getAddrIdx();
change_address = BIP49Util.getInstance(BatchSendActivity.this).getAddressAt(AddressFactory.CHANGE_CHAIN, change_idx).getAddressAsString();
receivers.put(change_address, BigInteger.valueOf(changeAmount));
Log.d("BatchSendActivity", "change output:" + changeAmount);
Log.d("BatchSendActivity", "change output:" + change_address);
}
Transaction tx = SendFactory.getInstance(BatchSendActivity.this).makeTransaction(0, outpoints, receivers);
if (tx != null) {
final RBFSpend rbf;
if (PrefsUtil.getInstance(BatchSendActivity.this).getValue(PrefsUtil.RBF_OPT_IN, false) == true) {
rbf = new RBFSpend();
for (TransactionInput input : tx.getInputs()) {
boolean _isBIP49 = false;
String _addr = null;
Address _address = input.getConnectedOutput().getAddressFromP2PKHScript(SamouraiWallet.getInstance().getCurrentNetworkParams());
if (_address != null) {
_addr = _address.toString();
}
if (_addr == null) {
_addr = input.getConnectedOutput().getAddressFromP2SH(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString();
_isBIP49 = true;
}
String path = APIFactory.getInstance(BatchSendActivity.this).getUnspentPaths().get(_addr);
if (path != null) {
if (_isBIP49) {
rbf.addKey(input.getOutpoint().toString(), path + "/49");
} else {
rbf.addKey(input.getOutpoint().toString(), path);
}
} else {
String pcode = BIP47Meta.getInstance().getPCode4Addr(_addr);
int idx = BIP47Meta.getInstance().getIdx4Addr(_addr);
rbf.addKey(input.getOutpoint().toString(), pcode + "/" + idx);
}
}
} else {
rbf = null;
}
String strChangeIsDust = "";
String strPrivacyWarning = "";
String strMessage = strChangeIsDust + strPrivacyWarning + "Send " + Coin.valueOf(amount).toPlainString() + " BTC. (fee:" + Coin.valueOf(fee.longValue()).toPlainString() + ")?\n";
final long _change = changeAmount;
final String _change_address = change_address;
final int _change_idx = change_idx;
tx = SendFactory.getInstance(BatchSendActivity.this).signTransaction(tx);
final String hexTx = new String(Hex.encode(tx.bitcoinSerialize()));
final String strTxHash = tx.getHashAsString();
// Log.d("BatchSendActivity", "tx hash:" + tx.getHashAsString());
// Log.d("BatchSendActivity", "hex signed tx:" + hexTx);
AlertDialog.Builder dlg = new AlertDialog.Builder(BatchSendActivity.this).setTitle(R.string.app_name).setMessage(strMessage).setCancelable(false).setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(final DialogInterface dialog, int whichButton) {
dialog.dismiss();
if (PrefsUtil.getInstance(BatchSendActivity.this).getValue(PrefsUtil.BROADCAST_TX, true) == false) {
doShowTx(hexTx, strTxHash);
return;
}
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
boolean isOK = false;
String response = null;
try {
if (PrefsUtil.getInstance(BatchSendActivity.this).getValue(PrefsUtil.USE_TRUSTED_NODE, false) == true) {
if (TrustedNodeUtil.getInstance().isSet()) {
response = PushTx.getInstance(BatchSendActivity.this).trustedNode(hexTx);
JSONObject jsonObject = new org.json.JSONObject(response);
if (jsonObject.has("result")) {
if (jsonObject.getString("result").matches("^[A-Za-z0-9]{64}$")) {
isOK = true;
} else {
Toast.makeText(BatchSendActivity.this, R.string.trusted_node_tx_error, Toast.LENGTH_SHORT).show();
}
}
} else {
Toast.makeText(BatchSendActivity.this, R.string.trusted_node_not_valid, Toast.LENGTH_SHORT).show();
}
} else {
response = PushTx.getInstance(BatchSendActivity.this).samourai(hexTx);
if (response != null) {
JSONObject jsonObject = new org.json.JSONObject(response);
if (jsonObject.has("status")) {
if (jsonObject.getString("status").equals("ok")) {
isOK = true;
}
}
} else {
Toast.makeText(BatchSendActivity.this, R.string.pushtx_returns_null, Toast.LENGTH_SHORT).show();
}
}
if (isOK) {
BatchSendUtil.getInstance().clear();
if (PrefsUtil.getInstance(BatchSendActivity.this).getValue(PrefsUtil.USE_TRUSTED_NODE, false) == false) {
Toast.makeText(BatchSendActivity.this, R.string.tx_sent, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(BatchSendActivity.this, R.string.trusted_node_tx_sent, Toast.LENGTH_SHORT).show();
}
if (_change > 0L) {
BIP49Util.getInstance(BatchSendActivity.this).getWallet().getAccount(0).getChange().incAddrIdx();
}
if (PrefsUtil.getInstance(BatchSendActivity.this).getValue(PrefsUtil.RBF_OPT_IN, false) == true) {
if (_change > 0L && _change_address != null) {
rbf.addChangeAddr(_change_address);
}
rbf.setHash(strTxHash);
rbf.setSerializedTx(hexTx);
RBFUtil.getInstance().add(rbf);
}
for (BatchSendUtil.BatchSend d : data) {
String address = d.addr;
String pcode = d.pcode;
// increment counter if BIP47 spend
if (pcode != null && pcode.length() > 0) {
BIP47Meta.getInstance().getPCode4AddrLookup().put(address, pcode);
BIP47Meta.getInstance().inc(pcode);
SimpleDateFormat sd = new SimpleDateFormat("dd MMM");
String strTS = sd.format(currentTimeMillis());
String event = strTS + " " + BatchSendActivity.this.getString(R.string.sent) + " " + MonetaryUtil.getInstance().getBTCFormat().format((double) d.amount / 1e8) + " BTC";
BIP47Meta.getInstance().setLatestEvent(strPCode, event);
}
}
/*
if(strPrivacyWarning.length() > 0 && cbShowAgain != null) {
SendAddressUtil.getInstance().add(address, cbShowAgain.isChecked() ? false : true);
}
else if(SendAddressUtil.getInstance().get(address) == 0) {
SendAddressUtil.getInstance().add(address, false);
}
else {
SendAddressUtil.getInstance().add(address, true);
}
*/
/*
Intent intent = new Intent("com.samourai.wallet.BalanceFragment.REFRESH");
intent.putExtra("notifTx", false);
intent.putExtra("fetch", true);
LocalBroadcastManager.getInstance(BatchSendActivity.this).sendBroadcast(intent);
*/
View view = BatchSendActivity.this.getCurrentFocus();
if (view != null) {
InputMethodManager imm = (InputMethodManager) BatchSendActivity.this.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
Intent _intent = new Intent(BatchSendActivity.this, BalanceActivity.class);
_intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(_intent);
} else {
Toast.makeText(BatchSendActivity.this, R.string.tx_failed, Toast.LENGTH_SHORT).show();
// reset change index upon tx fail
BIP49Util.getInstance(BatchSendActivity.this).getWallet().getAccount(0).getChange().setAddrIdx(_change_idx);
}
} catch (JSONException je) {
Toast.makeText(BatchSendActivity.this, "pushTx:" + je.getMessage(), Toast.LENGTH_SHORT).show();
} catch (DecoderException de) {
Toast.makeText(BatchSendActivity.this, "pushTx:" + de.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
/*
BatchSendActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
btSend.setActivated(true);
btSend.setClickable(true);
progress.dismiss();
dialog.dismiss();
}
});
*/
}
Looper.loop();
}
}).start();
}
}).setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
dialog.dismiss();
}
});
if (!isFinishing()) {
dlg.show();
}
} else {
// Log.d("SendActivity", "tx error");
Toast.makeText(BatchSendActivity.this, "tx error", Toast.LENGTH_SHORT).show();
}
}
use of org.bitcoinj.core.TransactionInput in project samourai-wallet-android by Samourai-Wallet.
the class BatchSendActivity method markUTXOAsUnspendable.
private void markUTXOAsUnspendable(String hexTx) {
HashMap<String, Long> utxos = new HashMap<String, Long>();
for (UTXO utxo : APIFactory.getInstance(BatchSendActivity.this).getUtxos(true)) {
for (MyTransactionOutPoint outpoint : utxo.getOutpoints()) {
utxos.put(outpoint.getTxHash().toString() + "-" + outpoint.getTxOutputN(), outpoint.getValue().longValue());
}
}
Transaction tx = new Transaction(SamouraiWallet.getInstance().getCurrentNetworkParams(), Hex.decode(hexTx));
for (TransactionInput input : tx.getInputs()) {
BlockedUTXO.getInstance().add(input.getOutpoint().getHash().toString(), (int) input.getOutpoint().getIndex(), utxos.get(input.getOutpoint().getHash().toString() + "-" + (int) input.getOutpoint().getIndex()));
}
}
use of org.bitcoinj.core.TransactionInput in project samourai-wallet-android by Samourai-Wallet.
the class RicochetMeta method getHopTx.
private Transaction getHopTx(String prevTxHash, int prevTxN, String scriptPubKey, int prevIndex, long spendAmount, String destination) {
Transaction tx = null;
HD_Address address = null;
try {
address = HD_WalletFactory.getInstance(context).get().getAccountAt(RICOCHET_ACCOUNT).getChain(0).getAddressAt(prevIndex);
ECKey ecKey = address.getECKey();
// Log.d("RicochetMeta", "getHopTx address:" + ecKey.toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString());
byte[] hashBytes = Hex.decode(prevTxHash);
Sha256Hash txHash = new Sha256Hash(hashBytes);
TransactionOutPoint outpoint = new TransactionOutPoint(SamouraiWallet.getInstance().getCurrentNetworkParams(), prevTxN, txHash);
TransactionInput input = new TransactionInput(SamouraiWallet.getInstance().getCurrentNetworkParams(), null, Hex.decode(scriptPubKey), outpoint);
Script outputScript = null;
TransactionOutput output = null;
if (destination.toLowerCase().startsWith("tb") || destination.toLowerCase().startsWith("bc")) {
byte[] bScriptPubKey = null;
try {
Pair<Byte, byte[]> pair = Bech32Segwit.decode(SamouraiWallet.getInstance().isTestNet() ? "tb" : "bc", destination);
bScriptPubKey = Bech32Segwit.getScriptPubkey(pair.getLeft(), pair.getRight());
} catch (Exception e) {
return null;
}
output = new TransactionOutput(SamouraiWallet.getInstance().getCurrentNetworkParams(), null, Coin.valueOf(spendAmount), bScriptPubKey);
} else {
outputScript = ScriptBuilder.createOutputScript(org.bitcoinj.core.Address.fromBase58(SamouraiWallet.getInstance().getCurrentNetworkParams(), destination));
output = new TransactionOutput(SamouraiWallet.getInstance().getCurrentNetworkParams(), null, Coin.valueOf(spendAmount), outputScript.getProgram());
}
tx = new Transaction(SamouraiWallet.getInstance().getCurrentNetworkParams());
tx.addInput(input);
tx.addOutput(output);
TransactionSignature sig = tx.calculateSignature(0, ecKey, Hex.decode(scriptPubKey), Transaction.SigHash.ALL, false);
tx.getInput(0).setScriptSig(ScriptBuilder.createInputScript(sig, ecKey));
} catch (IOException ioe) {
return null;
} catch (MnemonicException.MnemonicLengthException mle) {
return null;
}
return tx;
}
Aggregations