From 51498192c6154a077d972fae1df6046deb52e8e1 Mon Sep 17 00:00:00 2001 From: hvarona Date: Wed, 31 Oct 2018 23:14:13 -0400 Subject: [PATCH] Create and import Bitcoin Like Account request implementation --- .../apigenerator/InsightApiGenerator.java | 15 ++- .../insightapi/GetTransactionByAddress.java | 16 ++- .../crystalwallet/dao/BitcoinAddressDao.java | 3 + .../manager/GeneralAccountManager.java | 108 +++++++++++++++++- 4 files changed, 133 insertions(+), 9 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 1e647a9..f4536ee 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/InsightApiGenerator.java +++ b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/InsightApiGenerator.java @@ -22,12 +22,17 @@ public class InsightApiGenerator { * @param address The address String * @param subscribe If needs to follow the address (Real time) */ - public static void getTransactionFromAddress(CryptoCoin cryptoCoin, String address, boolean subscribe){ - if(!transactionGetters.containsKey(cryptoCoin)){ + public static void getTransactionFromAddress(CryptoCoin cryptoCoin, String address, boolean subscribe, HasTransactionListener listener){ + /*if(!transactionGetters.containsKey(cryptoCoin)){ transactionGetters.put(cryptoCoin,new GetTransactionByAddress(cryptoCoin,CryptoNetManager.getURL(cryptoCoin.getCryptoNet()),PATH)); } transactionGetters.get(cryptoCoin).addAddress(address); - transactionGetters.get(cryptoCoin).start(); + transactionGetters.get(cryptoCoin).start();*/ + + GetTransactionByAddress transByAddr = new GetTransactionByAddress(cryptoCoin,CryptoNetManager.getURL(cryptoCoin.getCryptoNet()),PATH); + transByAddr.addAddress(address); + transByAddr.start(); + if(subscribe){ if(!transactionFollowers.containsKey(cryptoCoin)){ transactionFollowers.put(cryptoCoin,new AddressesActivityWatcher(CryptoNetManager.getURL(cryptoCoin.getCryptoNet()),PATH,cryptoCoin)); @@ -80,4 +85,8 @@ public class InsightApiGenerator { } }); } + + public interface HasTransactionListener{ + public void hasTransaction(boolean value); + } } 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 f14c392..ed0c1c2 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 @@ -5,6 +5,7 @@ import android.util.Log; import java.util.ArrayList; 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.enums.CryptoCoin; @@ -35,14 +36,17 @@ public class GetTransactionByAddress extends Thread implements Callback call, Response response) { inProcess = false; if (response.isSuccessful()) { - boolean changed = false; AddressTxi addressTxi = response.body(); + if(listener != null) { + if (addressTxi.items.length > 0 ) { + listener.hasTransaction(true); + }else{ + listener.hasTransaction(false); + } + } for (Txi txi : addressTxi.items) { GeneralAccountManager.getAccountManager(this.cryptoNet).processTxi(txi); } + }else{ + listener.hasTransaction(false); } } diff --git a/app/src/main/java/cy/agorise/crystalwallet/dao/BitcoinAddressDao.java b/app/src/main/java/cy/agorise/crystalwallet/dao/BitcoinAddressDao.java index 51088c6..357fba4 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/dao/BitcoinAddressDao.java +++ b/app/src/main/java/cy/agorise/crystalwallet/dao/BitcoinAddressDao.java @@ -28,6 +28,9 @@ public interface BitcoinAddressDao { @Query("SELECT * FROM bitcoin_address ba WHERE ba.address_index = :index and ba.is_change = 'true'") BitcoinAddress getChangeByIndex(long index); + @Query("SELECT * FROM bitcoin_address ba WHERE ba.address_index = :index and ba.is_change = 'false'") + BitcoinAddress getExternalByIndex(long index); + @Query("SELECT MAX(ba.address_index) FROM bitcoin_address ba WHERE ba.account_id = :accountId and ba.is_change = 'true' ") long getLastChangeAddress(long accountId); 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 01ad0e6..c051b8b 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/manager/GeneralAccountManager.java +++ b/app/src/main/java/cy/agorise/crystalwallet/manager/GeneralAccountManager.java @@ -25,6 +25,7 @@ import cy.agorise.crystalwallet.apigenerator.InsightApiGenerator; 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.dao.BitcoinAddressDao; import cy.agorise.crystalwallet.dao.CrystalDatabase; import cy.agorise.crystalwallet.enums.CryptoCoin; import cy.agorise.crystalwallet.models.AccountSeed; @@ -77,18 +78,69 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf } @Override - public void loadAccountFromDB(CryptoNetAccount account, Context context) { + public void loadAccountFromDB(final CryptoNetAccount account, Context context) { + final CrystalDatabase db = CrystalDatabase.getAppDatabase(context); + AccountSeed seed = db.accountSeedDao().findById(account.getSeedId()); + DeterministicKey purposeKey = HDKeyDerivation.deriveChildKey((DeterministicKey) seed.getPrivateKey(), + new ChildNumber(44, true)); + DeterministicKey coinKey = HDKeyDerivation.deriveChildKey(purposeKey, + new ChildNumber(cryptoCoin.getCoinNumber(), true)); + DeterministicKey accountKey = HDKeyDerivation.deriveChildKey(coinKey, + new ChildNumber(account.getAccountIndex(), true)); + final DeterministicKey externalKey = HDKeyDerivation.deriveChildKey(accountKey, + new ChildNumber(0, false)); + final DeterministicKey changeKey = HDKeyDerivation.deriveChildKey(accountKey, + new ChildNumber(1, false)); + + long indexExternal = db.bitcoinAddressDao().getLastExternalAddress(account.getId()); + if(indexExternal > 0){ + for(int i = 0; i < indexExternal;i++){ + BitcoinAddress address = db.bitcoinAddressDao().getExternalByIndex(i); + InsightApiGenerator.getTransactionFromAddress(cryptoCoin,address.getAddress(),true,null); + } + }else { + ECKey externalAddrKey = HDKeyDerivation.deriveChildKey(externalKey, new ChildNumber((int) 0, true)); + BitcoinAddress address = new BitcoinAddress(); + address.setChange(false); + address.setAccountId(account.getId()); + address.setIndex(0); + String addressString =externalAddrKey.toAddress(this.cryptoCoin.getParameters()).toString(); + address.setAddress(addressString); + db.bitcoinAddressDao().insertBitcoinAddresses(address); + InsightApiGenerator.getTransactionFromAddress(cryptoCoin,addressString,true, + new CheckAddressForTransaction(db.bitcoinAddressDao(),account.getId(),externalKey,false,0)); + } + + long indexChange = db.bitcoinAddressDao().getLastChangeAddress(account.getId()); + if(indexChange > 0){ + for(int i = 0; i < indexChange;i++){ + BitcoinAddress address = db.bitcoinAddressDao().getChangeByIndex(i); + InsightApiGenerator.getTransactionFromAddress(cryptoCoin,address.getAddress(),true,null); + } + }else { + ECKey changeAddrKey = HDKeyDerivation.deriveChildKey(changeKey, new ChildNumber((int) 0, true)); + BitcoinAddress address = new BitcoinAddress(); + address.setChange(true); + address.setAccountId(account.getId()); + address.setIndex(0); + String addressString =changeAddrKey.toAddress(this.cryptoCoin.getParameters()).toString(); + address.setAddress(addressString); + db.bitcoinAddressDao().insertBitcoinAddresses(address); + InsightApiGenerator.getTransactionFromAddress(cryptoCoin,addressString,true, + new CheckAddressForTransaction(db.bitcoinAddressDao(),account.getId(),externalKey,true,0)); + } } + + @Override public void onNewRequest(CryptoNetInfoRequest request) { //if(Arrays.asList(SUPPORTED_COINS).contains(request.getCoin())){ if(request.getCoin().equals(this.cryptoCoin)){ if(request instanceof BitcoinSendRequest) { - this.send((BitcoinSendRequest) request); }else if(request instanceof CreateBitcoinAccountRequest){ - + this.createGeneralAccount((CreateBitcoinAccountRequest) request); }else if(request instanceof NextBitcoinAccountAddressRequest){ this.getNextAddress((NextBitcoinAccountAddressRequest) request); }else{ @@ -235,6 +287,21 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf } } + private void createGeneralAccount(CreateBitcoinAccountRequest request){ + CrystalDatabase db = CrystalDatabase.getAppDatabase(this.context); + CryptoNetAccount account = new CryptoNetAccount(); + account.setAccountIndex(0); + account.setCryptoNet(this.cryptoCoin.getCryptoNet()); + account.setName(request.getAccountSeed().getName()); + account.setSeedId(request.getAccountSeed().getId()); + long idAccount = db.cryptoNetAccountDao().insertCryptoNetAccount(account)[0]; + account.setId(idAccount); + + loadAccountFromDB(account,request.getContext()); + request.setStatus(CreateBitcoinAccountRequest.StatusCode.SUCCEEDED); + + } + private void updateBalance(CryptoCoinTransaction ccTransaction, long amount, CrystalDatabase db){ CryptoCurrency currency = db.cryptoCurrencyDao().getByNameAndCryptoNet(this.cryptoCoin.name(), this.cryptoCoin.getCryptoNet().name()); if (currency == null) { @@ -392,7 +459,7 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf String addressString =addrKey.toAddress(this.cryptoCoin.getParameters()).toString(); address.setAddress(addressString); db.bitcoinAddressDao().insertBitcoinAddresses(address); - InsightApiGenerator.getTransactionFromAddress(this.cryptoCoin,addressString,true); + InsightApiGenerator.getTransactionFromAddress(this.cryptoCoin,addressString,true, null); request.setAddress(addressString); request.setStatus(NextBitcoinAccountAddressRequest.StatusCode.SUCCEEDED); @@ -430,4 +497,37 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf return answer; } + + class CheckAddressForTransaction implements InsightApiGenerator.HasTransactionListener{ + BitcoinAddressDao bitcoinAddressDao; + long idAccount; + DeterministicKey addressKey; + boolean isChange; + int lastIndex; + + public CheckAddressForTransaction(BitcoinAddressDao bitcoinAddressDao, long idAccount, DeterministicKey addressKey, boolean isChange, int lastIndex) { + this.bitcoinAddressDao = bitcoinAddressDao; + this.idAccount = idAccount; + this.addressKey = addressKey; + this.isChange = isChange; + this.lastIndex = lastIndex; + } + + @Override + public void hasTransaction(boolean value) { + if(value){ + + ECKey externalAddrKey = HDKeyDerivation.deriveChildKey(addressKey, new ChildNumber(lastIndex+1, true)); + BitcoinAddress address = new BitcoinAddress(); + address.setChange(isChange); + address.setAccountId(idAccount); + address.setIndex(lastIndex+1); + String addressString =externalAddrKey.toAddress(cryptoCoin.getParameters()).toString(); + address.setAddress(addressString); + bitcoinAddressDao.insertBitcoinAddresses(address); + InsightApiGenerator.getTransactionFromAddress(cryptoCoin,addressString,true, + new CheckAddressForTransaction(bitcoinAddressDao,idAccount,addressKey,isChange,lastIndex+1)); + } + } + } }