2017-09-27 02:48:34 +00:00
|
|
|
package cy.agorise.crystalwallet.manager;
|
|
|
|
|
2017-10-10 02:44:44 +00:00
|
|
|
import android.arch.lifecycle.LiveData;
|
2017-10-16 00:23:44 +00:00
|
|
|
import android.content.Context;
|
2017-10-10 02:44:44 +00:00
|
|
|
|
2017-10-09 00:10:46 +00:00
|
|
|
import com.google.common.primitives.UnsignedLong;
|
|
|
|
|
|
|
|
import org.bitcoinj.core.ECKey;
|
|
|
|
|
|
|
|
import java.util.ArrayList;
|
2017-10-16 00:23:44 +00:00
|
|
|
import java.util.List;
|
|
|
|
import java.util.Objects;
|
2017-10-09 00:10:46 +00:00
|
|
|
|
2017-10-03 02:49:17 +00:00
|
|
|
import cy.agorise.crystalwallet.apigenerator.ApiRequest;
|
|
|
|
import cy.agorise.crystalwallet.apigenerator.ApiRequestListener;
|
|
|
|
import cy.agorise.crystalwallet.apigenerator.GrapheneApiGenerator;
|
2017-10-02 02:18:56 +00:00
|
|
|
import cy.agorise.crystalwallet.cryptonetinforequests.CryptoNetInfoRequest;
|
|
|
|
import cy.agorise.crystalwallet.cryptonetinforequests.CryptoNetInfoRequestsListener;
|
2017-10-09 00:10:46 +00:00
|
|
|
import cy.agorise.crystalwallet.cryptonetinforequests.ValidateBitsharesSendRequest;
|
2017-10-08 16:02:11 +00:00
|
|
|
import cy.agorise.crystalwallet.cryptonetinforequests.ValidateExistBitsharesAccountRequest;
|
2017-10-02 02:18:56 +00:00
|
|
|
import cy.agorise.crystalwallet.cryptonetinforequests.ValidateImportBitsharesAccountRequest;
|
2017-10-10 02:44:44 +00:00
|
|
|
import cy.agorise.crystalwallet.dao.CrystalDatabase;
|
|
|
|
import cy.agorise.crystalwallet.models.AccountSeed;
|
2017-10-16 00:23:44 +00:00
|
|
|
import cy.agorise.crystalwallet.models.BitsharesAsset;
|
|
|
|
import cy.agorise.crystalwallet.models.CryptoCoinTransaction;
|
|
|
|
import cy.agorise.crystalwallet.models.CryptoCurrency;
|
2017-09-27 02:48:34 +00:00
|
|
|
import cy.agorise.crystalwallet.models.CryptoNetAccount;
|
2017-10-12 03:37:05 +00:00
|
|
|
import cy.agorise.crystalwallet.models.GrapheneAccount;
|
2017-10-05 03:28:19 +00:00
|
|
|
import cy.agorise.graphenej.Address;
|
2017-10-09 00:10:46 +00:00
|
|
|
import cy.agorise.graphenej.Asset;
|
|
|
|
import cy.agorise.graphenej.AssetAmount;
|
|
|
|
import cy.agorise.graphenej.BaseOperation;
|
2017-10-04 01:31:16 +00:00
|
|
|
import cy.agorise.graphenej.BrainKey;
|
|
|
|
import cy.agorise.graphenej.PublicKey;
|
2017-10-09 00:10:46 +00:00
|
|
|
import cy.agorise.graphenej.Transaction;
|
|
|
|
import cy.agorise.graphenej.UserAccount;
|
2017-10-04 01:31:16 +00:00
|
|
|
import cy.agorise.graphenej.models.AccountProperties;
|
2017-10-16 00:23:44 +00:00
|
|
|
import cy.agorise.graphenej.models.HistoricalTransfer;
|
2017-10-09 00:10:46 +00:00
|
|
|
import cy.agorise.graphenej.operations.TransferOperationBuilder;
|
2017-09-27 02:48:34 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Created by henry on 26/9/2017.
|
|
|
|
*/
|
|
|
|
|
2017-10-02 02:18:56 +00:00
|
|
|
public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetInfoRequestsListener {
|
2017-09-27 02:48:34 +00:00
|
|
|
@Override
|
2017-10-16 00:23:44 +00:00
|
|
|
public CryptoNetAccount createAccountFromSeed(CryptoNetAccount account, Context context) {
|
2017-10-12 03:37:05 +00:00
|
|
|
//TODO generate account keys
|
2017-10-16 00:23:44 +00:00
|
|
|
//TODO register account faucet api
|
2017-10-12 03:37:05 +00:00
|
|
|
//TODO save account on DB
|
|
|
|
//TODO subscribe account
|
2017-09-27 02:48:34 +00:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2017-10-16 00:23:44 +00:00
|
|
|
public CryptoNetAccount importAccountFromSeed(CryptoNetAccount account, Context context) {
|
|
|
|
|
|
|
|
if(account instanceof GrapheneAccount) {
|
|
|
|
GrapheneAccount grapheneAccount = (GrapheneAccount) account;
|
|
|
|
|
|
|
|
if(grapheneAccount.getAccountId() == null){
|
|
|
|
grapheneAccount = this.getAccountInfoByName(grapheneAccount.getName());
|
|
|
|
}else if(grapheneAccount.getName() == null){
|
|
|
|
grapheneAccount = this.getAccountInfoById(grapheneAccount.getAccountId());
|
|
|
|
}
|
|
|
|
//TODO grapaheneAccount null, error fetching
|
|
|
|
|
|
|
|
CrystalDatabase db = CrystalDatabase.getAppDatabase(context);
|
|
|
|
//TODO save account on DB
|
|
|
|
|
|
|
|
GrapheneApiGenerator.subscribeBitsharesAccount(grapheneAccount.getId(), grapheneAccount.getAccountId(), context);
|
|
|
|
this.refreshAccountTransactions(account.getId(), context);
|
|
|
|
GrapheneApiGenerator.getAccountBalance(grapheneAccount.getId(), grapheneAccount.getAccountId(), context);
|
|
|
|
return grapheneAccount;
|
|
|
|
}
|
2017-09-27 02:48:34 +00:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2017-10-16 00:23:44 +00:00
|
|
|
public void loadAccountFromDB(CryptoNetAccount account, Context context) {
|
2017-10-12 03:37:05 +00:00
|
|
|
if(account instanceof GrapheneAccount){
|
|
|
|
GrapheneAccount grapheneAccount = (GrapheneAccount) account;
|
|
|
|
if(grapheneAccount.getAccountId() == null){
|
2017-10-16 00:23:44 +00:00
|
|
|
grapheneAccount = this.getAccountInfoByName(grapheneAccount.getName());
|
2017-10-12 03:37:05 +00:00
|
|
|
}else if(grapheneAccount.getName() == null){
|
2017-10-16 00:23:44 +00:00
|
|
|
grapheneAccount = this.getAccountInfoById(grapheneAccount.getAccountId());
|
2017-10-12 03:37:05 +00:00
|
|
|
}
|
2017-10-16 00:23:44 +00:00
|
|
|
//TODO grapaheneAccount null, error fetching
|
2017-09-27 02:48:34 +00:00
|
|
|
|
2017-10-16 00:23:44 +00:00
|
|
|
GrapheneApiGenerator.subscribeBitsharesAccount(grapheneAccount.getId(),grapheneAccount.getAccountId(),context);
|
|
|
|
this.refreshAccountTransactions(account.getId(),context);
|
|
|
|
GrapheneApiGenerator.getAccountBalance(grapheneAccount.getId(),grapheneAccount.getAccountId(),context);
|
2017-10-12 03:37:05 +00:00
|
|
|
}
|
2017-09-27 02:48:34 +00:00
|
|
|
}
|
2017-10-02 02:18:56 +00:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onNewRequest(CryptoNetInfoRequest request) {
|
|
|
|
if (request instanceof ValidateImportBitsharesAccountRequest){
|
2017-10-09 00:10:46 +00:00
|
|
|
this.validateImportAccount((ValidateImportBitsharesAccountRequest) request);
|
|
|
|
} else if (request instanceof ValidateExistBitsharesAccountRequest){
|
|
|
|
this.validateExistAcccount((ValidateExistBitsharesAccountRequest) request);
|
2017-10-16 00:23:44 +00:00
|
|
|
} else if (request instanceof ValidateBitsharesSendRequest){
|
|
|
|
this.validateSendRequest((ValidateBitsharesSendRequest) request);
|
2017-10-09 00:10:46 +00:00
|
|
|
}
|
|
|
|
}
|
2017-10-05 02:04:42 +00:00
|
|
|
|
2017-10-09 00:10:46 +00:00
|
|
|
private void validateImportAccount(final ValidateImportBitsharesAccountRequest importRequest){
|
|
|
|
ApiRequest checkAccountName = new ApiRequest(0, new ApiRequestListener() {
|
|
|
|
@Override
|
|
|
|
public void success(Object answer, int idPetition) {
|
|
|
|
importRequest.setAccountExists(true);
|
|
|
|
ApiRequest getAccountInfo = new ApiRequest(1,new ApiRequestListener(){
|
|
|
|
@Override
|
|
|
|
public void success(Object answer, int idPetition) {
|
|
|
|
if(answer != null && answer instanceof AccountProperties) {
|
|
|
|
AccountProperties prop = (AccountProperties) answer;
|
|
|
|
//TODO change the way to compare keys
|
|
|
|
|
|
|
|
BrainKey bk = new BrainKey(importRequest.getMnemonic(), 0);
|
|
|
|
for(PublicKey activeKey : prop.active.getKeyAuthList()){
|
2017-10-05 03:28:19 +00:00
|
|
|
if((new Address(activeKey.getKey(),"BTS")).toString().equals(bk.getPublicAddress("BTS").toString())){
|
2017-10-04 01:31:16 +00:00
|
|
|
importRequest.setMnemonicIsCorrect(true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2017-10-09 00:10:46 +00:00
|
|
|
importRequest.setMnemonicIsCorrect(false);
|
2017-10-03 02:49:17 +00:00
|
|
|
}
|
|
|
|
|
2017-10-09 00:10:46 +00:00
|
|
|
}
|
2017-10-03 02:49:17 +00:00
|
|
|
|
2017-10-09 00:10:46 +00:00
|
|
|
@Override
|
|
|
|
public void fail(int idPetition) {
|
|
|
|
//
|
|
|
|
}
|
|
|
|
});
|
|
|
|
GrapheneApiGenerator.getAccountById((String)answer,getAccountInfo);
|
|
|
|
}
|
2017-10-03 02:49:17 +00:00
|
|
|
|
2017-10-09 00:10:46 +00:00
|
|
|
@Override
|
|
|
|
public void fail(int idPetition) {
|
|
|
|
//
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
GrapheneApiGenerator.getAccountIdByName(importRequest.getAccountName(),checkAccountName);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void validateExistAcccount(final ValidateExistBitsharesAccountRequest validateRequest){
|
|
|
|
ApiRequest checkAccountName = new ApiRequest(0, new ApiRequestListener() {
|
|
|
|
@Override
|
|
|
|
public void success(Object answer, int idPetition) {
|
|
|
|
validateRequest.setAccountExists(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void fail(int idPetition) {
|
|
|
|
//TODO verified
|
|
|
|
validateRequest.setAccountExists(false);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
GrapheneApiGenerator.getAccountIdByName(validateRequest.getAccountName(),checkAccountName);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void validateSendRequest(final ValidateBitsharesSendRequest sendRequest){
|
|
|
|
Asset feeAsset = new Asset(sendRequest.getFeeAsset());
|
|
|
|
TransferOperationBuilder builder = new TransferOperationBuilder()
|
2017-10-10 02:44:44 +00:00
|
|
|
.setSource(new UserAccount(sendRequest.getSourceAccount().getAccountId()))
|
2017-10-09 00:10:46 +00:00
|
|
|
.setDestination(new UserAccount(sendRequest.getToAccount()))
|
|
|
|
.setTransferAmount(new AssetAmount(UnsignedLong.valueOf(sendRequest.getBaseAmount()), new Asset(sendRequest.getBaseAsset())))
|
|
|
|
.setFee(new AssetAmount(UnsignedLong.valueOf(sendRequest.getFeeAmount()), feeAsset));
|
|
|
|
//TODO memo
|
|
|
|
ArrayList<BaseOperation> operationList = new ArrayList();
|
|
|
|
operationList.add(builder.build());
|
|
|
|
|
2017-10-10 02:44:44 +00:00
|
|
|
//TODO get privateKey with seed model
|
|
|
|
LiveData<AccountSeed> seed = CrystalDatabase.getAppDatabase(sendRequest.getContext()).accountSeedDao().findById(sendRequest.getSourceAccount().getSeedId());
|
|
|
|
|
|
|
|
ECKey privateKey = new BrainKey(seed.getValue().getMasterSeed(),0).getPrivateKey();
|
|
|
|
Transaction transaction = new Transaction(privateKey, null, operationList);
|
2017-10-09 00:10:46 +00:00
|
|
|
|
|
|
|
ApiRequest transactionRequest = new ApiRequest(0, new ApiRequestListener() {
|
|
|
|
@Override
|
|
|
|
public void success(Object answer, int idPetition) {
|
|
|
|
sendRequest.setSend(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void fail(int idPetition) {
|
|
|
|
sendRequest.setSend(false);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
GrapheneApiGenerator.broadcastTransaction(transaction,feeAsset, transactionRequest);
|
2017-10-02 02:18:56 +00:00
|
|
|
}
|
2017-10-16 00:23:44 +00:00
|
|
|
|
|
|
|
private GrapheneAccount getAccountInfoById(String grapheneId){
|
|
|
|
final Object SYNC = new Object();
|
|
|
|
long timeout = 60000;
|
|
|
|
|
|
|
|
AccountIdOrNameListener listener = new AccountIdOrNameListener(SYNC);
|
|
|
|
|
|
|
|
ApiRequest request = new ApiRequest(0, listener);
|
|
|
|
GrapheneApiGenerator.getAccountById(grapheneId,request);
|
|
|
|
|
|
|
|
long cTime = System.currentTimeMillis();
|
|
|
|
|
|
|
|
while(!listener.ready && (System.currentTimeMillis()-cTime) < timeout){
|
|
|
|
synchronized (SYNC){
|
|
|
|
try {
|
|
|
|
SYNC.wait(100);
|
|
|
|
} catch (InterruptedException e) {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return listener.account;
|
|
|
|
}
|
|
|
|
|
|
|
|
private GrapheneAccount getAccountInfoByName(String grapheneName){
|
|
|
|
final Object SYNC = new Object();
|
|
|
|
long timeout = 60000;
|
|
|
|
|
|
|
|
AccountIdOrNameListener listener = new AccountIdOrNameListener(SYNC);
|
|
|
|
|
|
|
|
ApiRequest request = new ApiRequest(0, listener);
|
|
|
|
GrapheneApiGenerator.getAccountByName(grapheneName,request);
|
|
|
|
|
|
|
|
long cTime = System.currentTimeMillis();
|
|
|
|
|
|
|
|
while(!listener.ready && (System.currentTimeMillis()-cTime) < timeout){
|
|
|
|
synchronized (SYNC){
|
|
|
|
try {
|
|
|
|
SYNC.wait(100);
|
|
|
|
} catch (InterruptedException e) {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return listener.account;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void refreshAccountTransactions(final long idAccount, Context context){
|
|
|
|
final CrystalDatabase db = CrystalDatabase.getAppDatabase(context);
|
|
|
|
final LiveData<List<CryptoCoinTransaction>> transactions = db.transactionDao().getByIdAccount(idAccount);
|
|
|
|
final LiveData<GrapheneAccount> account = null;
|
|
|
|
//TODO find account
|
|
|
|
int start = transactions.getValue().size();
|
|
|
|
int limit = 50;
|
|
|
|
int stop = start + limit;
|
|
|
|
|
|
|
|
ApiRequest transactionRequest = new ApiRequest(0, new TransactionRequestListener(start,stop,limit,account.getValue(),db));
|
|
|
|
|
|
|
|
|
|
|
|
GrapheneApiGenerator.getAccountTransaction(account.getValue().getName(),start,stop,limit,transactionRequest);
|
|
|
|
}
|
|
|
|
|
|
|
|
private class TransactionRequestListener implements ApiRequestListener{
|
|
|
|
|
|
|
|
int start;
|
|
|
|
int stop;
|
|
|
|
int limit;
|
|
|
|
GrapheneAccount account;
|
|
|
|
CrystalDatabase db;
|
|
|
|
|
|
|
|
public TransactionRequestListener(int start, int stop, int limit, GrapheneAccount account, CrystalDatabase db) {
|
|
|
|
this.start = start;
|
|
|
|
this.stop = stop;
|
|
|
|
this.limit = limit;
|
|
|
|
this.account = account;
|
|
|
|
this.db = db;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void success(Object answer, int idPetition) {
|
|
|
|
List<HistoricalTransfer> transfers = (List<HistoricalTransfer>) answer ;
|
|
|
|
for(HistoricalTransfer transfer : transfers){
|
|
|
|
CryptoCoinTransaction transaction = new CryptoCoinTransaction();
|
|
|
|
transaction.setAccountId(account.getId());
|
|
|
|
transaction.setAmount(transfer.getOperation().getAssetAmount().getAmount().longValue());
|
|
|
|
BitsharesAsset currency = null;
|
|
|
|
//TODO find currency by symbol db.cryptoCurrencyDao().getBySymbol(transfer.getOperation().getAssetAmount().getAsset().getSymbol())
|
|
|
|
if(currency == null){
|
|
|
|
//CryptoCurrency not in database
|
|
|
|
Asset asset = transfer.getOperation().getAssetAmount().getAsset();
|
|
|
|
BitsharesAsset.Type assetType = null;
|
|
|
|
if(asset.getAssetType() == Asset.AssetType.CORE_ASSET){
|
|
|
|
assetType = BitsharesAsset.Type.CORE;
|
|
|
|
}else if(asset.getAssetType() == Asset.AssetType.SMART_COIN){
|
|
|
|
assetType = BitsharesAsset.Type.SMART_COIN;
|
|
|
|
}else if(asset.getAssetType() == Asset.AssetType.PREDICTION_MARKET){
|
|
|
|
assetType = BitsharesAsset.Type.PREDICTION_MARKET;
|
|
|
|
}else if(asset.getAssetType() == Asset.AssetType.UIA){
|
|
|
|
assetType = BitsharesAsset.Type.UIA;
|
|
|
|
}
|
|
|
|
currency = new BitsharesAsset(asset.getSymbol(),asset.getPrecision(),asset.getObjectId(), assetType);
|
|
|
|
db.cryptoCurrencyDao().insertCryptoCurrency(currency);
|
|
|
|
|
|
|
|
}
|
|
|
|
transaction.setIdCurrency(currency.getId());
|
|
|
|
transaction.setConfirmed(true); //graphene transaction are always confirmed
|
|
|
|
//TODO date of the transaction transaction.setDate(transfer.);
|
|
|
|
transaction.setFrom(transfer.getOperation().getFrom().getName());
|
|
|
|
transaction.setInput(!transfer.getOperation().getFrom().getName().equals(account.getName()));
|
|
|
|
transaction.setTo(transfer.getOperation().getTo().getName());
|
|
|
|
db.transactionDao().insertTransaction(transaction);
|
|
|
|
}
|
|
|
|
if(transfers.size()>= limit){
|
|
|
|
int newStart= start + limit;
|
|
|
|
int newStop= stop + limit;
|
|
|
|
ApiRequest transactionRequest = new ApiRequest(newStart/limit, new TransactionRequestListener(newStart,newStop,limit,account,db));
|
|
|
|
GrapheneApiGenerator.getAccountTransaction(account.getName(),newStart,newStop,limit,transactionRequest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void fail(int idPetition) {
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private class AccountIdOrNameListener implements ApiRequestListener{
|
|
|
|
Object SYNC;
|
|
|
|
boolean ready = false;
|
|
|
|
|
|
|
|
GrapheneAccount account;
|
|
|
|
|
|
|
|
public AccountIdOrNameListener(Object SYNC) {
|
|
|
|
this.SYNC = SYNC;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void success(Object answer, int idPetition) {
|
|
|
|
if(answer instanceof AccountProperties){
|
|
|
|
AccountProperties props = (AccountProperties) answer;
|
|
|
|
account = new GrapheneAccount();
|
|
|
|
account.setAccountId(props.id);
|
|
|
|
account.setName(props.name);
|
|
|
|
}
|
|
|
|
|
|
|
|
synchronized (SYNC){
|
|
|
|
ready = true;
|
|
|
|
SYNC.notifyAll();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void fail(int idPetition) {
|
|
|
|
synchronized (SYNC){
|
|
|
|
ready = true;
|
|
|
|
SYNC.notifyAll();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-27 02:48:34 +00:00
|
|
|
}
|