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 7a5505f..d6229c9 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/InsightApiGenerator.java +++ b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/InsightApiGenerator.java @@ -18,11 +18,9 @@ public class InsightApiGenerator { * Fecth all the transaciton for a giving address * @param cryptoCoin 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(CryptoCoin cryptoCoin, String address, - ApiRequest request, boolean subscribe){ + public static void getTransactionFromAddress(CryptoCoin cryptoCoin, String address, boolean subscribe){ if(!transactionGetters.containsKey(cryptoCoin)){ transactionGetters.put(cryptoCoin,new GetTransactionByAddress(cryptoCoin,CryptoNetManager.getURL(cryptoCoin.getCryptoNet()))); } 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 5260595..51088c6 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/dao/BitcoinAddressDao.java +++ b/app/src/main/java/cy/agorise/crystalwallet/dao/BitcoinAddressDao.java @@ -31,6 +31,9 @@ public interface BitcoinAddressDao { @Query("SELECT MAX(ba.address_index) FROM bitcoin_address ba WHERE ba.account_id = :accountId and ba.is_change = 'true' ") long getLastChangeAddress(long accountId); + @Query("SELECT MAX(ba.address_index) FROM bitcoin_address ba WHERE ba.account_id = :accountId and ba.is_change = 'false' ") + long getLastExternalAddress(long accountId); + @Insert(onConflict = OnConflictStrategy.REPLACE) public long[] insertBitcoinAddresses(BitcoinAddress... addresses); } 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 3895f73..01ad0e6 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/manager/GeneralAccountManager.java +++ b/app/src/main/java/cy/agorise/crystalwallet/manager/GeneralAccountManager.java @@ -1,6 +1,5 @@ package cy.agorise.crystalwallet.manager; -import android.accounts.Account; import android.content.Context; import org.bitcoinj.core.Address; @@ -26,7 +25,6 @@ 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.application.CrystalApplication; import cy.agorise.crystalwallet.dao.CrystalDatabase; import cy.agorise.crystalwallet.enums.CryptoCoin; import cy.agorise.crystalwallet.models.AccountSeed; @@ -37,11 +35,11 @@ import cy.agorise.crystalwallet.models.CryptoCoinBalance; import cy.agorise.crystalwallet.models.CryptoCoinTransaction; import cy.agorise.crystalwallet.models.CryptoCurrency; import cy.agorise.crystalwallet.models.CryptoNetAccount; -import cy.agorise.crystalwallet.models.GTxIO; -import cy.agorise.crystalwallet.models.GeneralCoinAddress; +import cy.agorise.crystalwallet.requestmanagers.BitcoinSendRequest; +import cy.agorise.crystalwallet.requestmanagers.CreateBitcoinAccountRequest; import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequest; import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequestsListener; -import cy.agorise.crystalwallet.requestmanagers.GeneralAccountSendRequest; +import cy.agorise.crystalwallet.requestmanagers.NextBitcoinAccountAddressRequest; import cy.agorise.graphenej.Util; public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInfoRequestsListener { @@ -85,9 +83,14 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf @Override public void onNewRequest(CryptoNetInfoRequest request) { - if(Arrays.asList(SUPPORTED_COINS).contains(request.getCoin())){ - if(request instanceof GeneralAccountSendRequest){ - this.send((GeneralAccountSendRequest)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){ + + }else if(request instanceof NextBitcoinAccountAddressRequest){ + this.getNextAddress((NextBitcoinAccountAddressRequest) request); }else{ System.out.println("Invalid " +this.cryptoCoin.getLabel() + " request "); } @@ -255,7 +258,7 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf db.cryptoCoinBalanceDao().insertCryptoCoinBalance(balance); } - public void send(final GeneralAccountSendRequest request){ + public void send(final BitcoinSendRequest request){ //TODO check server connection //TODO validate to address @@ -271,19 +274,19 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf CrystalDatabase db = CrystalDatabase.getAppDatabase(request.getContext()); db.bitcoinTransactionDao(); - List utxos = getUtxos(request.getAccount().getId(),db); + List utxos = getUtxos(request.getSourceAccount().getId(),db); if(currentAmount< request.getAmount() + fee){ - request.setStatus(GeneralAccountSendRequest.StatusCode.NO_BALANCE); + request.setStatus(BitcoinSendRequest.StatusCode.NO_BALANCE); return; } - AccountSeed seed = db.accountSeedDao().findById(request.getAccount().getSeedId()); + AccountSeed seed = db.accountSeedDao().findById(request.getSourceAccount().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(request.getAccount().getAccountIndex(), true)); + new ChildNumber(request.getSourceAccount().getAccountIndex(), true)); DeterministicKey externalKey = HDKeyDerivation.deriveChildKey(accountKey, new ChildNumber(0, false)); DeterministicKey changeKey = HDKeyDerivation.deriveChildKey(accountKey, @@ -309,7 +312,7 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf //Change address long remain = currentAmount - request.getAmount() - fee; if( remain > 0 ) { - long index = db.bitcoinAddressDao().getLastChangeAddress(request.getAccount().getId()); + long index = db.bitcoinAddressDao().getLastChangeAddress(request.getSourceAccount().getId()); BitcoinAddress btAddress = db.bitcoinAddressDao().getChangeByIndex(index); Address changeAddr; if(btAddress != null && db.bitcoinTransactionDao().getGtxIOByAddress(btAddress.getAddress()).size()<=0){ @@ -323,7 +326,7 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf } btAddress = new BitcoinAddress(); btAddress.setIndex(index); - btAddress.setAccountId(request.getAccount().getId()); + btAddress.setAccountId(request.getSourceAccount().getId()); btAddress.setChange(true); btAddress.setAddress(HDKeyDerivation.deriveChildKey(changeKey, new ChildNumber((int) btAddress.getIndex(), false)).toAddress(cryptoCoin.getParameters()).toString()); db.bitcoinAddressDao().insertBitcoinAddresses(btAddress); @@ -342,7 +345,7 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf if(btAddress.isChange()){ addrKey = HDKeyDerivation.deriveChildKey(changeKey, new ChildNumber((int) btAddress.getIndex(), false)); }else{ - addrKey = HDKeyDerivation.deriveChildKey(changeKey, new ChildNumber((int) btAddress.getIndex(), true)); + addrKey = HDKeyDerivation.deriveChildKey(externalKey, new ChildNumber((int) btAddress.getIndex(), true)); } tx.addSignedInput(outPoint, script, addrKey, Transaction.SigHash.ALL, true); } @@ -350,24 +353,51 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf InsightApiGenerator.broadcastTransaction(cryptoCoin,Util.bytesToHex(tx.bitcoinSerialize()),new ApiRequest(1, new ApiRequestListener() { @Override public void success(Object answer, int idPetition) { - request.setStatus(GeneralAccountSendRequest.StatusCode.SUCCEEDED); + request.setStatus(BitcoinSendRequest.StatusCode.SUCCEEDED); } @Override public void fail(int idPetition) { - request.setStatus(GeneralAccountSendRequest.StatusCode.PETITION_FAILED); + request.setStatus(BitcoinSendRequest.StatusCode.PETITION_FAILED); } })); } @Override public void fail(int idPetition) { - request.setStatus(GeneralAccountSendRequest.StatusCode.NO_FEE); + request.setStatus(BitcoinSendRequest.StatusCode.NO_FEE); } })); } + private void getNextAddress(NextBitcoinAccountAddressRequest request){ + CrystalDatabase db = CrystalDatabase.getAppDatabase(request.getContext()); + long index = db.bitcoinAddressDao().getLastExternalAddress(request.getAccount().getId()); + index++; + AccountSeed seed = db.accountSeedDao().findById(request.getAccount().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(request.getAccount().getAccountIndex(), true)); + DeterministicKey externalKey = HDKeyDerivation.deriveChildKey(accountKey, + new ChildNumber(0, false)); + ECKey addrKey = HDKeyDerivation.deriveChildKey(externalKey, new ChildNumber((int) index, true)); + BitcoinAddress address = new BitcoinAddress(); + address.setChange(false); + address.setAccountId(request.getAccount().getId()); + address.setIndex(index); + String addressString =addrKey.toAddress(this.cryptoCoin.getParameters()).toString(); + address.setAddress(addressString); + db.bitcoinAddressDao().insertBitcoinAddresses(address); + InsightApiGenerator.getTransactionFromAddress(this.cryptoCoin,addressString,true); + + request.setAddress(addressString); + request.setStatus(NextBitcoinAccountAddressRequest.StatusCode.SUCCEEDED); + } + private List getUtxos(long accountId, CrystalDatabase db){ List answer = new ArrayList<>(); List bTGTxI = new ArrayList<>(); diff --git a/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/BitcoinSendRequest.java b/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/BitcoinSendRequest.java index b104c78..762d107 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/BitcoinSendRequest.java +++ b/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/BitcoinSendRequest.java @@ -21,6 +21,8 @@ public class BitcoinSendRequest extends CryptoNetInfoRequest { SUCCEEDED, NO_INTERNET, NO_SERVER_CONNECTION, + NO_BALANCE, + NO_FEE, PETITION_FAILED } diff --git a/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/GeneralAccountSendRequest.java b/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/GeneralAccountSendRequest.java deleted file mode 100644 index de98bb5..0000000 --- a/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/GeneralAccountSendRequest.java +++ /dev/null @@ -1,85 +0,0 @@ -package cy.agorise.crystalwallet.requestmanagers; - -import android.content.Context; - -import cy.agorise.crystalwallet.enums.CryptoCoin; -import cy.agorise.crystalwallet.models.CryptoNetAccount; - -public class GeneralAccountSendRequest extends CryptoNetInfoRequest { - /** - * The status code of this request - */ - public enum StatusCode{ - NOT_STARTED, - SUCCEEDED, - NO_INTERNET, - NO_SERVER_CONNECTION, - BAD_TO_ADDRESS, - NO_FEE, - NO_BALANCE, - PETITION_FAILED - } - - // The app context - private Context mContext; - //The soruce Account - private CryptoNetAccount mAccount; - // The destination account address - private String mToAccount; - // The amount of the transaction - private long mAmount; - // The memo, can be null - private String mMemo; - // The state of this request - private StatusCode status = StatusCode.NOT_STARTED; - - public GeneralAccountSendRequest(CryptoCoin coin, Context context, CryptoNetAccount account, String toAccount, long amount, String memo) { - super(coin); - this.mContext = context; - this.mAccount = account; - this.mToAccount = toAccount; - this.mAmount = amount; - this.mMemo = memo; - } - - public GeneralAccountSendRequest(CryptoCoin coin, Context context, CryptoNetAccount account, String toAccount, long amount) { - this(coin,context,account,toAccount,amount,null); - - } - - public Context getContext() { - return mContext; - } - - public CryptoNetAccount getAccount() { - return mAccount; - } - - public String getToAccount() { - return mToAccount; - } - - public long getAmount() { - return mAmount; - } - - public String getMemo() { - return mMemo; - } - - public void validate(){ - if ((this.status != StatusCode.NOT_STARTED)){ - this._fireOnCarryOutEvent(); - } - } - - public void setStatus(StatusCode code){ - this.status = code; - this._fireOnCarryOutEvent(); - } - - public StatusCode getStatus() { - return status; - } - -} diff --git a/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/NextBitcoinAccountAddressRequest.java b/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/NextBitcoinAccountAddressRequest.java index fa55102..f7fdbd0 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/NextBitcoinAccountAddressRequest.java +++ b/app/src/main/java/cy/agorise/crystalwallet/requestmanagers/NextBitcoinAccountAddressRequest.java @@ -19,6 +19,8 @@ public class NextBitcoinAccountAddressRequest extends CryptoNetInfoRequest { private CryptoCoin cryptoCoin; private Context context; + private String address = null; + /** * The status code of this request */ @@ -62,4 +64,12 @@ public class NextBitcoinAccountAddressRequest extends CryptoNetInfoRequest { public StatusCode getStatus() { return status; } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } }