Search in sources :

Example 1 with Address

use of com.sparrowwallet.drongo.address.Address in project drongo by sparrowwallet.

the class TransactionTask method checkWallet.

private void checkWallet(Transaction transaction) {
    for (WatchWallet wallet : drongo.getWallets()) {
        List<Address> fromAddresses = new ArrayList<>();
        for (TransactionInput input : transaction.getInputs()) {
            for (Address address : input.getOutpoint().getAddresses()) {
                if (wallet.containsAddress(address)) {
                    fromAddresses.add(address);
                }
            }
        }
        Map<Address, Long> toAddresses = new HashMap<>();
        for (TransactionOutput output : transaction.getOutputs()) {
            for (Address address : output.getAddresses()) {
                if (wallet.containsAddress(address)) {
                    toAddresses.put(address, output.getValue());
                }
            }
        }
        if (!fromAddresses.isEmpty()) {
            StringBuilder builder = new StringBuilder();
            builder.append("Wallet ").append(wallet.getName()).append(" sent from address").append(fromAddresses.size() == 1 ? " " : "es ");
            StringJoiner fromJoiner = new StringJoiner(", ", "[", "]");
            for (Address address : fromAddresses) {
                fromJoiner.add(address.toString() + " [" + Utils.formatHDPath(wallet.getAddressPath(address)) + "]");
            }
            builder.append(fromJoiner.toString()).append(" in txid ").append(transaction.getTxId());
            log.info(builder.toString());
        }
        if (!toAddresses.isEmpty()) {
            StringBuilder builder = new StringBuilder();
            builder.append("Wallet ").append(wallet.getName()).append(" received to address").append(toAddresses.size() == 1 ? " " : "es ");
            StringJoiner toJoiner = new StringJoiner(", ", "[", "]");
            for (Address address : toAddresses.keySet()) {
                toJoiner.add(address.toString() + " [" + Utils.formatHDPath(wallet.getAddressPath(address)) + "]" + " (" + toAddresses.get(address) + " sats)");
            }
            builder.append(toJoiner.toString()).append(" in txid ").append(transaction.getTxId());
            log.info(builder.toString());
        }
    }
}
Also used : Address(com.sparrowwallet.drongo.address.Address)

Example 2 with Address

use of com.sparrowwallet.drongo.address.Address in project drongo by sparrowwallet.

the class PaymentCodeTest method testNotificationAddress.

