Repository: alphawallet/alpha-wallet-android
Issue: "no data" on TokenScript action pages

Expected:
- Open ENS and click on any action button
- See the action page 

Actual:
- Open ENS and click on any action button 
- See "no data" in page (works only the first time, each time after requires you to kill the app and do it again)

Happening on xiaomi redmi

Changed files:
app/src/main/java/com/alphawallet/app/repository/TokenRepositoryType.java, app/src/main/java/com/alphawallet/app/di/RepositoriesModule.java, app/src/main/java/com/alphawallet/app/service/TokensService.java, app/src/main/java/com/alphawallet/app/interact/FetchTokensInteract.java, app/src/main/java/com/alphawallet/app/repository/TokenRepository.java, app/src/main/java/com/alphawallet/app/repository/TokenLocalSource.java, app/src/main/java/com/alphawallet/app/repository/TokensRealmSource.java

diff --git a/app/src/main/java/com/alphawallet/app/di/RepositoriesModule.java b/app/src/main/java/com/alphawallet/app/di/RepositoriesModule.java
index aeee6300f..cbeec7704 100644
--- a/app/src/main/java/com/alphawallet/app/di/RepositoriesModule.java
+++ b/app/src/main/java/com/alphawallet/app/di/RepositoriesModule.java
@@ -123,13 +123,11 @@ public class RepositoriesModule {
     TokenRepositoryType provideTokenRepository(
             EthereumNetworkRepositoryType ethereumNetworkRepository,
             TokenLocalSource tokenLocalSource,
-			GasService gasService,
-			TokensService tokensService) {
+			GasService gasService) {
 	    return new TokenRepository(
 	            ethereumNetworkRepository,
                 tokenLocalSource,
-				gasService,
-				tokensService);
+				gasService);
     }
 
     @Singleton
@@ -146,8 +144,8 @@ public class RepositoriesModule {
 
 	@Singleton
 	@Provides
-	TokensService provideTokensService(EthereumNetworkRepositoryType ethereumNetworkRepository, RealmManager realmManager, OkHttpClient okHttpClient, PreferenceRepositoryType preferenceRepository) {
-		return new TokensService(ethereumNetworkRepository, realmManager, okHttpClient, preferenceRepository);
+	TokensService provideTokensService(EthereumNetworkRepositoryType ethereumNetworkRepository, TokenRepositoryType tokenRepository, OkHttpClient okHttpClient, PreferenceRepositoryType preferenceRepository) {
+		return new TokensService(ethereumNetworkRepository, tokenRepository, okHttpClient, preferenceRepository);
 	}
 
 	@Singleton
diff --git a/app/src/main/java/com/alphawallet/app/interact/FetchTokensInteract.java b/app/src/main/java/com/alphawallet/app/interact/FetchTokensInteract.java
index b15f3910d..4efda255f 100644
--- a/app/src/main/java/com/alphawallet/app/interact/FetchTokensInteract.java
+++ b/app/src/main/java/com/alphawallet/app/interact/FetchTokensInteract.java
@@ -33,7 +33,7 @@ public class FetchTokensInteract {
 
     public Observable<Token> fetchStoredToken(NetworkInfo network, Wallet wallet, String tokenAddress) {
         if (TextUtils.isEmpty(tokenAddress)) tokenAddress = wallet.address.toLowerCase();
-        return tokenRepository.fetchCachedSingleToken(network, wallet.address, tokenAddress)
+        return tokenRepository.fetchCachedSingleToken(network.chainId, wallet.address, tokenAddress)
                 .subscribeOn(Schedulers.io())
                 .observeOn(AndroidSchedulers.mainThread());
     }
diff --git a/app/src/main/java/com/alphawallet/app/repository/TokenLocalSource.java b/app/src/main/java/com/alphawallet/app/repository/TokenLocalSource.java
index 37cafa886..1b01421c4 100644
--- a/app/src/main/java/com/alphawallet/app/repository/TokenLocalSource.java
+++ b/app/src/main/java/com/alphawallet/app/repository/TokenLocalSource.java
@@ -18,10 +18,11 @@ public interface TokenLocalSource {
     Single<Token[]> saveTokens(Wallet wallet, Token[] items);
     void updateTokenBalance(NetworkInfo network, Wallet wallet, Token token);
     Token getTokenBalance(NetworkInfo network, Wallet wallet, String address);
+    Token fetchToken(int chainId, Wallet wallet, String address);
     Map<Integer, Token> getTokenBalances(Wallet wallet, String address);
     void setEnable(NetworkInfo network, Wallet wallet, Token token, boolean isEnabled);
 
-    Single<Token> fetchEnabledToken(NetworkInfo networkInfo, Wallet wallet, String address);
+    Single<Token> fetchEnabledToken(int chainId, Wallet wallet, String address);
     Single<Token[]> fetchTokensWithBalance(Wallet wallet);
     Single<Token> saveTicker(Wallet wallet, Token token);
     Single<Token[]> saveTickers(Wallet wallet, Token[] tokens);
diff --git a/app/src/main/java/com/alphawallet/app/repository/TokenRepository.java b/app/src/main/java/com/alphawallet/app/repository/TokenRepository.java
index d028bfa48..8064f5dc1 100644
--- a/app/src/main/java/com/alphawallet/app/repository/TokenRepository.java
+++ b/app/src/main/java/com/alphawallet/app/repository/TokenRepository.java
@@ -77,7 +77,6 @@ public class TokenRepository implements TokenRepositoryType {
     private final TokenLocalSource localSource;
     private final EthereumNetworkRepositoryType ethereumNetworkRepository;
     private final GasService gasService;
-    private final TokensService tokensService;
 
     public static final String INVALID_CONTRACT = "<invalid>";
 
@@ -96,13 +95,11 @@ public class TokenRepository implements TokenRepositoryType {
     public TokenRepository(
             EthereumNetworkRepositoryType ethereumNetworkRepository,
             TokenLocalSource localSource,
-            GasService gasService,
-            TokensService tokensService) {
+            GasService gasService) {
         this.ethereumNetworkRepository = ethereumNetworkRepository;
         this.localSource = localSource;
         this.ethereumNetworkRepository.addOnChangeDefaultNetwork(this::buildWeb3jClient);
         this.gasService = gasService;
-        this.tokensService = tokensService;
 
         web3jNodeServers = new ConcurrentHashMap<>();
         okClient = new OkHttpClient.Builder()
@@ -249,19 +246,26 @@ public class TokenRepository implements TokenRepositoryType {
         NetworkInfo network = ethereumNetworkRepository.getNetworkByChain(token.tokenInfo.chainId);
         Wallet wallet = new Wallet(walletAddress);
         return Single.merge(
-                fetchCachedToken(network, wallet, token.getAddress()),
+                fetchCachedToken(network.chainId, wallet, token.getAddress()),
                 updateBalance(network, wallet, token)) // Looking for new tokens
                 .toObservable();
     }
 
     @Override
-    public Observable<Token> fetchCachedSingleToken(NetworkInfo network, String walletAddress, String tokenAddress)
+    public Observable<Token> fetchCachedSingleToken(int chainId, String walletAddress, String tokenAddress)
     {
         Wallet wallet = new Wallet(walletAddress);
-        return fetchCachedToken(network, wallet, tokenAddress)
+        return fetchCachedToken(chainId, wallet, tokenAddress)
                 .toObservable();
     }
 
+    @Override
+    public Token fetchToken(int chainId, String walletAddress, String address)
+    {
+        Wallet wallet = new Wallet(walletAddress);
+        return localSource.fetchToken(chainId, wallet, address);
+    }
+
     /**
      * Just updates the balance of a token
      *
@@ -582,7 +586,7 @@ public class TokenRepository implements TokenRepositoryType {
     private void updateInService(Token t)
     {
         t.walletUIUpdateRequired = true;
-        tokensService.addToken(t);
+        TokensService.setInterfaceSpec(t.tokenInfo.chainId, t.getAddress(), t.getInterfaceSpec());
     }
 
     /**
@@ -638,15 +642,15 @@ public class TokenRepository implements TokenRepositoryType {
                 .fetchTokensWithBalance(wallet);
     }
 
-    private Single<Token> fetchCachedToken(NetworkInfo network, Wallet wallet, String address)
+    private Single<Token> fetchCachedToken(int chainId, Wallet wallet, String address)
     {
         return localSource
-                .fetchEnabledToken(network, wallet, address);
+                .fetchEnabledToken(chainId, wallet, address);
     }
 
     private BigDecimal updatePending(Token oldToken, BigDecimal pendingBalance)
     {
-        if (!tokensService.getCurrentAddress().equals(oldToken.getWallet()))
+        if (!TokensService.getCurrentWalletAddress().equals(oldToken.getWallet()))
         {
             oldToken.pendingBalance = oldToken.balance;
         }
diff --git a/app/src/main/java/com/alphawallet/app/repository/TokenRepositoryType.java b/app/src/main/java/com/alphawallet/app/repository/TokenRepositoryType.java
index d0bda136b..29fe9e662 100644
--- a/app/src/main/java/com/alphawallet/app/repository/TokenRepositoryType.java
+++ b/app/src/main/java/com/alphawallet/app/repository/TokenRepositoryType.java
@@ -23,7 +23,7 @@ public interface TokenRepositoryType {
     Observable<Token[]> fetchStored(String walletAddress);
     Observable<Token[]> fetchActiveStoredPlusEth(String walletAddress);
     Observable<Token> fetchActiveSingle(String walletAddress, Token token);
-    Observable<Token> fetchCachedSingleToken(NetworkInfo network, String walletAddress, String tokenAddress);
+    Observable<Token> fetchCachedSingleToken(int chainId, String walletAddress, String tokenAddress);
     Observable<Token> fetchActiveTokenBalance(String walletAddress, Token token);
     Single<ContractResult> getTokenResponse(String address, int chainId, String method);
     Completable setEnable(Wallet wallet, Token token, boolean isEnabled);
@@ -36,6 +36,7 @@ public interface TokenRepositoryType {
     Single<TokenTicker> getTokenTicker(Token token);
     Single<Token> getEthBalance(NetworkInfo network, Wallet wallet);
     Single<BigInteger> fetchLatestBlockNumber(int chainId);
+    Token fetchToken(int chainId, String walletAddress, String address);
 
     Disposable terminateToken(Token token, Wallet wallet, NetworkInfo network);
 
diff --git a/app/src/main/java/com/alphawallet/app/repository/TokensRealmSource.java b/app/src/main/java/com/alphawallet/app/repository/TokensRealmSource.java
index 65f597fe2..c321d496e 100644
--- a/app/src/main/java/com/alphawallet/app/repository/TokensRealmSource.java
+++ b/app/src/main/java/com/alphawallet/app/repository/TokensRealmSource.java
@@ -167,18 +167,22 @@ public class TokensRealmSource implements TokenLocalSource {
     }
 
     @Override
-    public Single<Token> fetchEnabledToken(NetworkInfo networkInfo, Wallet wallet, String address) {
-        return Single.fromCallable(() -> {
-            try (Realm realm = realmManager.getRealmInstance(wallet))
-            {
-                RealmToken realmItem = realm.where(RealmToken.class)
-                        .equalTo("address", databaseKey(networkInfo.chainId, address))
-                        .equalTo("chainId", networkInfo.chainId)
-                        .findFirst();
+    public Single<Token> fetchEnabledToken(int chainId, Wallet wallet, String address) {
+        return Single.fromCallable(() -> fetchToken(chainId, wallet, address));
+    }
 
-                return convertSingle(realmItem, realm, null, wallet);
-            }
-        });
+    @Override
+    public Token fetchToken(int chainId, Wallet wallet, String address)
+    {
+        try (Realm realm = realmManager.getRealmInstance(wallet))
+        {
+            RealmToken realmItem = realm.where(RealmToken.class)
+                    .equalTo("address", databaseKey(chainId, address))
+                    .equalTo("chainId", chainId)
+                    .findFirst();
+
+            return convertSingle(realmItem, realm, null, wallet);
+        }
     }
 
     @Override
diff --git a/app/src/main/java/com/alphawallet/app/service/TokensService.java b/app/src/main/java/com/alphawallet/app/service/TokensService.java
index 5bea89b37..5de13737f 100644
--- a/app/src/main/java/com/alphawallet/app/service/TokensService.java
+++ b/app/src/main/java/com/alphawallet/app/service/TokensService.java
@@ -10,6 +10,8 @@ import com.alphawallet.app.entity.tokens.TokenTicker;
 import com.alphawallet.app.interact.GenericWalletInteract;
 import com.alphawallet.app.repository.EthereumNetworkRepositoryType;
 import com.alphawallet.app.repository.PreferenceRepositoryType;
+import com.alphawallet.app.repository.TokenRepositoryType;
+import com.alphawallet.app.repository.entity.RealmToken;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -17,27 +19,28 @@ import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
+import io.realm.Realm;
 import okhttp3.OkHttpClient;
 
 public class TokensService
 {
     private final Map<String, SparseArray<Token>> tokenMap = new ConcurrentHashMap<>();
     private static final Map<String, SparseArray<ContractType>> interfaceSpecMap = new ConcurrentHashMap<>();
-    private String currentAddress = null;
+    private static String currentAddress = null;
     private boolean loaded;
     private final EthereumNetworkRepositoryType ethereumNetworkRepository;
-    private final RealmManager realmManager;
+    private final TokenRepositoryType tokenRepository;
     private final List<Integer> networkFilter;
     private Token focusToken;
     private final OkHttpClient okHttpClient;
     private int currencyCheckCount;
 
     public TokensService(EthereumNetworkRepositoryType ethereumNetworkRepository,
-                         RealmManager realmManager,
+                         TokenRepositoryType tokenRepository,
                          OkHttpClient client,
                          PreferenceRepositoryType preferenceRepository) {
         this.ethereumNetworkRepository = ethereumNetworkRepository;
-        this.realmManager = realmManager;
+        this.tokenRepository = tokenRepository;
         loaded = false;
         networkFilter = new ArrayList<>(10);
         setupFilter();
@@ -54,8 +57,6 @@ public class TokensService
      */
     public Token addToken(Token t)
     {
-        Token e = getToken(t.tokenInfo.chainId, t.tokenInfo.address);
-        if (e != null && e.walletUIUpdateRequired) return t; //ensure tokens marked as requiring UI update complete operation
         if (t.checkTokenWallet(currentAddress))
         {
             if (t.equals(focusToken))
@@ -93,29 +94,26 @@ public class TokensService
         }
 
         tokenAddr.put(chainId, t);
-        setSpec(t);
+        updatedSpec(t);
     }
 
-    private void setSpec(Token t)
+    public Token getToken(int chainId, String addr)
     {
-        SparseArray<ContractType> types = interfaceSpecMap.get(t.getAddress());
-        if (types != null && types.get(t.tokenInfo.chainId, null) != null)
+        Token token = null;
+        if (addr != null)
         {
-            if (t.getInterfaceSpec() == null || t.getInterfaceSpec() == ContractType.NOT_SET || t.getInterfaceSpec() == ContractType.OTHER)
+            if (tokenMap.containsKey(addr.toLowerCase()))
             {
-                t.setInterfaceSpec(interfaceSpecMap.get(t.getAddress()).get(t.tokenInfo.chainId));
+                token = tokenMap.get(addr.toLowerCase()).get(chainId, null);
             }
-        }
-    }
 
-    public Token getToken(int chainId, String addr)
-    {
-        if (addr != null && tokenMap.containsKey(addr.toLowerCase()))
-        {
-            return tokenMap.get(addr.toLowerCase()).get(chainId, null);
+            if (token == null)
+            {
+                token = tokenRepository.fetchToken(chainId, currentAddress, addr);
+            }
         }
 
-        return null;
+        return token;
     }
 
     public String getTokenName(int chainId, String addr)
@@ -309,25 +307,27 @@ public class TokensService
         networkFilter.addAll(ethereumNetworkRepository.getFilterNetworkList());
     }
 
-    public ContractType getInterfaceSpec(int chainId, String address)
+    private boolean updatedSpec(Token token)
     {
-        SparseArray<ContractType> types = interfaceSpecMap.get(address);
-        ContractType result = types != null ? types.get(chainId) : ContractType.OTHER;
-
-        if (result == ContractType.OTHER && tokenMap.containsKey(address))
+        String normalisedAddr = token.getAddress().toLowerCase();
+        SparseArray<ContractType> types = interfaceSpecMap.get(normalisedAddr);
+        if (types != null)
         {
-            List<Token> tokens = getAllAtAddress(address);
-            for (Token token : tokens)
+            ContractType updatedType = types.get(token.tokenInfo.chainId);
+            if (updatedType != null)
             {
-                if (token.tokenInfo.chainId == chainId && token.getInterfaceSpec() != null)
+                token.setInterfaceSpec(updatedType);
+                //clean up the revise spec map
+                interfaceSpecMap.get(normalisedAddr).delete(token.tokenInfo.chainId);
+                if (interfaceSpecMap.get(normalisedAddr).size() == 0)
                 {
-                    result = token.getInterfaceSpec();
-                    break;
+                    interfaceSpecMap.remove(normalisedAddr);
                 }
+                return true;
             }
         }
 
-        return result;
+        return false;
     }
 
     private List<Token> getAllClass(int chainId, ContractType[] filter)
@@ -472,4 +472,9 @@ public class TokensService
     {
         return ethereumNetworkRepository.getTokenTicker(token);
     }
+
+    public static String getCurrentWalletAddress()
+    {
+        return currentAddress;
+    }
 }