diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml deleted file mode 100644 index 30aa626c23..0000000000 --- a/.idea/codeStyles/Project.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index d70d548ee7..7d8d06f4cc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,7 +5,7 @@ apply plugin: 'kotlin-kapt' static def generateVersionName() { def gitCommitsCount = "git rev-list HEAD --count".execute().text.trim() - def gitCurrentBranch = "git rev-parse --abbrev-ref HEAD".execute().text.trim() +// def gitCurrentBranch = "git rev-parse --abbrev-ref HEAD".execute().text.trim() return gitCommitsCount.toInteger() + 831// + "\\n" + gitCurrentBranch } diff --git a/app/src/main/java/com/tangem/data/network/ServerApiSoChain.java b/app/src/main/java/com/tangem/data/network/ServerApiSoChain.java index 862af12b63..df8cac1af1 100644 --- a/app/src/main/java/com/tangem/data/network/ServerApiSoChain.java +++ b/app/src/main/java/com/tangem/data/network/ServerApiSoChain.java @@ -24,9 +24,7 @@ public class ServerApiSoChain { return requestsCount <= 0; } - private ResponseListener responseListener; - - public interface ResponseListener { + public interface AddressInfoListener { void onSuccess(SoChain.Response.AddressBalance response); void onSuccess(SoChain.Response.TxUnspent response); @@ -34,8 +32,22 @@ public class ServerApiSoChain { void onFail(String message); } - public void setResponseListener(ResponseListener listener) { - responseListener = listener; + private AddressInfoListener addressInfoListener; + + public void setAddressInfoListener(AddressInfoListener listener) { + addressInfoListener = listener; + } + + public interface SendTxListener { + void onSuccess(SoChain.Response.SendTx response); + + void onFail(String message); + } + + private SendTxListener sendTxListener; + + public void setSendTxListener(SendTxListener listener) { + sendTxListener = listener; } private String getNetwork(Blockchain blockchain) throws Exception { @@ -62,16 +74,16 @@ public class ServerApiSoChain { Log.i(TAG, "requestAddressBalance onResponse " + response.code()); if (response.code() == 200) { requestsCount--; - responseListener.onSuccess(response.body()); + addressInfoListener.onSuccess(response.body()); } else { - responseListener.onFail(String.valueOf(response.code())); + addressInfoListener.onFail(String.valueOf(response.code())); } } @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) { Log.e(TAG, "requestAddressBalance onFailure " + t.getMessage()); - responseListener.onFail(String.valueOf(t.getMessage())); + addressInfoListener.onFail(String.valueOf(t.getMessage())); } }); } @@ -87,16 +99,43 @@ public class ServerApiSoChain { Log.i(TAG, "requestAddressBalance onResponse " + response.code()); if (response.code() == 200) { requestsCount--; - responseListener.onSuccess(response.body()); + addressInfoListener.onSuccess(response.body()); } else { - responseListener.onFail(String.valueOf(response.code())); + addressInfoListener.onFail(String.valueOf(response.code())); } } @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) { Log.e(TAG, "requestAddressBalance onFailure " + t.getMessage()); - responseListener.onFail(String.valueOf(t.getMessage())); + addressInfoListener.onFail(String.valueOf(t.getMessage())); + } + }); + } + + public void requestSendTransaction(Blockchain blockchain, String txHEX) throws Exception { + requestsCount++; + SoChainApi api = App.Companion.getNetworkComponent().getRetrofitSoChain().create(SoChainApi.class); + + SoChain.Request.SendTx tx=new SoChain.Request.SendTx(); + tx.setTx_hex(txHEX); + Call call = api.sendTransaction(getNetwork(blockchain), tx); + call.enqueue(new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + Log.i(TAG, "requestAddressBalance onResponse " + response.code()); + if (response.code() == 200) { + requestsCount--; + sendTxListener.onSuccess(response.body()); + } else { + sendTxListener.onFail(String.valueOf(response.code())); + } + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + Log.e(TAG, "requestAddressBalance onFailure " + t.getMessage()); + sendTxListener.onFail(String.valueOf(t.getMessage())); } }); } diff --git a/app/src/main/java/com/tangem/data/network/SoChainApi.java b/app/src/main/java/com/tangem/data/network/SoChainApi.java index b9c956a000..ddb982d09a 100644 --- a/app/src/main/java/com/tangem/data/network/SoChainApi.java +++ b/app/src/main/java/com/tangem/data/network/SoChainApi.java @@ -19,5 +19,5 @@ public interface SoChainApi { @Headers("Content-Type: application/json") @POST(Server.ApiSoChain.Method.SEND_TRANSACTION) - Call sendTransaction(@Path("network") String network, @Body SoChain.Request.SendTx body); + Call sendTransaction(@Path("network") String network, @Body SoChain.Request.SendTx body); } diff --git a/app/src/main/java/com/tangem/data/network/model/SoChain.kt b/app/src/main/java/com/tangem/data/network/model/SoChain.kt index 2730df7776..cc42d6204a 100644 --- a/app/src/main/java/com/tangem/data/network/model/SoChain.kt +++ b/app/src/main/java/com/tangem/data/network/model/SoChain.kt @@ -42,5 +42,15 @@ class SoChain { var data: Data? = null } + + class SendTx { + class Data { + var network: String? = null + var txid: String? = null + var tx_hex: String? = null + } + var status: String? = null + var data: Data? = null + } } } \ No newline at end of file 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 73b6871752..6e2ea3aef5 100644 --- a/app/src/main/java/com/tangem/wallet/btc/BtcEngine.java +++ b/app/src/main/java/com/tangem/wallet/btc/BtcEngine.java @@ -13,6 +13,7 @@ import com.tangem.data.Blockchain; import com.tangem.data.local.PendingTransactionsStorage; import com.tangem.data.network.ElectrumRequest; import com.tangem.data.network.Server; +import com.tangem.data.network.ServerApiCommon; import com.tangem.data.network.ServerApiElectrum; import com.tangem.data.network.ServerApiSoChain; import com.tangem.data.network.model.SoChain; @@ -639,7 +640,7 @@ public class BtcEngine extends CoinEngine { } else { final ServerApiSoChain serverApi = new ServerApiSoChain(); - ServerApiSoChain.ResponseListener responseListener = new ServerApiSoChain.ResponseListener() { + ServerApiSoChain.AddressInfoListener addressInfoListener = new ServerApiSoChain.AddressInfoListener() { @Override public void onSuccess(SoChain.Response.AddressBalance response) { try { @@ -738,7 +739,7 @@ public class BtcEngine extends CoinEngine { }; - serverApi.setResponseListener(responseListener); + serverApi.setAddressInfoListener(addressInfoListener); serverApi.requestAddressBalance(ctx.getBlockchain(), coinData.getWallet()); serverApi.requestUnspentTx(ctx.getBlockchain(), coinData.getWallet()); @@ -888,71 +889,177 @@ public class BtcEngine extends CoinEngine { coinData.maxFee = null; coinData.normalFee = null; - final ServerApiElectrum serverApiElectrum = new ServerApiElectrum(); + if (useElectrum) { - final ServerApiElectrum.ResponseListener electrumListener = new ServerApiElectrum.ResponseListener() { - @Override - public void onSuccess(ElectrumRequest electrumRequest) { - BigDecimal kbFee; - if (electrumRequest.isMethod(ElectrumRequest.METHOD_GetFee)) { - try { - kbFee = new BigDecimal(electrumRequest.getResultString()); //fee per KB + final ServerApiElectrum serverApiElectrum = new ServerApiElectrum(); - if (kbFee.equals(BigDecimal.ZERO)) { - serverApiElectrum.requestData(ctx, ElectrumRequest.getFee()); - } + final ServerApiElectrum.ResponseListener electrumListener = new ServerApiElectrum.ResponseListener() { + @Override + public void onSuccess(ElectrumRequest electrumRequest) { + BigDecimal kbFee; + if (electrumRequest.isMethod(ElectrumRequest.METHOD_GetFee)) { + try { + kbFee = new BigDecimal(electrumRequest.getResultString()); //fee per KB - BigDecimal minByteFee = kbFee.divide(new BigDecimal(1024)); // per KB -> per byte - BigDecimal normalByteFee = minByteFee.add(new BigDecimal(0.00000010)); - BigDecimal maxByteFee = minByteFee.add(new BigDecimal(0.00000025)); + if (kbFee.equals(BigDecimal.ZERO)) { + serverApiElectrum.requestData(ctx, ElectrumRequest.getFee()); + } - BigDecimal minFee = minByteFee.multiply(new BigDecimal(calcSize)).setScale(8, RoundingMode.DOWN); - BigDecimal normalFee = normalByteFee.multiply(new BigDecimal(calcSize)).setScale(8, RoundingMode.DOWN); - BigDecimal maxFee = maxByteFee.multiply(new BigDecimal(calcSize)).setScale(8, RoundingMode.DOWN); + BigDecimal minByteFee = kbFee.divide(new BigDecimal(1024)); // per KB -> per byte + BigDecimal normalByteFee = minByteFee.add(new BigDecimal(0.00000010)); + BigDecimal maxByteFee = minByteFee.add(new BigDecimal(0.00000025)); - CoinEngine.Amount minAmount = new CoinEngine.Amount(minFee, ctx.getBlockchain().getCurrency()); - CoinEngine.Amount normalAmount = new CoinEngine.Amount(normalFee, ctx.getBlockchain().getCurrency()); - CoinEngine.Amount maxAmount = new CoinEngine.Amount(maxFee, ctx.getBlockchain().getCurrency()); + BigDecimal minFee = minByteFee.multiply(new BigDecimal(calcSize)).setScale(8, RoundingMode.DOWN); + BigDecimal normalFee = normalByteFee.multiply(new BigDecimal(calcSize)).setScale(8, RoundingMode.DOWN); + BigDecimal maxFee = maxByteFee.multiply(new BigDecimal(calcSize)).setScale(8, RoundingMode.DOWN); - coinData.minFee = minAmount; - coinData.normalFee = normalAmount; - coinData.maxFee = maxAmount; + CoinEngine.Amount minAmount = new CoinEngine.Amount(minFee, ctx.getBlockchain().getCurrency()); + CoinEngine.Amount normalAmount = new CoinEngine.Amount(normalFee, ctx.getBlockchain().getCurrency()); + CoinEngine.Amount maxAmount = new CoinEngine.Amount(maxFee, ctx.getBlockchain().getCurrency()); + + coinData.minFee = minAmount; + coinData.normalFee = normalAmount; + coinData.maxFee = maxAmount; // if (coinData.minFee != null && coinData.normalFee != null && coinData.maxFee != null) { - blockchainRequestsCallbacks.onComplete(true); + blockchainRequestsCallbacks.onComplete(true); // } else { // blockchainRequestsCallbacks.onProgress(); // } - } catch (JSONException e) { - e.printStackTrace(); + } catch (JSONException e) { + e.printStackTrace(); + } } } - } - @Override - public void onFail(ElectrumRequest electrumRequest) { - ctx.setError(electrumRequest.getError()); - blockchainRequestsCallbacks.onComplete(false); - } - }; - serverApiElectrum.setResponseListener(electrumListener); + @Override + public void onFail(ElectrumRequest electrumRequest) { + ctx.setError(electrumRequest.getError()); + blockchainRequestsCallbacks.onComplete(false); + } + }; + serverApiElectrum.setResponseListener(electrumListener); - serverApiElectrum.requestData(ctx, ElectrumRequest.getFee()); + serverApiElectrum.requestData(ctx, ElectrumRequest.getFee()); + } else { + + final ServerApiCommon serverApiCommon = new ServerApiCommon(); + + final ServerApiCommon.EstimatedFeeListener estimatedFeeListener = new ServerApiCommon.EstimatedFeeListener() { + @Override + public void onSuccess(int blockCount, String estimateFeeResponse) { + BigDecimal fee = new BigDecimal(estimateFeeResponse); // BTC per 1 kb + + if (fee.equals(BigDecimal.ZERO)) { + if (blockchainRequestsCallbacks.allowAdvance()) { + serverApiCommon.requestBtcEstimatedFee(blockCount); + } + return; + } + + if (calcSize != 0) { + fee = fee.multiply(new BigDecimal(calcSize)).divide(new BigDecimal(1024), BigDecimal.ROUND_DOWN); // per Kb -> per byte + } else { + if (blockchainRequestsCallbacks.allowAdvance()) { + serverApiCommon.requestBtcEstimatedFee(blockCount); + } + return; + } + + fee = fee.setScale(8, RoundingMode.DOWN); + + switch (blockCount) { + case ServerApiCommon.ESTIMATE_FEE_MINIMAL: + coinData.minFee = new CoinEngine.Amount(fee, getFeeCurrency()); + break; + case ServerApiCommon.ESTIMATE_FEE_NORMAL: + coinData.normalFee = new CoinEngine.Amount(fee, getFeeCurrency()); + break; + case ServerApiCommon.ESTIMATE_FEE_PRIORITY: + coinData.maxFee = new CoinEngine.Amount(fee, getFeeCurrency()); + break; + } + + if (coinData.minFee != null && coinData.normalFee != null && coinData.maxFee != null) { + blockchainRequestsCallbacks.onComplete(true); + } else { + blockchainRequestsCallbacks.onProgress(); + } + } + + @Override + public void onFail(int blockCount, String message) { + // TODO - add fail counter to terminate after NNN tries + if (blockchainRequestsCallbacks.allowAdvance()) { + serverApiCommon.requestBtcEstimatedFee(blockCount); + return; + } + ctx.setError(ctx.getContext().getString(R.string.cannot_calculate_fee_wrong_data_received_from_node)); + blockchainRequestsCallbacks.onComplete(false); + } + }; + serverApiCommon.setBtcEstimatedFeeListener(estimatedFeeListener); + + serverApiCommon.requestBtcEstimatedFee(ServerApiCommon.ESTIMATE_FEE_PRIORITY); + serverApiCommon.requestBtcEstimatedFee(ServerApiCommon.ESTIMATE_FEE_NORMAL); + serverApiCommon.requestBtcEstimatedFee(ServerApiCommon.ESTIMATE_FEE_MINIMAL); + + } } @Override - public void requestSendTransaction(BlockchainRequestsCallbacks blockchainRequestsCallbacks, byte[] txForSend) { - final ServerApiElectrum serverApiElectrum = new ServerApiElectrum(); + public void requestSendTransaction(BlockchainRequestsCallbacks blockchainRequestsCallbacks, byte[] txForSend) throws Exception { final String txStr = BTCUtils.toHex(txForSend); + if (useElectrum) { + final ServerApiElectrum serverApiElectrum = new ServerApiElectrum(); - ServerApiElectrum.ResponseListener electrumListener = new ServerApiElectrum.ResponseListener() { - @Override - public void onSuccess(ElectrumRequest electrumRequest) { - if (electrumRequest.isMethod(ElectrumRequest.METHOD_SendTransaction)) { + ServerApiElectrum.ResponseListener electrumListener = new ServerApiElectrum.ResponseListener() { + @Override + public void onSuccess(ElectrumRequest electrumRequest) { + if (electrumRequest.isMethod(ElectrumRequest.METHOD_SendTransaction)) { + try { + String resultString = electrumRequest.getResultString(); + if (resultString == null || resultString.isEmpty()) { + ctx.setError("Rejected by node: " + electrumRequest.getError()); + blockchainRequestsCallbacks.onComplete(false); + } else { + ctx.setError(null); + blockchainRequestsCallbacks.onComplete(true); + } + } catch (Exception e) { + if (e.getMessage() != null) { + ctx.setError(e.getMessage()); + blockchainRequestsCallbacks.onComplete(false); + } else { + ctx.setError(e.getClass().getName()); + blockchainRequestsCallbacks.onComplete(false); + } + } + } + } + + @Override + public void onFail(ElectrumRequest electrumRequest) { + ctx.setError(electrumRequest.getError()); + blockchainRequestsCallbacks.onComplete(false); + } + }; + serverApiElectrum.setResponseListener(electrumListener); + + + serverApiElectrum.requestData(ctx, ElectrumRequest.broadcast(ctx.getCoinData().getWallet(), txStr)); + } else { + final ServerApiSoChain serverApi = new ServerApiSoChain(); + + ServerApiSoChain.SendTxListener listener = new ServerApiSoChain.SendTxListener() { + @Override + public void onSuccess(SoChain.Response.SendTx response) { try { - String resultString = electrumRequest.getResultString(); - if (resultString == null || resultString.isEmpty()) { - ctx.setError("Rejected by node: " + electrumRequest.getError()); + if (response.getStatus() == null || response.getData() == null) { + ctx.setError("Rejected by node: invalid answer received"); + blockchainRequestsCallbacks.onComplete(false); + } else if (response.getStatus().equals("fail") || response.getData().getTxid() == null) { + ctx.setError("Rejected by node: " + response.getData()); blockchainRequestsCallbacks.onComplete(false); } else { ctx.setError(null); @@ -968,19 +1075,17 @@ public class BtcEngine extends CoinEngine { } } } - } - @Override - public void onFail(ElectrumRequest electrumRequest) { - ctx.setError(electrumRequest.getError()); - blockchainRequestsCallbacks.onComplete(false); - } - }; - serverApiElectrum.setResponseListener(electrumListener); - - - serverApiElectrum.requestData(ctx, ElectrumRequest.broadcast(ctx.getCoinData().getWallet(), txStr)); + @Override + public void onFail(String message) { + ctx.setError(message); + blockchainRequestsCallbacks.onComplete(false); + } + }; + serverApi.setSendTxListener(listener); + serverApi.requestSendTransaction(ctx.getBlockchain(), txStr); + } } } \ No newline at end of file diff --git a/build.gradle b/build.gradle index 07821a2684..c4a30cd5d8 100644 --- a/build.gradle +++ b/build.gradle @@ -1,11 +1,11 @@ buildscript { - ext.kotlin_version = '1.3.21' + ext.kotlin_version = '1.3.30' repositories { google() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.3.2' + classpath 'com.android.tools.build:gradle:3.4.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' } diff --git a/card-android/build.gradle b/card-android/build.gradle index 6d22133a08..956d0c88fe 100644 --- a/card-android/build.gradle +++ b/card-android/build.gradle @@ -29,7 +29,7 @@ dependencies { implementation project(':card-common') // implementation 'com.github.TangemCash.card_android-common:card_android-android:0.1.0' - implementation 'androidx.appcompat:appcompat:1.1.0-alpha01' + implementation 'androidx.appcompat:appcompat:1.1.0-alpha04' implementation 'com.google.code.gson:gson:2.8.5' implementation 'com.scottyab:rootbeer-lib:0.0.7' testImplementation 'junit:junit:4.12' diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6fea634781..c494404a7f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Jan 18 12:06:47 MSK 2019 +#Wed Apr 17 22:33:22 MSK 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip diff --git a/server-android/build.gradle b/server-android/build.gradle index f79ad5009e..7aaa4af308 100644 --- a/server-android/build.gradle +++ b/server-android/build.gradle @@ -29,7 +29,7 @@ dependencies { implementation project(':card-common') // implementation 'com.github.TangemCash.card_android-common:card_android-android:0.1.0' - implementation 'androidx.appcompat:appcompat:1.1.0-alpha03' + implementation 'androidx.appcompat:appcompat:1.1.0-alpha04' implementation 'com.google.code.gson:gson:2.8.5' implementation 'com.squareup.retrofit2:converter-gson:2.5.0' implementation 'com.squareup.retrofit2:retrofit:2.5.0'