@Test
public void testNotificationAddress() throws InvalidPaymentCodeException, InvalidKeySpecException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, MnemonicException {
    PaymentCode alicePaymentCode = new PaymentCode("PM8TJTLJbPRGxSbc8EJi42Wrr6QbNSaSSVJ5Y3E4pbCYiTHUskHg13935Ubb7q8tx9GVbh2UuRnBc3WSyJHhUrw8KhprKnn9eDznYGieTzFcwQRya4GA");
    Address aliceNotificationAddress = alicePaymentCode.getNotificationAddress();
    Assert.assertEquals("1JDdmqFLhpzcUwPeinhJbUPw4Co3aWLyzW", aliceNotificationAddress.toString());
    ECKey alicePrivKey = DumpedPrivateKey.fromBase58("Kx983SRhAZpAhj7Aac1wUXMJ6XZeyJKqCxJJ49dxEbYCT4a1ozRD").getKey();
    byte[] alicePayload = alicePaymentCode.getPayload();
    Assert.assertEquals("010002b85034fb08a8bfefd22848238257b252721454bbbfba2c3667f168837ea2cdad671af9f65904632e2dcc0c6ad314e11d53fc82fa4c4ea27a4a14eccecc478fee00000000000000000000000000", Utils.bytesToHex(alicePayload));
    PaymentCode paymentCodeBob = new PaymentCode("PM8TJS2JxQ5ztXUpBBRnpTbcUXbUHy2T1abfrb3KkAAtMEGNbey4oumH7Hc578WgQJhPjBxteQ5GHHToTYHE3A1w6p7tU6KSoFmWBVbFGjKPisZDbP97");
    ECKey bobNotificationPubKey = paymentCodeBob.getNotificationKey();
    Assert.assertEquals("024ce8e3b04ea205ff49f529950616c3db615b1e37753858cc60c1ce64d17e2ad8", Utils.bytesToHex(bobNotificationPubKey.getPubKey()));
    TransactionOutPoint transactionOutPoint = new TransactionOutPoint(Sha256Hash.wrapReversed(Utils.hexToBytes("86f411ab1c8e70ae8a0795ab7a6757aea6e4d5ae1826fc7b8f00c597d500609c")), 1);
    Assert.assertEquals("86f411ab1c8e70ae8a0795ab7a6757aea6e4d5ae1826fc7b8f00c597d500609c01000000", Utils.bytesToHex(transactionOutPoint.bitcoinSerialize()));
    SecretPoint secretPoint = new SecretPoint(alicePrivKey.getPrivKeyBytes(), bobNotificationPubKey.getPubKey());
    Assert.assertEquals("736a25d9250238ad64ed5da03450c6a3f4f8f4dcdf0b58d1ed69029d76ead48d", Utils.bytesToHex(secretPoint.ECDHSecretAsBytes()));
    byte[] blindingMask = PaymentCode.getMask(secretPoint.ECDHSecretAsBytes(), transactionOutPoint.bitcoinSerialize());
    Assert.assertEquals("be6e7a4256cac6f4d4ed4639b8c39c4cb8bece40010908e70d17ea9d77b4dc57f1da36f2d6641ccb37cf2b9f3146686462e0fa3161ae74f88c0afd4e307adbd5", Utils.bytesToHex(blindingMask));
    byte[] blindedPaymentCode = PaymentCode.blind(alicePayload, blindingMask);
    Assert.assertEquals("010002063e4eb95e62791b06c50e1a3a942e1ecaaa9afbbeb324d16ae6821e091611fa96c0cf048f607fe51a0327f5e2528979311c78cb2de0d682c61e1180fc3d543b00000000000000000000000000", Utils.bytesToHex(blindedPaymentCode));
    Transaction transaction = new Transaction();
    List<ScriptChunk> inputChunks = List.of(ScriptChunk.fromData(Utils.hexToBytes("3045022100ac8c6dbc482c79e86c18928a8b364923c774bfdbd852059f6b3778f2319b59a7022029d7cc5724e2f41ab1fcfc0ba5a0d4f57ca76f72f19530ba97c860c70a6bf0a801")), ScriptChunk.fromData(alicePrivKey.getPubKey()));
    transaction.addInput(transactionOutPoint.getHash(), transactionOutPoint.getIndex(), new Script(inputChunks));
    transaction.addOutput(10000, paymentCodeBob.getNotificationAddress());
    List<ScriptChunk> opReturnChunks = List.of(ScriptChunk.fromOpcode(ScriptOpCodes.OP_RETURN), ScriptChunk.fromData(blindedPaymentCode));
    transaction.addOutput(10000, new Script(opReturnChunks));
    Assert.assertEquals("010000000186f411ab1c8e70ae8a0795ab7a6757aea6e4d5ae1826fc7b8f00c597d500609c010000006b483045022100ac8c6dbc482c79e86c18928a8b364923c774bfdb" + "d852059f6b3778f2319b59a7022029d7cc5724e2f41ab1fcfc0ba5a0d4f57ca76f72f19530ba97c860c70a6bf0a801210272d83d8a1fa323feab1c085157a0791b46eba34afb8bfbfaeb3a3fcc3f2" + "c9ad8ffffffff0210270000000000001976a9148066a8e7ee82e5c5b9b7dc1765038340dc5420a988ac1027000000000000536a4c50010002063e4eb95e62791b06c50e1a3a942e1ecaaa9afbbeb3" + "24d16ae6821e091611fa96c0cf048f607fe51a0327f5e2528979311c78cb2de0d682c61e1180fc3d543b0000000000000000000000000000000000", Utils.bytesToHex(transaction.bitcoinSerialize()));
    Assert.assertEquals("9414f1681fb1255bd168a806254321a837008dd4480c02226063183deb100204", transaction.getTxId().toString());
    ECKey alicePubKey = ECKey.fromPublicOnly(transaction.getInputs().get(0).getScriptSig().getChunks().get(1).data);
    Assert.assertArrayEquals(alicePubKey.getPubKey(), alicePrivKey.getPubKey());
    DeterministicSeed bobSeed = new DeterministicSeed("reward upper indicate eight swift arch injury crystal super wrestle already dentist", "", 0, DeterministicSeed.Type.BIP39);
    Keystore bobKeystore = Keystore.fromSeed(bobSeed, List.of(new ChildNumber(47, true), ChildNumber.ZERO_HARDENED, ChildNumber.ZERO_HARDENED));
    ECKey bobNotificationPrivKey = bobKeystore.getBip47ExtendedPrivateKey().getKey(List.of(ChildNumber.ZERO_HARDENED, new ChildNumber(0)));
    SecretPoint bobSecretPoint = new SecretPoint(bobNotificationPrivKey.getPrivKeyBytes(), alicePubKey.getPubKey());
    Assert.assertEquals("736a25d9250238ad64ed5da03450c6a3f4f8f4dcdf0b58d1ed69029d76ead48d", Utils.bytesToHex(bobSecretPoint.ECDHSecretAsBytes()));
    byte[] bobBlindingMask = PaymentCode.getMask(secretPoint.ECDHSecretAsBytes(), transaction.getInputs().get(0).getOutpoint().bitcoinSerialize());
    Assert.assertEquals("be6e7a4256cac6f4d4ed4639b8c39c4cb8bece40010908e70d17ea9d77b4dc57f1da36f2d6641ccb37cf2b9f3146686462e0fa3161ae74f88c0afd4e307adbd5", Utils.bytesToHex(bobBlindingMask));
    PaymentCode unblindedPaymentCode = new PaymentCode(PaymentCode.blind(transaction.getOutputs().get(1).getScript().getChunks().get(1).data, blindingMask));
    Assert.assertEquals(alicePaymentCode, unblindedPaymentCode);
    PaymentCode unblindedPaymentCode2 = PaymentCode.getPaymentCode(transaction, bobKeystore);
    Assert.assertEquals(alicePaymentCode, unblindedPaymentCode2);
}
Also used : Address(com.sparrowwallet.drongo.address.Address) ECKey(com.sparrowwallet.drongo.crypto.ECKey) ChildNumber(com.sparrowwallet.drongo.crypto.ChildNumber) Test(org.junit.Test)

