Implemented the send service of bitcoin likes account with the new architecture
This commit is contained in:
parent
6b37db9279
commit
b3442a511e
7 changed files with 211 additions and 71 deletions
|
@ -25,6 +25,12 @@ public interface BitcoinAddressDao {
|
||||||
@Query("SELECT * FROM bitcoin_address ba WHERE ba.address = :address")
|
@Query("SELECT * FROM bitcoin_address ba WHERE ba.address = :address")
|
||||||
BitcoinAddress getdadress(String address);
|
BitcoinAddress getdadress(String address);
|
||||||
|
|
||||||
|
@Query("SELECT * FROM bitcoin_address ba WHERE ba.address_index = :index and ba.is_change = 'true'")
|
||||||
|
BitcoinAddress getChangeByIndex(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);
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
public long[] insertBitcoinAddresses(BitcoinAddress... addresses);
|
public long[] insertBitcoinAddresses(BitcoinAddress... addresses);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,15 @@ public interface BitcoinTransactionDao {
|
||||||
@Query("SELECT * FROM bitcoin_transaction bt WHERE bt.tx_id = :txid")
|
@Query("SELECT * FROM bitcoin_transaction bt WHERE bt.tx_id = :txid")
|
||||||
List<BitcoinTransaction> getTransactionsByTxid(String txid);
|
List<BitcoinTransaction> getTransactionsByTxid(String txid);
|
||||||
|
|
||||||
|
@Query("SELECT * FROM bitcoin_transaction bt WHERE bt.crypto_coin_transaction_id = :idCryptoCoinTransaction")
|
||||||
|
BitcoinTransaction getBitcoinTransactionByCryptoCoinTransaction(long idCryptoCoinTransaction);
|
||||||
|
|
||||||
|
@Query("SELECT * FROM bitcoin_transaction_gt_io bt WHERE bt.bitcoin_transaction_id= :idBitcoinTransaction")
|
||||||
|
List<BitcoinTransactionGTxIO> getGtxIOByTransaction(long idBitcoinTransaction);
|
||||||
|
|
||||||
|
@Query("SELECT * FROM bitcoin_transaction_gt_io bt WHERE bt.address= :address")
|
||||||
|
List<BitcoinTransactionGTxIO> getGtxIOByAddress(String address);
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
public long[] insertBitcoinTransaction(BitcoinTransaction... transactions);
|
public long[] insertBitcoinTransaction(BitcoinTransaction... transactions);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package cy.agorise.crystalwallet.enums;
|
package cy.agorise.crystalwallet.enums;
|
||||||
|
|
||||||
|
import org.bitcoinj.core.NetworkParameters;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -11,21 +13,25 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public enum CryptoCoin implements Serializable {
|
public enum CryptoCoin implements Serializable {
|
||||||
BITCOIN(CryptoNet.BITCOIN,"BTC",8),
|
BITCOIN(CryptoNet.BITCOIN,"BTC",8,0,NetworkParameters.fromID(NetworkParameters.ID_MAINNET)),
|
||||||
BITCOIN_TEST(CryptoNet.BITCOIN_TEST,"BTC",8),
|
BITCOIN_TEST(CryptoNet.BITCOIN_TEST,"BTC",8,1,NetworkParameters.fromID(NetworkParameters.ID_TESTNET)),
|
||||||
LITECOIN(CryptoNet.LITECOIN,"LTC",8),
|
LITECOIN(CryptoNet.LITECOIN,"LTC",8,2,null),
|
||||||
DASH(CryptoNet.DASH,"DASH",8),
|
DASH(CryptoNet.DASH,"DASH",8,5,null),
|
||||||
DOGECOIN(CryptoNet.DOGECOIN,"DOGE",8),
|
DOGECOIN(CryptoNet.DOGECOIN,"DOGE",8,3,null),
|
||||||
BITSHARES(CryptoNet.BITSHARES,"BTS",5);
|
BITSHARES(CryptoNet.BITSHARES,"BTS",5,0,null);
|
||||||
|
|
||||||
protected CryptoNet cryptoNet;
|
protected CryptoNet cryptoNet;
|
||||||
protected String label;
|
protected String label;
|
||||||
protected int precision;
|
protected int precision;
|
||||||
|
protected int coinNumber;
|
||||||
|
protected NetworkParameters parameters;
|
||||||
|
|
||||||
CryptoCoin(CryptoNet cryptoNet, String label, int precision){
|
CryptoCoin(CryptoNet cryptoNet, String label, int precision, int coinNumber, NetworkParameters parameters){
|
||||||
this.cryptoNet = cryptoNet;
|
this.cryptoNet = cryptoNet;
|
||||||
this.label = label;
|
this.label = label;
|
||||||
this.precision = precision;
|
this.precision = precision;
|
||||||
|
this.coinNumber = coinNumber;
|
||||||
|
this.parameters = parameters;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +44,14 @@ public enum CryptoCoin implements Serializable {
|
||||||
public int getPrecision(){
|
public int getPrecision(){
|
||||||
return this.precision;
|
return this.precision;
|
||||||
}
|
}
|
||||||
|
public NetworkParameters getParameters() {
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCoinNumber() {
|
||||||
|
return coinNumber;
|
||||||
|
}
|
||||||
|
|
||||||
public static List<CryptoCoin> getByCryptoNet(CryptoNet cryptoNet){
|
public static List<CryptoCoin> getByCryptoNet(CryptoNet cryptoNet){
|
||||||
List<CryptoCoin> result = new ArrayList<CryptoCoin>();
|
List<CryptoCoin> result = new ArrayList<CryptoCoin>();
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
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;
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
|
import org.bitcoinj.core.ECKey;
|
||||||
import org.bitcoinj.core.Sha256Hash;
|
import org.bitcoinj.core.Sha256Hash;
|
||||||
import org.bitcoinj.core.Transaction;
|
import org.bitcoinj.core.Transaction;
|
||||||
import org.bitcoinj.core.TransactionOutPoint;
|
import org.bitcoinj.core.TransactionOutPoint;
|
||||||
import org.bitcoinj.crypto.ChildNumber;
|
import org.bitcoinj.crypto.ChildNumber;
|
||||||
|
import org.bitcoinj.crypto.DeterministicKey;
|
||||||
import org.bitcoinj.crypto.HDKeyDerivation;
|
import org.bitcoinj.crypto.HDKeyDerivation;
|
||||||
import org.bitcoinj.script.Script;
|
import org.bitcoinj.script.Script;
|
||||||
|
|
||||||
|
@ -23,11 +26,16 @@ 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.BitcoinAddress;
|
||||||
import cy.agorise.crystalwallet.models.BitcoinTransaction;
|
import cy.agorise.crystalwallet.models.BitcoinTransaction;
|
||||||
import cy.agorise.crystalwallet.models.BitcoinTransactionGTxIO;
|
import cy.agorise.crystalwallet.models.BitcoinTransactionGTxIO;
|
||||||
|
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.CryptoNetAccount;
|
import cy.agorise.crystalwallet.models.CryptoNetAccount;
|
||||||
import cy.agorise.crystalwallet.models.GTxIO;
|
import cy.agorise.crystalwallet.models.GTxIO;
|
||||||
import cy.agorise.crystalwallet.models.GeneralCoinAddress;
|
import cy.agorise.crystalwallet.models.GeneralCoinAddress;
|
||||||
|
@ -102,6 +110,7 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf
|
||||||
if (!ccTransaction.isConfirmed() && btTransaction.getConfirmations() >= cryptoCoin.getCryptoNet().getConfirmationsNeeded()) {
|
if (!ccTransaction.isConfirmed() && btTransaction.getConfirmations() >= cryptoCoin.getCryptoNet().getConfirmationsNeeded()) {
|
||||||
ccTransaction.setConfirmed(true);
|
ccTransaction.setConfirmed(true);
|
||||||
db.transactionDao().insertTransaction(ccTransaction);
|
db.transactionDao().insertTransaction(ccTransaction);
|
||||||
|
updateBalance(ccTransaction,(ccTransaction.getInput()?1:-1)*ccTransaction.getAmount(),db);
|
||||||
}
|
}
|
||||||
|
|
||||||
db.bitcoinTransactionDao().insertBitcoinTransaction(btTransaction);
|
db.bitcoinTransactionDao().insertBitcoinTransaction(btTransaction);
|
||||||
|
@ -140,8 +149,26 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf
|
||||||
input.setOriginalTxId(vin.txid);
|
input.setOriginalTxId(vin.txid);
|
||||||
input.setScriptHex(vin.scriptSig.hex);
|
input.setScriptHex(vin.scriptSig.hex);
|
||||||
|
|
||||||
|
BitcoinAddress address = db.bitcoinAddressDao().getdadress(addr);
|
||||||
|
if(address != null){
|
||||||
|
if(ccTransaction.getAccountId() < 0){
|
||||||
|
ccTransaction.setAccountId(address.getAccountId());
|
||||||
|
ccTransaction.setFrom(addr);
|
||||||
|
ccTransaction.setInput(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ccTransaction.getAccountId()== address.getAccountId()){
|
||||||
|
amount -= vin.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ccTransaction.getFrom() == null || ccTransaction.getFrom().isEmpty()){
|
||||||
|
ccTransaction.setFrom(addr);
|
||||||
|
}
|
||||||
|
|
||||||
gtxios.add(input);
|
gtxios.add(input);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Vout vout : txi.vout) {
|
for (Vout vout : txi.vout) {
|
||||||
|
@ -155,90 +182,118 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf
|
||||||
output.setOutput(false);
|
output.setOutput(false);
|
||||||
output.setAmount((long) (vout.value * Math.pow(10, cryptoCoin.getPrecision())));
|
output.setAmount((long) (vout.value * Math.pow(10, cryptoCoin.getPrecision())));
|
||||||
output.setScriptHex(vout.scriptPubKey.hex);
|
output.setScriptHex(vout.scriptPubKey.hex);
|
||||||
|
output.setOriginalTxId(txi.txid);
|
||||||
|
|
||||||
gtxios.add(output);
|
gtxios.add(output);
|
||||||
/*for (GeneralCoinAddress address : this.mAddresses) {
|
BitcoinAddress address = db.bitcoinAddressDao().getdadress(addr);
|
||||||
if (address.getAddressString(this.mAccount.getNetworkParam()).equals(addr)) {
|
if(address != null){
|
||||||
output.setAddress(address);
|
if(ccTransaction.getAccountId() < 0){
|
||||||
tempAccount = address.getAccount();
|
ccTransaction.setAccountId(address.getAccountId());
|
||||||
|
ccTransaction.setInput(true);
|
||||||
|
ccTransaction.setTo(addr);
|
||||||
|
}
|
||||||
|
|
||||||
if (!address.hasTransactionInput(output, this.mAccount.getNetworkParam())) {
|
if(ccTransaction.getAccountId()== address.getAccountId()){
|
||||||
address.getTransactionInput().add(output);
|
amount += vout.value;
|
||||||
}
|
}
|
||||||
changed = true;
|
}else{
|
||||||
}
|
//TOOD multiple send address
|
||||||
}*/
|
if(ccTransaction.getTo() == null || ccTransaction.getTo().isEmpty()){
|
||||||
|
ccTransaction.setTo(addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ccTransaction.setAmount(amount);
|
||||||
|
CryptoCurrency currency = db.cryptoCurrencyDao().getByNameAndCryptoNet(this.cryptoCoin.name(), this.cryptoCoin.getCryptoNet().name());
|
||||||
|
if (currency == null) {
|
||||||
|
currency = new CryptoCurrency();
|
||||||
|
currency.setCryptoNet(this.cryptoCoin.getCryptoNet());
|
||||||
|
currency.setName(this.cryptoCoin.name());
|
||||||
|
currency.setPrecision(this.cryptoCoin.getPrecision());
|
||||||
|
long idCurrency = db.cryptoCurrencyDao().insertCryptoCurrency(currency)[0];
|
||||||
|
currency.setId(idCurrency);
|
||||||
|
}
|
||||||
|
|
||||||
|
ccTransaction.setIdCurrency((int)currency.getId());
|
||||||
|
|
||||||
long ccId = db.transactionDao().insertTransaction(ccTransaction)[0];
|
long ccId = db.transactionDao().insertTransaction(ccTransaction)[0];
|
||||||
btTransaction.setCryptoCoinTransactionId(ccId);
|
btTransaction.setCryptoCoinTransactionId(ccId);
|
||||||
long btId = db.bitcoinTransactionDao().insertBitcoinTransaction(btTransaction)[0];
|
long btId = db.bitcoinTransactionDao().insertBitcoinTransaction(btTransaction)[0];
|
||||||
for(BitcoinTransactionGTxIO gtxio : gtxios){
|
for(BitcoinTransactionGTxIO gtxio : gtxios){
|
||||||
gtxio.setBitcoinTransactionId(btId);
|
gtxio.setBitcoinTransactionId(btId);
|
||||||
|
db.bitcoinTransactionDao().insertBitcoinTransactionGTxIO(gtxio);
|
||||||
}
|
}
|
||||||
//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()) {
|
if(ccTransaction.isConfirmed()) {
|
||||||
InsightApiGenerator.followTransaction();
|
updateBalance(ccTransaction,amount,db);
|
||||||
new GetTransactionData(transaction.getTxid(), tempAccount, this.serverUrl, this.mContext, true).start();
|
|
||||||
}
|
}
|
||||||
for (GeneralCoinAddress address : this.mAddresses) {
|
|
||||||
if (address.updateTransaction(transaction)) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateBalance(CryptoCoinTransaction ccTransaction, long amount, CrystalDatabase db){
|
||||||
|
CryptoCurrency currency = db.cryptoCurrencyDao().getByNameAndCryptoNet(this.cryptoCoin.name(), this.cryptoCoin.getCryptoNet().name());
|
||||||
|
if (currency == null) {
|
||||||
|
currency = new CryptoCurrency();
|
||||||
|
currency.setCryptoNet(this.cryptoCoin.getCryptoNet());
|
||||||
|
currency.setName(this.cryptoCoin.name());
|
||||||
|
currency.setPrecision(this.cryptoCoin.getPrecision());
|
||||||
|
long idCurrency = db.cryptoCurrencyDao().insertCryptoCurrency(currency)[0];
|
||||||
|
currency.setId(idCurrency);
|
||||||
|
}
|
||||||
|
|
||||||
|
CryptoCoinBalance balance = db.cryptoCoinBalanceDao().getBalanceFromAccount(ccTransaction.getAccountId(), currency.getId());
|
||||||
|
if (balance == null) {
|
||||||
|
balance = new CryptoCoinBalance();
|
||||||
|
balance.setAccountId(ccTransaction.getAccountId());
|
||||||
|
balance.setCryptoCurrencyId(currency.getId());
|
||||||
|
long idBalance = db.cryptoCoinBalanceDao().insertCryptoCoinBalance(balance)[0];
|
||||||
|
balance.setId(idBalance);
|
||||||
|
}
|
||||||
|
balance.setBalance(balance.getBalance()+amount);
|
||||||
|
db.cryptoCoinBalanceDao().insertCryptoCoinBalance(balance);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void send(final GeneralAccountSendRequest request){
|
public void send(final GeneralAccountSendRequest request){
|
||||||
//TODO check server connection
|
//TODO check server connection
|
||||||
//TODO validate to address
|
//TODO validate to address
|
||||||
|
|
||||||
InsightApiGenerator.getEstimateFee(request.getAccount().getCryptoCoin(),new ApiRequest(1, new ApiRequestListener() {
|
InsightApiGenerator.getEstimateFee(this.cryptoCoin,new ApiRequest(1, new ApiRequestListener() {
|
||||||
@Override
|
@Override
|
||||||
public void success(Object answer, int idPetition) {
|
public void success(Object answer, int idPetition) {
|
||||||
Transaction tx = new Transaction(request.getAccount().getNetworkParam());
|
Transaction tx = new Transaction(cryptoCoin.getParameters());
|
||||||
long currentAmount = 0;
|
long currentAmount = 0;
|
||||||
long fee = -1;
|
long fee = -1;
|
||||||
long feeRate = (Long) answer;
|
long feeRate = (Long) answer;
|
||||||
fee = 226 * feeRate;
|
fee = 226 * feeRate;
|
||||||
|
|
||||||
List<GeneralCoinAddress> addresses = request.getAccount().getAddresses();
|
CrystalDatabase db = CrystalDatabase.getAppDatabase(request.getContext());
|
||||||
List<GTxIO> utxos = new ArrayList();
|
db.bitcoinTransactionDao();
|
||||||
for(GeneralCoinAddress address : addresses){
|
|
||||||
List<GTxIO> addrUtxos = address.getUTXos();
|
|
||||||
for(GTxIO addrUtxo : addrUtxos){
|
|
||||||
utxos.add(addrUtxo);
|
|
||||||
currentAmount += addrUtxo.getAmount();
|
|
||||||
if(currentAmount >= request.getAmount()+ fee){
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(currentAmount >= request.getAmount() + fee){
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
List<BitcoinTransactionGTxIO> utxos = getUtxos(request.getAccount().getId(),db);
|
||||||
|
|
||||||
if(currentAmount< request.getAmount() + fee){
|
if(currentAmount< request.getAmount() + fee){
|
||||||
request.setStatus(GeneralAccountSendRequest.StatusCode.NO_BALANCE);
|
request.setStatus(GeneralAccountSendRequest.StatusCode.NO_BALANCE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
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));
|
||||||
|
DeterministicKey changeKey = HDKeyDerivation.deriveChildKey(accountKey,
|
||||||
|
new ChildNumber(1, false));
|
||||||
|
|
||||||
//String to an address
|
//String to an address
|
||||||
Address toAddr = Address.fromBase58(request.getAccount().getNetworkParam(), request.getToAccount());
|
Address toAddr = Address.fromBase58(cryptoCoin.getParameters(), request.getToAccount());
|
||||||
tx.addOutput(Coin.valueOf(request.getAmount()), toAddr);
|
tx.addOutput(Coin.valueOf(request.getAmount()), toAddr);
|
||||||
|
|
||||||
if(request.getMemo()!= null && !request.getMemo().isEmpty()){
|
/*if(request.getMemo()!= null && !request.getMemo().isEmpty()){
|
||||||
String memo = request.getMemo();
|
String memo = request.getMemo();
|
||||||
if(request.getMemo().length()>40){
|
if(request.getMemo().length()>40){
|
||||||
memo = memo.substring(0,40);
|
memo = memo.substring(0,40);
|
||||||
|
@ -249,30 +304,50 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf
|
||||||
System.arraycopy(memo.getBytes(),0,scriptByte,2,memo.length());
|
System.arraycopy(memo.getBytes(),0,scriptByte,2,memo.length());
|
||||||
Script memoScript = new Script(scriptByte);
|
Script memoScript = new Script(scriptByte);
|
||||||
tx.addOutput(Coin.valueOf(0),memoScript);
|
tx.addOutput(Coin.valueOf(0),memoScript);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
//Change address
|
//Change address
|
||||||
long remain = currentAmount - request.getAmount() - fee;
|
long remain = currentAmount - request.getAmount() - fee;
|
||||||
if( remain > 0 ) {
|
if( remain > 0 ) {
|
||||||
Address changeAddr = Address.fromBase58(request.getAccount().getNetworkParam(), request.getAccount().getNextChangeAddress());
|
long index = db.bitcoinAddressDao().getLastChangeAddress(request.getAccount().getId());
|
||||||
|
BitcoinAddress btAddress = db.bitcoinAddressDao().getChangeByIndex(index);
|
||||||
|
Address changeAddr;
|
||||||
|
if(btAddress != null && db.bitcoinTransactionDao().getGtxIOByAddress(btAddress.getAddress()).size()<=0){
|
||||||
|
changeAddr = Address.fromBase58(cryptoCoin.getParameters(), btAddress.getAddress());
|
||||||
|
|
||||||
|
}else{
|
||||||
|
if(btAddress == null){
|
||||||
|
index = 0;
|
||||||
|
}else{
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
btAddress = new BitcoinAddress();
|
||||||
|
btAddress.setIndex(index);
|
||||||
|
btAddress.setAccountId(request.getAccount().getId());
|
||||||
|
btAddress.setChange(true);
|
||||||
|
btAddress.setAddress(HDKeyDerivation.deriveChildKey(changeKey, new ChildNumber((int) btAddress.getIndex(), false)).toAddress(cryptoCoin.getParameters()).toString());
|
||||||
|
db.bitcoinAddressDao().insertBitcoinAddresses(btAddress);
|
||||||
|
changeAddr = Address.fromBase58(cryptoCoin.getParameters(), btAddress.getAddress());
|
||||||
|
}
|
||||||
tx.addOutput(Coin.valueOf(remain), changeAddr);
|
tx.addOutput(Coin.valueOf(remain), changeAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(GTxIO utxo: utxos) {
|
for(BitcoinTransactionGTxIO utxo: utxos) {
|
||||||
Sha256Hash txHash = Sha256Hash.wrap(utxo.getTransaction().getTxid());
|
Sha256Hash txHash = Sha256Hash.wrap(utxo.getOriginalTxId());
|
||||||
Script script = new Script(Util.hexToBytes(utxo.getScriptHex()));
|
Script script = new Script(Util.hexToBytes(utxo.getScriptHex()));
|
||||||
TransactionOutPoint outPoint = new TransactionOutPoint(request.getAccount().getNetworkParam(), utxo.getIndex(), txHash);
|
TransactionOutPoint outPoint = new TransactionOutPoint(cryptoCoin.getParameters(), utxo.getIndex(), txHash);
|
||||||
if(utxo.getAddress().getKey().isPubKeyOnly()){
|
BitcoinAddress btAddress = db.bitcoinAddressDao().getdadress(utxo.getAddress());
|
||||||
if(utxo.getAddress().isIsChange()){
|
ECKey addrKey;
|
||||||
utxo.getAddress().setKey(HDKeyDerivation.deriveChildKey(request.getAccount().getChangeKey(), new ChildNumber(utxo.getAddress().getIndex(), false)));
|
|
||||||
|
if(btAddress.isChange()){
|
||||||
|
addrKey = HDKeyDerivation.deriveChildKey(changeKey, new ChildNumber((int) btAddress.getIndex(), false));
|
||||||
}else{
|
}else{
|
||||||
utxo.getAddress().setKey(HDKeyDerivation.deriveChildKey(request.getAccount().getExternalKey(), new ChildNumber(utxo.getAddress().getIndex(), false)));
|
addrKey = HDKeyDerivation.deriveChildKey(changeKey, new ChildNumber((int) btAddress.getIndex(), true));
|
||||||
}
|
}
|
||||||
}
|
tx.addSignedInput(outPoint, script, addrKey, Transaction.SigHash.ALL, true);
|
||||||
tx.addSignedInput(outPoint, script, utxo.getAddress().getKey(), Transaction.SigHash.ALL, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InsightApiGenerator.broadcastTransaction(request.getAccount().getCryptoCoin(),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(GeneralAccountSendRequest.StatusCode.SUCCEEDED);
|
||||||
|
@ -292,4 +367,37 @@ public class GeneralAccountManager implements CryptoAccountManager, CryptoNetInf
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<BitcoinTransactionGTxIO> getUtxos(long accountId, CrystalDatabase db){
|
||||||
|
List<BitcoinTransactionGTxIO> answer = new ArrayList<>();
|
||||||
|
List<BitcoinTransactionGTxIO> bTGTxI = new ArrayList<>();
|
||||||
|
List<BitcoinTransactionGTxIO> bTGTxO = new ArrayList<>();
|
||||||
|
List<CryptoCoinTransaction> ccTransactions = db.transactionDao().getByIdAccount(accountId);
|
||||||
|
for(CryptoCoinTransaction ccTransaction : ccTransactions) {
|
||||||
|
List<BitcoinTransactionGTxIO> gtxios = db.bitcoinTransactionDao().getGtxIOByTransaction(ccTransaction.getId());
|
||||||
|
for(BitcoinTransactionGTxIO gtxio : gtxios){
|
||||||
|
if(db.bitcoinAddressDao().addressExists(gtxio.getAddress())){
|
||||||
|
if(gtxio.isOutput()){
|
||||||
|
bTGTxO.add(gtxio);
|
||||||
|
}else{
|
||||||
|
bTGTxI.add(gtxio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(BitcoinTransactionGTxIO gtxi : bTGTxI){
|
||||||
|
boolean find = false;
|
||||||
|
for(BitcoinTransactionGTxIO gtxo : bTGTxO){
|
||||||
|
if(gtxo.getOriginalTxId().equals(gtxi.getOriginalTxId())){
|
||||||
|
find = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!find){
|
||||||
|
answer.add(gtxi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return answer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,9 @@ public class BitcoinAddress {
|
||||||
this.address = address;
|
this.address = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BitcoinAddress() {
|
||||||
|
}
|
||||||
|
|
||||||
public long getAccountId() {
|
public long getAccountId() {
|
||||||
return accountId;
|
return accountId;
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ public class CryptoCoinTransaction {
|
||||||
* The id of the account assoiciated, this is used for the foreign key definition
|
* The id of the account assoiciated, this is used for the foreign key definition
|
||||||
*/
|
*/
|
||||||
@ColumnInfo(name="account_id")
|
@ColumnInfo(name="account_id")
|
||||||
protected long accountId;
|
protected long accountId = -1;
|
||||||
/**
|
/**
|
||||||
* The amount of asset is moved in this transaction
|
* The amount of asset is moved in this transaction
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -3,7 +3,7 @@ package cy.agorise.crystalwallet.requestmanagers;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import cy.agorise.crystalwallet.enums.CryptoCoin;
|
import cy.agorise.crystalwallet.enums.CryptoCoin;
|
||||||
import cy.agorise.crystalwallet.models.GeneralCoinAccount;
|
import cy.agorise.crystalwallet.models.CryptoNetAccount;
|
||||||
|
|
||||||
public class GeneralAccountSendRequest extends CryptoNetInfoRequest {
|
public class GeneralAccountSendRequest extends CryptoNetInfoRequest {
|
||||||
/**
|
/**
|
||||||
|
@ -23,7 +23,7 @@ public class GeneralAccountSendRequest extends CryptoNetInfoRequest {
|
||||||
// The app context
|
// The app context
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
//The soruce Account
|
//The soruce Account
|
||||||
private GeneralCoinAccount mAccount;
|
private CryptoNetAccount mAccount;
|
||||||
// The destination account address
|
// The destination account address
|
||||||
private String mToAccount;
|
private String mToAccount;
|
||||||
// The amount of the transaction
|
// The amount of the transaction
|
||||||
|
@ -33,7 +33,7 @@ public class GeneralAccountSendRequest extends CryptoNetInfoRequest {
|
||||||
// The state of this request
|
// The state of this request
|
||||||
private StatusCode status = StatusCode.NOT_STARTED;
|
private StatusCode status = StatusCode.NOT_STARTED;
|
||||||
|
|
||||||
public GeneralAccountSendRequest(CryptoCoin coin, Context context, GeneralCoinAccount account, String toAccount, long amount, String memo) {
|
public GeneralAccountSendRequest(CryptoCoin coin, Context context, CryptoNetAccount account, String toAccount, long amount, String memo) {
|
||||||
super(coin);
|
super(coin);
|
||||||
this.mContext = context;
|
this.mContext = context;
|
||||||
this.mAccount = account;
|
this.mAccount = account;
|
||||||
|
@ -42,7 +42,7 @@ public class GeneralAccountSendRequest extends CryptoNetInfoRequest {
|
||||||
this.mMemo = memo;
|
this.mMemo = memo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GeneralAccountSendRequest(CryptoCoin coin, Context context, GeneralCoinAccount account, String toAccount, long amount) {
|
public GeneralAccountSendRequest(CryptoCoin coin, Context context, CryptoNetAccount account, String toAccount, long amount) {
|
||||||
this(coin,context,account,toAccount,amount,null);
|
this(coin,context,account,toAccount,amount,null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ public class GeneralAccountSendRequest extends CryptoNetInfoRequest {
|
||||||
return mContext;
|
return mContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GeneralCoinAccount getAccount() {
|
public CryptoNetAccount getAccount() {
|
||||||
return mAccount;
|
return mAccount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue