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