Example 3 with Address

use of com.sparrowwallet.drongo.address.Address in project drongo by sparrowwallet.

the class Wallet method getMaxSpendable.

/**
 * Determines the maximum total amount this wallet can send for the number and type of addresses at the given fee rate
 *
 * @param paymentAddresses the addresses to sent to (amounts are irrelevant)
 * @param feeRate the fee rate in sats/vB
 * @return the maximum spendable amount (can be negative if the fee is higher than the combined UTXO value)
 */
public long getMaxSpendable(List<Address> paymentAddresses, double feeRate, boolean includeSpentMempoolOutputs) {
    long maxInputValue = 0;
    Transaction transaction = new Transaction();
    for (Map.Entry<BlockTransactionHashIndex, WalletNode> utxo : getWalletUtxos(includeSpentMempoolOutputs).entrySet()) {
        int inputWeightUnits = utxo.getValue().getWallet().getInputWeightUnits();
        long minInputValue = (long) Math.ceil(feeRate * inputWeightUnits / WITNESS_SCALE_FACTOR);
        if (utxo.getKey().getValue() > minInputValue) {
            Transaction prevTx = getWalletTransaction(utxo.getKey().getHash()).getTransaction();
            TransactionOutput prevTxOut = prevTx.getOutputs().get((int) utxo.getKey().getIndex());
            addDummySpendingInput(transaction, utxo.getValue(), prevTxOut);
            maxInputValue += utxo.getKey().getValue();
        }
    }
    for (Address address : paymentAddresses) {
        transaction.addOutput(1L, address);
    }
    long fee = (long) Math.floor(transaction.getVirtualSize() * feeRate);
    return maxInputValue - fee;
}
Also used : Address(com.sparrowwallet.drongo.address.Address)

