Fix realm issues (#1819)

* normalise Realm use consistent.
* Fix for opensea querying
* ensure key upgrade works correctly
* Always show testnet message
pull/1826/head
James Brown 4 years ago committed by GitHub
parent cb27462773
commit f195a654ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      app/src/main/java/com/alphawallet/app/di/RepositoriesModule.java
  2. 2
      app/src/main/java/com/alphawallet/app/entity/ContractLocator.java
  3. 17
      app/src/main/java/com/alphawallet/app/entity/Transaction.java
  4. 3
      app/src/main/java/com/alphawallet/app/entity/tokenscript/TokenScriptFile.java
  5. 13
      app/src/main/java/com/alphawallet/app/interact/FetchTransactionsInteract.java
  6. 4
      app/src/main/java/com/alphawallet/app/interact/FetchWalletsInteract.java
  7. 12
      app/src/main/java/com/alphawallet/app/interact/GenericWalletInteract.java
  8. 15
      app/src/main/java/com/alphawallet/app/repository/TokenRepository.java
  9. 58
      app/src/main/java/com/alphawallet/app/repository/TokensRealmSource.java
  10. 113
      app/src/main/java/com/alphawallet/app/repository/TransactionsRealmCache.java
  11. 137
      app/src/main/java/com/alphawallet/app/repository/WalletDataRealmSource.java
  12. 12
      app/src/main/java/com/alphawallet/app/repository/WalletRepository.java
  13. 6
      app/src/main/java/com/alphawallet/app/repository/WalletRepositoryType.java
  14. 62
      app/src/main/java/com/alphawallet/app/service/AssetDefinitionService.java
  15. 6
      app/src/main/java/com/alphawallet/app/service/GasService2.java
  16. 2
      app/src/main/java/com/alphawallet/app/service/OpenseaService.java
  17. 56
      app/src/main/java/com/alphawallet/app/service/TickerService.java
  18. 34
      app/src/main/java/com/alphawallet/app/service/TokensService.java
  19. 132
      app/src/main/java/com/alphawallet/app/service/TransactionsNetworkClient.java
  20. 2
      app/src/main/java/com/alphawallet/app/service/TransactionsNetworkClientType.java
  21. 190
      app/src/main/java/com/alphawallet/app/service/TransactionsService.java
  22. 15
      app/src/main/java/com/alphawallet/app/ui/BackupFlowActivity.java
  23. 11
      app/src/main/java/com/alphawallet/app/ui/BackupKeyActivity.java
  24. 18
      app/src/main/java/com/alphawallet/app/ui/HomeActivity.java
  25. 3
      app/src/main/java/com/alphawallet/app/ui/NewSettingsFragment.java
  26. 2
      app/src/main/java/com/alphawallet/app/ui/SelectCurrencyActivity.java
  27. 2
      app/src/main/java/com/alphawallet/app/ui/SelectLocaleActivity.java
  28. 21
      app/src/main/java/com/alphawallet/app/ui/SelectNetworkActivity.java
  29. 2
      app/src/main/java/com/alphawallet/app/ui/SignDetailActivity.java
  30. 2
      app/src/main/java/com/alphawallet/app/ui/WalletConnectSessionActivity.java
  31. 4
      app/src/main/java/com/alphawallet/app/ui/WalletFragment.java
  32. 2
      app/src/main/java/com/alphawallet/app/viewmodel/BackupKeyViewModel.java
  33. 4
      app/src/main/java/com/alphawallet/app/viewmodel/NewSettingsViewModel.java
  34. 207
      app/src/main/java/com/alphawallet/app/viewmodel/WalletConnectViewModel.java
  35. 8
      app/src/main/java/com/alphawallet/app/viewmodel/WalletViewModel.java
  36. 16
      app/src/main/java/com/alphawallet/app/widget/ActionSheetDialog.java
  37. 2
      app/src/main/java/com/alphawallet/app/widget/AddressDetailView.java
  38. 122
      app/src/main/res/layout/activity_list.xml
  39. 37
      app/src/main/res/layout/basic_list_activity.xml
  40. 2
      build.gradle

@ -171,9 +171,8 @@ public class RepositoriesModule {
PreferenceRepositoryType preferenceRepository,
EthereumNetworkRepositoryType ethereumNetworkRepositoryType,
TransactionsNetworkClientType transactionsNetworkClientType,
TransactionLocalSource transactionLocalSource,
Context context) {
return new TransactionsService(tokensService, preferenceRepository, ethereumNetworkRepositoryType, transactionsNetworkClientType, transactionLocalSource, context);
TransactionLocalSource transactionLocalSource) {
return new TransactionsService(tokensService, preferenceRepository, ethereumNetworkRepositoryType, transactionsNetworkClientType, transactionLocalSource);
}
@Singleton

@ -44,7 +44,7 @@ public class ContractLocator implements Parcelable
public boolean equals(Token token)
{
return (token != null && address != null && address.equalsIgnoreCase(token.getAddress()) && chainId == token.tokenInfo.chainId);
return (token != null && address != null && chainId == token.tokenInfo.chainId && address.equalsIgnoreCase(token.getAddress()) );
}
public boolean equals(TokenCardMeta token)

@ -355,6 +355,23 @@ public class Transaction implements Parcelable
}
}
public TransactionType getTransactionType(String wallet)
{
if (hasError())
{
return TransactionType.UNKNOWN;
}
else if (hasInput())
{
decodeTransactionInput(wallet);
return transactionInput.type;
}
else
{
return TransactionType.SEND_ETH;
}
}
/**
* Supplimental info in this case is the intrinsic root value attached to a contract call
* EG: Calling cryptokitties ERC721 'breedWithAuto' function requires you to call the function and also attach a small amount of ETH

@ -10,6 +10,7 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
import com.alphawallet.app.BuildConfig;
import com.alphawallet.app.R;
import com.alphawallet.token.entity.SigReturnType;
import com.alphawallet.token.entity.XMLDsigDescriptor;
@ -62,7 +63,7 @@ public class TokenScriptFile extends File
}
catch (IOException e)
{
e.printStackTrace();
if (BuildConfig.DEBUG) e.printStackTrace();
}
}
}

@ -66,25 +66,12 @@ public class FetchTransactionsInteract {
return transactionRepository.getRealmInstance(wallet);
}
public Single<ActivityMeta[]> fetchTransactionMetas(Wallet wallet, int chainId, String tokenAddress, int historyCount)
{
return transactionRepository
.fetchCachedTransactionMetas(wallet, chainId, tokenAddress, historyCount)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
public RealmAuxData fetchEvent(String walletAddress, String eventKey)
{
return transactionRepository
.fetchCachedEvent(walletAddress, eventKey);
}
public Single<Transaction> storeRawTx(Wallet wallet, EthTransaction rawTx, long timeStamp)
{
return transactionRepository.storeRawTx(wallet, rawTx, timeStamp);
}
public void restartTransactionService()
{
transactionRepository.restartService();

@ -47,9 +47,9 @@ public class FetchWalletsInteract {
*
* @param walletAddr
*/
public Disposable updateBackupTime(String walletAddr)
public void updateBackupTime(String walletAddr)
{
return accountRepository.updateBackupTime(walletAddr);
accountRepository.updateBackupTime(walletAddr);
}
public Single<Wallet> updateENS(Wallet wallet)

