use of com.samourai.wallet.segwit.SegwitAddress in project samourai-wallet-android by Samourai-Wallet.
the class RicochetMeta method getDestinationAddress.
private String getDestinationAddress(int idx) {
HD_Address hd_addr = BIP84Util.getInstance(context).getWallet().getAccountAt(RICOCHET_ACCOUNT).getChain(AddressFactory.RECEIVE_CHAIN).getAddressAt(idx);
SegwitAddress segwitAddress = new SegwitAddress(hd_addr.getECKey().getPubKey(), SamouraiWallet.getInstance().getCurrentNetworkParams());
String address = segwitAddress.getBech32AsString();
return address;
}
use of com.samourai.wallet.segwit.SegwitAddress 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;
}
use of com.samourai.wallet.segwit.SegwitAddress in project samourai-wallet-android by Samourai-Wallet.
the class RicochetMeta method getHopTx.
private Transaction getHopTx(String prevTxHash, int prevTxN, int prevIndex, long prevSpendAmount, long spendAmount, String destination, Pair<String, Long> samouraiFeePair, long nTimeLock) {
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 {
Script outputScript = ScriptBuilder.createOutputScript(org.bitcoinj.core.Address.fromBase58(SamouraiWallet.getInstance().getCurrentNetworkParams(), destination));
output = new TransactionOutput(SamouraiWallet.getInstance().getCurrentNetworkParams(), null, Coin.valueOf(spendAmount), outputScript.getProgram());
}
HD_Address address = BIP84Util.getInstance(context).getWallet().getAccountAt(RICOCHET_ACCOUNT).getChain(AddressFactory.RECEIVE_CHAIN).getAddressAt(prevIndex);
ECKey ecKey = address.getECKey();
SegwitAddress p2wpkh = new SegwitAddress(ecKey.getPubKey(), SamouraiWallet.getInstance().getCurrentNetworkParams());
Script redeemScript = p2wpkh.segWitRedeemScript();
Transaction tx = new Transaction(SamouraiWallet.getInstance().getCurrentNetworkParams());
if (nTimeLock > 0L) {
tx.setLockTime(nTimeLock);
}
tx.addOutput(output);
if (samouraiFeePair != null) {
byte[] bScriptPubKey = null;
try {
Pair<Byte, byte[]> pair = Bech32Segwit.decode(SamouraiWallet.getInstance().isTestNet() ? "tb" : "bc", samouraiFeePair.getLeft());
bScriptPubKey = Bech32Segwit.getScriptPubkey(pair.getLeft(), pair.getRight());
} catch (Exception e) {
return null;
}
TransactionOutput _output = new TransactionOutput(SamouraiWallet.getInstance().getCurrentNetworkParams(), null, Coin.valueOf(samouraiFeePair.getRight()), bScriptPubKey);
tx.addOutput(_output);
}
// Log.d("RicochetMeta", "spending from:" + p2wpkh.getBech32AsString());
// Log.d("RicochetMeta", "pubkey:" + Hex.toHexString(ecKey.getPubKey()));
Sha256Hash txHash = Sha256Hash.wrap(prevTxHash);
TransactionOutPoint outPoint = new TransactionOutPoint(SamouraiWallet.getInstance().getCurrentNetworkParams(), prevTxN, txHash, Coin.valueOf(prevSpendAmount));
TransactionInput txInput = new TransactionInput(SamouraiWallet.getInstance().getCurrentNetworkParams(), null, new byte[] {}, outPoint, Coin.valueOf(prevSpendAmount));
if (PrefsUtil.getInstance(context).getValue(PrefsUtil.RBF_OPT_IN, false) == true) {
txInput.setSequenceNumber(SamouraiWallet.RBF_SEQUENCE_VAL.longValue());
}
tx.addInput(txInput);
TransactionSignature sig = tx.calculateWitnessSignature(0, ecKey, redeemScript.scriptCode(), Coin.valueOf(prevSpendAmount), Transaction.SigHash.ALL, false);
final TransactionWitness witness = new TransactionWitness(2);
witness.setPush(0, sig.encodeToBitcoin());
witness.setPush(1, ecKey.getPubKey());
tx.setWitness(0, witness);
assert (0 == tx.getInput(0).getScriptBytes().length);
// Log.d("RicochetMeta", "script sig length:" + tx.getInput(0).getScriptBytes().length);
tx.verify();
return tx;
}
use of com.samourai.wallet.segwit.SegwitAddress in project samourai-wallet-android by Samourai-Wallet.
the class APIFactory method lockXPUB.
/*
public synchronized JSONObject deleteXPUB(String xpub, boolean bip49) {
String _url = SamouraiWallet.getInstance().isTestNet() ? WebUtil.SAMOURAI_API2_TESTNET : WebUtil.SAMOURAI_API2;
JSONObject jsonObject = null;
try {
String response = null;
ECKey ecKey = null;
if(AddressFactory.getInstance(context).xpub2account().get(xpub) != null || xpub.equals(BIP49Util.getInstance(context).getWallet().getAccount(0).ypubstr())) {
HD_Address addr = null;
if(bip49) {
addr = BIP49Util.getInstance(context).getWallet().getAccountAt(0).getChange().getAddressAt(0);
}
else {
addr = HD_WalletFactory.getInstance(context).get().getAccount(0).getChain(AddressFactory.CHANGE_CHAIN).getAddressAt(0);
}
ecKey = addr.getECKey();
if(ecKey != null && ecKey.hasPrivKey()) {
String sig = ecKey.signMessage(xpub);
String address = null;
if(bip49) {
SegwitAddress segwitAddress = new SegwitAddress(ecKey.getPubKey(), SamouraiWallet.getInstance().getCurrentNetworkParams());
address = segwitAddress.getAddressAsString();
}
else {
address = ecKey.toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString();
}
if(!TorUtil.getInstance(context).statusFromBroadcast()) {
StringBuilder args = new StringBuilder();
args.append("message=");
args.append(xpub);
args.append("address=");
args.append(address);
args.append("&signature=");
args.append(Uri.encode(sig));
info("APIFactory", "delete XPUB:" + args.toString());
response = WebUtil.getInstance(context).deleteURL(_url + "delete/" + xpub, args.toString());
info("APIFactory", "delete XPUB response:" + response);
}
else {
HashMap<String,String> args = new HashMap<String,String>();
args.put("message", xpub);
args.put("address", address);
args.put("signature", Uri.encode(sig));
info("APIFactory", "delete XPUB:" + args.toString());
response = WebUtil.getInstance(context).tor_deleteURL(_url + "delete", args);
info("APIFactory", "delete XPUB response:" + response);
}
try {
jsonObject = new JSONObject(response);
if(jsonObject.has("status") && jsonObject.getString("status").equals("ok")) {
;
}
}
catch(JSONException je) {
je.printStackTrace();
jsonObject = null;
}
}
}
}
catch(Exception e) {
jsonObject = null;
e.printStackTrace();
}
return jsonObject;
}
*/
public synchronized JSONObject lockXPUB(String xpub, int purpose, String tag) {
String _url = WebUtil.getAPIUrl(context);
JSONObject jsonObject = null;
try {
String response = null;
ECKey ecKey = null;
if (AddressFactory.getInstance(context).xpub2account().get(xpub) != null || xpub.equals(BIP49Util.getInstance(context).getWallet().getAccount(0).ypubstr()) || xpub.equals(BIP84Util.getInstance(context).getWallet().getAccount(0).zpubstr()) || xpub.equals(BIP84Util.getInstance(context).getWallet().getAccountAt(WhirlpoolMeta.getInstance(context).getWhirlpoolPremixAccount()).zpubstr()) || xpub.equals(BIP84Util.getInstance(context).getWallet().getAccountAt(WhirlpoolMeta.getInstance(context).getWhirlpoolPostmix()).zpubstr())) {
HD_Address addr = null;
switch(purpose) {
case 49:
addr = BIP49Util.getInstance(context).getWallet().getAccountAt(0).getChange().getAddressAt(0);
break;
case 84:
if (tag != null && tag.equals(PrefsUtil.XPUBPRELOCK)) {
addr = BIP84Util.getInstance(context).getWallet().getAccountAt(WhirlpoolMeta.getInstance(context).getWhirlpoolPremixAccount()).getChange().getAddressAt(0);
} else if (tag != null && tag.equals(PrefsUtil.XPUBPOSTLOCK)) {
addr = BIP84Util.getInstance(context).getWallet().getAccountAt(WhirlpoolMeta.getInstance(context).getWhirlpoolPostmix()).getChange().getAddressAt(0);
} else {
addr = BIP84Util.getInstance(context).getWallet().getAccountAt(0).getChange().getAddressAt(0);
}
break;
default:
addr = HD_WalletFactory.getInstance(context).get().getAccount(0).getChain(AddressFactory.CHANGE_CHAIN).getAddressAt(0);
break;
}
ecKey = addr.getECKey();
if (ecKey != null && ecKey.hasPrivKey()) {
String sig = ecKey.signMessage("lock");
String address = null;
switch(purpose) {
case 49:
SegwitAddress p2shp2wpkh = new SegwitAddress(ecKey.getPubKey(), SamouraiWallet.getInstance().getCurrentNetworkParams());
address = p2shp2wpkh.getAddressAsString();
break;
case 84:
SegwitAddress segwitAddress = new SegwitAddress(ecKey.getPubKey(), SamouraiWallet.getInstance().getCurrentNetworkParams());
address = segwitAddress.getBech32AsString();
break;
default:
address = ecKey.toAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString();
break;
}
if (!TorManager.getInstance(context).isRequired()) {
StringBuilder args = new StringBuilder();
args.append("address=");
args.append(address);
args.append("&signature=");
args.append(Uri.encode(sig));
args.append("&message=");
args.append("lock");
// info("APIFactory", "lock XPUB:" + args.toString());
args.append("&at=");
args.append(getAccessToken());
response = WebUtil.getInstance(context).postURL(_url + "xpub/" + xpub + "/lock/", args.toString());
// info("APIFactory", "lock XPUB response:" + response);
} else {
HashMap<String, String> args = new HashMap<String, String>();
args.put("address", address);
// args.put("signature", Uri.encode(sig));
args.put("signature", sig);
args.put("message", "lock");
args.put("at", getAccessToken());
info("APIFactory", "lock XPUB:" + _url);
info("APIFactory", "lock XPUB:" + args.toString());
response = WebUtil.getInstance(context).tor_postURL(_url + "xpub/" + xpub + "/lock/", args);
info("APIFactory", "lock XPUB response:" + response);
}
try {
jsonObject = new JSONObject(response);
if (jsonObject.has("status") && jsonObject.getString("status").equals("ok")) {
if (tag != null) {
PrefsUtil.getInstance(context).setValue(tag, true);
} else {
switch(purpose) {
case 49:
PrefsUtil.getInstance(context).setValue(PrefsUtil.XPUB49LOCK, true);
break;
case 84:
PrefsUtil.getInstance(context).setValue(PrefsUtil.XPUB84LOCK, true);
break;
default:
PrefsUtil.getInstance(context).setValue(PrefsUtil.XPUB44LOCK, true);
break;
}
}
}
} catch (JSONException je) {
je.printStackTrace();
jsonObject = null;
}
}
}
} catch (Exception e) {
jsonObject = null;
e.printStackTrace();
}
return jsonObject;
}
use of com.samourai.wallet.segwit.SegwitAddress in project samourai-wallet-android by Samourai-Wallet.
the class Cahoots method signTx.
protected void signTx(HashMap<String, ECKey> keyBag) {
Transaction transaction = psbt.getTransaction();
debug("Cahoots", "signTx:" + transaction.toString());
for (int i = 0; i < transaction.getInputs().size(); i++) {
TransactionInput input = transaction.getInput(i);
TransactionOutPoint outpoint = input.getOutpoint();
if (keyBag.containsKey(outpoint.toString())) {
debug("Cahoots", "signTx outpoint:" + outpoint.toString());
ECKey key = keyBag.get(outpoint.toString());
SegwitAddress segwitAddress = new SegwitAddress(key.getPubKey(), params);
debug("Cahoots", "signTx bech32:" + segwitAddress.getBech32AsString());
final Script redeemScript = segwitAddress.segWitRedeemScript();
final Script scriptCode = redeemScript.scriptCode();
long value = outpoints.get(outpoint.getHash().toString() + "-" + outpoint.getIndex());
debug("Cahoots", "signTx value:" + value);
TransactionSignature sig = transaction.calculateWitnessSignature(i, key, scriptCode, Coin.valueOf(value), Transaction.SigHash.ALL, false);
final TransactionWitness witness = new TransactionWitness(2);
witness.setPush(0, sig.encodeToBitcoin());
witness.setPush(1, key.getPubKey());
transaction.setWitness(i, witness);
}
}
psbt.setTransaction(transaction);
}
Aggregations