Example 4 with Address

use of com.sparrowwallet.drongo.address.Address in project drongo by sparrowwallet.

the class TransactionTest method verifyConstructedTxLengthP2PKH.

@Test
public void verifyConstructedTxLengthP2PKH() throws NonStandardScriptException, IOException {
    String hex = "0100000003c07f2ee6dd4e55c6eefdc53659d1fb340beb5eb824d13bc15ba5269ade8de446000000006b483045022100d3f7526a8d1e22233c1f193b63f55406b32010aefeecdc802c07829b583d53a002205f1b666f156433baf6e976b8c43702cfe098e6d6c3c90e4bf2d24eeb1724740a012102faea485f773dbc2f57fe8cf664781a58d499c1f10ad55d370d5b08b92b8ee0c4ffffffffcac7a96d74d8a2b9177c7e0ce735f366d717e759d1f07bbd8a6db55e4b21304e000000006b483045022100d11822be0768c78cdb28ce613051facfa68c6689199505e7d0c75e95b7bd210c02202c5a610ceab38fc6816f6b792c43a1a25ae8507e80cd657dbfecfbff804a455101210287571cbb133887664c47917df7192017906916f7ce470532699c00ae4f10a178ffffffff3b16c58d5d76e119d337a56751b62b60c614ceca73d8e6403476c9e5a74497ab000000006b483045022100cb865e7b13f61f5968a734e0d8257fca72ad6f6b37c80e409e7f986a94f1269d022025e28e140e8087f1804a79b072ae18f69064f53223f2baa169685fe951f16b72012103f23d4fb4ab152b5f6b5e4a0bf79cfcac071c1f2cf07211c8cd176469b2a00628ffffffff02b3070000000000001976a914c3a1a5b559ff4db7f9c92c3d10274a3a18dcea3788ac4be28a00000000001976a914fe0c8a170be39d30f5447e57556e7836ed29e49088ac00000000";
    Transaction parsedTransaction = new Transaction(Utils.hexToBytes(hex));
    Transaction transaction = new Transaction();
    for (TransactionInput txInput : parsedTransaction.getInputs()) {
        transaction.addInput(txInput.getOutpoint().getHash(), txInput.getOutpoint().getIndex(), txInput.getScriptSig());
    }
    for (TransactionOutput txOutput : parsedTransaction.getOutputs()) {
        Address address = txOutput.getScript().getToAddresses()[0];
        transaction.addOutput(txOutput.getValue(), address);
    }
    Assert.assertEquals(parsedTransaction.getLength(), transaction.getLength());
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    transaction.bitcoinSerializeToStream(baos);
    String constructedHex = Utils.bytesToHex(baos.toByteArray());
    Assert.assertEquals(hex, constructedHex);
}
Also used : Address(com.sparrowwallet.drongo.address.Address) ByteArrayOutputStream(java.io.ByteArrayOutputStream) Test(org.junit.Test)

Example 5 with Address

use of com.sparrowwallet.drongo.address.Address in project drongo by sparrowwallet.

the class TransactionTest method verifyConstructedTxLengthP2WPKHMulti.

