From 7ba040e3177e97c74ca3e18dc7bfb93914827655 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 17 Apr 2020 18:18:31 +0300 Subject: [PATCH 1/3] Updated on 2026-08-14 --- .../com/tangem/wallet/bch/BtcCashEngine.java | 3 -- .../java/com/tangem/wallet/btc/BtcEngine.java | 2 -- .../tangem/wallet/ducatus/DucatusEngine.java | 6 ---- .../java/com/tangem/wallet/ltc/LtcEngine.java | 2 -- .../tangem/tangem_card/tasks/SignTask.java | 32 +++++++++++++++++-- 5 files changed, 29 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/tangem/wallet/bch/BtcCashEngine.java b/app/src/main/java/com/tangem/wallet/bch/BtcCashEngine.java index 4c126fbc3f..549ef88649 100644 --- a/app/src/main/java/com/tangem/wallet/bch/BtcCashEngine.java +++ b/app/src/main/java/com/tangem/wallet/bch/BtcCashEngine.java @@ -39,7 +39,6 @@ import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import io.reactivex.CompletableObserver; import io.reactivex.SingleObserver; @@ -425,8 +424,6 @@ public class BtcCashEngine extends CoinEngine { @Override public byte[][] getHashesToSign() throws Exception { byte[][] dataForSign = new byte[unspentOutputs.size()][]; - if (txForSign.length > 10) - throw new Exception("To much hashes in one transaction!"); for (int i = 0; i < unspentOutputs.size(); ++i) { dataForSign[i] = bodyDoubleHash[i]; } diff --git a/app/src/main/java/com/tangem/wallet/btc/BtcEngine.java b/app/src/main/java/com/tangem/wallet/btc/BtcEngine.java index 05b489ba07..e9782bcf5d 100644 --- a/app/src/main/java/com/tangem/wallet/btc/BtcEngine.java +++ b/app/src/main/java/com/tangem/wallet/btc/BtcEngine.java @@ -517,8 +517,6 @@ public class BtcEngine extends CoinEngine { @Override public byte[][] getHashesToSign() throws Exception { byte[][] dataForSign = new byte[unspentOutputs.size()][]; - if (txForSign.length > 10) - throw new Exception("To much hashes in one transaction!"); for (int i = 0; i < unspentOutputs.size(); ++i) { dataForSign[i] = bodyDoubleHash[i]; } diff --git a/app/src/main/java/com/tangem/wallet/ducatus/DucatusEngine.java b/app/src/main/java/com/tangem/wallet/ducatus/DucatusEngine.java index d6fb31aad1..f346435773 100644 --- a/app/src/main/java/com/tangem/wallet/ducatus/DucatusEngine.java +++ b/app/src/main/java/com/tangem/wallet/ducatus/DucatusEngine.java @@ -6,12 +6,9 @@ import android.util.Log; import com.tangem.App; import com.tangem.data.network.ServerApiBitcore; -import com.tangem.data.network.ServerApiInsight; import com.tangem.data.network.model.BitcoreBalanceAndUnspents; import com.tangem.data.network.model.BitcoreSendResponse; import com.tangem.data.network.model.BitcoreUtxo; -import com.tangem.data.network.model.InsightResponse; -import com.tangem.data.network.model.InsightUtxo; import com.tangem.tangem_card.data.TangemCard; import com.tangem.tangem_card.reader.CardProtocol; import com.tangem.tangem_card.tasks.SignTask; @@ -39,7 +36,6 @@ import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import io.reactivex.SingleObserver; import io.reactivex.observers.DisposableSingleObserver; @@ -449,8 +445,6 @@ public class DucatusEngine extends BtcEngine { @Override public byte[][] getHashesToSign() throws Exception { byte[][] dataForSign = new byte[unspentOutputs.size()][]; - if (txForSign.length > 10) - throw new Exception("To much hashes in one transaction!"); for (int i = 0; i < unspentOutputs.size(); ++i) { dataForSign[i] = bodyDoubleHash[i]; } diff --git a/app/src/main/java/com/tangem/wallet/ltc/LtcEngine.java b/app/src/main/java/com/tangem/wallet/ltc/LtcEngine.java index e8ebfa3fd3..3e0520bdf2 100644 --- a/app/src/main/java/com/tangem/wallet/ltc/LtcEngine.java +++ b/app/src/main/java/com/tangem/wallet/ltc/LtcEngine.java @@ -450,8 +450,6 @@ public class LtcEngine extends BtcEngine { @Override public byte[][] getHashesToSign() throws Exception { byte[][] dataForSign = new byte[unspentOutputs.size()][]; - if (txForSign.length > 10) - throw new Exception("To much hashes in one transaction!"); for (int i = 0; i < unspentOutputs.size(); ++i) { dataForSign[i] = bodyDoubleHash[i]; } diff --git a/tangem-card-old/src/main/java/com/tangem/tangem_card/tasks/SignTask.java b/tangem-card-old/src/main/java/com/tangem/tangem_card/tasks/SignTask.java index 92140edb11..ce86f2fbdd 100644 --- a/tangem-card-old/src/main/java/com/tangem/tangem_card/tasks/SignTask.java +++ b/tangem-card-old/src/main/java/com/tangem/tangem_card/tasks/SignTask.java @@ -14,6 +14,8 @@ import java.io.ByteArrayOutputStream; public class SignTask extends CustomReadCardTask { public static final String TAG = SignTask.class.getSimpleName(); + private static final int MAX_HASHES_TO_SIGN = 10; + /** * Transaction Engine request/notifications during sign process */ @@ -58,13 +60,31 @@ public class SignTask extends CustomReadCardTask { TLVList signResult; switch (mCard.getSigningMethod()) { case Sign_Hash: - signResult = protocol.run_SignHashes(pinsProvider.getPIN2(), transactionToSign.getHashesToSign(), null, null, null); - break; + byte[][] remainingHashes = transactionToSign.getHashesToSign(); + ByteArrayOutputStream signatures = new ByteArrayOutputStream(); + while (remainingHashes.length > 0) { + byte[][] hashesToSign; + if (remainingHashes.length <= MAX_HASHES_TO_SIGN) { + hashesToSign = remainingHashes.clone(); + remainingHashes = new byte[0][]; + } else { + hashesToSign = new byte[MAX_HASHES_TO_SIGN][]; + System.arraycopy(remainingHashes, 0, hashesToSign, 0, MAX_HASHES_TO_SIGN); + remainingHashes = removeFirstTenEntries(remainingHashes); + } + + signResult = protocol.run_SignHashes(pinsProvider.getPIN2(), hashesToSign, null, null, null); + signatures.write(signResult.getTLV(TLV.Tag.TAG_Signature).Value); + } + mNotifications.onReadProgress(protocol, 100); + transactionToSign.onSignCompleted(signatures.toByteArray()); + return; + case Sign_Hash_Validated_By_Issuer: case Sign_Hash_Validated_By_Issuer_And_WriteIssuerData: ByteArrayOutputStream bs = new ByteArrayOutputStream(); byte[][] hashes = transactionToSign.getHashesToSign(); - if (hashes.length > 10) throw new CardProtocol.TangemException("To much hashes in one transaction!"); + if (hashes.length > MAX_HASHES_TO_SIGN) throw new CardProtocol.TangemException("To much hashes in one transaction!"); for (int i = 0; i < hashes.length; i++) { if (i != 0 && hashes[0].length != hashes[i].length) throw new CardProtocol.TangemException("Hashes length must be identical!"); @@ -89,4 +109,10 @@ public class SignTask extends CustomReadCardTask { mNotifications.onReadProgress(protocol, 100); } + + private byte[][] removeFirstTenEntries(byte[][] array) { + byte[][] temp = new byte[array.length - MAX_HASHES_TO_SIGN][]; + System.arraycopy(array, MAX_HASHES_TO_SIGN, temp, 0, temp.length); + return temp; + } } From 2b04de06616272489851a7a6c312dcc8427e5da7 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 20 Apr 2020 16:12:36 +0300 Subject: [PATCH 2/3] Updated on 2026-08-14 --- .../java/com/tangem/wallet/ltc/LtcEngine.java | 74 +++++++++++++++++-- 1 file changed, 66 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/tangem/wallet/ltc/LtcEngine.java b/app/src/main/java/com/tangem/wallet/ltc/LtcEngine.java index 3e0520bdf2..9312a17a87 100644 --- a/app/src/main/java/com/tangem/wallet/ltc/LtcEngine.java +++ b/app/src/main/java/com/tangem/wallet/ltc/LtcEngine.java @@ -23,6 +23,7 @@ import com.tangem.wallet.BTCUtils; import com.tangem.wallet.BalanceValidator; import com.tangem.wallet.Base58; import com.tangem.wallet.CoinData; +import com.tangem.wallet.CoinEngine; import com.tangem.wallet.R; import com.tangem.wallet.TangemContext; import com.tangem.wallet.Transaction; @@ -621,12 +622,74 @@ public class LtcEngine extends BtcEngine { } } - private final static BigDecimal relayFee = new BigDecimal(0.00001).setScale(8, RoundingMode.DOWN); + private final static Amount relayFee = new Amount(new BigDecimal(0.00001).setScale(8, RoundingMode.DOWN), "LTC"); + + private void forceRelayFeeMinimum(Amount fee) { + if (fee.compareTo(relayFee) < 0) { + fee = relayFee; + } + } @Override public void requestFee(BlockchainRequestsCallbacks blockchainRequestsCallbacks, String targetAddress, Amount amount) throws Exception { - coinData.minFee = coinData.normalFee = coinData.maxFee = new Amount(relayFee, "LTC"); - blockchainRequestsCallbacks.onComplete(true); + final int calcSize = calculateEstimatedTransactionSize(targetAddress, amount.toValueString()); + Log.e(TAG, String.format("Estimated tx size %d", calcSize)); + coinData.minFee = null; + coinData.maxFee = null; + coinData.normalFee = null; + + final ServerApiBlockcypher serverApiBlockcypher = new ServerApiBlockcypher(); + + ServerApiBlockcypher.ResponseListener blockcypherListener = new ServerApiBlockcypher.ResponseListener() { + @Override + public void onSuccess(String method, BlockcypherResponse blockcypherResponse) { + Log.e(TAG, "Wrong response type for requestFee"); + ctx.setError("Wrong response type for requestFee"); + blockchainRequestsCallbacks.onComplete(false); + } + + public void onSuccess(String method, BlockcypherFee blockcypherFee) { + Log.i(TAG, "onSuccess: " + method); + try { + BigDecimal minByteFee = new BigDecimal(blockcypherFee.getLow_fee_per_kb()).divide(BigDecimal.valueOf(1024)); + BigDecimal normalByteFee = new BigDecimal(blockcypherFee.getMedium_fee_per_kb()).divide(BigDecimal.valueOf(1024)); + BigDecimal maxByteFee = new BigDecimal(blockcypherFee.getHigh_fee_per_kb()).divide(BigDecimal.valueOf(1024)); + + CoinEngine.InternalAmount minIntAmount = new CoinEngine.InternalAmount(minByteFee.multiply(BigDecimal.valueOf(calcSize)), "satoshi"); + CoinEngine.InternalAmount normalIntAmount = new CoinEngine.InternalAmount(normalByteFee.multiply(BigDecimal.valueOf(calcSize)), "satoshi"); + CoinEngine.InternalAmount maxIntAmount = new CoinEngine.InternalAmount(maxByteFee.multiply(BigDecimal.valueOf(calcSize)), "satoshi"); + + coinData.minFee = convertToAmount(minIntAmount); + coinData.normalFee = convertToAmount(normalIntAmount); + coinData.maxFee = convertToAmount(maxIntAmount); + + forceRelayFeeMinimum(coinData.minFee); + forceRelayFeeMinimum(coinData.normalFee); + forceRelayFeeMinimum(coinData.maxFee); + + } catch (Exception e) { + e.printStackTrace(); + Log.e(TAG, "FAIL BLOCKCYPHER_FEE Exception"); + } + + if (serverApiBlockcypher.isRequestsSequenceCompleted()) { + blockchainRequestsCallbacks.onComplete(!ctx.hasError()); + } else { + blockchainRequestsCallbacks.onProgress(); + } + } + + @Override + public void onFail(String method, String message) { + Log.i(TAG, "onFail: " + method + " " + message); + ctx.setError(message); + blockchainRequestsCallbacks.onComplete(false); + } + }; + + serverApiBlockcypher.setResponseListener(blockcypherListener); + + serverApiBlockcypher.requestData(ctx.getBlockchain().getID(), ServerApiBlockcypher.BLOCKCYPHER_FEE, "", ""); } @Override @@ -675,9 +738,4 @@ public class LtcEngine extends BtcEngine { serverApiBlockcypher.requestData(ctx.getBlockchain().getID(), ServerApiBlockcypher.BLOCKCYPHER_SEND, "", txStr); } - - @Override - public boolean allowSelectFeeLevel() { - return false; - } } \ No newline at end of file From a6e47aab8ba7203ebfdf731bbfe7dd0ab62dbba7 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 20 Apr 2020 17:32:15 +0300 Subject: [PATCH 3/3] Updated on 2026-08-14 --- app/src/main/java/com/tangem/wallet/ltc/LtcEngine.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/tangem/wallet/ltc/LtcEngine.java b/app/src/main/java/com/tangem/wallet/ltc/LtcEngine.java index 9312a17a87..d5020b0fef 100644 --- a/app/src/main/java/com/tangem/wallet/ltc/LtcEngine.java +++ b/app/src/main/java/com/tangem/wallet/ltc/LtcEngine.java @@ -349,7 +349,7 @@ public class LtcEngine extends BtcEngine { @Override public Amount convertToAmount(InternalAmount internalAmount) { - BigDecimal d = internalAmount.divide(new BigDecimal("100000000")); + BigDecimal d = internalAmount.divide(new BigDecimal("100000000")).setScale(getDecimals(), RoundingMode.DOWN); return new Amount(d, getBalanceCurrency()); }