From 47088391dedb46c93d0c497fd77945138cb88d5d Mon Sep 17 00:00:00 2001 From: Henry Varona Date: Fri, 21 Sep 2018 23:09:09 -0400 Subject: [PATCH 01/39] Change version code --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 29eb088..1ed2db8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,8 +15,8 @@ android { applicationId "cy.agorise.crystalwallet" minSdkVersion 21 targetSdkVersion 27 - versionCode 2 - versionName "0.2M.alpha" + versionCode 3 + versionName "0.3M.alpha" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" vectorDrawables { useSupportLibrary true From 53cf2ef25be21c92b6b40b074da0454728a66c8a Mon Sep 17 00:00:00 2001 From: Javier Varona Date: Sun, 23 Sep 2018 20:01:45 -0400 Subject: [PATCH 02/39] - Fixing transaction duplication when importing an account. --- .../crystalwallet/manager/BitsharesAccountManager.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/cy/agorise/crystalwallet/manager/BitsharesAccountManager.java b/app/src/main/java/cy/agorise/crystalwallet/manager/BitsharesAccountManager.java index a3871fb..0789568 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/manager/BitsharesAccountManager.java +++ b/app/src/main/java/cy/agorise/crystalwallet/manager/BitsharesAccountManager.java @@ -2,6 +2,7 @@ package cy.agorise.crystalwallet.manager; import android.annotation.SuppressLint; import android.content.Context; +import android.util.Log; import com.google.common.primitives.UnsignedLong; @@ -129,7 +130,7 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI long[] idAccount = db.cryptoNetAccountDao().insertCryptoNetAccount(grapheneAccount); grapheneAccount.setId(idAccount[0]); db.grapheneAccountInfoDao().insertGrapheneAccountInfo(new GrapheneAccountInfo(grapheneAccount)); - subscribeBitsharesAccount(grapheneAccount.getId(),grapheneAccount.getAccountId(),context); + //subscribeBitsharesAccount(grapheneAccount.getId(),grapheneAccount.getAccountId(),context); } @Override @@ -147,7 +148,7 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI CrystalDatabase db = CrystalDatabase.getAppDatabase(context); db.cryptoNetAccountDao().insertCryptoNetAccount(grapheneAccount); db.grapheneAccountInfoDao().insertGrapheneAccountInfo(new GrapheneAccountInfo(grapheneAccount)); - subscribeBitsharesAccount(grapheneAccount.getId(),grapheneAccount.getAccountId(),context); + //subscribeBitsharesAccount(grapheneAccount.getId(),grapheneAccount.getAccountId(),context); } @Override @@ -159,7 +160,7 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI CrystalDatabase db = CrystalDatabase.getAppDatabase(context); db.cryptoNetAccountDao().insertCryptoNetAccount(grapheneAccount); db.grapheneAccountInfoDao().insertGrapheneAccountInfo(new GrapheneAccountInfo(grapheneAccount)); - subscribeBitsharesAccount(grapheneAccount.getId(), grapheneAccount.getAccountId(), context); + //subscribeBitsharesAccount(grapheneAccount.getId(), grapheneAccount.getAccountId(), context); } } } From 037787afd0e76ea478bb6e1c277891bc8740ecd3 Mon Sep 17 00:00:00 2001 From: Javier Varona Date: Mon, 24 Sep 2018 22:10:43 -0400 Subject: [PATCH 03/39] - Added loading dialog when sending. - Now the send dialog closes after sending the funds successfully --- .../fragments/SendTransactionFragment.java | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/cy/agorise/crystalwallet/fragments/SendTransactionFragment.java b/app/src/main/java/cy/agorise/crystalwallet/fragments/SendTransactionFragment.java index ae2f4fb..d0ece8c 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/fragments/SendTransactionFragment.java +++ b/app/src/main/java/cy/agorise/crystalwallet/fragments/SendTransactionFragment.java @@ -36,6 +36,7 @@ import android.widget.ImageView; import android.widget.ScrollView; import android.widget.Spinner; import android.widget.TextView; +import android.widget.Toast; import com.google.zxing.BarcodeFormat; import com.google.zxing.Result; @@ -56,6 +57,7 @@ import butterknife.OnClick; import butterknife.OnItemSelected; import butterknife.OnTextChanged; import cy.agorise.crystalwallet.R; +import cy.agorise.crystalwallet.dialogs.material.CrystalDialog; import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequestListener; import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequests; import cy.agorise.crystalwallet.requestmanagers.ValidateBitsharesSendRequest; @@ -131,7 +133,10 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat private FloatingActionButton fabSend; private AlertDialog.Builder builder; - + /* + Dialog for loading + */ + private CrystalDialog crystalDialog; public static SendTransactionFragment newInstance(long cryptoNetAccountId) { SendTransactionFragment f = new SendTransactionFragment(); @@ -408,6 +413,8 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat @OnClick(R.id.btnSend) public void sendTransaction(){ + final SendTransactionFragment thisFragment = this; + if (this.sendTransactionValidator.isValid()) { CryptoNetAccount fromAccountSelected = (CryptoNetAccount) spFrom.getItems().get(spFrom.getSelectedIndex()); @@ -439,13 +446,26 @@ public class SendTransactionFragment extends DialogFragment implements UIValidat public void onCarryOut() { if (sendRequest.getStatus().equals(ValidateBitsharesSendRequest.StatusCode.SUCCEEDED)){ try { - this.finalize(); + crystalDialog.dismiss(); + thisFragment.dismiss(); + //thisFragment.finalize(); } catch (Throwable throwable) { throwable.printStackTrace(); } + } else { + Toast.makeText(getContext(), getContext().getString(R.string.unable_to_send_amount), Toast.LENGTH_LONG); } } }); + + /* + * Show loading dialog + * */ + crystalDialog = new CrystalDialog((Activity) getContext()); + crystalDialog.setText("Sending"); + crystalDialog.progress(); + crystalDialog.show(); + CryptoNetInfoRequests.getInstance().addRequest(sendRequest); } } From 6eab51c89f3af6ba90cedd6982109ecd50315cbe Mon Sep 17 00:00:00 2001 From: Javier Varona Date: Wed, 26 Sep 2018 22:45:09 -0400 Subject: [PATCH 04/39] - Fixed string "infinity" in equivalent totals when the equivalence value of a currency is 0 - Added equivalent currency name in the cryptonet equivalent totals --- .../views/CryptoCoinBalanceViewHolder.java | 19 +++++++++++++------ .../views/CryptoNetBalanceViewHolder.java | 17 ++++++++++++++++- app/src/main/res/layout/send_transaction.xml | 2 +- 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/cy/agorise/crystalwallet/views/CryptoCoinBalanceViewHolder.java b/app/src/main/java/cy/agorise/crystalwallet/views/CryptoCoinBalanceViewHolder.java index 954933b..fbab252 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/views/CryptoCoinBalanceViewHolder.java +++ b/app/src/main/java/cy/agorise/crystalwallet/views/CryptoCoinBalanceViewHolder.java @@ -105,12 +105,19 @@ public class CryptoCoinBalanceViewHolder extends RecyclerView.ViewHolder { public void onChanged(@Nullable CryptoCurrencyEquivalence cryptoCurrencyEquivalence) { if (cryptoCurrencyEquivalence != null) { CryptoCurrency toCurrency = CrystalDatabase.getAppDatabase(context).cryptoCurrencyDao().getById(cryptoCurrencyEquivalence.getFromCurrencyId()); - double equivalentValue = (balance.getBalance() / Math.pow(10, currencyFrom.getPrecision())) / - (cryptoCurrencyEquivalence.getValue() / Math.pow(10, toCurrency.getPrecision())); - String equivalenceString = String.format( - "%.2f", - equivalentValue - ); + double equivalentValue = 0; + String equivalenceString = ""; + if (cryptoCurrencyEquivalence.getValue() > 0) { + equivalentValue = (balance.getBalance() / Math.pow(10, currencyFrom.getPrecision())) / + (cryptoCurrencyEquivalence.getValue() / Math.pow(10, toCurrency.getPrecision())); + equivalenceString = String.format( + "%.2f", + equivalentValue + ); + } else { + equivalentValue = 0; + equivalenceString = "0"; + } cryptoNetBalanceViewHolder.setEquivalentBalance(balance,equivalentValue); cryptoCoinBalanceEquivalence.setText( diff --git a/app/src/main/java/cy/agorise/crystalwallet/views/CryptoNetBalanceViewHolder.java b/app/src/main/java/cy/agorise/crystalwallet/views/CryptoNetBalanceViewHolder.java index 4a2043c..1596577 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/views/CryptoNetBalanceViewHolder.java +++ b/app/src/main/java/cy/agorise/crystalwallet/views/CryptoNetBalanceViewHolder.java @@ -3,6 +3,7 @@ package cy.agorise.crystalwallet.views; import android.app.Activity; import android.content.Context; import android.content.Intent; +import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.arch.lifecycle.LifecycleOwner; import android.arch.lifecycle.LiveData; @@ -24,12 +25,14 @@ import butterknife.ButterKnife; import butterknife.OnClick; import cy.agorise.crystalwallet.R; import cy.agorise.crystalwallet.activities.SendTransactionActivity; +import cy.agorise.crystalwallet.dao.CrystalDatabase; import cy.agorise.crystalwallet.fragments.ReceiveTransactionFragment; import cy.agorise.crystalwallet.fragments.SendTransactionFragment; import cy.agorise.crystalwallet.models.CryptoCoinBalance; import cy.agorise.crystalwallet.models.CryptoCoinTransaction; import cy.agorise.crystalwallet.models.CryptoCurrencyEquivalence; import cy.agorise.crystalwallet.models.CryptoNetBalance; +import cy.agorise.crystalwallet.models.GeneralSetting; import cy.agorise.crystalwallet.viewmodels.CryptoCoinBalanceListViewModel; /** @@ -86,6 +89,8 @@ public class CryptoNetBalanceViewHolder extends RecyclerView.ViewHolder { */ private Fragment fragment; + String preferredCurrency = ""; + public CryptoNetBalanceViewHolder(View itemView, Fragment fragment) { super(itemView); //-1 represents a crypto net account not loaded yet @@ -114,6 +119,16 @@ public class CryptoNetBalanceViewHolder extends RecyclerView.ViewHolder { }); this.fragment = fragment; this.context = itemView.getContext(); + + LiveData preferedCurrencySetting = CrystalDatabase.getAppDatabase(this.context).generalSettingDao().getByName(GeneralSetting.SETTING_NAME_PREFERRED_CURRENCY); + + preferedCurrencySetting.observe((LifecycleOwner)this.itemView.getContext(), new Observer() { + @Override + public void onChanged(@Nullable GeneralSetting generalSetting) { + preferredCurrency = generalSetting.getValue(); + } + }); + } public void clear(){ @@ -179,7 +194,7 @@ public class CryptoNetBalanceViewHolder extends RecyclerView.ViewHolder { totalEquivalent += nextEquivalent; } - this.cryptoNetEquivalentTotal.setText(""+totalEquivalent); + this.cryptoNetEquivalentTotal.setText(""+totalEquivalent+" "+preferredCurrency); } } diff --git a/app/src/main/res/layout/send_transaction.xml b/app/src/main/res/layout/send_transaction.xml index 028d967..584e511 100644 --- a/app/src/main/res/layout/send_transaction.xml +++ b/app/src/main/res/layout/send_transaction.xml @@ -186,7 +186,7 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/tvMemoError" /> - Date: Thu, 27 Sep 2018 22:19:19 -0400 Subject: [PATCH 05/39] Change Insight api classes to handle multiple address and to adapt to the new architecture. Added Bitshares Account Manager to handle all txi response TODOs: Add cache data to handle incoming transaction and balances --- .../apigenerator/InsightApiGenerator.java | 55 +++++-- .../insightapi/BroadcastTransaction.java | 41 +++--- .../insightapi/GetTransactionByAddress.java | 136 +++--------------- .../insightapi/GetTransactionData.java | 2 +- .../manager/BitsharesAccountManager.java | 2 - .../manager/GeneralAccountManager.java | 111 ++++++++++++++ 6 files changed, 191 insertions(+), 156 deletions(-) diff --git a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/InsightApiGenerator.java b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/InsightApiGenerator.java index 54fe88e..35b0f71 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/InsightApiGenerator.java +++ b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/InsightApiGenerator.java @@ -13,33 +13,62 @@ import cy.agorise.crystalwallet.network.CryptoNetManager; public class InsightApiGenerator { - private static HashMap broadcaster = new HashMap(); private static HashMap transactionGetters = new HashMap(); private static HashMap transacitonFollowers = new HashMap(); + /** + * Fecth all the transaciton for a giving address + * @param cryptoNet the crypto net of the address + * @param address The address String + * @param request the request api to response + * @param subscribe If needs to follow the address (Real time) + */ public static void getTransactionFromAddress(CryptoNet cryptoNet, String address, - ApiRequest request, Context context, - boolean subscribe){ + ApiRequest request, boolean subscribe){ if(!transactionGetters.containsKey(cryptoNet)){ - //TODO change this line - transactionGetters.put(cryptoNet,new GetTransactionByAddress(null,CryptoNetManager.getURL(cryptoNet),context)); + transactionGetters.put(cryptoNet,new GetTransactionByAddress(cryptoNet,CryptoNetManager.getURL(cryptoNet))); } - + transactionGetters.get(cryptoNet).addAddress(address); + //TODO process request } + /** + * Funciton used for unconfirmed transactions + * @param cryptoNet + * @param txid + * @param context + */ public static void followTransaction(CryptoNet cryptoNet, String txid, Context context){ } - public static void broadcastTransaction(CryptoNet cryptoNet, String rawtx, ApiRequest request){ - if(!broadcaster.containsKey(cryptoNet)){ - //TODO change to multiple broadcast - broadcaster.put(cryptoNet,new BroadcastTransaction(rawtx,null, - CryptoNetManager.getURL(cryptoNet),null)); - broadcaster.get(cryptoNet).start(); - } + /** + * Broadcast an insight api transaction + * @param cryptoNet The cryptoNet of the transaction + * @param rawtx the transaction to be broadcasted + */ + public static void broadcastTransaction(CryptoNet cryptoNet, String rawtx, final ApiRequest request){ + BroadcastTransaction bTransaction = new BroadcastTransaction(rawtx, CryptoNetManager.getURL(cryptoNet), "api", new BroadcastTransaction.BroadCastTransactionListener() { + @Override + public void onSuccess() { + request.getListener().success(true,request.getId()); + } + + @Override + public void onFailure(String msg) { + request.getListener().fail(request.getId()); + } + + @Override + public void onConnecitonFailure() { + request.getListener().fail(request.getId()); + } + }); } + /** + * Fetch the estimated fee for a transaction + */ public static void getEstimateFee(CryptoNet cryptoNet, final ApiRequest request){ GetEstimateFee.getEstimateFee(CryptoNetManager.getURL(cryptoNet), new GetEstimateFee.estimateFeeListener() { @Override diff --git a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/BroadcastTransaction.java b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/BroadcastTransaction.java index 1736b6a..c4fa9cc 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/BroadcastTransaction.java +++ b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/BroadcastTransaction.java @@ -22,29 +22,21 @@ public class BroadcastTransaction extends Thread implements Callback { * The serviceGenerator to call */ private InsightApiServiceGenerator mServiceGenerator; - /** - * This app context, used to save on the DB - */ - private Context mContext; - /** - * The account who sign the transaction - */ - private GeneralCoinAccount mAccount; - private String serverUrl; + private String mPath; + + private BroadCastTransactionListener listener; /** * Basic Consturctor * @param RawTx The RawTX in Hex String - * @param account The account who signs the transaction - * @param context This app context + * */ - public BroadcastTransaction(String RawTx, GeneralCoinAccount account, String serverUrl, Context context){ - this.serverUrl = serverUrl; + public BroadcastTransaction(String RawTx, String serverUrl, String path, BroadCastTransactionListener listener){ this.mServiceGenerator = new InsightApiServiceGenerator(serverUrl); - this.mContext = context; this.mRawTx = RawTx; - this.mAccount = account; + this.listener = listener; + this.mPath = path; } /** @@ -54,13 +46,9 @@ public class BroadcastTransaction extends Thread implements Callback { @Override public void onResponse(Call call, Response response) { if (response.isSuccessful()) { - //TODO invalidated send - //TODO call getTransactionData - GetTransactionData trData = new GetTransactionData(response.body().txid,this.mAccount, this.serverUrl, this.mContext); - trData.start(); + listener.onSuccess(); } else { - System.out.println("SENDTEST: not succesful " + response.message()); - //TODO change how to handle invalid transaction + listener.onFailure(response.message()); } } @@ -69,8 +57,7 @@ public class BroadcastTransaction extends Thread implements Callback { */ @Override public void onFailure(Call call, Throwable t) { - //TODO change how to handle invalid transaction - System.out.println("SENDTEST: sendError " + t.getMessage() ); + listener.onConnecitonFailure(); } /** @@ -79,7 +66,13 @@ public class BroadcastTransaction extends Thread implements Callback { @Override public void run() { InsightApiService service = this.mServiceGenerator.getService(InsightApiService.class); - Call broadcastTransaction = service.broadcastTransaction(InsightApiConstants.getPath(this.mAccount.getCryptoCoin()),this.mRawTx); + Call broadcastTransaction = service.broadcastTransaction(this.mPath,this.mRawTx); broadcastTransaction.enqueue(this); } + + public interface BroadCastTransactionListener{ + void onSuccess(); + void onFailure(String msg); + void onConnecitonFailure(); + } } diff --git a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/GetTransactionByAddress.java b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/GetTransactionByAddress.java index 8d92b39..853d1f7 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/GetTransactionByAddress.java +++ b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/GetTransactionByAddress.java @@ -3,14 +3,20 @@ package cy.agorise.crystalwallet.apigenerator.insightapi; import android.content.Context; import android.util.Log; +import com.idescout.sql.SqlScoutServer; + import java.util.ArrayList; import java.util.Date; import java.util.List; +import cy.agorise.crystalwallet.apigenerator.InsightApiGenerator; import cy.agorise.crystalwallet.apigenerator.insightapi.models.AddressTxi; import cy.agorise.crystalwallet.apigenerator.insightapi.models.Txi; import cy.agorise.crystalwallet.apigenerator.insightapi.models.Vin; import cy.agorise.crystalwallet.apigenerator.insightapi.models.Vout; +import cy.agorise.crystalwallet.enums.CryptoCoin; +import cy.agorise.crystalwallet.enums.CryptoNet; +import cy.agorise.crystalwallet.models.CryptoCurrency; import cy.agorise.crystalwallet.models.GTxIO; import cy.agorise.crystalwallet.models.GeneralCoinAccount; import cy.agorise.crystalwallet.models.GeneralCoinAddress; @@ -25,43 +31,34 @@ import retrofit2.Response; */ public class GetTransactionByAddress extends Thread implements Callback { - /** - * The account to be query - */ - private GeneralCoinAccount mAccount; /** * The list of address to query */ - private List mAddresses = new ArrayList<>(); + private List mAddresses = new ArrayList<>(); /** * The serviceGenerator to call */ private InsightApiServiceGenerator mServiceGenerator; - /** - * This app context, used to save on the DB - */ - private Context mContext; private String serverUrl; + private CryptoNet cryptoNet; + private boolean inProcess = false; /** * Basic consturcotr - * @param account The account to be query - * @param context This app context */ - public GetTransactionByAddress(GeneralCoinAccount account, String serverUrl, Context context) { + public GetTransactionByAddress(CryptoNet cryptoNet, String serverUrl) { + this.cryptoNet = cryptoNet; this.serverUrl = serverUrl; - this.mAccount = account; this.mServiceGenerator = new InsightApiServiceGenerator(serverUrl); - this.mContext = context; } /** * add an address to be query * @param address the address to be query */ - public void addAddress(GeneralCoinAddress address) { + public void addAddress(String address) { this.mAddresses.add(address); } @@ -73,110 +70,15 @@ public class GetTransactionByAddress extends Thread implements Callback call, Response response) { + inProcess = false; if (response.isSuccessful()) { boolean changed = false; AddressTxi addressTxi = response.body(); for (Txi txi : addressTxi.items) { - GeneralCoinAccount tempAccount = null; - GeneralTransaction transaction = new GeneralTransaction(); - transaction.setAccount(this.mAccount); - transaction.setTxid(txi.txid); - transaction.setBlock(txi.blockheight); - transaction.setDate(new Date(txi.time * 1000)); - transaction.setFee((long) (txi.fee * Math.pow(10,this.mAccount.getCryptoCoin().getPrecision()))); - transaction.setConfirm(txi.confirmations); - transaction.setType(this.mAccount.getCryptoCoin()); - transaction.setBlockHeight(txi.blockheight); - - for (Vin vin : txi.vin) { - GTxIO input = new GTxIO(); - input.setAmount((long) (vin.value * Math.pow(10,this.mAccount.getCryptoCoin().getPrecision()))); - input.setTransaction(transaction); - input.setOut(true); - input.setType(this.mAccount.getCryptoCoin()); - String addr = vin.addr; - input.setAddressString(addr); - input.setIndex(vin.n); - input.setScriptHex(vin.scriptSig.hex); - input.setOriginalTxid(vin.txid); - for (GeneralCoinAddress address : this.mAddresses) { - if (address.getAddressString(this.mAccount.getNetworkParam()).equals(addr)) { - input.setAddress(address); - tempAccount = address.getAccount(); - - if (!address.hasTransactionOutput(input, this.mAccount.getNetworkParam())) { - address.getTransactionOutput().add(input); - } - changed = true; - } - } - transaction.getTxInputs().add(input); - } - - for (Vout vout : txi.vout) { - if(vout.scriptPubKey.addresses == null || vout.scriptPubKey.addresses.length <= 0){ - // The address is null, this must be a memo - String hex = vout.scriptPubKey.hex; - int opReturnIndex = hex.indexOf("6a"); - if(opReturnIndex >= 0) { - byte[] memoBytes = new byte[Integer.parseInt(hex.substring(opReturnIndex+2,opReturnIndex+4),16)]; - for(int i = 0; i < memoBytes.length;i++){ - memoBytes[i] = Byte.parseByte(hex.substring(opReturnIndex+4+(i*2),opReturnIndex+6+(i*2)),16); - } - transaction.setMemo(new String(memoBytes)); - } - }else { - GTxIO output = new GTxIO(); - output.setAmount((long) (vout.value * Math.pow(10, this.mAccount.getCryptoCoin().getPrecision()))); - output.setTransaction(transaction); - output.setOut(false); - output.setType(this.mAccount.getCryptoCoin()); - String addr = vout.scriptPubKey.addresses[0]; - output.setAddressString(addr); - output.setIndex(vout.n); - output.setScriptHex(vout.scriptPubKey.hex); - for (GeneralCoinAddress address : this.mAddresses) { - if (address.getAddressString(this.mAccount.getNetworkParam()).equals(addr)) { - output.setAddress(address); - tempAccount = address.getAccount(); - - if (!address.hasTransactionInput(output, this.mAccount.getNetworkParam())) { - address.getTransactionInput().add(output); - } - changed = true; - } - } - - transaction.getTxOutputs().add(output); - } - } - if(txi.txlock && txi.confirmations< this.mAccount.getCryptoNet().getConfirmationsNeeded()){ - transaction.setConfirm(this.mAccount.getCryptoNet().getConfirmationsNeeded()); - } - //TODO database - /*SCWallDatabase db = new SCWallDatabase(this.mContext); - long idTransaction = db.getGeneralTransactionId(transaction); - if (idTransaction == -1) { - db.putGeneralTransaction(transaction); - } else { - transaction.setId(idTransaction); - db.updateGeneralTransaction(transaction); - }*/ - - if (tempAccount != null && transaction.getConfirm() < this.mAccount.getCryptoNet().getConfirmationsNeeded()) { - new GetTransactionData(transaction.getTxid(), tempAccount, this.serverUrl, this.mContext, true).start(); - } - for (GeneralCoinAddress address : this.mAddresses) { - if (address.updateTransaction(transaction)) { - break; - } - } + //TODO call manager } - if(changed) { - this.mAccount.balanceChange(); - } } } @@ -187,6 +89,7 @@ public class GetTransactionByAddress extends Thread implements Callback call, Throwable t) { + inProcess = false; Log.e("GetTransactionByAddress", "Error in json format"); } @@ -195,14 +98,15 @@ public class GetTransactionByAddress extends Thread implements Callback 0) { + if (this.mAddresses.size() > 0 && !inProcess) { + inProcess = true; StringBuilder addressToQuery = new StringBuilder(); - for (GeneralCoinAddress address : this.mAddresses) { - addressToQuery.append(address.getAddressString(this.mAccount.getNetworkParam())).append(","); + for (String address : this.mAddresses) { + addressToQuery.append(address).append(","); } addressToQuery.deleteCharAt(addressToQuery.length() - 1); InsightApiService service = this.mServiceGenerator.getService(InsightApiService.class); - Call addressTxiCall = service.getTransactionByAddress(InsightApiConstants.getPath(this.mAccount.getCryptoCoin()),addressToQuery.toString()); + Call addressTxiCall = service.getTransactionByAddress(this.serverUrl,addressToQuery.toString()); addressTxiCall.enqueue(this); } } diff --git a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/GetTransactionData.java b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/GetTransactionData.java index d50d5dc..e962cef 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/GetTransactionData.java +++ b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/insightapi/GetTransactionData.java @@ -84,7 +84,7 @@ public class GetTransactionData extends Thread implements Callback { } InsightApiService service = this.mServiceGenerator.getService(InsightApiService.class); - Call txiCall = service.getTransaction(InsightApiConstants.getPath(this.mAccount.getCryptoCoin()),this.mTxId); + Call txiCall = service.getTransaction(this.mServerUrl,this.mTxId); txiCall.enqueue(this); } diff --git a/app/src/main/java/cy/agorise/crystalwallet/manager/BitsharesAccountManager.java b/app/src/main/java/cy/agorise/crystalwallet/manager/BitsharesAccountManager.java index a3871fb..32a0591 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/manager/BitsharesAccountManager.java +++ b/app/src/main/java/cy/agorise/crystalwallet/manager/BitsharesAccountManager.java @@ -64,8 +64,6 @@ import cy.agorise.graphenej.operations.TransferOperationBuilder; */ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetInfoRequestsListener { - //private final static String BITSHARES_TESTNET_CHAIN_ID= "9cf6f255a208100d2bb275a3c52f4b1589b7ec9c9bfc2cb2a5fe6411295106d8"; - private final static String SIMPLE_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss"; private final static String DEFAULT_TIME_ZONE = "GMT"; diff --git a/app/src/main/java/cy/agorise/crystalwallet/manager/GeneralAccountManager.java b/app/src/main/java/cy/agorise/crystalwallet/manager/GeneralAccountManager.java index 1a4c6fa..ed2222c 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/manager/GeneralAccountManager.java +++ b/app/src/main/java/cy/agorise/crystalwallet/manager/GeneralAccountManager.java @@ -12,14 +12,21 @@ import org.bitcoinj.crypto.HDKeyDerivation; import org.bitcoinj.script.Script; import java.util.ArrayList; +import java.util.Date; import java.util.List; import cy.agorise.crystalwallet.apigenerator.ApiRequest; import cy.agorise.crystalwallet.apigenerator.ApiRequestListener; import cy.agorise.crystalwallet.apigenerator.InsightApiGenerator; import cy.agorise.crystalwallet.apigenerator.insightapi.BroadcastTransaction; +import cy.agorise.crystalwallet.apigenerator.insightapi.GetTransactionData; +import cy.agorise.crystalwallet.apigenerator.insightapi.models.Txi; +import cy.agorise.crystalwallet.apigenerator.insightapi.models.Vin; +import cy.agorise.crystalwallet.apigenerator.insightapi.models.Vout; +import cy.agorise.crystalwallet.enums.CryptoCoin; import cy.agorise.crystalwallet.models.CryptoNetAccount; import cy.agorise.crystalwallet.models.GTxIO; +import cy.agorise.crystalwallet.models.GeneralCoinAccount; import cy.agorise.crystalwallet.models.GeneralCoinAddress; import cy.agorise.crystalwallet.models.GeneralTransaction; import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequest; @@ -29,6 +36,8 @@ import cy.agorise.graphenej.Util; public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInfoRequestsListener { + CryptoCoin cryptoCoin; + @Override public void createAccountFromSeed(CryptoNetAccount account, ManagerRequest request, Context context) { @@ -49,6 +58,108 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf } + /** + * Class that process each transaction fetched by the insight api + * @param txi + */ + public void processTxi(Txi txi){ + + GeneralCoinAccount tempAccount = null; + GeneralTransaction transaction = new GeneralTransaction(); + //transaction.setAccount(this.mAccount); + transaction.setTxid(txi.txid); + transaction.setBlock(txi.blockheight); + transaction.setDate(new Date(txi.time * 1000)); + transaction.setFee((long) (txi.fee * Math.pow(10,cryptoCoin.getPrecision()))); + transaction.setConfirm(txi.confirmations); + transaction.setType(cryptoCoin); + transaction.setBlockHeight(txi.blockheight); + + for (Vin vin : txi.vin) { + GTxIO input = new GTxIO(); + input.setAmount((long) (vin.value * Math.pow(10,cryptoCoin.getPrecision()))); + input.setTransaction(transaction); + input.setOut(true); + input.setType(cryptoCoin); + String addr = vin.addr; + input.setAddressString(addr); + input.setIndex(vin.n); + input.setScriptHex(vin.scriptSig.hex); + input.setOriginalTxid(vin.txid); + /*for (GeneralCoinAddress address : this.mAddresses) { + if (address.getAddressString(this.mAccount.getNetworkParam()).equals(addr)) { + input.setAddress(address); + tempAccount = address.getAccount(); + + if (!address.hasTransactionOutput(input, this.mAccount.getNetworkParam())) { + address.getTransactionOutput().add(input); + } + } + }*/ + transaction.getTxInputs().add(input); + } + + for (Vout vout : txi.vout) { + if(vout.scriptPubKey.addresses == null || vout.scriptPubKey.addresses.length <= 0){ + // The address is null, this must be a memo + String hex = vout.scriptPubKey.hex; + int opReturnIndex = hex.indexOf("6a"); + if(opReturnIndex >= 0) { + byte[] memoBytes = new byte[Integer.parseInt(hex.substring(opReturnIndex+2,opReturnIndex+4),16)]; + for(int i = 0; i < memoBytes.length;i++){ + memoBytes[i] = Byte.parseByte(hex.substring(opReturnIndex+4+(i*2),opReturnIndex+6+(i*2)),16); + } + transaction.setMemo(new String(memoBytes)); + } + }else { + GTxIO output = new GTxIO(); + output.setAmount((long) (vout.value * Math.pow(10, cryptoCoin.getPrecision()))); + output.setTransaction(transaction); + output.setOut(false); + output.setType(cryptoCoin); + String addr = vout.scriptPubKey.addresses[0]; + output.setAddressString(addr); + output.setIndex(vout.n); + output.setScriptHex(vout.scriptPubKey.hex); + /*for (GeneralCoinAddress address : this.mAddresses) { + if (address.getAddressString(this.mAccount.getNetworkParam()).equals(addr)) { + output.setAddress(address); + tempAccount = address.getAccount(); + + if (!address.hasTransactionInput(output, this.mAccount.getNetworkParam())) { + address.getTransactionInput().add(output); + } + changed = true; + } + }*/ + + transaction.getTxOutputs().add(output); + } + } + if(txi.txlock && txi.confirmations< cryptoCoin.getCryptoNet().getConfirmationsNeeded()){ + transaction.setConfirm(cryptoCoin.getCryptoNet().getConfirmationsNeeded()); + } + //TODO database + /*SCWallDatabase db = new SCWallDatabase(this.mContext); + long idTransaction = db.getGeneralTransactionId(transaction); + if (idTransaction == -1) { + db.putGeneralTransaction(transaction); + } else { + transaction.setId(idTransaction); + db.updateGeneralTransaction(transaction); + }*/ + + /*if (tempAccount != null && transaction.getConfirm() < this.mAccount.getCryptoNet().getConfirmationsNeeded()) { + InsightApiGenerator.followTransaction(); + new GetTransactionData(transaction.getTxid(), tempAccount, this.serverUrl, this.mContext, true).start(); + } + for (GeneralCoinAddress address : this.mAddresses) { + if (address.updateTransaction(transaction)) { + break; + } + }*/ + } + public void send(final GeneralAccountSendRequest request){ //TODO check server connection //TODO validate to address From 17c61b12a7fa2b641618a99992901f4ab9a1fc92 Mon Sep 17 00:00:00 2001 From: dtvv Date: Sat, 29 Sep 2018 15:46:35 -0500 Subject: [PATCH 06/39] Adjust kotlin puglin version to compile proyect --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 635a6c8..a977936 100644 --- a/build.gradle +++ b/build.gradle @@ -8,9 +8,9 @@ buildscript { } ext.kotlin_version = '1.2.51' dependencies { - classpath 'com.android.tools.build:gradle:3.1.4' + classpath 'com.android.tools.build:gradle:3.2.0' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.60" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.51" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } From 0fc4392a525075e4a8ac201157de8b4636bc32b5 Mon Sep 17 00:00:00 2001 From: dtvv Date: Sat, 29 Sep 2018 16:00:13 -0500 Subject: [PATCH 07/39] Adjust kotlin puglin version to compile proyect 2 --- app/build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/build.gradle b/app/build.gradle index 1ed2db8..f8fa21f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,8 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-kapt' // add this line + kapt { generateStubs = true From 31f809048f3dc548b11be9719b39f2f0689f8c1c Mon Sep 17 00:00:00 2001 From: hvarona Date: Sat, 29 Sep 2018 20:51:59 -0400 Subject: [PATCH 08/39] Updated Faucet --- .../crystalwallet/apigenerator/BitsharesFaucetApiGenerator.java | 2 +- .../crystalwallet/application/constant/BitsharesConstant.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/BitsharesFaucetApiGenerator.java b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/BitsharesFaucetApiGenerator.java index 5b2b6d2..7ce7f5e 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/BitsharesFaucetApiGenerator.java +++ b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/BitsharesFaucetApiGenerator.java @@ -219,7 +219,7 @@ public abstract class BitsharesFaucetApiGenerator { public interface IWebService { @Headers({"Content-Type: application/json"}) - @POST("/faucet/api/v1/accounts") + @POST("/api/v1/accounts") Call getReg(@Body Map params); } diff --git a/app/src/main/java/cy/agorise/crystalwallet/application/constant/BitsharesConstant.java b/app/src/main/java/cy/agorise/crystalwallet/application/constant/BitsharesConstant.java index 0b807fa..6783404 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/application/constant/BitsharesConstant.java +++ b/app/src/main/java/cy/agorise/crystalwallet/application/constant/BitsharesConstant.java @@ -32,7 +32,7 @@ public abstract class BitsharesConstant { //testnet faucet //public final static String FAUCET_URL = "http://185.208.208.147:5010"; - public final static String FAUCET_URL = "https://de.palmpay.io"; + public final static String FAUCET_URL = "https://faucet.palmpay.io"; public final static String EQUIVALENT_URL = "wss://bitshares.openledger.info/ws"; public final static BitsharesAsset[] SMARTCOINS = new BitsharesAsset[]{ From ad0c14e3891c33988f9bd6a5bf4f43ade5a8446c Mon Sep 17 00:00:00 2001 From: dtvv Date: Sat, 29 Sep 2018 20:51:47 -0500 Subject: [PATCH 09/39] Prevent null pointer exception --- .../crystalwallet/views/CryptoNetBalanceViewHolder.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/cy/agorise/crystalwallet/views/CryptoNetBalanceViewHolder.java b/app/src/main/java/cy/agorise/crystalwallet/views/CryptoNetBalanceViewHolder.java index 1596577..4a2e126 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/views/CryptoNetBalanceViewHolder.java +++ b/app/src/main/java/cy/agorise/crystalwallet/views/CryptoNetBalanceViewHolder.java @@ -125,7 +125,9 @@ public class CryptoNetBalanceViewHolder extends RecyclerView.ViewHolder { preferedCurrencySetting.observe((LifecycleOwner)this.itemView.getContext(), new Observer() { @Override public void onChanged(@Nullable GeneralSetting generalSetting) { - preferredCurrency = generalSetting.getValue(); + if(generalSetting != null){ + preferredCurrency = generalSetting.getValue(); + } } }); From d86fe35a6bd5b0c55692c19582f948577bebcaa7 Mon Sep 17 00:00:00 2001 From: dtvv Date: Sat, 29 Sep 2018 22:21:15 -0500 Subject: [PATCH 10/39] When you create a new account the cancel button does not have to show, only when you check the brainkey --- .../crystalwallet/activities/BackupSeedActivity.java | 11 +++++++++++ .../crystalwallet/activities/CreateSeedActivity.kt | 1 + .../crystalwallet/activities/IntroActivity.java | 2 ++ .../res/layout/fragment_import_account_options.xml | 5 +++-- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/cy/agorise/crystalwallet/activities/BackupSeedActivity.java b/app/src/main/java/cy/agorise/crystalwallet/activities/BackupSeedActivity.java index 52fef67..999d66a 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/activities/BackupSeedActivity.java +++ b/app/src/main/java/cy/agorise/crystalwallet/activities/BackupSeedActivity.java @@ -10,6 +10,7 @@ import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; +import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; @@ -34,6 +35,7 @@ public class BackupSeedActivity extends AppCompatActivity { @BindView(R.id.btnCopy) Button btnCopy; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -41,6 +43,15 @@ public class BackupSeedActivity extends AppCompatActivity { ButterKnife.bind(this); + /* + * If comes from new account creation hide the cancel button + * */ + Bundle b = getIntent().getExtras(); + boolean newAccount = b.getBoolean("newAccount"); + if(newAccount ){ + btnOk.setVisibility(View.INVISIBLE); + } + long seedId = getIntent().getLongExtra("SEED_ID",-1); if (seedId > -1) { diff --git a/app/src/main/java/cy/agorise/crystalwallet/activities/CreateSeedActivity.kt b/app/src/main/java/cy/agorise/crystalwallet/activities/CreateSeedActivity.kt index 1f3f535..fdeaf06 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/activities/CreateSeedActivity.kt +++ b/app/src/main/java/cy/agorise/crystalwallet/activities/CreateSeedActivity.kt @@ -200,6 +200,7 @@ class CreateSeedActivity : CustomActivity() { val intent = Intent(applicationContext, BackupSeedActivity::class.java) intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK intent.putExtra("SEED_ID", accountSeed.id) + intent.putExtra("newAccount", true) startActivity(intent) } else if (request.status == ValidateCreateBitsharesAccountRequest.StatusCode.ACCOUNT_EXIST) { diff --git a/app/src/main/java/cy/agorise/crystalwallet/activities/IntroActivity.java b/app/src/main/java/cy/agorise/crystalwallet/activities/IntroActivity.java index f0e00d3..555ca66 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/activities/IntroActivity.java +++ b/app/src/main/java/cy/agorise/crystalwallet/activities/IntroActivity.java @@ -2,9 +2,11 @@ package cy.agorise.crystalwallet.activities; import android.arch.lifecycle.ViewModelProviders; import android.content.Intent; +import android.content.pm.PackageManager; import android.media.MediaPlayer; import android.os.Bundle; import android.support.annotation.Nullable; +import android.support.v4.app.ActivityCompat; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AppCompatActivity; diff --git a/app/src/main/res/layout/fragment_import_account_options.xml b/app/src/main/res/layout/fragment_import_account_options.xml index dc12e70..0ed744c 100644 --- a/app/src/main/res/layout/fragment_import_account_options.xml +++ b/app/src/main/res/layout/fragment_import_account_options.xml @@ -32,9 +32,10 @@ android:textColor="@color/white" android:textSize="18sp" android:textStyle="bold" - app:layout_constraintTop_toBottomOf="@id/tvDescription" + app:layout_constraintEnd_toEndOf="@id/tvDescription" + app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="@id/tvDescription" - app:layout_constraintEnd_toEndOf="@id/tvDescription"/> + app:layout_constraintTop_toBottomOf="@id/tvDescription" />