@Test
public void verifyConstructedTxLengthP2WPKHMulti() throws NonStandardScriptException, IOException {
    String hex = "02000000000102ba4dc5a4a14bfaa941b7d115b379b5e15f960635cf694c178b9116763cbd63b11600000017160014fc164cbcac023f5eacfcead2d17d8768c41949affeffffff074d44d2856beb68ba52e8832da60a1682768c2421c2d9a8109ef4e66babd1fd1e000000171600148c3098be6b430859115f5ee99c84c368afecd0481500400002305310000000000017a914ffaf369c2212b178c7a2c21c9ccdd5d126e74c4187327f0300000000001976a914a7cda2e06b102a143ab606937a01d152e300cd3e88ac02473044022006da0ca227f765179219e08a33026b94e7cacff77f87b8cd8eb1b46d6dda11d6022064faa7912924fd23406b6ed3328f1bbbc3760dc51109a49c1b38bf57029d304f012103c6a2fcd030270427d4abe1041c8af929a9e2dbab07b243673453847ab842ee1f024730440220786316a16095105a0af28dccac5cf80f449dea2ea810a9559a89ecb989c2cb3d02205cbd9913d1217ffec144ae4f2bd895f16d778c2ec49ae9c929fdc8bcc2a2b1db0121024d4985241609d072a59be6418d700e87688f6c4d99a51ad68e66078211f076ee38820900";
    Transaction parsedTransaction = new Transaction(Utils.hexToBytes(hex));
    Transaction transaction = new Transaction();
    transaction.setVersion(parsedTransaction.getVersion());
    transaction.setSegwitFlag(parsedTransaction.getSegwitFlag());
    transaction.setLocktime(parsedTransaction.getLocktime());
    for (TransactionInput txInput : parsedTransaction.getInputs()) {
        TransactionInput newInput = transaction.addInput(txInput.getOutpoint().getHash(), txInput.getOutpoint().getIndex(), txInput.getScriptSig(), txInput.getWitness());
        newInput.setSequenceNumber(txInput.getSequenceNumber());
    }
    for (TransactionOutput txOutput : parsedTransaction.getOutputs()) {
        Address address = txOutput.getScript().getToAddresses()[0];
        transaction.addOutput(txOutput.getValue(), address);
    }
    Assert.assertEquals(parsedTransaction.getLength(), transaction.getLength());
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    transaction.bitcoinSerializeToStream(baos);
    String constructedHex = Utils.bytesToHex(baos.toByteArray());
    Assert.assertEquals(hex, constructedHex);
}
Also used : Address(com.sparrowwallet.drongo.address.Address) ByteArrayOutputStream(java.io.ByteArrayOutputStream) Test(org.junit.Test)

Aggregations

Address (com.sparrowwallet.drongo.address.Address)26 Test (org.junit.Test)6 InvalidAddressException (com.sparrowwallet.drongo.address.InvalidAddressException)5 ECKey (com.sparrowwallet.drongo.crypto.ECKey)5 KeyPurpose (com.sparrowwallet.drongo.KeyPurpose)4 TransactionOutput (com.sparrowwallet.drongo.protocol.TransactionOutput)4 P2PKHAddress (com.sparrowwallet.drongo.address.P2PKHAddress)3 com.sparrowwallet.drongo.wallet (com.sparrowwallet.drongo.wallet)3 PayNymAddress (com.sparrowwallet.sparrow.paynym.PayNymAddress)3 ByteArrayOutputStream (java.io.ByteArrayOutputStream)3 java.util (java.util)3 Collectors (java.util.stream.Collectors)3 InvalidPaymentCodeException (com.sparrowwallet.drongo.bip47.InvalidPaymentCodeException)2 DumpedPrivateKey (com.sparrowwallet.drongo.crypto.DumpedPrivateKey)2 NonStandardScriptException (com.sparrowwallet.drongo.protocol.NonStandardScriptException)2 ScriptType (com.sparrowwallet.drongo.protocol.ScriptType)2 Transaction (com.sparrowwallet.drongo.protocol.Transaction)2 BitcoinURI (com.sparrowwallet.drongo.uri.BitcoinURI)2 AppServices (com.sparrowwallet.sparrow.AppServices)2 EventManager (com.sparrowwallet.sparrow.EventManager)2