@ -37,9 +37,9 @@ public class GenericWalletInteract
*
* @param walletAddr
*/
public Disposable updateBackupTime(String walletAddr)
public void updateBackupTime(String walletAddr)
{
return walletRepository.updateBackupTime(walletAddr);
walletRepository.updateBackupTime(walletAddr);
}
/**
@ -48,9 +48,9 @@ public class GenericWalletInteract
*
* @param walletAddr
*/
public Disposable updateWarningTime(String walletAddr)
public void updateWarningTime(String walletAddr)
{
return walletRepository.updateWarningTime(walletAddr);
walletRepository.updateWarningTime(walletAddr);
}
public Single<String> getWalletNeedsBackup(String walletAddr)
@ -58,9 +58,9 @@ public class GenericWalletInteract
return walletRepository.getWalletRequiresBackup(walletAddr);
}
public Single<String> setIsDismissed(String walletAddr, boolean isDismissed)
public void setIsDismissed(String walletAddr, boolean isDismissed)
{
return walletRepository.setIsDismissed(walletAddr, isDismissed);
walletRepository.setIsDismissed(walletAddr, isDismissed);
}
/**

@ -84,6 +84,8 @@ public class TokenRepository implements TokenRepositoryType {
public static final String INVALID_CONTRACT = "<invalid>";
private static final boolean LOG_CONTRACT_EXCEPTION_EVENTS = false;
public static final BigInteger INTERFACE_CRYPTOKITTIES = new BigInteger ("9a20483d", 16);
public static final BigInteger INTERFACE_OFFICIAL_ERC721 = new BigInteger ("80ac58cd", 16);
public static final BigInteger INTERFACE_OLD_ERC721 = new BigInteger ("6466353c", 16);
@ -451,7 +453,6 @@ public class TokenRepository implements TokenRepositoryType {
@Override
public Completable setVisibilityChanged(Wallet wallet, Token token)
{
NetworkInfo network = ethereumNetworkRepository.getDefaultNetwork();
localSource.setVisibilityChanged(wallet, token);
return Completable.fromAction(() -> {});
}
@ -513,7 +514,7 @@ public class TokenRepository implements TokenRepositoryType {
}
catch (Exception e)
{
e.printStackTrace();
if (LOG_CONTRACT_EXCEPTION_EVENTS) e.printStackTrace();
}
return hasBalanceChanged;
@ -602,7 +603,7 @@ public class TokenRepository implements TokenRepositoryType {
}
catch (Exception e)
{
e.printStackTrace();
if (LOG_CONTRACT_EXCEPTION_EVENTS) e.printStackTrace();
return token;
}
});
@ -777,7 +778,7 @@ public class TokenRepository implements TokenRepositoryType {
}
catch (Exception e)
{
e.printStackTrace();
if (LOG_CONTRACT_EXCEPTION_EVENTS) e.printStackTrace();
return BigDecimal.valueOf(-1);
}
}
@ -797,7 +798,7 @@ public class TokenRepository implements TokenRepositoryType {
}
catch (Exception e)
{
e.printStackTrace();
if (LOG_CONTRACT_EXCEPTION_EVENTS) e.printStackTrace();
return BigDecimal.valueOf(-1);
}
}).subscribeOn(Schedulers.io());
@ -1171,7 +1172,7 @@ public class TokenRepository implements TokenRepositoryType {
}
catch (Exception e)
{
e.printStackTrace();
if (LOG_CONTRACT_EXCEPTION_EVENTS) e.printStackTrace();
return null;
}
}
@ -1221,7 +1222,7 @@ public class TokenRepository implements TokenRepositoryType {
}
catch (Exception e)
{
e.printStackTrace();
if (LOG_CONTRACT_EXCEPTION_EVENTS) e.printStackTrace();
return null;
}
}

@ -134,7 +134,7 @@ public class TokensRealmSource implements TokenLocalSource {
}
else
{
realm.executeTransaction(instance -> {
realm.executeTransaction(r -> {
realmToken.setInterfaceSpec(type.ordinal());
realmToken.setName(token.tokenInfo.name);
realmToken.setSymbol(token.tokenInfo.symbol);
@ -307,17 +307,17 @@ public class TokensRealmSource implements TokenLocalSource {
{
try (Realm realm = realmManager.getRealmInstance(wallet))
{
RealmToken realmToken = realm.where(RealmToken.class)
.equalTo("address", databaseKey(token))
.equalTo("chainId", token.tokenInfo.chainId)
.findFirst();
realm.executeTransactionAsync(r -> {
RealmToken realmToken = r.where(RealmToken.class)
.equalTo("address", databaseKey(token))
.equalTo("chainId", token.tokenInfo.chainId)
.findFirst();
if (realmToken != null)
{
realm.executeTransaction(r -> {
if (realmToken != null)
{
realmToken.setVisibilityChanged(true);
});
}
}
});
}
catch (Exception ex)
{
@ -357,16 +357,17 @@ public class TokensRealmSource implements TokenLocalSource {
String key = databaseKey(chainId, tokenAddress.toLowerCase());
try (Realm realm = realmManager.getRealmInstance(wallet))
{
RealmToken realmToken = realm.where(RealmToken.class)
.equalTo("address", key)
.equalTo("chainId", chainId)
.findFirst();
realm.executeTransactionAsync(r -> {
RealmToken realmToken = r.where(RealmToken.class)
.equalTo("address", key)
.equalTo("chainId", chainId)
.findFirst();
if (realmToken != null)
{
realm.executeTransaction(instance ->
realmToken.setUpdateTime(System.currentTimeMillis()));
}
if (realmToken != null)
{
realmToken.setUpdateTime(System.currentTimeMillis());
}
});
}
catch (Exception e)
{
@ -562,8 +563,8 @@ public class TokensRealmSource implements TokenLocalSource {
if (!Utils.isAddressValid(wallet.address)) return;
try (Realm realm = realmManager.getRealmInstance(wallet))
{
realm.executeTransaction(instance -> {
saveToken(realm, token);
realm.executeTransaction(r -> {
saveToken(r, token);
});
}
catch (Exception ex)
@ -774,17 +775,16 @@ public class TokensRealmSource implements TokenLocalSource {
private void removeLocalTickers(Realm realm)
{
try
{
RealmResults<RealmTokenTicker> realmItems = realm.where(RealmTokenTicker.class)
.findAll();
if (realmItems.size() > 0)
{
realm.executeTransaction(r -> {
realm.executeTransactionAsync(r -> {
RealmResults<RealmTokenTicker> realmItems = r.where(RealmTokenTicker.class)
.findAll();
if (realmItems.size() > 0)
{
realmItems.deleteAllFromRealm();
});
}
}
});
}
catch (Exception e)
{

@ -11,6 +11,7 @@ import com.alphawallet.app.repository.entity.RealmAuxData;
import com.alphawallet.app.repository.entity.RealmTransaction;
import com.alphawallet.app.service.RealmManager;
import org.jetbrains.annotations.NotNull;
import org.web3j.protocol.core.methods.response.EthTransaction;
import java.util.ArrayList;
@ -18,6 +19,7 @@ import java.util.List;
import io.reactivex.Single;
import io.realm.Realm;
import io.realm.RealmQuery;
import io.realm.RealmResults;
import io.realm.Sort;
@ -168,27 +170,12 @@ public class TransactionsRealmCache implements TransactionLocalSource {
{
return Single.fromCallable(() -> {
List<ActivityMeta> metas = new ArrayList<>();
try (Realm instance = realmManager.getRealmInstance(wallet))
{
RealmResults<RealmTransaction> txs;
if (fetchTime > 0)
{
txs = instance.where(RealmTransaction.class)
.sort("timeStamp", Sort.DESCENDING)
.lessThan("timeStamp", fetchTime)
.limit(fetchLimit)
.findAll();
}
else
{
txs = instance.where(RealmTransaction.class)
.sort("timeStamp", Sort.DESCENDING)
.limit(fetchLimit)
.findAll();
}
final RealmResults<RealmTransaction> txs = generateRealmQuery(instance, fetchTime, fetchLimit).findAll();
Log.d(TAG, "Found " + txs.size() + " TX Results");
fixBadTXValues(instance, txs);
fixBadTXValues(instance, fetchTime, fetchLimit);
for (RealmTransaction item : txs)
{
@ -208,23 +195,41 @@ public class TransactionsRealmCache implements TransactionLocalSource {
});
}
private RealmQuery<RealmTransaction> generateRealmQuery(Realm instance, long fetchTime, int fetchLimit)
{
if (fetchTime > 0)
{
return instance.where(RealmTransaction.class)
.sort("timeStamp", Sort.DESCENDING)
.lessThan("timeStamp", fetchTime)
.limit(fetchLimit);
}
else
{
return instance.where(RealmTransaction.class)
.sort("timeStamp", Sort.DESCENDING)
.limit(fetchLimit);
}
}
//Correct any bad value that was previously recorded in a way that wrote the wrong time value
//TODO: Remove this after a couple more releases, but it's harmless
private void fixBadTXValues(Realm instance, RealmResults<RealmTransaction> txs) throws Exception
private void fixBadTXValues(@NotNull Realm instance, final long fetchTime, final int fetchLimit)
{
long currentTime = System.currentTimeMillis()/1000L;
for (RealmTransaction item : txs)
{
if ((currentTime - item.getTimeStamp()) < -3000*24*60*60 && (item.getBlockNumber().equals("-1") || item.getBlockNumber().equals("0")))
long currentTime = System.currentTimeMillis() / 1000L;
instance.executeTransactionAsync(r -> {
final RealmResults<RealmTransaction> txs = generateRealmQuery(r, fetchTime, fetchLimit).findAll();
for (RealmTransaction item : txs)
{
// potentially incorrectly recorded tx, change to pending to re-scan
instance.executeTransaction(realm -> {
if ((currentTime - item.getTimeStamp()) < -3000 * 24 * 60 * 60 && (item.getBlockNumber().equals("-1") || item.getBlockNumber().equals("0")))
{
// potentially incorrectly recorded tx, change to pending to re-scan
item.setBlockNumber("0");
item.setError("0");
item.setTimeStamp(currentTime);
});
}
}
}
});
}
@Override
@ -243,22 +248,22 @@ public class TransactionsRealmCache implements TransactionLocalSource {
}
@Override
public void putTransaction(Wallet wallet, Transaction tx)
public void putTransaction(Wallet wallet, final Transaction tx)
{
try (Realm instance = realmManager.getRealmInstance(wallet))
{
instance.executeTransaction(realm -> {
RealmTransaction realmTx = instance.where(RealmTransaction.class)
instance.executeTransactionAsync(r -> {
RealmTransaction realmTx = r.where(RealmTransaction.class)
.equalTo("hash", tx.hash)
.findFirst();
if (realmTx == null)
{
realmTx = instance.createObject(RealmTransaction.class, tx.hash);
realmTx = r.createObject(RealmTransaction.class, tx.hash);
}
fill(instance, realmTx, tx);
realm.insertOrUpdate(realmTx);
fill(r, realmTx, tx);
r.insertOrUpdate(realmTx);
});
}
catch (Exception e)
@ -279,10 +284,10 @@ public class TransactionsRealmCache implements TransactionLocalSource {
deleteTransaction(wallet, ethTx.getHash());
try (Realm instance = realmManager.getRealmInstance(wallet))
{
instance.executeTransaction(realm -> {
RealmTransaction item = instance.createObject(RealmTransaction.class, ethTx.getHash());
fill(instance, item, tx);
realm.insertOrUpdate(item);
instance.executeTransactionAsync(r -> {
RealmTransaction item = r.createObject(RealmTransaction.class, ethTx.getHash());
fill(r, item, tx);
r.insertOrUpdate(item);
});
}
catch (Exception e)
@ -298,17 +303,17 @@ public class TransactionsRealmCache implements TransactionLocalSource {
{
try (Realm instance = realmManager.getRealmInstance(wallet))
{
RealmTransaction realmTx = instance.where(RealmTransaction.class)
.equalTo("hash", oldTxHash)
.findFirst();
instance.executeTransactionAsync(r -> {
RealmTransaction realmTx = r.where(RealmTransaction.class)
.equalTo("hash", oldTxHash)
.findFirst();
if (realmTx != null)
{
instance.executeTransaction(realm -> {
if (realmTx != null)
{
//deleteOperations(realmTx);
realmTx.deleteFromRealm();
});
}
}
});
}
catch (Exception e)
{
@ -359,17 +364,17 @@ public class TransactionsRealmCache implements TransactionLocalSource {
{
try (Realm instance = realmManager.getRealmInstance(new Wallet(walletAddress)))
{
RealmTransaction realmTx = instance.where(RealmTransaction.class)
.equalTo("hash", hash)
.findFirst();
instance.executeTransactionAsync(r -> {
RealmTransaction realmTx = r.where(RealmTransaction.class)
.equalTo("hash", hash)
.findFirst();
if (realmTx != null)
{
instance.executeTransaction(realm -> {
if (realmTx != null)
{
realmTx.setBlockNumber(String.valueOf(blockValue));
realmTx.setTimeStamp(System.currentTimeMillis()/1000); //update timestamp so it's updated on the UI
});
}
realmTx.setTimeStamp(System.currentTimeMillis() / 1000); //update timestamp so it's updated on the UI
}
});
}
catch (Exception e)
{

@ -269,42 +269,35 @@ public class WalletDataRealmSource {
});
}
private Disposable updateTimeInternal(String walletAddr, boolean isBackupTime)
public void updateBackupTime(String walletAddr)
{
return Single.fromCallable(() -> {
try (Realm realm = realmManager.getWalletDataRealmInstance())
{
realm.executeTransaction(r -> {
RealmWalletData realmWallet = realm.where(RealmWalletData.class)
.equalTo("address", walletAddr, Case.INSENSITIVE)
.findFirst();
updateWarningTime(walletAddr);
if (realmWallet != null)
{
//Always update warning time but only update backup time if a backup was made
realmWallet.setLastWarning(System.currentTimeMillis());
}
});
return 1;
}
catch (RealmException e)
realmManager.getWalletTypeRealmInstance().executeTransactionAsync(r -> {
RealmKeyType realmKey = r.where(RealmKeyType.class)
.equalTo("address", walletAddr, Case.INSENSITIVE)
.findFirst();
if (realmKey != null)
{
e.printStackTrace();
realmKey.setLastBackup(System.currentTimeMillis());
}
return 0;
}).subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe();
});
}
public Disposable updateBackupTime(String walletAddr)
public void updateWarningTime(String walletAddr)
{
return updateTimeInternal(walletAddr, true);
}
realmManager.getWalletDataRealmInstance().executeTransactionAsync(r -> {
RealmWalletData realmWallet = r.where(RealmWalletData.class)
.equalTo("address", walletAddr)
.findFirst();
public Disposable updateWarningTime(String walletAddr)
{
return updateTimeInternal(walletAddr, false);
if (realmWallet != null)
{
//Always update warning time but only update backup time if a backup was made
realmWallet.setLastWarning(System.currentTimeMillis());
}
});
}
public Single<String> getWalletRequiresBackup(String walletAddr)
@ -397,56 +390,39 @@ public class WalletDataRealmSource {
}).subscribeOn(Schedulers.io());
}
public Single<String> setIsDismissed(String walletAddr, boolean isDismissed)
public void setIsDismissed(String walletAddr, boolean isDismissed)
{
return Single.fromCallable(() -> {
try (Realm realm = realmManager.getWalletDataRealmInstance())
realmManager.getWalletDataRealmInstance().executeTransactionAsync(r -> {
RealmWalletData realmWallet = r.where(RealmWalletData.class)
.equalTo("address", walletAddr, Case.INSENSITIVE)
.findFirst();
if (realmWallet != null)
{
realm.executeTransaction(r -> {
RealmWalletData realmWallet = r.where(RealmWalletData.class)
.equalTo("address", walletAddr, Case.INSENSITIVE)
.findFirst();
if (realmWallet != null)
{
realmWallet.setIsDismissedInSettings(isDismissed);
}
});
realmWallet.setIsDismissedInSettings(isDismissed);
}
catch (RealmException e)
{
e.printStackTrace();
}
return walletAddr;
});
}
private void storeKeyData(Wallet wallet)
{
try (Realm realm = realmManager.getWalletTypeRealmInstance())
{
realm.executeTransaction(r -> {
RealmKeyType realmKey = r.where(RealmKeyType.class)
.equalTo("address", wallet.address, Case.INSENSITIVE)
.findFirst();
if (realmKey == null)
{
realmKey = r.createObject(RealmKeyType.class, wallet.address);
realmKey.setDateAdded(System.currentTimeMillis());
}
else if (realmKey.getDateAdded() == 0)
realmKey.setDateAdded(System.currentTimeMillis());
realmKey.setType(wallet.type);
realmKey.setLastBackup(wallet.lastBackupTime);
realmKey.setAuthLevel(wallet.authLevel);
realmKey.setKeyModulus("");
if (BuildConfig.DEBUG) Log.d("RealmDebug", "storedKeyData " + wallet.address);
});
}
catch (Exception e)
{
e.printStackTrace();
}
realmManager.getWalletTypeRealmInstance().executeTransactionAsync(r -> {
RealmKeyType realmKey = r.where(RealmKeyType.class)
.equalTo("address", wallet.address, Case.INSENSITIVE)
.findFirst();
if (realmKey == null)
{
realmKey = r.createObject(RealmKeyType.class, wallet.address);
realmKey.setDateAdded(System.currentTimeMillis());
}
else if (realmKey.getDateAdded() == 0)
realmKey.setDateAdded(System.currentTimeMillis());
realmKey.setType(wallet.type);
realmKey.setLastBackup(wallet.lastBackupTime);
realmKey.setAuthLevel(wallet.authLevel);
realmKey.setKeyModulus("");
if (BuildConfig.DEBUG) Log.d("RealmDebug", "storedKeyData " + wallet.address);
});
}
private void storeWalletData(Wallet wallet)
@ -470,27 +446,6 @@ public class WalletDataRealmSource {
}
}
private void setKeyBackupTime(String walletAddr)
{
try (Realm realm = realmManager.getWalletTypeRealmInstance())
{
realm.executeTransaction(r -> {
RealmKeyType realmKey = r.where(RealmKeyType.class)
.equalTo("address", walletAddr, Case.INSENSITIVE)
.findFirst();
if (realmKey != null)
{
realmKey.setLastBackup(System.currentTimeMillis());
}
});
}
catch (Exception e)
{
e.printStackTrace();
}
}
private boolean isDismissedInSettings(String wallet)
{
RealmWalletData data = realmManager.getWalletDataRealmInstance().where(RealmWalletData.class)

@ -111,15 +111,15 @@ public class WalletRepository implements WalletRepositoryType
}
@Override
public Disposable updateBackupTime(String walletAddr)
public void updateBackupTime(String walletAddr)
{
return walletDataRealmSource.updateBackupTime(walletAddr);
walletDataRealmSource.updateBackupTime(walletAddr);
}
@Override
public Disposable updateWarningTime(String walletAddr)
public void updateWarningTime(String walletAddr)
{
return walletDataRealmSource.updateWarningTime(walletAddr);
walletDataRealmSource.updateWarningTime(walletAddr);
}
@Override
@ -135,9 +135,9 @@ public class WalletRepository implements WalletRepositoryType
}
@Override
public Single<String> setIsDismissed(String walletAddr, boolean isDismissed)
public void setIsDismissed(String walletAddr, boolean isDismissed)
{
return walletDataRealmSource.setIsDismissed(walletAddr, isDismissed);
walletDataRealmSource.setIsDismissed(walletAddr, isDismissed);
}
@Override

@ -38,13 +38,13 @@ public interface WalletRepositoryType {
Single<String> getName(String address);
Disposable updateBackupTime(String walletAddr);
Disposable updateWarningTime(String walletAddr);
void updateBackupTime(String walletAddr);
void updateWarningTime(String walletAddr);
Single<Boolean> getWalletBackupWarning(String walletAddr);
Single<String> getWalletRequiresBackup(String walletAddr);
Single<String> setIsDismissed(String walletAddr, boolean isDismissed);
void setIsDismissed(String walletAddr, boolean isDismissed);
boolean keystoreExists(String address);

@ -153,7 +153,6 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
private FragmentMessenger homeMessenger;
private final TokenscriptFunction tokenscriptUtility;
private final Realm realm;
@Nullable
private Disposable checkEventDisposable;
@ -180,7 +179,6 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
transactionRespository = trt;
assetLoadingLock = new Semaphore(1);
eventConnection = new Semaphore(1);
realm = realmManager.getRealmInstance(ASSET_DEFINITION_DB);
//deleteAllEventData();
loadAssetScripts();
}
@ -358,7 +356,7 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
{
try
{
realm.executeTransactionAsync(r -> {
realmManager.getRealmInstance(ASSET_DEFINITION_DB).executeTransactionAsync(r -> {
//have to remove all instances of this hash
RealmResults<RealmTokenScriptData> hashInstances = r.where(RealmTokenScriptData.class)
.equalTo("fileHash", BUNDLED_SCRIPT)
@ -936,7 +934,7 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
}
catch (Exception e)
{
e.printStackTrace();
if (BuildConfig.DEBUG) e.printStackTrace();
}
return Single.fromCallable(TokenDefinition::new);
@ -944,17 +942,17 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
private void deleteScriptEntriesFromRealm(List<ContractLocator> origins, boolean isDebug)
{
realm.executeTransactionAsync(r -> {
realmManager.getRealmInstance(ASSET_DEFINITION_DB).executeTransactionAsync(r -> {
for (ContractLocator cl : origins)
{
String entryKey = getTSDataKey(cl.chainId, cl.address);
RealmTokenScriptData realmData = realm.where(RealmTokenScriptData.class)
RealmTokenScriptData realmData = r.where(RealmTokenScriptData.class)
.equalTo("instanceKey", entryKey)
.findFirst();
if (realmData != null && (isDebug || isInSecureZone(realmData.getFilePath()))) //delete the existing entry if this script is debug, or if the old script is in the server area
{
RealmCertificateData realmCert = realm.where(RealmCertificateData.class)
RealmCertificateData realmCert = r.where(RealmCertificateData.class)
.equalTo("instanceKey", realmData.getFileHash())
.findFirst();
if (realmCert != null) realmCert.deleteFromRealm();
@ -1137,13 +1135,13 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
private void updateRealmForBundledScript(int chainId, String address, String asset, TokenDefinition td)
{
realm.executeTransactionAsync(r -> {
realmManager.getRealmInstance(ASSET_DEFINITION_DB).executeTransactionAsync(r -> {
String entryKey = getTSDataKey(chainId, address);
RealmTokenScriptData entry = realm.where(RealmTokenScriptData.class)
RealmTokenScriptData entry = r.where(RealmTokenScriptData.class)
.equalTo("instanceKey", entryKey)
.findFirst();
if (entry == null) entry = realm.createObject(RealmTokenScriptData.class, entryKey);
if (entry == null) entry = r.createObject(RealmTokenScriptData.class, entryKey);
entry.setFilePath(asset);
entry.setViewList(td.getViews());
entry.setNames(td.getTokenNameList());
@ -1362,11 +1360,11 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
String eventAddress = ev.getEventContractAddress();
String eventName = ev.activityName != null ? ev.activityName : ev.attributeName;
String databaseKey = TokensRealmSource.eventBlockKey(chainId, eventAddress, ev.type.name, ev.filter);
realm.executeTransaction(r -> {
RealmAuxData realmToken = realm.where(RealmAuxData.class)
realm.executeTransactionAsync(r -> {
RealmAuxData realmToken = r.where(RealmAuxData.class)
.equalTo("instanceKey", databaseKey)
.findFirst();
if (realmToken == null) realmToken = realm.createObject(RealmAuxData.class, databaseKey);
if (realmToken == null) realmToken = r.createObject(RealmAuxData.class, databaseKey);
realmToken.setResultTime(System.currentTimeMillis());
realmToken.setResult(ev.readBlock.toString(16));
realmToken.setFunctionId(eventName);
@ -1401,11 +1399,11 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
{
try (Realm realm = realmManager.getRealmInstance(walletAddress))
{
realm.executeTransaction(r -> {
RealmAuxData realmToken = realm.where(RealmAuxData.class)
realm.executeTransactionAsync(r -> {
RealmAuxData realmToken = r.where(RealmAuxData.class)
.equalTo("instanceKey", databaseKey)
.findFirst();
if (realmToken == null) realmToken = realm.createObject(RealmAuxData.class, databaseKey);
if (realmToken == null) realmToken = r.createObject(RealmAuxData.class, databaseKey);
realmToken.setResultTime(blockTime);
realmToken.setResult(eventData);
realmToken.setFunctionId(activityName);
@ -1557,14 +1555,14 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
private void storeCertificateData(String hash, XMLDsigDescriptor sig) throws RealmException
{
realm.executeTransaction(r -> {
realmManager.getRealmInstance(ASSET_DEFINITION_DB).executeTransactionAsync(r -> {
//if signature present, then just update
RealmCertificateData realmData = realm.where(RealmCertificateData.class)
RealmCertificateData realmData = r.where(RealmCertificateData.class)
.equalTo("instanceKey", hash)
.findFirst();
if (realmData == null)
realmData = realm.createObject(RealmCertificateData.class, hash);
realmData = r.createObject(RealmCertificateData.class, hash);
realmData.setFromSig(sig);
});
}
@ -2067,15 +2065,15 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
{
ContractAddress cAddr = new ContractAddress(tResult.contractChainId, tResult.contractAddress);
String databaseKey = functionKey(cAddr, tResult.tokenId, tResult.attrId);
RealmAuxData realmToken = realm.where(RealmAuxData.class)
.equalTo("instanceKey", databaseKey)
.equalTo("chainId", tResult.contractChainId)
.findFirst();
realm.executeTransactionAsync(r -> {
RealmAuxData realmToken = r.where(RealmAuxData.class)
.equalTo("instanceKey", databaseKey)
.equalTo("chainId", tResult.contractChainId)
.findFirst();
realm.executeTransaction(r -> {
if (realmToken == null)
{
createAuxData(realm, tResult, databaseKey);
createAuxData(r, tResult, databaseKey);
}
else if (tResult.result != null)
{
@ -2122,8 +2120,8 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
//delete all realm event/attribute result data
try (Realm realm = realmManager.getRealmInstance(tokensService.getCurrentAddress()))
{
realm.executeTransaction(r -> {
RealmResults<RealmAuxData> realmEvents = realm.where(RealmAuxData.class)
realm.executeTransactionAsync(r -> {
RealmResults<RealmAuxData> realmEvents = r.where(RealmAuxData.class)
.findAll();
realmEvents.deleteAllFromRealm();
});
@ -2136,13 +2134,13 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
//Delete all tokenscript data
try (Realm realm = realmManager.getRealmInstance(ASSET_DEFINITION_DB))
{
RealmResults<RealmTokenScriptData> rd = realm.where(RealmTokenScriptData.class)
.findAll();
realm.executeTransactionAsync(r -> {
RealmResults<RealmTokenScriptData> rd = r.where(RealmTokenScriptData.class)
.findAll();
RealmResults<RealmCertificateData> realmCert = realm.where(RealmCertificateData.class)
.findAll();
RealmResults<RealmCertificateData> realmCert = r.where(RealmCertificateData.class)
.findAll();
realm.executeTransaction(r -> {
rd.deleteAllFromRealm();
realmCert.deleteAllFromRealm();
});

@ -247,8 +247,8 @@ public class GasService2 implements ContractGasProvider
{
try (Realm realm = realmManager.getRealmInstance(TICKER_DB))
{
realm.executeTransaction(r -> {
RealmGasSpread rgs = realm.where(RealmGasSpread.class)
realm.executeTransactionAsync(r -> {
RealmGasSpread rgs = r.where(RealmGasSpread.class)
.equalTo("timeStamp", gasPriceSpread.timeStamp)
.findFirst();
if (rgs == null) rgs = realm.createObject(RealmGasSpread.class, gasPriceSpread.timeStamp);
@ -256,7 +256,7 @@ public class GasService2 implements ContractGasProvider
rgs.setGasSpread(gasPriceSpread, chainId);
//remove old results
realm.where(RealmGasSpread.class)
r.where(RealmGasSpread.class)
.lessThan("timeStamp", gasPriceSpread.timeStamp - TWELVE_HOURS)
.findAll().deleteAllFromRealm();
});

@ -70,7 +70,7 @@ public class OpenseaService {
JSONObject result = new JSONObject(jsonData);
JSONArray assets = result.getJSONArray("assets");
receivedTokens = assets.length();
offset++;
offset += assets.length();
//process this page of results
processOpenseaTokens(foundTokens, assets, address, networkId, networkName, tokensService);

@ -72,12 +72,9 @@ import static org.web3j.protocol.core.methods.request.Transaction.createEthCallT
public class TickerService
{
private static final int UPDATE_TICKER_CYCLE = 5; //5 Minutes
private static final String COINMARKET_API_URL = "https://pro-api.coinmarketcap.com";
private static final String MEDIANIZER = "0x729D19f657BD0614b4985Cf1D82531c67569197B";
private static final String BLOCKSCOUT = "https://blockscout.com/poa/[CORE]/api?module=stats&action=ethprice";
private static final String ETHERSCAN = "https://api.etherscan.io/api?module=stats&action=ethprice";
private static final String MARKET_ORACLE_CONTRACT = "0xf155a7eb4a2993c8cf08a76bca137ee9ac0a01d8";
private static final String ORACLE_ETHERSCAN_API = "https://api-rinkeby.etherscan.io/api?module=account&action=txlist&address=[ORACLE]&sort=desc&page=1&offset=1".replace("[ORACLE]", MARKET_ORACLE_CONTRACT);
private static final String CONTRACT_ADDR = "[CONTRACT_ADDR]";
private static final String COINGECKO_API = "https://api.coingecko.com/api/v3/simple/token_price/ethereum?contract_addresses=" +CONTRACT_ADDR + "&vs_currencies=USD&include_24hr_change=true";
private static final String COINGECKO_COINS_API = "https://api.coingecko.com/api/v3/simple/price?ids=ethereum%2Cxdai%2Cetc&vs_currencies=USD&include_24hr_change=true";
@ -97,13 +94,6 @@ public class TickerService
private static String currentCurrencySymbol;
private boolean canUpdate = false;
public static native String getCMCKey();
public static native String getAmberDataKey();
static {
System.loadLibrary("keys");
}
public TickerService(OkHttpClient httpClient, Gson gson, Context ctx, TokenLocalSource localSource)
{
this.httpClient = httpClient;
@ -126,7 +116,6 @@ public class TickerService
private void tickerUpdate()
{
updateCurrencyConversion()
.flatMap(this::fetchLastMarketContractWrite)
.flatMap(this::updateTickersFromOracle)
.flatMap(this::fetchTickersSeparatelyIfRequired)
.flatMap(this::addArtisTicker)
@ -149,11 +138,13 @@ public class TickerService
.flatMap(count -> fetchBlockScoutTicker(POA_ID, "core", count));
}
private Single<Integer> updateTickersFromOracle(long lastTxTime)
private Single<Integer> updateTickersFromOracle(double conversionRate)
{
canUpdate = true;
currentConversionRate = conversionRate;
return Single.fromCallable(() -> {
int tickerSize = 0;
Web3j web3j = TokenRepository.getWeb3jService(RINKEBY_ID);
final Web3j web3j = TokenRepository.getWeb3jService(RINKEBY_ID);
//fetch current tickers
Function function = getTickers();
String responseValue = callSmartContractFunction(web3j, function, MARKET_ORACLE_CONTRACT);
@ -163,7 +154,7 @@ public class TickerService
{
Type T = responseValues.get(0);
List<Uint256> values = (List) T.getValue();
long tickerUpdateTime = (lastTxTime > 0 ? lastTxTime : values.get(0).getValue().longValue()) * 1000L;
long tickerUpdateTime = values.get(0).getValue().longValue() * 1000L;
if ((System.currentTimeMillis() - tickerUpdateTime) < TICKER_STALE_TIMEOUT)
{
@ -181,43 +172,6 @@ public class TickerService
});
}
private Single<Long> fetchLastMarketContractWrite(double conversionRate)
{
canUpdate = true;
currentConversionRate = conversionRate;
return Single.fromCallable(() -> {
Long lastTxTime = 0L;
try
{
Request request = new Request.Builder()
.url(ORACLE_ETHERSCAN_API)
.get()
.build();
okhttp3.Response response = httpClient.newCall(request)
.execute();
if (response.code() / 200 == 1)
{
String result = response.body()
.string();
EtherscanTransaction[] txs = getEtherscanTransactions(result);
if (txs.length > 0)
{
Transaction tx = txs[0].createTransaction(null, RINKEBY_ID);
lastTxTime = tx.timeStamp;
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
return lastTxTime;
});
}
public Single<Integer> getERC20Tickers(List<TokenCardMeta> erc20Tokens)
{
if (!canUpdate || erc20Tokens.size() == 0) return Single.fromCallable(() -> 0);

@ -78,7 +78,7 @@ public class TokensService
private boolean appHasFocus = true;
@Nullable
private Disposable tokenCheckDisposable;
private Disposable openSeaCheckDisposable;
@Nullable
private Disposable eventTimer;
@Nullable
@ -128,7 +128,7 @@ public class TokensService
.flatMap(contractType -> tokenRepository.addToken(new Wallet(currentAddress), tokenInfo, contractType).toObservable()))
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(this::finishAddToken, Throwable::printStackTrace, this::finishTokenCheck);
.subscribe(this::finishAddToken, this::onCheckError, this::finishTokenCheck);
}
else if (t == null)
{
@ -139,6 +139,11 @@ public class TokensService
}
}
private void onCheckError(Throwable throwable)
{
if (BuildConfig.DEBUG) throwable.printStackTrace();
}
private void finishTokenCheck()
{
queryUnknownTokensDisposable = null;
@ -308,6 +313,11 @@ public class TokensService
focusToken = null;
}
private boolean isFocusToken(Token t)
{
return focusToken != null && focusToken.equals(t);
}
/**
* This method will add unknown token to the list and discover it
* @param cAddr Contract Address
@ -398,8 +408,8 @@ public class TokensService
}
if (balanceCheckDisposable != null && !balanceCheckDisposable.isDisposed()) balanceCheckDisposable.dispose();
if (tokenCheckDisposable != null && !tokenCheckDisposable.isDisposed()) tokenCheckDisposable.dispose();
if (erc20CheckDisposable != null && !erc20CheckDisposable.isDisposed()) erc20CheckDisposable.dispose();
if (openSeaCheckDisposable != null && !openSeaCheckDisposable.isDisposed()) openSeaCheckDisposable.dispose();
addUnresolvedContracts(ethereumNetworkRepository.getAllKnownContracts(getNetworkFilters()));
@ -474,17 +484,20 @@ public class TokensService
private void checkOpenSea()
{
if (openSeaCheckDisposable != null && !openSeaCheckDisposable.isDisposed()) { checkERC20(); return; }
openSeaCount++;
nextOpenSeaCheck = System.currentTimeMillis() + OPENSEA_CHECK_INTERVAL;
final Wallet wallet = new Wallet(currentAddress);
NetworkInfo info = getOpenSeaNetwork();
if (BuildConfig.DEBUG) Log.d("OPENSEA", "Fetch from opensea : " + currentAddress + " : " + info.getShortName());
tokenCheckDisposable = openseaService.getTokens(currentAddress, info.chainId, info.getShortName(), this)
openSeaCheckDisposable = openseaService.getTokens(currentAddress, info.chainId, info.getShortName(), this)
.flatMap(tokens -> tokenRepository.checkInterface(tokens, wallet)) //check the token interface
.flatMap(tokens -> tokenRepository.storeTokens(wallet, tokens)) //store fetched tokens
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::checkERC20, this::onOpenseaError);
.subscribe(t -> { openSeaCheckDisposable = null; checkERC20(); },
e -> { openSeaCheckDisposable = null; checkERC20(); });
if (openSeaCount >= OPENSEA_RINKEBY_CHECK) openSeaCount = 0;
}
@ -510,7 +523,7 @@ public class TokensService
ethereumNetworkRepository.getNetworkByChain(MAINNET_ID) : ethereumNetworkRepository.getNetworkByChain(RINKEBY_ID);
}
private void checkERC20(Token[] checkedERC721Tokens)
private void checkERC20()
{
if (erc20CheckDisposable == null || erc20CheckDisposable.isDisposed())
{
@ -548,11 +561,6 @@ public class TokensService
if (BuildConfig.DEBUG) throwable.printStackTrace();
}
private void onOpenseaError(Throwable throwable)
{
checkERC20(null);
}
public void updateTickers()
{
tickerService.updateTickers();
@ -642,13 +650,13 @@ public class TokensService
long lastUpdateDiff = currentTime - check.lastUpdate;
float weighting = check.calculateBalanceUpdateWeight();
if (!appHasFocus && !token.isEthereum()) continue; //only check chains when wallet out of focus
if (!appHasFocus && (!token.isEthereum() && !isFocusToken(token))) continue; //only check chains when wallet out of focus
//simply multiply the weighting by the last diff.
float updateFactor = weighting * (float) lastUpdateDiff;
long cutoffCheck = 30*DateUtils.SECOND_IN_MILLIS; //normal minimum update frequency for token 30 seconds
if (focusToken != null && token.tokenInfo.chainId == focusToken.chainId && token.getAddress().equalsIgnoreCase(focusToken.address))
if (isFocusToken(token))
{
updateFactor = 3.0f * (float) lastUpdateDiff;
cutoffCheck = 15*DateUtils.SECOND_IN_MILLIS; //focus token can be checked every 15 seconds - focus token when erc20 or chain clicked on in wallet

@ -449,12 +449,12 @@ public class TransactionsNetworkClient implements TransactionsNetworkClientType
//See if we require a refresh of transaction checks
@Override
public Completable checkTransactionsForEmptyFunctions(String currentAddress)
public void checkTransactionsForEmptyFunctions(String currentAddress)
{
return Completable.fromAction(() -> {
try (Realm instance = realmManager.getRealmInstance(new Wallet(currentAddress)))
{
RealmResults<RealmAuxData> checkMarkers = instance.where(RealmAuxData.class)
try (Realm instance = realmManager.getRealmInstance(new Wallet(currentAddress)))
{
instance.executeTransactionAsync(r -> {
RealmResults<RealmAuxData> checkMarkers = r.where(RealmAuxData.class)
.like("instanceKey", BLOCK_ENTRY + "*")
.findAll();
@ -466,34 +466,28 @@ public class TransactionsNetworkClient implements TransactionsNetworkClientType
{
String chainIdStr = aux.getInstanceKey().substring(BLOCK_ENTRY.length());
int chainId = Integer.parseInt(chainIdStr);
writeNFTokenBlockRead(instance, chainId, 0); //check from start
writeTokenBlockRead(instance, chainId, 0); //check from start
instance.executeTransaction(r -> {
aux.setResult(DB_RESET);
});
writeNFTokenBlockRead(r, chainId, 0); //check from start
writeTokenBlockRead(r, chainId, 0); //check from start
aux.setResult(DB_RESET);
delete = true;
}
}
if (delete)
{
instance.beginTransaction();
RealmResults<RealmAuxData> realmEvents = instance.where(RealmAuxData.class)
RealmResults<RealmAuxData> realmEvents = r.where(RealmAuxData.class)
.findAll();
realmEvents.deleteAllFromRealm();
RealmResults<RealmTransfer> realmTransfers = instance.where(RealmTransfer.class)
.findAll();
RealmResults<RealmTransfer> realmTransfers = r.where(RealmTransfer.class)
.findAll();
realmTransfers.deleteAllFromRealm();
instance.commitTransaction();
}
}
catch (Exception e)
{
//
}
});
});
}
catch (Exception e)
{
//
}
}
/**
@ -747,13 +741,13 @@ public class TransactionsNetworkClient implements TransactionsNetworkClientType
private void writeTokenBlockRead(Realm instance, int chainId, long lastBlockChecked)
{
instance.executeTransaction(r -> {
RealmAuxData rd = instance.where(RealmAuxData.class)
instance.executeTransactionAsync(r -> {
RealmAuxData rd = r.where(RealmAuxData.class)
.equalTo("instanceKey", BLOCK_ENTRY + chainId)
.findFirst();
if (rd == null)
{
rd = instance.createObject(RealmAuxData.class, BLOCK_ENTRY + chainId);
rd = r.createObject(RealmAuxData.class, BLOCK_ENTRY + chainId);
rd.setResult(DB_RESET);
}
rd.setResultTime(lastBlockChecked);
@ -762,13 +756,13 @@ public class TransactionsNetworkClient implements TransactionsNetworkClientType
private void writeNFTokenBlockRead(Realm instance, int chainId, long lastBlockChecked)
{
instance.executeTransaction(r -> {
RealmAuxData rd = instance.where(RealmAuxData.class)
instance.executeTransactionAsync(r -> {
RealmAuxData rd = r.where(RealmAuxData.class)
.equalTo("instanceKey", BLOCK_ENTRY + chainId)
.findFirst();
if (rd == null)
{
rd = instance.createObject(RealmAuxData.class, BLOCK_ENTRY + chainId);
rd = r.createObject(RealmAuxData.class, BLOCK_ENTRY + chainId);
rd.setResult(DB_RESET);
}
rd.setResultReceivedTime(lastBlockChecked);
@ -853,18 +847,18 @@ public class TransactionsNetworkClient implements TransactionsNetworkClientType
{
try (Realm instance = realmManager.getRealmInstance(walletAddress))
{
RealmToken realmToken = instance.where(RealmToken.class)
.equalTo("address", databaseKey(chainId, tokenAddress))
.equalTo("chainId", chainId)
.findFirst();
instance.executeTransactionAsync(r -> {
RealmToken realmToken = r.where(RealmToken.class)
.equalTo("address", databaseKey(chainId, tokenAddress))
.equalTo("chainId", chainId)
.findFirst();
if (realmToken != null)
{
instance.executeTransaction(realm -> {
if (realmToken != null)
{
realmToken.setLastBlock(Long.parseLong(lastBlockRead));
realmToken.setLastTxTime(System.currentTimeMillis());
});
}
}
});
}
catch (Exception e)
{
@ -876,17 +870,17 @@ public class TransactionsNetworkClient implements TransactionsNetworkClientType
{
try
{
RealmToken realmToken = instance.where(RealmToken.class)
.equalTo("address", databaseKey(chainId, walletAddress))
.equalTo("chainId", chainId)
.findFirst();
instance.executeTransactionAsync(r -> {
RealmToken realmToken = r.where(RealmToken.class)
.equalTo("address", databaseKey(chainId, walletAddress))
.equalTo("chainId", chainId)
.findFirst();
if (realmToken != null)
{
instance.executeTransaction(realm -> {
if (realmToken != null)
{
realmToken.setEarliestTransactionBlock(earliestBlock);
});
}
}
});
}
catch (Exception e)
{
@ -898,18 +892,18 @@ public class TransactionsNetworkClient implements TransactionsNetworkClientType
{
try
{
RealmResults<RealmTransaction> txs = instance.where(RealmTransaction.class)
.equalTo("chainId", chainId)
.findAll();
instance.executeTransaction(r -> {
RealmResults<RealmTransaction> txs = r.where(RealmTransaction.class)
.equalTo("chainId", chainId)
.findAll();
if (txs != null && txs.size() > 0)
{
instance.executeTransaction(realm -> {
if (txs != null && txs.size() > 0)
{
txs.deleteAllFromRealm();
});
}
}
resetBlockRead(instance, chainId, walletAddress);
resetBlockRead(r, chainId, walletAddress);
});
}
catch (Exception e)
{
@ -921,19 +915,19 @@ public class TransactionsNetworkClient implements TransactionsNetworkClientType
{
try
{
RealmToken realmToken = instance.where(RealmToken.class)
.equalTo("address", databaseKey(chainId, walletAddress))
.equalTo("chainId", chainId)
.findFirst();
instance.executeTransactionAsync(r -> {
RealmToken realmToken = r.where(RealmToken.class)
.equalTo("address", databaseKey(chainId, walletAddress))
.equalTo("chainId", chainId)
.findFirst();
if (realmToken != null)
{
instance.executeTransaction(realm -> {
if (realmToken != null)
{
realmToken.setEarliestTransactionBlock(0);
realmToken.setLastBlock(0);
realmToken.setLastTxTime(0);
});
}
}
});
}
catch (Exception e)
{
@ -1043,18 +1037,18 @@ public class TransactionsNetworkClient implements TransactionsNetworkClientType
private void writeTransaction(Realm instance, Transaction tx)
{
instance.executeTransaction(r -> {
RealmTransaction realmTx = instance.where(RealmTransaction.class)
instance.executeTransactionAsync(r -> {
RealmTransaction realmTx = r.where(RealmTransaction.class)
.equalTo("hash", tx.hash)
.findFirst();
if (realmTx == null)
{
realmTx = instance.createObject(RealmTransaction.class, tx.hash);
realmTx = r.createObject(RealmTransaction.class, tx.hash);
}
if (realmTx.getInput() == null || realmTx.getInput().length() <= 10)
{
TransactionsRealmCache.fill(instance, realmTx, tx);
TransactionsRealmCache.fill(r, realmTx, tx);
}
});
}

@ -11,5 +11,5 @@ public interface TransactionsNetworkClientType {
Single<Transaction[]> storeNewTransactions(String walletAddress, NetworkInfo networkInfo, String tokenAddress, long lastBlock);
Single<TransactionMeta[]> fetchMoreTransactions(String walletAddress, NetworkInfo network, long lastTxTime);
Single<Integer> readTransactions(String currentAddress, NetworkInfo networkByChain, TokensService tokensService, boolean nftCheck);
Completable checkTransactionsForEmptyFunctions(String currentAddress);
void checkTransactionsForEmptyFunctions(String currentAddress);
}

@ -1,14 +1,15 @@
package com.alphawallet.app.service;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.Nullable;
import com.alphawallet.app.BuildConfig;
import com.alphawallet.app.entity.NetworkInfo;
import com.alphawallet.app.entity.Transaction;
import com.alphawallet.app.entity.TransactionMeta;
import com.alphawallet.app.entity.TransactionType;
import com.alphawallet.app.entity.Wallet;
import com.alphawallet.app.entity.tokens.Token;
import com.alphawallet.app.entity.tokenscript.EventUtils;
@ -46,8 +47,6 @@ public class TransactionsService
private final EthereumNetworkRepositoryType ethereumNetworkRepository;
private final TransactionsNetworkClientType transactionsClient;
private final TransactionLocalSource transactionsCache;
private final Context context;
private String currentAddress;
private int currentChainIndex;
private boolean nftCheck;
@ -62,21 +61,20 @@ public class TransactionsService
private Disposable erc20EventCheckCycle;
@Nullable
private Disposable eventFetch;
@Nullable
private Disposable pendingTransactionFetch;
public TransactionsService(TokensService tokensService,
PreferenceRepositoryType preferenceRepositoryType,
EthereumNetworkRepositoryType ethereumNetworkRepositoryType,
TransactionsNetworkClientType transactionsClient,
TransactionLocalSource transactionsCache,
Context ctx)
TransactionLocalSource transactionsCache)
{
this.tokensService = tokensService;
this.preferenceRepository = preferenceRepositoryType;
this.ethereumNetworkRepository = ethereumNetworkRepositoryType;
this.transactionsClient = transactionsClient;
this.transactionsCache = transactionsCache;
this.currentAddress = preferenceRepository.getCurrentWalletAddress();
this.context = ctx;
checkTransactionReset();
fetchTransactions();
@ -84,11 +82,9 @@ public class TransactionsService
private void checkTransactionReset()
{
if (currentAddress == null) return;
if (tokensService.getCurrentAddress() == null) return;
//checks to see if we need a tx fetch reset
transactionsClient.checkTransactionsForEmptyFunctions(currentAddress)
.subscribeOn(Schedulers.computation())
.subscribe();
transactionsClient.checkTransactionsForEmptyFunctions(tokensService.getCurrentAddress());
}
private void fetchTransactions()
@ -108,9 +104,15 @@ public class TransactionsService
if (erc20EventCheckCycle == null || erc20EventCheckCycle.isDisposed())
{
erc20EventCheckCycle = Observable.interval(2, 10, TimeUnit.SECONDS)
erc20EventCheckCycle = Observable.interval(2, 15, TimeUnit.SECONDS)
.doOnNext(l -> checkTransactions()).subscribe();
}
if (pendingTransactionFetch == null || pendingTransactionFetch.isDisposed())
{
pendingTransactionFetch = Observable.interval(15, 30, TimeUnit.SECONDS)
.doOnNext(l -> checkPendingTransactions()).subscribe();
}
}
public void startUpdateCycle()
@ -129,15 +131,11 @@ public class TransactionsService
private void checkTransactions()
{
List<Integer> filters = tokensService.getNetworkFilters();
if (currentAddress == null || filters.size() == 0 ||
if (tokensService.getCurrentAddress() == null || filters.size() == 0 ||
(eventFetch != null && !eventFetch.isDisposed())) { return; }
if (currentChainIndex >= filters.size()) currentChainIndex = 0;
int chainId = filters.get(currentChainIndex);
eventFetch = transactionsClient.readTransactions(currentAddress, ethereumNetworkRepository.getNetworkByChain(chainId), tokensService, nftCheck)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(count -> { eventFetch = null; System.out.println("Received: " + count); });
readTokenMoves(filters.get(currentChainIndex), nftCheck);
if (!nftCheck)
{
@ -150,9 +148,17 @@ public class TransactionsService
}
}
private void readTokenMoves(int chainId, boolean isNFT)
{
eventFetch = transactionsClient.readTransactions(tokensService.getCurrentAddress(), ethereumNetworkRepository.getNetworkByChain(chainId), tokensService, isNFT)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(count -> { eventFetch = null; System.out.println("Received: " + count); });
}
private void checkTransactionQueue()
{
if (currentAddress == null) return;
if (tokensService.getCurrentAddress() == null) return;
if (fetchTransactionDisposable == null)
{
Token t = tokensService.getRequiresTransactionUpdate(getPendingChains());
@ -164,7 +170,7 @@ public class TransactionsService
System.out.println("Transaction check for: " + t.tokenInfo.chainId + " (" + t.getNetworkName() + ") " + tick);
NetworkInfo network = ethereumNetworkRepository.getNetworkByChain(t.tokenInfo.chainId);
fetchTransactionDisposable =
transactionsClient.storeNewTransactions(currentAddress, network, t.getAddress(), t.lastBlockCheck)
transactionsClient.storeNewTransactions(tokensService.getCurrentAddress(), network, t.getAddress(), t.lastBlockCheck)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(transactions -> onUpdateTransactions(transactions, t), this::onTxError);
@ -175,7 +181,7 @@ public class TransactionsService
public Single<TransactionMeta[]> fetchAndStoreTransactions(int chainId, long lastTxTime)
{
NetworkInfo network = ethereumNetworkRepository.getNetworkByChain(chainId);
return transactionsClient.fetchMoreTransactions(currentAddress, network, lastTxTime);
return transactionsClient.fetchMoreTransactions(tokensService.getCurrentAddress(), network, lastTxTime);
}
private List<Integer> getPendingChains()
@ -192,9 +198,9 @@ public class TransactionsService
private Transaction[] fetchPendingTransactions()
{
if (!TextUtils.isEmpty(currentAddress))
if (!TextUtils.isEmpty(tokensService.getCurrentAddress()))
{
return transactionsCache.fetchPendingTransactions(currentAddress);
return transactionsCache.fetchPendingTransactions(tokensService.getCurrentAddress());
}
else
{
@ -211,11 +217,12 @@ public class TransactionsService
{
//got a new transaction
fetchTransactionDisposable = null;
checkPendingTransactions(token.tokenInfo.chainId);
if (transactions.length == 0) return;
Log.d("TRANSACTION", "Queried for " + token.tokenInfo.name + " : " + transactions.length + " Network transactions");
//should we only check here for chain moves?
//now check for unknown tokens
checkTokens(transactions);
}
@ -241,10 +248,9 @@ public class TransactionsService
public void changeWallet(Wallet newWallet)
{
if (!newWallet.address.equalsIgnoreCase(currentAddress))
if (!newWallet.address.equalsIgnoreCase(tokensService.getCurrentAddress()))
{
stopUpdate();
currentAddress = newWallet.address;
stopAllChainUpdate();
fetchTransactions();
checkTransactionReset();
}
@ -253,10 +259,10 @@ public class TransactionsService
public void lostFocus()
{
tokensService.appOutOfFocus();
stopUpdate();
stopAllChainUpdate();
}
public void stopUpdate()
private void stopAllChainUpdate()
{
if (fetchTransactionDisposable != null && !fetchTransactionDisposable.isDisposed())
{
@ -283,63 +289,87 @@ public class TransactionsService
tokensService.markChainPending(tx.chainId);
}
private void checkPendingTransactions(int chainId)
private void checkPendingTransactions()
{
final String currentWallet = tokensService.getCurrentAddress();
Transaction[] pendingTxs = fetchPendingTransactions();
for (Transaction tx : pendingTxs)
if (BuildConfig.DEBUG) Log.d("TRANSACTION", "Checking " + pendingTxs.length + " Transactions");
for (final Transaction tx : pendingTxs)
{
Web3j web3j = TokenRepository.getWeb3jService(tx.chainId);
web3j.ethGetTransactionByHash(tx.hash).sendAsync().thenAccept(txDetails -> {
org.web3j.protocol.core.methods.response.Transaction fetchedTx = txDetails.getTransaction().orElseThrow(); //try to read the transaction data
//if transaction is complete; record it here
BigInteger blockNumber;
try
{
blockNumber = fetchedTx.getBlockNumber();
}
catch (MessageDecodingException e)
{
blockNumber = BigInteger.valueOf(-1);
}
if (blockNumber.compareTo(BigInteger.ZERO) > 0)
{
//Write to database (including detecting Transaction write error)
web3j.ethGetTransactionReceipt(tx.hash).sendAsync().thenAccept(receipt -> {
if (receipt != null)
{
//get timestamp and write tx
EventUtils.getBlockDetails(fetchedTx.getBlockHash(), web3j)
.map(ethBlock -> storeRawTx(ethBlock, tx.chainId, receipt, txDetails, currentWallet))
.map(this::triggerTokenMoveCheck)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe().isDisposed();
}
}).exceptionally(throwable -> {
throwable.printStackTrace();
return null;
});
}
else if (!tx.blockNumber.equals(String.valueOf(TRANSACTION_SEEN)))
{
//detected the tx in the pool, mark as seen
transactionsCache.markTransactionBlock(currentWallet, tx.hash, TRANSACTION_SEEN);
}
}).exceptionally(throwable -> {
String c1 = throwable.getMessage(); //java.util.NoSuchElementException: No value present
if (!TextUtils.isEmpty(c1) && c1.contains(NO_TRANSACTION_EXCEPTION) && tx.blockNumber.equals(String.valueOf(TRANSACTION_SEEN))) //we sighted this tx in the pool, now it's gone
{
//transaction is no longer in pool or on chain. Cause: dropped from mining pool
//mark transaction as dropped
transactionsCache.markTransactionBlock(currentWallet, tx.hash, TRANSACTION_DROPPED);
}
return null;
});
}
}
private Transaction triggerTokenMoveCheck(Transaction transaction)
{
final String currentWallet = tokensService.getCurrentAddress();
Token t = tokensService.getToken(transaction.chainId, transaction.to);
if (t != null && transaction.hasInput() && (t.isERC20() || t.isERC721()))
{
if (tx.chainId == chainId)
//trigger ERC20 token move check
TransactionType type = transaction.getTransactionType(currentWallet);
switch (type)
{
final String currentWallet = currentAddress;
Web3j web3j = TokenRepository.getWeb3jService(tx.chainId);
web3j.ethGetTransactionByHash(tx.hash).sendAsync().thenAccept(txDetails -> {
org.web3j.protocol.core.methods.response.Transaction fetchedTx = txDetails.getTransaction().orElseThrow(); //try to read the transaction data
//if transaction is complete; record it here
BigInteger blockNumber;
try
{
blockNumber = fetchedTx.getBlockNumber();
}
catch (MessageDecodingException e)
{
blockNumber = BigInteger.valueOf(-1);
}
if (blockNumber.compareTo(BigInteger.ZERO) > 0)
{
//Write to database (including detecting Transaction write error)
web3j.ethGetTransactionReceipt(tx.hash).sendAsync().thenAccept(receipt -> {
if (receipt != null)
{
//get timestamp and write tx
EventUtils.getBlockDetails(fetchedTx.getBlockHash(), web3j)
.map(ethBlock -> storeRawTx(ethBlock, chainId, receipt, txDetails, currentWallet))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe().isDisposed();
}
}).exceptionally(throwable -> {
throwable.printStackTrace();
return null;
});
}
else if (!tx.blockNumber.equals(String.valueOf(TRANSACTION_SEEN)))
{
//detected the tx in the pool, mark as seen
transactionsCache.markTransactionBlock(currentAddress, tx.hash, TRANSACTION_SEEN);
}
}).exceptionally(throwable -> {
String c1 = throwable.getMessage(); //java.util.NoSuchElementException: No value present
if (!TextUtils.isEmpty(c1) && c1.contains(NO_TRANSACTION_EXCEPTION) && tx.blockNumber.equals(String.valueOf(TRANSACTION_SEEN))) //we sighted this tx in the pool, now it's gone
{
//transaction is no longer in pool or on chain. Cause: dropped from mining pool
//mark transaction as dropped
transactionsCache.markTransactionBlock(currentAddress, tx.hash, TRANSACTION_DROPPED);
}
return null;
});
case TRANSFER_TO:
case RECEIVE_FROM:
case TRANSFER_FROM:
case RECEIVED:
case SEND:
if (BuildConfig.DEBUG) Log.d("TRANSACTION", "Checking Token moves for " + t.getFullName());
readTokenMoves(transaction.chainId, t.isERC721());
default:
break;
}
}
return transaction;
}
private Transaction storeRawTx(EthBlock ethBlock, int chainId, EthGetTransactionReceipt receipt, EthTransaction txDetails, String currentWallet)

@ -41,12 +41,14 @@ public class BackupFlowActivity extends BaseActivity implements
private AWalletAlertDialog alertDialog;
private FunctionButtonBar functionButtonBar;
private BackupOperationType type;
private boolean launchedBackup;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
alertDialog = null;
lockOrientation();
launchedBackup = false;
type = (BackupOperationType) getIntent().getSerializableExtra("TYPE");
wallet = getIntent().getParcelableExtra(WALLET);
@ -185,6 +187,16 @@ public class BackupFlowActivity extends BaseActivity implements
alertDialog.show();
}
@Override
public void onResume()
{
super.onResume();
if (launchedBackup) //avoid orphaned view.
{
finish();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
@ -196,6 +208,7 @@ public class BackupFlowActivity extends BaseActivity implements
finishBackupSuccess(data);
}
}
finish();
}
private void finishBackupSuccess(Intent data) {
@ -222,6 +235,7 @@ public class BackupFlowActivity extends BaseActivity implements
public void handleClick(String action, int id) {
Intent intent = new Intent(this, BackupKeyActivity.class);
intent.putExtra(WALLET, wallet);
launchedBackup = true;
switch (type)
{
@ -236,6 +250,5 @@ public class BackupFlowActivity extends BaseActivity implements
break;
}
startActivityForResult(intent, C.REQUEST_BACKUP_WALLET);
finish();
}
}

@ -114,17 +114,6 @@ public class BackupKeyActivity extends BaseActivity implements
}
}
/*
case BACKUP_HD_KEY:
intent.putExtra("STATE", ENTER_BACKUP_STATE_HD);
break;
case BACKUP_KEYSTORE_KEY:
intent.putExtra("STATE", ENTER_JSON_BACKUP);
break;
case UPGRADE_KEY:
intent.putExtra("STATE", UPGRADE_KEY_SECURITY);
*/
private void initBackupState() {
state = (BackupState) getIntent().getSerializableExtra("STATE");

@ -111,6 +111,7 @@ public class HomeActivity extends BaseNavigationActivity implements View.OnClick
private TutoShowcase backupWalletDialog;
private PinAuthenticationCallbackInterface authInterface;
private int navBarHeight;
private boolean isForeground;
public static final int RC_DOWNLOAD_EXTERNAL_WRITE_PERM = 222;
public static final int RC_ASSET_EXTERNAL_WRITE_PERM = 223;
@ -135,15 +136,25 @@ public class HomeActivity extends BaseNavigationActivity implements View.OnClick
Log.d("LIFE", "AlphaWallet into foreground");
((WalletFragment) walletFragment).walletInFocus();
if (viewModel != null) viewModel.startTransactionUpdate();
isForeground = true;
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
private void onMoveToBackground()
{
Log.d("LIFE", "AlphaWallet into background");
if (viewModel != null) viewModel.stopTransactionUpdate();
isForeground = false;
}
@Override
public void onTrimMemory(int level)
{
super.onTrimMemory(level);
Log.d("LIFE", "AlphaWallet into background");
((WalletFragment) walletFragment).walletOutOfFocus();
if (viewModel != null) viewModel.stopTransactionUpdate();
if (!isForeground)
{
onMoveToBackground();
}
}
@Override
@ -176,6 +187,7 @@ public class HomeActivity extends BaseNavigationActivity implements View.OnClick
super.onCreate(savedInstanceState);
LocaleUtils.setActiveLocale(this);
getLifecycle().addObserver(this);
isForeground = true;
if (getSupportActionBar() != null) getSupportActionBar().hide();

@ -393,7 +393,8 @@ public class NewSettingsFragment extends BaseFragment {
int height = LinearLayout.LayoutParams.WRAP_CONTENT;
final PopupWindow popupWindow = new PopupWindow(popupView, width, height, true);
popupView.setOnClickListener(v -> {
viewModel.setIsDismissed(walletAddress, true).subscribe(this::backedUp);
viewModel.setIsDismissed(walletAddress, true);
backedUp(walletAddress);
popupWindow.dismiss();
});
popupWindow.showAsDropDown(view, 0, 0);

@ -27,7 +27,7 @@ public class SelectCurrencyActivity extends BaseActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
setContentView(R.layout.basic_list_activity);
toolbar();
setTitle(getString(R.string.dialog_title_select_currency));
currentCurrency = getIntent().getStringExtra(C.EXTRA_CURRENCY);

@ -27,7 +27,7 @@ public class SelectLocaleActivity extends BaseActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
setContentView(R.layout.basic_list_activity);
toolbar();
setTitle(getString(R.string.settings_locale_lang));

@ -141,15 +141,18 @@ public class SelectNetworkActivity extends BaseActivity {
}
else
{
if (!viewModel.hasShownTestNetWarning())
{
dialog.show();
viewModel.setShownTestNetWarning();
}
else
{
pickNewBrowserNetwork();
}
dialog.show();
viewModel.setShownTestNetWarning();
//enable if we want to be able to do a 'don't show me again'
// if (!viewModel.hasShownTestNetWarning())
// {
// dialog.show();
// viewModel.setShownTestNetWarning();
// }
// else
// {
// pickNewBrowserNetwork();
// }
}
};

@ -33,7 +33,7 @@ public class SignDetailActivity extends BaseActivity
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
setContentView(R.layout.basic_list_activity);
toolbar();
setTitle(getString(R.string.signed_transactions));
signRecords = getIntent().getParcelableArrayListExtra(C.EXTRA_STATE);

@ -70,7 +70,7 @@ public class WalletConnectSessionActivity extends BaseActivity
super.onCreate(savedInstanceState);
AndroidInjection.inject(this);
setContentView(R.layout.activity_list);
setContentView(R.layout.basic_list_activity);
toolbar();
setTitle(getString(R.string.title_wallet_connect));
wallet = getIntent().getParcelableExtra(WALLET);

@ -552,7 +552,7 @@ public class WalletFragment extends BaseFragment implements
public void remindMeLater(Wallet wallet)
{
handler.post(() -> {
if (viewModel != null) viewModel.setKeyWarningDismissTime(wallet.address).isDisposed();
if (viewModel != null) viewModel.setKeyWarningDismissTime(wallet.address);
if (adapter != null) adapter.removeBackupWarning();
});
}
@ -560,7 +560,7 @@ public class WalletFragment extends BaseFragment implements
public void storeWalletBackupTime(String backedUpKey)
{
handler.post(() -> {
if (viewModel != null) viewModel.setKeyBackupTime(backedUpKey).isDisposed();
if (viewModel != null) viewModel.setKeyBackupTime(backedUpKey);
if (adapter != null) adapter.removeBackupWarning();
});
}

@ -149,7 +149,7 @@ public class BackupKeyViewModel extends BaseViewModel {
public void backupSuccess(Wallet wallet)
{
fetchWalletsInteract.updateBackupTime(wallet.address).isDisposed();
fetchWalletsInteract.updateBackupTime(wallet.address);
}
public void resetSignDialog()

@ -102,8 +102,8 @@ public class NewSettingsViewModel extends BaseViewModel {
myAddressRouter.open(context, defaultWallet.getValue());
}
public Single<String> setIsDismissed(String walletAddr, boolean isDismissed)
public void setIsDismissed(String walletAddr, boolean isDismissed)
{
return genericWalletInteract.setIsDismissed(walletAddr, isDismissed);
genericWalletInteract.setIsDismissed(walletAddr, isDismissed);
}
}

@ -153,24 +153,21 @@ public class WalletConnectViewModel extends BaseViewModel {
public void pruneSession(String sessionId)
{
try (Realm realm = realmManager.getRealmInstance(WC_SESSION_DB))
{
RealmWCSession item = realm.where(RealmWCSession.class)
realmManager.getRealmInstance(WC_SESSION_DB).executeTransactionAsync(r -> {
RealmWCSession item = r.where(RealmWCSession.class)
.equalTo("sessionId", sessionId)
.findFirst();
RealmResults<RealmWCSignElement> signItems = realm.where(RealmWCSignElement.class)
RealmResults<RealmWCSignElement> signItems = r.where(RealmWCSignElement.class)
.equalTo("sessionId", sessionId)
.findAll();
if (item != null && signItems.size() == 0)
{
realm.executeTransaction(r -> {
Log.d(TAG, "Delete from realm: " + sessionId);
item.deleteFromRealm();
});
Log.d(TAG, "Delete from realm: " + sessionId);
item.deleteFromRealm();
}
}
});
}
public void startGasCycle(int chainId)
@ -304,16 +301,13 @@ public class WalletConnectViewModel extends BaseViewModel {
public WCSession getSession(String sessionId)
{
WCSession session = null;
try (Realm realm = realmManager.getRealmInstance(WC_SESSION_DB))
{
RealmWCSession sessionData = realm.where(RealmWCSession.class)
.equalTo("sessionId", sessionId)
.findFirst();
RealmWCSession sessionData = realmManager.getRealmInstance(WC_SESSION_DB).where(RealmWCSession.class)
.equalTo("sessionId", sessionId)
.findFirst();
if (sessionData != null)
{
session = sessionData.getSession();
}
if (sessionData != null)
{
session = sessionData.getSession();
}
return session;
@ -322,16 +316,13 @@ public class WalletConnectViewModel extends BaseViewModel {
public WCPeerMeta getRemotePeer(String sessionId)
{
WCPeerMeta peerMeta = null;
try (Realm realm = realmManager.getRealmInstance(WC_SESSION_DB))
{
RealmWCSession sessionData = realm.where(RealmWCSession.class)
.equalTo("sessionId", sessionId)
.findFirst();
RealmWCSession sessionData = realmManager.getRealmInstance(WC_SESSION_DB).where(RealmWCSession.class)
.equalTo("sessionId", sessionId)
.findFirst();
if (sessionData != null)
{
peerMeta = sessionData.getRemotePeerData();
}
if (sessionData != null)
{
peerMeta = sessionData.getRemotePeerData();
}
return peerMeta;
@ -340,16 +331,13 @@ public class WalletConnectViewModel extends BaseViewModel {
public String getRemotePeerId(String sessionId)
{
String remotePeerId = null;
try (Realm realm = realmManager.getRealmInstance(WC_SESSION_DB))
{
RealmWCSession sessionData = realm.where(RealmWCSession.class)
.equalTo("sessionId", sessionId)
.findFirst();
RealmWCSession sessionData = realmManager.getRealmInstance(WC_SESSION_DB).where(RealmWCSession.class)
.equalTo("sessionId", sessionId)
.findFirst();
if (sessionData != null)
{
remotePeerId = sessionData.getRemotePeerId();
}
if (sessionData != null)
{
remotePeerId = sessionData.getRemotePeerId();
}
return remotePeerId;
@ -358,16 +346,13 @@ public class WalletConnectViewModel extends BaseViewModel {
public String getPeerId(String sessionId)
{
String peerId = null;
try (Realm realm = realmManager.getRealmInstance(WC_SESSION_DB))
{
RealmWCSession sessionData = realm.where(RealmWCSession.class)
.equalTo("sessionId", sessionId)
.findFirst();
RealmWCSession sessionData = realmManager.getRealmInstance(WC_SESSION_DB).where(RealmWCSession.class)
.equalTo("sessionId", sessionId)
.findFirst();
if (sessionData != null)
{
peerId = sessionData.getPeerId();
}
if (sessionData != null)
{
peerId = sessionData.getPeerId();
}
return peerId;
@ -376,16 +361,13 @@ public class WalletConnectViewModel extends BaseViewModel {
public int getChainId(String sessionId)
{
int chainId = MAINNET_ID;
try (Realm realm = realmManager.getRealmInstance(WC_SESSION_DB))
{
RealmWCSession sessionData = realm.where(RealmWCSession.class)
.equalTo("sessionId", sessionId)
.findFirst();
RealmWCSession sessionData = realmManager.getRealmInstance(WC_SESSION_DB).where(RealmWCSession.class)
.equalTo("sessionId", sessionId)
.findFirst();
if (sessionData != null)
{
chainId = sessionData.getChainId();
}
if (sessionData != null)
{
chainId = sessionData.getChainId();
}
return chainId;
@ -394,94 +376,78 @@ public class WalletConnectViewModel extends BaseViewModel {
public void createNewSession(String sessionId, String peerId, String remotePeerId, String sessionData,
String remotePeerData, int sessionChainId)
{
try (Realm realm = realmManager.getRealmInstance(WC_SESSION_DB))
{
realm.executeTransaction(r -> {
RealmWCSession sessionAux = realm.where(RealmWCSession.class)
.equalTo("sessionId", sessionId)
.findFirst();
if (sessionAux == null) sessionAux = realm.createObject(RealmWCSession.class, sessionId);
sessionAux.setLastUsageTime(System.currentTimeMillis());
sessionAux.setRemotePeerId(remotePeerId);
sessionAux.setPeerId(peerId);
sessionAux.setRemotePeerData(remotePeerData);
sessionAux.setSessionData(sessionData);
sessionAux.setUsageCount(0);
sessionAux.setWalletAccount(defaultWallet.getValue().address);
sessionAux.setChainId(sessionChainId);
});
}
realmManager.getRealmInstance(WC_SESSION_DB).executeTransactionAsync(r -> {
RealmWCSession sessionAux = r.where(RealmWCSession.class)
.equalTo("sessionId", sessionId)
.findFirst();
if (sessionAux == null)
sessionAux = r.createObject(RealmWCSession.class, sessionId);
sessionAux.setLastUsageTime(System.currentTimeMillis());
sessionAux.setRemotePeerId(remotePeerId);
sessionAux.setPeerId(peerId);
sessionAux.setRemotePeerData(remotePeerData);
sessionAux.setSessionData(sessionData);
sessionAux.setUsageCount(0);
sessionAux.setWalletAccount(defaultWallet.getValue().address);
sessionAux.setChainId(sessionChainId);
});
gasService.startGasPriceCycle(sessionChainId);
}
public void deleteSession(String sessionId)
{
try (Realm realm = realmManager.getRealmInstance(WC_SESSION_DB))
{
realm.executeTransaction(r -> {
RealmWCSession sessionAux = realm.where(RealmWCSession.class)
.equalTo("sessionId", sessionId)
.findFirst();
realmManager.getRealmInstance(WC_SESSION_DB).executeTransactionAsync(r -> {
RealmWCSession sessionAux = r.where(RealmWCSession.class)
.equalTo("sessionId", sessionId)
.findFirst();
if (sessionAux != null)
{
sessionAux.deleteFromRealm();
}
});
}
if (sessionAux != null)
{
sessionAux.deleteFromRealm();
}
});
}
public void recordSign(Signable signable, String sessionId)
{
try (Realm realm = realmManager.getRealmInstance(WC_SESSION_DB))
{
realm.executeTransaction(r -> {
RealmWCSignElement signMessage = realm.createObject(RealmWCSignElement.class);
realmManager.getRealmInstance(WC_SESSION_DB).executeTransactionAsync(r -> {
RealmWCSignElement signMessage = r.createObject(RealmWCSignElement.class);
String signType = "Message";
if (signable instanceof EthereumTypedMessage) signType = "TypedMessage";
String signType = "Message";
if (signable instanceof EthereumTypedMessage) signType = "TypedMessage";
signMessage.setSessionId(sessionId);
signMessage.setSignType(signType);
signMessage.setSignTime(System.currentTimeMillis());
signMessage.setSignMessage(signable.getUserMessage());
});
}
signMessage.setSessionId(sessionId);
signMessage.setSignType(signType);
signMessage.setSignTime(System.currentTimeMillis());
signMessage.setSignMessage(signable.getUserMessage());
});
}
public void recordSignTransaction(Context ctx, Web3Transaction tx, int chainId, String sessionId)
{
try (Realm realm = realmManager.getRealmInstance(WC_SESSION_DB))
{
realm.executeTransaction(r -> {
RealmWCSignElement signMessage = realm.createObject(RealmWCSignElement.class);
realmManager.getRealmInstance(WC_SESSION_DB).executeTransactionAsync(r -> {
RealmWCSignElement signMessage = r.createObject(RealmWCSignElement.class);
String signType = "Transaction";
signMessage.setSessionId(sessionId);
signMessage.setSignType(signType);
signMessage.setSignTime(System.currentTimeMillis());
signMessage.setSignMessage(tx.getFormattedTransaction(ctx, chainId, getNetworkSymbol(chainId)));
});
}
}
public ArrayList<SignRecord> getSignRecords(String sessionId)
{
ArrayList<SignRecord> records = new ArrayList<>();
try (Realm realm = realmManager.getRealmInstance(WC_SESSION_DB))
{
RealmResults<RealmWCSignElement> sessionList = realm.where(RealmWCSignElement.class)
.equalTo("sessionId", sessionId)
.findAll();
RealmResults<RealmWCSignElement> sessionList = realmManager.getRealmInstance(WC_SESSION_DB).where(RealmWCSignElement.class)
.equalTo("sessionId", sessionId)
.findAll();
for (RealmWCSignElement s : sessionList)
{
records.add(new SignRecord(s));
}
for (RealmWCSignElement s : sessionList)
{
records.add(new SignRecord(s));
}
return records;
@ -490,16 +456,13 @@ public class WalletConnectViewModel extends BaseViewModel {
public List<WalletConnectSessionItem> getSessions()
{
List<WalletConnectSessionItem> sessions = new ArrayList<>();
try (Realm realm = realmManager.getRealmInstance(WC_SESSION_DB))
{
RealmResults<RealmWCSession> items = realm.where(RealmWCSession.class)
.sort("lastUsageTime", Sort.DESCENDING)
.findAll();
RealmResults<RealmWCSession> items = realmManager.getRealmInstance(WC_SESSION_DB).where(RealmWCSession.class)
.sort("lastUsageTime", Sort.DESCENDING)
.findAll();
for (RealmWCSession r : items)
{
sessions.add(new WalletConnectSessionItem(r));
}
for (RealmWCSession r : items)
{
sessions.add(new WalletConnectSessionItem(r));
}
return sessions;

@ -133,14 +133,14 @@ public class WalletViewModel extends BaseViewModel
return defaultWallet.getValue();
}
public Disposable setKeyBackupTime(String walletAddr)
public void setKeyBackupTime(String walletAddr)
{
return genericWalletInteract.updateBackupTime(walletAddr);
genericWalletInteract.updateBackupTime(walletAddr);
}
public Disposable setKeyWarningDismissTime(String walletAddr)
public void setKeyWarningDismissTime(String walletAddr)
{
return genericWalletInteract.updateWarningTime(walletAddr);
genericWalletInteract.updateWarningTime(walletAddr);
}
public void setTokenEnabled(Token token, boolean enabled) {

@ -338,16 +338,16 @@ public class ActionSheetDialog extends BottomSheetDialog implements StandardFunc
{
try (Realm realm = tokensService.getWalletRealmInstance())
{
RealmTransaction rt = realm.where(RealmTransaction.class)
.equalTo("hash", txHash)
.findFirst();
realm.executeTransactionAsync(r -> {
RealmTransaction rt = r.where(RealmTransaction.class)
.equalTo("hash", txHash)
.findFirst();
if (rt != null)
{
realm.executeTransaction(instance -> {
if (rt != null)
{
rt.setExpectedCompletion(System.currentTimeMillis() + gasWidget.getExpectedTransactionTime() * 1000);
});
}
}
});
}
}

@ -95,7 +95,7 @@ public class AddressDetailView extends LinearLayout
if (inputURL.length() > 32)
{
int index = inputURL.indexOf("/", 20);
return inputURL.substring(0,index);
return index >= 0 ? inputURL.substring(0,index) : inputURL;
}
else
{

@ -1,122 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
android:orientation="vertical"
android:scrollbarAlwaysDrawVerticalTrack="true"
android:scrollbars="vertical">
<include
android:id="@+id/include3"
layout="@layout/layout_app_bar" />
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/include3" >
<LinearLayout
android:id="@+id/layout_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/alabaster"
android:descendantFocusability="blocksDescendants"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/mercury" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/alabaster"
android:fontFamily="@font/font_semibold"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:text="@string/mainnet"
android:textAllCaps="true"
android:textColor="@color/dove"
android:textSize="15sp" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/mainnet_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:clickable="true"
android:focusable="true"
android:layout_gravity="center_vertical|end"
android:theme="@style/SettingsItemSwitchAppearance"
android:visibility="visible" />
</FrameLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/mercury" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/main_list"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/mercury" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/alabaster"
android:fontFamily="@font/font_semibold"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:text="@string/testnet"
android:textAllCaps="true"
android:textColor="@color/dove"
android:textSize="15sp" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/testnet_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:clickable="true"
android:focusable="true"
android:layout_gravity="center_vertical|end"
android:theme="@style/SettingsItemSwitchAppearance"
android:visibility="visible" />
</FrameLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/mercury" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/test_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</RelativeLayout>

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
android:orientation="vertical"
android:scrollbarAlwaysDrawVerticalTrack="true"
android:scrollbars="vertical">
<include layout="@layout/layout_app_bar" />
<LinearLayout
android:id="@+id/layout_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?android:attr/actionBarSize"
android:background="@color/alabaster"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/mercury" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/mercury" />
</LinearLayout>
</RelativeLayout>

@ -12,7 +12,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:3.5.4' //NB - there is an issue with newer versions of gradle. The APK balloons out, so far haven't diagnosed why.
//If you want to try upgrading gradle plugin past 3.5.4 you will need to also diagnose the APK ballooning issue.
classpath "io.realm:realm-gradle-plugin:10.0.1"
classpath "io.realm:realm-gradle-plugin:10.4.0"
// WARNING WARNING WARNING
// you are about to add here a dependency to be used in the Android app
// don't do that. add that dependency to app/build.gradle

Loading…
Cancel
Save