Added Get Next Bitcoin and Bitcoin like coins request and manager

This commit is contained in:
hvarona 2018-10-23 23:28:53 -04:00
parent 2027677956
commit cd00923ebc
6 changed files with 65 additions and 107 deletions

View file

@ -18,11 +18,9 @@ public class InsightApiGenerator {
* Fecth all the transaciton for a giving address * Fecth all the transaciton for a giving address
* @param cryptoCoin the crypto net of the address * @param cryptoCoin the crypto net of the address
* @param address The address String * @param address The address String
* @param request the request api to response
* @param subscribe If needs to follow the address (Real time) * @param subscribe If needs to follow the address (Real time)
*/ */
public static void getTransactionFromAddress(CryptoCoin cryptoCoin, String address, public static void getTransactionFromAddress(CryptoCoin cryptoCoin, String address, boolean subscribe){
ApiRequest request, boolean subscribe){
if(!transactionGetters.containsKey(cryptoCoin)){ if(!transactionGetters.containsKey(cryptoCoin)){
transactionGetters.put(cryptoCoin,new GetTransactionByAddress(cryptoCoin,CryptoNetManager.getURL(cryptoCoin.getCryptoNet()))); transactionGetters.put(cryptoCoin,new GetTransactionByAddress(cryptoCoin,CryptoNetManager.getURL(cryptoCoin.getCryptoNet())));
} }

View file

@ -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' ") @Query("SELECT MAX(ba.address_index) FROM bitcoin_address ba WHERE ba.account_id = :accountId and ba.is_change = 'true' ")
long getLastChangeAddress(long accountId); 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) @Insert(onConflict = OnConflictStrategy.REPLACE)
public long[] insertBitcoinAddresses(BitcoinAddress... addresses); public long[] insertBitcoinAddresses(BitcoinAddress... addresses);
} }

View file

@ -1,6 +1,5 @@
package cy.agorise.crystalwallet.manager; package cy.agorise.crystalwallet.manager;
import android.accounts.Account;
import android.content.Context; import android.content.Context;
import org.bitcoinj.core.Address; 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.Txi;
import cy.agorise.crystalwallet.apigenerator.insightapi.models.Vin; import cy.agorise.crystalwallet.apigenerator.insightapi.models.Vin;
import cy.agorise.crystalwallet.apigenerator.insightapi.models.Vout; import cy.agorise.crystalwallet.apigenerator.insightapi.models.Vout;
import cy.agorise.crystalwallet.application.CrystalApplication;
import cy.agorise.crystalwallet.dao.CrystalDatabase; import cy.agorise.crystalwallet.dao.CrystalDatabase;
import cy.agorise.crystalwallet.enums.CryptoCoin; import cy.agorise.crystalwallet.enums.CryptoCoin;
import cy.agorise.crystalwallet.models.AccountSeed; 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.CryptoCoinTransaction;
import cy.agorise.crystalwallet.models.CryptoCurrency; import cy.agorise.crystalwallet.models.CryptoCurrency;
import cy.agorise.crystalwallet.models.CryptoNetAccount; import cy.agorise.crystalwallet.models.CryptoNetAccount;
import cy.agorise.crystalwallet.models.GTxIO; import cy.agorise.crystalwallet.requestmanagers.BitcoinSendRequest;
import cy.agorise.crystalwallet.models.GeneralCoinAddress; import cy.agorise.crystalwallet.requestmanagers.CreateBitcoinAccountRequest;
import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequest; import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequest;
import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequestsListener; import cy.agorise.crystalwallet.requestmanagers.CryptoNetInfoRequestsListener;
import cy.agorise.crystalwallet.requestmanagers.GeneralAccountSendRequest; import cy.agorise.crystalwallet.requestmanagers.NextBitcoinAccountAddressRequest;
import cy.agorise.graphenej.Util; import cy.agorise.graphenej.Util;
public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInfoRequestsListener { public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInfoRequestsListener {
@ -85,9 +83,14 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf
@Override @Override
public void onNewRequest(CryptoNetInfoRequest request) { public void onNewRequest(CryptoNetInfoRequest request) {
if(Arrays.asList(SUPPORTED_COINS).contains(request.getCoin())){ //if(Arrays.asList(SUPPORTED_COINS).contains(request.getCoin())){
if(request instanceof GeneralAccountSendRequest){ if(request.getCoin().equals(this.cryptoCoin)){
this.send((GeneralAccountSendRequest)request); if(request instanceof BitcoinSendRequest) {
this.send((BitcoinSendRequest) request);
}else if(request instanceof CreateBitcoinAccountRequest){
}else if(request instanceof NextBitcoinAccountAddressRequest){
this.getNextAddress((NextBitcoinAccountAddressRequest) request);
}else{ }else{
System.out.println("Invalid " +this.cryptoCoin.getLabel() + " request "); System.out.println("Invalid " +this.cryptoCoin.getLabel() + " request ");
} }
@ -255,7 +258,7 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf
db.cryptoCoinBalanceDao().insertCryptoCoinBalance(balance); db.cryptoCoinBalanceDao().insertCryptoCoinBalance(balance);
} }
public void send(final GeneralAccountSendRequest request){ public void send(final BitcoinSendRequest request){
//TODO check server connection //TODO check server connection
//TODO validate to address //TODO validate to address
@ -271,19 +274,19 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf
CrystalDatabase db = CrystalDatabase.getAppDatabase(request.getContext()); CrystalDatabase db = CrystalDatabase.getAppDatabase(request.getContext());
db.bitcoinTransactionDao(); db.bitcoinTransactionDao();
List<BitcoinTransactionGTxIO> utxos = getUtxos(request.getAccount().getId(),db); List<BitcoinTransactionGTxIO> utxos = getUtxos(request.getSourceAccount().getId(),db);
if(currentAmount< request.getAmount() + fee){ if(currentAmount< request.getAmount() + fee){
request.setStatus(GeneralAccountSendRequest.StatusCode.NO_BALANCE); request.setStatus(BitcoinSendRequest.StatusCode.NO_BALANCE);
return; return;
} }
AccountSeed seed = db.accountSeedDao().findById(request.getAccount().getSeedId()); AccountSeed seed = db.accountSeedDao().findById(request.getSourceAccount().getSeedId());
DeterministicKey purposeKey = HDKeyDerivation.deriveChildKey((DeterministicKey) seed.getPrivateKey(), DeterministicKey purposeKey = HDKeyDerivation.deriveChildKey((DeterministicKey) seed.getPrivateKey(),
new ChildNumber(44, true)); new ChildNumber(44, true));
DeterministicKey coinKey = HDKeyDerivation.deriveChildKey(purposeKey, DeterministicKey coinKey = HDKeyDerivation.deriveChildKey(purposeKey,
new ChildNumber(cryptoCoin.getCoinNumber(), true)); new ChildNumber(cryptoCoin.getCoinNumber(), true));
DeterministicKey accountKey = HDKeyDerivation.deriveChildKey(coinKey, DeterministicKey accountKey = HDKeyDerivation.deriveChildKey(coinKey,
new ChildNumber(request.getAccount().getAccountIndex(), true)); new ChildNumber(request.getSourceAccount().getAccountIndex(), true));
DeterministicKey externalKey = HDKeyDerivation.deriveChildKey(accountKey, DeterministicKey externalKey = HDKeyDerivation.deriveChildKey(accountKey,
new ChildNumber(0, false)); new ChildNumber(0, false));
DeterministicKey changeKey = HDKeyDerivation.deriveChildKey(accountKey, DeterministicKey changeKey = HDKeyDerivation.deriveChildKey(accountKey,
@ -309,7 +312,7 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf
//Change address //Change address
long remain = currentAmount - request.getAmount() - fee; long remain = currentAmount - request.getAmount() - fee;
if( remain > 0 ) { 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); BitcoinAddress btAddress = db.bitcoinAddressDao().getChangeByIndex(index);
Address changeAddr; Address changeAddr;
if(btAddress != null && db.bitcoinTransactionDao().getGtxIOByAddress(btAddress.getAddress()).size()<=0){ if(btAddress != null && db.bitcoinTransactionDao().getGtxIOByAddress(btAddress.getAddress()).size()<=0){
@ -323,7 +326,7 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf
} }
btAddress = new BitcoinAddress(); btAddress = new BitcoinAddress();
btAddress.setIndex(index); btAddress.setIndex(index);
btAddress.setAccountId(request.getAccount().getId()); btAddress.setAccountId(request.getSourceAccount().getId());
btAddress.setChange(true); btAddress.setChange(true);
btAddress.setAddress(HDKeyDerivation.deriveChildKey(changeKey, new ChildNumber((int) btAddress.getIndex(), false)).toAddress(cryptoCoin.getParameters()).toString()); btAddress.setAddress(HDKeyDerivation.deriveChildKey(changeKey, new ChildNumber((int) btAddress.getIndex(), false)).toAddress(cryptoCoin.getParameters()).toString());
db.bitcoinAddressDao().insertBitcoinAddresses(btAddress); db.bitcoinAddressDao().insertBitcoinAddresses(btAddress);
@ -342,7 +345,7 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf
if(btAddress.isChange()){ if(btAddress.isChange()){
addrKey = HDKeyDerivation.deriveChildKey(changeKey, new ChildNumber((int) btAddress.getIndex(), false)); addrKey = HDKeyDerivation.deriveChildKey(changeKey, new ChildNumber((int) btAddress.getIndex(), false));
}else{ }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); 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() { InsightApiGenerator.broadcastTransaction(cryptoCoin,Util.bytesToHex(tx.bitcoinSerialize()),new ApiRequest(1, new ApiRequestListener() {
@Override @Override
public void success(Object answer, int idPetition) { public void success(Object answer, int idPetition) {
request.setStatus(GeneralAccountSendRequest.StatusCode.SUCCEEDED); request.setStatus(BitcoinSendRequest.StatusCode.SUCCEEDED);
} }
@Override @Override
public void fail(int idPetition) { public void fail(int idPetition) {
request.setStatus(GeneralAccountSendRequest.StatusCode.PETITION_FAILED); request.setStatus(BitcoinSendRequest.StatusCode.PETITION_FAILED);
} }
})); }));
} }
@Override @Override
public void fail(int idPetition) { 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<BitcoinTransactionGTxIO> getUtxos(long accountId, CrystalDatabase db){ private List<BitcoinTransactionGTxIO> getUtxos(long accountId, CrystalDatabase db){
List<BitcoinTransactionGTxIO> answer = new ArrayList<>(); List<BitcoinTransactionGTxIO> answer = new ArrayList<>();
List<BitcoinTransactionGTxIO> bTGTxI = new ArrayList<>(); List<BitcoinTransactionGTxIO> bTGTxI = new ArrayList<>();

View file

@ -21,6 +21,8 @@ public class BitcoinSendRequest extends CryptoNetInfoRequest {
SUCCEEDED, SUCCEEDED,
NO_INTERNET, NO_INTERNET,
NO_SERVER_CONNECTION, NO_SERVER_CONNECTION,
NO_BALANCE,
NO_FEE,
PETITION_FAILED PETITION_FAILED
} }

View file

@ -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;
}
}

View file

@ -19,6 +19,8 @@ public class NextBitcoinAccountAddressRequest extends CryptoNetInfoRequest {
private CryptoCoin cryptoCoin; private CryptoCoin cryptoCoin;
private Context context; private Context context;
private String address = null;
/** /**
* The status code of this request * The status code of this request
*/ */
@ -62,4 +64,12 @@ public class NextBitcoinAccountAddressRequest extends CryptoNetInfoRequest {
public StatusCode getStatus() { public StatusCode getStatus() {
return status; return status;
} }
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
} }