From a8fc4385ed30d318bbfb6299567e0bd4e09a0b68 Mon Sep 17 00:00:00 2001 From: Asif Ghanchi Date: Wed, 15 Jun 2022 12:39:51 +0530 Subject: [PATCH 01/36] Enable desugar --- app/build.gradle | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 38be46d0f6..339e465211 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -184,6 +184,8 @@ android { abortOnError false } compileOptions { + // Flag to enable support for the new language APIs + coreLibraryDesugaringEnabled true targetCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8 } @@ -273,7 +275,7 @@ dependencies { implementation 'com.github.apl-devs:appintro:v4.2.2' implementation 'com.github.romandanylyk:PageIndicatorView:v1.0.0' - //coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.5' + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' // ReactiveX implementation 'io.reactivex.rxjava2:rxjava:2.2.21' From 70d52f0043009d2c9c1657443890e8ec32e86e0e Mon Sep 17 00:00:00 2001 From: Asif Ghanchi Date: Mon, 4 Jul 2022 17:40:17 +0530 Subject: [PATCH 02/36] Fixed API23 crashes and compatibility using modded web3j-3.3.1-android --- app/build.gradle | 1 + app/libs/core-4.8.8-android.jar | Bin 308416 -> 279897 bytes .../viewmodel/TransactionDetailViewModel.java | 2 +- .../alphawallet/app/widget/InputAmount.java | 23 +++++++++++++++--- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 339e465211..bfc33ae478 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -277,6 +277,7 @@ dependencies { coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' + implementation 'io.reactivex:rxjava:1.2.4' // ReactiveX implementation 'io.reactivex.rxjava2:rxjava:2.2.21' implementation "io.reactivex.rxjava2:rxandroid:2.1.1" diff --git a/app/libs/core-4.8.8-android.jar b/app/libs/core-4.8.8-android.jar index 4d7cf4511e1acf82462e29f9cb3d2adbfd448070..77e418cf4d29852d9ea2c246ea592538d1bb3493 100644 GIT binary patch delta 237166 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ⅇ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≷b)wh-;Xce5r~_jDZ>6)6}*dZZ1V+EVevXeveq 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 L_PiWLNAUPR{@YRj delta 266257 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

u7 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

AD{6--rHx_|SVx{+01^!u?@d}y8X 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 q!T6Vc=2;{r+ in API23 disposable = EventUtils.getBlockDetails(ethTx.getBlockHash(), web3j) .map(ethBlock -> new Transaction(ethTx, chainId, true, ethBlock.getBlock().getTimestamp().longValue())) .map(tx -> writeTransaction(wallet, tx)) diff --git a/app/src/main/java/com/alphawallet/app/widget/InputAmount.java b/app/src/main/java/com/alphawallet/app/widget/InputAmount.java index 4d49ba8deb..3f11386ad7 100644 --- a/app/src/main/java/com/alphawallet/app/widget/InputAmount.java +++ b/app/src/main/java/com/alphawallet/app/widget/InputAmount.java @@ -36,6 +36,9 @@ import java.math.RoundingMode; import java.text.DecimalFormat; +import io.reactivex.Completable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; import io.realm.Case; import io.realm.Realm; import io.realm.RealmQuery; @@ -396,9 +399,23 @@ private void setupAllFunds() { gasFetch.setVisibility(View.VISIBLE); Web3j web3j = TokenRepository.getWeb3jService(token.tokenInfo.chainId); - web3j.ethGasPrice().sendAsync() - .thenAccept(ethGasPrice -> onLatestGasPrice(ethGasPrice.getGasPrice())) - .exceptionally(this::onGasFetchError); + Completable.fromRunnable( () -> + { + try + { + onLatestGasPrice(web3j.ethGasPrice().sendAsync().get().getGasPrice()); + } + catch (Exception e) + { + e.printStackTrace(); + onGasFetchError(e); + } + } + ) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(() -> {}, this::onGasFetchError) + .isDisposed(); } } else From cfe58632ea1721334874baa4942cc43ff95f6487 Mon Sep 17 00:00:00 2001 From: James Brown Date: Tue, 20 Sep 2022 13:40:49 +1000 Subject: [PATCH 03/36] Update core web3j for ENS feature --- app/libs/core-4.8.8-android.jar | Bin 279897 -> 280265 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/app/libs/core-4.8.8-android.jar b/app/libs/core-4.8.8-android.jar index 77e418cf4d29852d9ea2c246ea592538d1bb3493..89fea5d83b509af5b696e5ea1c847d1a576ec7eb 100644 GIT binary patch delta 21270 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 b1Vn-7r@DV7Nqg>qeLj3cal^Y%4DbH{dJDgD From 00118c1fce9fbce928431998cfe1b04f5028e9b1 Mon Sep 17 00:00:00 2001 From: James Brown Date: Tue, 20 Sep 2022 14:03:00 +1000 Subject: [PATCH 04/36] fix formatting --- .../alphawallet/app/widget/InputAmount.java | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/alphawallet/app/widget/InputAmount.java b/app/src/main/java/com/alphawallet/app/widget/InputAmount.java index 3f11386ad7..88b5bc8bee 100644 --- a/app/src/main/java/com/alphawallet/app/widget/InputAmount.java +++ b/app/src/main/java/com/alphawallet/app/widget/InputAmount.java @@ -1,5 +1,8 @@ package com.alphawallet.app.widget; +import static com.alphawallet.app.C.GAS_LIMIT_MIN; +import static com.alphawallet.app.repository.TokensRealmSource.databaseKey; + import android.content.Context; import android.content.res.TypedArray; import android.os.Handler; @@ -44,9 +47,6 @@ import io.realm.RealmQuery; import timber.log.Timber; -import static com.alphawallet.app.C.GAS_LIMIT_MIN; -import static com.alphawallet.app.repository.TokensRealmSource.databaseKey; - /** * Created by JB on 10/11/2020. */ @@ -387,8 +387,8 @@ private void setupAllFunds() if (token.isEthereum() && token.hasPositiveBalance()) { RealmGasSpread gasSpread = tokensService.getTickerRealmInstance().where(RealmGasSpread.class) - .equalTo("chainId", token.tokenInfo.chainId) - .findFirst(); + .equalTo("chainId", token.tokenInfo.chainId) + .findFirst(); if (gasSpread != null && gasSpread.getGasPrice().compareTo(BigInteger.ZERO) > 0) { @@ -399,19 +399,19 @@ private void setupAllFunds() { gasFetch.setVisibility(View.VISIBLE); Web3j web3j = TokenRepository.getWeb3jService(token.tokenInfo.chainId); - Completable.fromRunnable( () -> - { - try - { - onLatestGasPrice(web3j.ethGasPrice().sendAsync().get().getGasPrice()); - } - catch (Exception e) - { - e.printStackTrace(); - onGasFetchError(e); - } - } - ) + Completable.fromRunnable(() -> + { + try + { + onLatestGasPrice(web3j.ethGasPrice().sendAsync().get().getGasPrice()); + } + catch (Exception e) + { + e.printStackTrace(); + onGasFetchError(e); + } + } + ) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(() -> {}, this::onGasFetchError) From e09aac9bc117b3fab072635204ddc7ea32d3c1e4 Mon Sep 17 00:00:00 2001 From: James Brown Date: Tue, 20 Sep 2022 14:22:41 +1000 Subject: [PATCH 05/36] Update final version message and library --- app/libs/core-4.8.8-android.jar | Bin 280265 -> 280155 bytes app/src/main/res/values-es/strings.xml | 2 +- app/src/main/res/values-fr/strings.xml | 2 +- app/src/main/res/values-id/strings.xml | 2 +- app/src/main/res/values-my/strings.xml | 2 +- app/src/main/res/values-vi/strings.xml | 2 +- app/src/main/res/values-zh/strings.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- 8 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/libs/core-4.8.8-android.jar b/app/libs/core-4.8.8-android.jar index 89fea5d83b509af5b696e5ea1c847d1a576ec7eb..236a3924c6be6909ce7286fd45be61079da8ce4d 100644 GIT binary patch delta 10275 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 PmT1vgy~}Bsv5Nl#yW_W8 delta 10161 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 monederos Copiar Actualización importante - A partir de la versión 3.0, AlphaWallet ya no será compatible con dispositivos que ejecuten Android 6.0 o inferior. + Esta es la versión final de los dispositivos compatibles con AlphaWallet que se ejecutan en Android 6. Ocultar notificación %1$s no encontrado Gestión de TokenScript diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 54b93d97a5..4d8692c96e 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -583,7 +583,7 @@ Vos Portefeuilles Copier Mise à jour importante - À partir de la version 3.0, AlphaWallet ne prendra plus en charge les appareils fonctionnant sous Android 6.0 et versions antérieures. + Il s\'agit de la version finale d\'AlphaWallet prenant en charge les appareils fonctionnant sous Android 6. Cacher Notification %1$s pas trouvé Gestion TokenScript diff --git a/app/src/main/res/values-id/strings.xml b/app/src/main/res/values-id/strings.xml index 564d4680a3..1813da9709 100644 --- a/app/src/main/res/values-id/strings.xml +++ b/app/src/main/res/values-id/strings.xml @@ -584,7 +584,7 @@ Dompet Anda Salin Pembaruan Penting - Mulai Versi 3.0, AlphaWallet tidak mendukung perangkat yang berjalan di Android 6.0 dan di bawahnya. + Ini adalah build terakhir dari perangkat pendukung AlphaWallet yang berjalan di Android 6. Sembunyikan Pemberitahuan %1$s tidak ditemukan Pengelolaan TokenScript diff --git a/app/src/main/res/values-my/strings.xml b/app/src/main/res/values-my/strings.xml index f52ca143b6..5cbbeade8e 100644 --- a/app/src/main/res/values-my/strings.xml +++ b/app/src/main/res/values-my/strings.xml @@ -590,7 +590,7 @@ သင်၏ ဝေါလက်များ ကူးယူမည် အရေးကြီးသောအသစ်ပြုပြင်မွမ်းမံမှုများ - Alphawalletဗားရှင်း 3.0မှစ၍ Wallet သည် Android ဗားရှင်း 6.0ထက်နိမ့်သောစက်များတွင်အသုံးမပြုနိုင်တော့ပါ။ + ၎င်းသည် Android 6 ပေါ်တွင် အသုံးပြုနေသည့် AlphaWallet ပံ့ပိုးပေးသည့် စက်ပစ္စည်းများ၏ နောက်ဆုံးတည်ဆောက်မှုဖြစ်သည်။ အသိပေးကြေငြာချက်များကိုပုန်းကွယ်မည် %1$s ကိုရှာမတွေ့ပါ TokenScriptကို စီမံခန့်ခွဲခြင်း diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 70f0aeb809..5ca3d08798 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -586,7 +586,7 @@ Ví của bạn Sao chép Important Update - Bắt đầu từ Phiên bản 3.0, AlphaWallet sẽ không còn hỗ trợ các thiết bị chạy trên Android 6.0 trở xuống. + Đây là bản dựng cuối cùng của AlphaWallet hỗ trợ các thiết bị chạy trên Android 6. Tắt thông báo %1$s not found TokenScript Management diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 31d044f2bc..f6076d7f29 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -573,7 +573,7 @@ 您的钱包 复制 重要更新 - 从版本 3.0 开始,AlphaWallet 将不再支持在 Android 6.0 及以下设备上运行。 + 这是 AlphaWallet 的最终版本,支持在 Android 6 上运行的设备。 隐藏通知 未找到%1$s TokenScript 管理 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 012b7a61bb..c71e964c64 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -616,7 +616,7 @@ Your Wallets Copy Important Update - Starting Version 3.0, AlphaWallet will no longer support devices running on Android 6.0 and below. + This is the final build of AlphaWallet supporting devices running on Android 6. Hide Notification %1$s not found TokenScript Management From 136a0094c326e460d444dfbfdff1197d55db7b57 Mon Sep 17 00:00:00 2001 From: James Brown Date: Wed, 21 Sep 2022 16:00:39 +1000 Subject: [PATCH 06/36] update API23 notice --- .../app/repository/PreferenceRepositoryType.java | 2 ++ .../app/repository/SharedPreferenceRepository.java | 13 +++++++++++++ .../com/alphawallet/app/ui/NewSettingsFragment.java | 4 ++-- .../java/com/alphawallet/app/ui/WalletFragment.java | 11 +++++------ .../app/viewmodel/NewSettingsViewModel.java | 13 ++++++++++--- 5 files changed, 32 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/alphawallet/app/repository/PreferenceRepositoryType.java b/app/src/main/java/com/alphawallet/app/repository/PreferenceRepositoryType.java index 99b177faad..8dc04155fe 100644 --- a/app/src/main/java/com/alphawallet/app/repository/PreferenceRepositoryType.java +++ b/app/src/main/java/com/alphawallet/app/repository/PreferenceRepositoryType.java @@ -60,6 +60,8 @@ public interface PreferenceRepositoryType { void setHasSetNetworkFilters(); boolean hasSetNetworkFilters(); void blankHasSetNetworkFilters(); + void cancelAPI23Notification(); + boolean hasCancelledAPI23Notification(); void commit(); diff --git a/app/src/main/java/com/alphawallet/app/repository/SharedPreferenceRepository.java b/app/src/main/java/com/alphawallet/app/repository/SharedPreferenceRepository.java index 61fa1e01f9..654c301027 100644 --- a/app/src/main/java/com/alphawallet/app/repository/SharedPreferenceRepository.java +++ b/app/src/main/java/com/alphawallet/app/repository/SharedPreferenceRepository.java @@ -45,6 +45,7 @@ public class SharedPreferenceRepository implements PreferenceRepositoryType { private static final String RATE_APP_SHOWN = "rate_us_shown"; private static final String LAUNCH_COUNT = "launch_count"; private static final String NEW_WALLET = "new_wallet_"; + private static final String API23_NOTIFICATION = "api23_notification"; private final SharedPreferences pref; @@ -243,6 +244,18 @@ public void blankHasSetNetworkFilters() pref.edit().putBoolean(SET_NETWORK_FILTERS, false).apply(); } + @Override + public void cancelAPI23Notification() + { + pref.edit().putBoolean(API23_NOTIFICATION, true).apply(); + } + + @Override + public boolean hasCancelledAPI23Notification() + { + return pref.getBoolean(API23_NOTIFICATION, false); + } + //Ensure settings are committed @SuppressLint("ApplySharedPref") @Override diff --git a/app/src/main/java/com/alphawallet/app/ui/NewSettingsFragment.java b/app/src/main/java/com/alphawallet/app/ui/NewSettingsFragment.java index 0c9bcd4e3a..b2e62b9a7d 100644 --- a/app/src/main/java/com/alphawallet/app/ui/NewSettingsFragment.java +++ b/app/src/main/java/com/alphawallet/app/ui/NewSettingsFragment.java @@ -175,7 +175,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c private void initNotificationView(View view) { notificationView = view.findViewById(R.id.notification); - if (android.os.Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) + if (android.os.Build.VERSION.SDK_INT <= Build.VERSION_CODES.M && !viewModel.hasShownAPI23Notification()) { notificationView.setTitle(getContext().getString(R.string.title_version_support_warning)); notificationView.setMessage(getContext().getString(R.string.message_version_support_warning)); @@ -183,7 +183,7 @@ private void initNotificationView(View view) notificationView.setPrimaryButtonListener(() -> { notificationView.setVisibility(View.GONE); - viewModel.setMarshMallowWarning(true); + viewModel.cancelAPI23Notification(); }); } else diff --git a/app/src/main/java/com/alphawallet/app/ui/WalletFragment.java b/app/src/main/java/com/alphawallet/app/ui/WalletFragment.java index 9d9f946406..903b1bb3e5 100644 --- a/app/src/main/java/com/alphawallet/app/ui/WalletFragment.java +++ b/app/src/main/java/com/alphawallet/app/ui/WalletFragment.java @@ -757,7 +757,7 @@ public boolean onMenuItemClick(MenuItem menuItem) { if (menuItem.getItemId() == R.id.action_my_wallet) { - viewModel.showMyAddress(getContext()); + viewModel.showMyAddress(requireContext()); } if (menuItem.getItemId() == R.id.action_scan) { @@ -769,13 +769,12 @@ public boolean onMenuItemClick(MenuItem menuItem) private void initNotificationView(View view) { NotificationView notificationView = view.findViewById(R.id.notification); - boolean hasShownWarning = viewModel.isMarshMallowWarningShown(); - if (!hasShownWarning && android.os.Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) + if (!viewModel.isMarshMallowWarningShown() && android.os.Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) { - notificationView.setTitle(getContext().getString(R.string.title_version_support_warning)); - notificationView.setMessage(getContext().getString(R.string.message_version_support_warning)); - notificationView.setPrimaryButtonText(getContext().getString(R.string.hide_notification)); + notificationView.setTitle(requireContext().getString(R.string.title_version_support_warning)); + notificationView.setMessage(requireContext().getString(R.string.message_version_support_warning)); + notificationView.setPrimaryButtonText(requireContext().getString(R.string.hide_notification)); notificationView.setPrimaryButtonListener(() -> { notificationView.setVisibility(View.GONE); diff --git a/app/src/main/java/com/alphawallet/app/viewmodel/NewSettingsViewModel.java b/app/src/main/java/com/alphawallet/app/viewmodel/NewSettingsViewModel.java index 37ac4e09d8..4505c2abdb 100644 --- a/app/src/main/java/com/alphawallet/app/viewmodel/NewSettingsViewModel.java +++ b/app/src/main/java/com/alphawallet/app/viewmodel/NewSettingsViewModel.java @@ -1,9 +1,10 @@ package com.alphawallet.app.viewmodel; +import android.content.Context; + import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; -import android.content.Context; import com.alphawallet.app.entity.CurrencyItem; import com.alphawallet.app.entity.LocaleItem; @@ -147,7 +148,13 @@ public void setIsDismissed(String walletAddr, boolean isDismissed) genericWalletInteract.setIsDismissed(walletAddr, isDismissed); } - public void setMarshMallowWarning(boolean shown) { - preferenceRepository.setMarshMallowWarning(shown); + public boolean hasShownAPI23Notification() + { + return preferenceRepository.hasCancelledAPI23Notification(); + } + + public void cancelAPI23Notification() + { + preferenceRepository.cancelAPI23Notification(); } } From 6d33440b83e4f37d1c5c111815df73919f36667e Mon Sep 17 00:00:00 2001 From: James Brown Date: Wed, 21 Sep 2022 16:01:55 +1000 Subject: [PATCH 07/36] Fix Inject for websites in same domain --- .../com/alphawallet/app/web3/Web3View.java | 44 +++++++++++++++---- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/alphawallet/app/web3/Web3View.java b/app/src/main/java/com/alphawallet/app/web3/Web3View.java index 91f774f712..9669d20355 100644 --- a/app/src/main/java/com/alphawallet/app/web3/Web3View.java +++ b/app/src/main/java/com/alphawallet/app/web3/Web3View.java @@ -1,11 +1,7 @@ package com.alphawallet.app.web3; -import static androidx.webkit.WebSettingsCompat.FORCE_DARK_OFF; -import static androidx.webkit.WebSettingsCompat.FORCE_DARK_ON; - import android.annotation.SuppressLint; import android.content.Context; -import android.content.res.Configuration; import android.graphics.Bitmap; import android.os.Build; import android.util.AttributeSet; @@ -19,8 +15,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; -import androidx.webkit.WebSettingsCompat; -import androidx.webkit.WebViewFeature; import com.alphawallet.app.BuildConfig; import com.alphawallet.app.entity.URLLoadInterface; @@ -35,6 +29,8 @@ import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; +import java.net.MalformedURLException; +import java.net.URL; import java.util.HashMap; import java.util.Map; @@ -380,7 +376,7 @@ else if (!loadingError && loadInterface != null) @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { - redirect = true; + redirect = isRedirect(view, url); return externalClient.shouldOverrideUrlLoading(view, url) || internalClient.shouldOverrideUrlLoading(view, url); @@ -398,10 +394,42 @@ public void onReceivedError(WebView view, WebResourceRequest request, WebResourc @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { - redirect = true; + redirect = isRedirect(view, request); return externalClient.shouldOverrideUrlLoading(view, request) || internalClient.shouldOverrideUrlLoading(view, request); } + + private boolean isRedirect(WebView view, String url) + { + try + { + return isRedirect(new URL(view.getUrl()), new URL(url)); + } + catch (MalformedURLException e) + { + return true; + } + } + + private boolean isRedirect(WebView view, WebResourceRequest request) + { + try + { + return isRedirect(new URL(view.getUrl()), new URL(request.toString())); + } + catch (MalformedURLException e) + { + return true; + } + } + + private boolean isRedirect(URL urlSource, URL urlDestination) + { + String sourceBase = urlSource.getHost(); + String destinationBase = urlDestination.getHost(); + + return !sourceBase.equals(destinationBase) || urlSource.toString().equals(urlDestination.toString()); + } } } From b22f8c5571b730f3d77fbc547159c3490020d98e Mon Sep 17 00:00:00 2001 From: James Brown Date: Wed, 21 Sep 2022 17:22:04 +1000 Subject: [PATCH 08/36] bump gradle --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index bfc33ae478..efdd2ae4c6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -85,8 +85,8 @@ android { } } defaultConfig { - versionCode 202 - versionName "3.58.3" + versionCode 203 + versionName "3.59" applicationId "io.stormbird.wallet" minSdkVersion 23 From f6ad8720d0cb3b9229fb90126086b2a5f66f8c6f Mon Sep 17 00:00:00 2001 From: James Brown Date: Sun, 30 Oct 2022 14:54:18 +1100 Subject: [PATCH 09/36] Update to current master for re-release --- app/build.gradle | 4 +- app/src/main/AndroidManifest.xml | 10 +- app/src/main/java/com/alphawallet/app/C.java | 13 +- .../app/di/RepositoriesModule.java | 8 + .../alphawallet/app/entity/Transaction.java | 1277 +++++++++-------- .../alphawallet/app/entity/lifi/Action.java | 50 + .../app/entity/lifi/Connection.java | 79 +- .../alphawallet/app/entity/lifi/Estimate.java | 100 ++ .../alphawallet/app/entity/lifi/FeeCost.java | 25 + .../alphawallet/app/entity/lifi/GasCost.java | 19 + .../alphawallet/app/entity/lifi/Quote.java | 181 +-- .../alphawallet/app/entity/lifi/Route.java | 36 + .../app/entity/lifi/RouteError.java | 23 + .../app/entity/lifi/RouteOptions.java | 33 + .../app/entity/lifi/SwapProvider.java | 25 + .../alphawallet/app/entity/lifi/Token.java | 91 ++ .../app/entity/opensea/OpenSeaAsset.java | 4 + .../app/entity/opensea/Rarity.java | 31 + .../entity/tokenscript/TokenScriptFile.java | 4 + .../app/repository/EthereumNetworkBase.java | 309 ++-- .../repository/PreferenceRepositoryType.java | 5 + .../SharedPreferenceRepository.java | 15 + .../app/repository/SwapRepository.java | 36 + .../app/repository/SwapRepositoryType.java | 10 + .../alphawallet/app/service/SwapService.java | 177 ++- .../app/service/TickerService.java | 8 +- .../alphawallet/app/ui/FunctionActivity.java | 1 + .../com/alphawallet/app/ui/HomeActivity.java | 30 +- .../app/ui/NFTAssetDetailActivity.java | 10 +- .../app/ui/NewSettingsFragment.java | 13 +- .../app/ui/SelectRouteActivity.java | 201 +++ .../app/ui/SelectSwapProvidersActivity.java | 78 + .../com/alphawallet/app/ui/SwapActivity.java | 249 ++-- .../adapter/MultiSelectNetworkAdapter.java | 11 + .../app/ui/widget/adapter/RouteAdapter.java | 105 ++ .../ui/widget/adapter/SelectChainAdapter.java | 24 +- .../ui/widget/adapter/SelectTokenAdapter.java | 15 +- .../widget/adapter/SwapProviderAdapter.java | 87 ++ .../app/ui/widget/adapter/TokenFilter.java | 31 +- .../entity/OnRouteSelectedListener.java | 6 + .../app/ui/widget/entity/ProgressInfo.java | 28 + .../com/alphawallet/app/util/SwapUtils.java | 46 +- .../java/com/alphawallet/app/util/Utils.java | 136 +- .../app/viewmodel/HomeViewModel.java | 5 - .../app/viewmodel/NewSettingsViewModel.java | 61 +- .../app/viewmodel/SelectRouteViewModel.java | 119 ++ .../SelectSwapProvidersViewModel.java | 85 ++ .../app/viewmodel/SwapViewModel.java | 127 +- .../com/alphawallet/app/viewmodel/Tokens.java | 8 +- .../alphawallet/app/walletconnect/WCClient.kt | 1 + .../app/widget/AddressDetailView.java | 3 +- .../alphawallet/app/widget/CopyTextView.java | 20 +- .../alphawallet/app/widget/InputAmount.java | 10 +- .../app/widget/SelectTokenDialog.java | 6 +- .../app/widget/StandardHeader.java | 36 +- .../app/widget/SwapSettingsDialog.java | 54 +- .../com/alphawallet/app/widget/TokenIcon.java | 19 + .../alphawallet/app/widget/TokenInfoView.java | 33 + .../alphawallet/app/widget/TokenSelector.java | 21 +- app/src/main/res/drawable/ic_sepolia_test.png | Bin 0 -> 127735 bytes .../main/res/drawable/ic_swap_horizontal.xml | 10 + .../res/drawable/select_masking_circle.xml | 5 +- .../main/res/layout/activity_my_address.xml | 3 +- .../res/layout/activity_nft_asset_detail.xml | 7 + .../main/res/layout/activity_select_route.xml | 137 ++ app/src/main/res/layout/activity_swap.xml | 37 +- .../main/res/layout/dialog_swap_settings.xml | 17 + .../main/res/layout/item_address_detail.xml | 2 + .../main/res/layout/item_amount_display.xml | 9 +- app/src/main/res/layout/item_chain_select.xml | 4 +- .../main/res/layout/item_copy_textview.xml | 14 +- app/src/main/res/layout/item_exchange.xml | 53 + .../main/res/layout/item_network_check.xml | 50 +- app/src/main/res/layout/item_route.xml | 119 ++ .../main/res/layout/item_standard_header.xml | 28 +- app/src/main/res/layout/item_token_info.xml | 2 + app/src/main/res/values-es/strings.xml | 14 + app/src/main/res/values-fr/strings.xml | 14 + app/src/main/res/values-id/strings.xml | 14 + app/src/main/res/values-my/strings.xml | 14 + app/src/main/res/values-vi/strings.xml | 14 + app/src/main/res/values-zh/strings.xml | 14 + app/src/main/res/values/attrs.xml | 5 + app/src/main/res/values/colors_misc.xml | 1 + app/src/main/res/values/strings.xml | 17 +- .../ethereum/EthereumNetworkBase.java | 28 +- 86 files changed, 3542 insertions(+), 1342 deletions(-) create mode 100644 app/src/main/java/com/alphawallet/app/entity/lifi/Action.java create mode 100644 app/src/main/java/com/alphawallet/app/entity/lifi/Estimate.java create mode 100644 app/src/main/java/com/alphawallet/app/entity/lifi/FeeCost.java create mode 100644 app/src/main/java/com/alphawallet/app/entity/lifi/GasCost.java create mode 100644 app/src/main/java/com/alphawallet/app/entity/lifi/Route.java create mode 100644 app/src/main/java/com/alphawallet/app/entity/lifi/RouteError.java create mode 100644 app/src/main/java/com/alphawallet/app/entity/lifi/RouteOptions.java create mode 100644 app/src/main/java/com/alphawallet/app/entity/lifi/SwapProvider.java create mode 100644 app/src/main/java/com/alphawallet/app/entity/lifi/Token.java create mode 100644 app/src/main/java/com/alphawallet/app/entity/opensea/Rarity.java create mode 100644 app/src/main/java/com/alphawallet/app/repository/SwapRepository.java create mode 100644 app/src/main/java/com/alphawallet/app/repository/SwapRepositoryType.java create mode 100644 app/src/main/java/com/alphawallet/app/ui/SelectRouteActivity.java create mode 100644 app/src/main/java/com/alphawallet/app/ui/SelectSwapProvidersActivity.java create mode 100644 app/src/main/java/com/alphawallet/app/ui/widget/adapter/RouteAdapter.java create mode 100644 app/src/main/java/com/alphawallet/app/ui/widget/adapter/SwapProviderAdapter.java create mode 100644 app/src/main/java/com/alphawallet/app/ui/widget/entity/OnRouteSelectedListener.java create mode 100644 app/src/main/java/com/alphawallet/app/ui/widget/entity/ProgressInfo.java create mode 100644 app/src/main/java/com/alphawallet/app/viewmodel/SelectRouteViewModel.java create mode 100644 app/src/main/java/com/alphawallet/app/viewmodel/SelectSwapProvidersViewModel.java create mode 100644 app/src/main/res/drawable/ic_sepolia_test.png create mode 100644 app/src/main/res/drawable/ic_swap_horizontal.xml create mode 100644 app/src/main/res/layout/activity_select_route.xml create mode 100644 app/src/main/res/layout/item_exchange.xml create mode 100644 app/src/main/res/layout/item_route.xml diff --git a/app/build.gradle b/app/build.gradle index efdd2ae4c6..fb1fd365f3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -85,8 +85,8 @@ android { } } defaultConfig { - versionCode 203 - versionName "3.59" + versionCode 207 + versionName "3.60" applicationId "io.stormbird.wallet" minSdkVersion 23 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d3bdc3f18a..69a9ec1da4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -307,6 +307,14 @@ android:label="Native Swap" android:windowSoftInputMode="adjustResize" /> + + + + @@ -314,7 +322,7 @@ - + diff --git a/app/src/main/java/com/alphawallet/app/C.java b/app/src/main/java/com/alphawallet/app/C.java index 8c39765503..f4408f1230 100644 --- a/app/src/main/java/com/alphawallet/app/C.java +++ b/app/src/main/java/com/alphawallet/app/C.java @@ -59,6 +59,9 @@ public abstract class C { public static final String MILKOMEDA_TESTNET_NAME = "Milkomeda Cardano (Test)"; public static final String PHI_NETWORK_NAME = "PHI"; public static final String PHI_V2_NETWORK_NAME = "PHI v2"; + public static final String SEPOLIA_TESTNET_NAME = "Sepolia (Test)"; + public static final String OPTIMISM_GOERLI_TESTNET_NAME = "Optimism Goerli (Test)"; + public static final String ARBITRUM_GOERLI_TESTNET_NAME = "Arbitrum Goerli (Test)"; public static final String ETHEREUM_TICKER_NAME = "ethereum"; public static final String CLASSIC_TICKER_NAME = "ethereum-classic"; @@ -92,6 +95,9 @@ public abstract class C { public static final String MILKOMEDA_SYMBOL = "milkADA"; public static final String MILKOMEDA_TEST_SYMBOL = "milktADA"; public static final String PHI_NETWORK_SYMBOL = "\u03d5"; + public static final String SEPOLIA_SYMBOL = "ETH"; + public static final String OPTIMISM_GOERLI_TEST_SYMBOL = "ETH"; + public static final String ARBITRUM_GOERLI_TEST_SYMBOL = "AGOR"; public static final String BURN_ADDRESS = "0x0000000000000000000000000000000000000000"; @@ -321,13 +327,6 @@ public enum TokenStatus { public static final String OPENSEA_SINGLE_ASSET_API_RINKEBY = "https://testnets-api.opensea.io/api/v1/asset/"; public static final String OPENSEA_SINGLE_ASSET_API_MATIC = "https://api.opensea.io/api/v2/metadata/matic/"; - // Progress Info - public interface ProgressInfo { - int FETCHING_CHAINS = 1; - int FETCHING_CONNECTIONS = 2; - int FETCHING_QUOTE = 3; - } - //Timing public static long CONNECT_TIMEOUT = 10; //Seconds public static long READ_TIMEOUT = 10; 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 127d9e6be5..1c45aa1082 100644 --- a/app/src/main/java/com/alphawallet/app/di/RepositoriesModule.java +++ b/app/src/main/java/com/alphawallet/app/di/RepositoriesModule.java @@ -12,6 +12,8 @@ import com.alphawallet.app.repository.OnRampRepositoryType; import com.alphawallet.app.repository.PreferenceRepositoryType; import com.alphawallet.app.repository.SharedPreferenceRepository; +import com.alphawallet.app.repository.SwapRepository; +import com.alphawallet.app.repository.SwapRepositoryType; import com.alphawallet.app.repository.TokenLocalSource; import com.alphawallet.app.repository.TokenRepository; import com.alphawallet.app.repository.TokenRepositoryType; @@ -117,6 +119,12 @@ OnRampRepositoryType provideOnRampRepository(@ApplicationContext Context context return new OnRampRepository(context, analyticsServiceType); } + @Singleton + @Provides + SwapRepositoryType provideSwapRepository(@ApplicationContext Context context) { + return new SwapRepository(context); + } + @Singleton @Provides CoinbasePayRepositoryType provideCoinbasePayRepository() { diff --git a/app/src/main/java/com/alphawallet/app/entity/Transaction.java b/app/src/main/java/com/alphawallet/app/entity/Transaction.java index 91e54e05d6..18037a924c 100644 --- a/app/src/main/java/com/alphawallet/app/entity/Transaction.java +++ b/app/src/main/java/com/alphawallet/app/entity/Transaction.java @@ -28,14 +28,13 @@ import java.util.Map; /** - * * This is supposed to be a generic transaction class which can * contain all of 3 stages of a transaction: - * + *

* 1. being compiled, in progress, or ready to be signed; * 2. compiled and signed, or ready to be broadcasted; - * 2. already broadcasted, obtained in its raw format from a node, - * including the signatures in it; + * 2. already broadcasted, obtained in its raw format from a node, + * including the signatures in it; * 4. already included in a blockchain. */ public class Transaction implements Parcelable @@ -61,654 +60,666 @@ public class Transaction implements Parcelable public TransactionInput transactionInput = null; public static final String CONSTRUCTOR = "Constructor"; - public static final TransactionDecoder decoder = new TransactionDecoder(); - public static ParseMagicLink parser = null; - - //placeholder for error - public Transaction() - { - //blank transaction - hash = ""; - blockNumber = ""; - timeStamp = 0; - nonce = 0; - from = ""; - to = ""; - value = ""; - gas = ""; - gasPrice = ""; - gasUsed = ""; - input = ""; - error = ""; - chainId = 0; - maxFeePerGas = ""; - maxPriorityFee = ""; - } - - public boolean isPending() - { - return TextUtils.isEmpty(blockNumber) || blockNumber.equals("0") || blockNumber.equals("-2"); - } - - public boolean hasError() - { - return !TextUtils.isEmpty(error) && error.equals("1"); - } - - public boolean hasData() - { - return !TextUtils.isEmpty(input) && input.length() > 2; - } + public static final TransactionDecoder decoder = new TransactionDecoder(); + public static ParseMagicLink parser = null; + + //placeholder for error + public Transaction() + { + //blank transaction + hash = ""; + blockNumber = ""; + timeStamp = 0; + nonce = 0; + from = ""; + to = ""; + value = ""; + gas = ""; + gasPrice = ""; + gasUsed = ""; + input = ""; + error = ""; + chainId = 0; + maxFeePerGas = ""; + maxPriorityFee = ""; + } + + public boolean isPending() + { + return TextUtils.isEmpty(blockNumber) || blockNumber.equals("0") || blockNumber.equals("-2"); + } + + public boolean hasError() + { + return !TextUtils.isEmpty(error) && error.equals("1"); + } + + public boolean hasData() + { + return !TextUtils.isEmpty(input) && input.length() > 2; + } public Transaction( String hash, String error, String blockNumber, long timeStamp, - int nonce, - String from, - String to, - String value, - String gas, - String gasPrice, - String input, - String gasUsed, + int nonce, + String from, + String to, + String value, + String gas, + String gasPrice, + String input, + String gasUsed, long chainId, - boolean isConstructor) { + boolean isConstructor) + { this.hash = hash; this.error = error; this.blockNumber = blockNumber; this.timeStamp = timeStamp; - this.nonce = nonce; - this.from = from; - this.to = to; - this.value = value; - this.gas = gas; - this.gasPrice = gasPrice; - this.input = input; - this.gasUsed = gasUsed; - this.chainId = chainId; - this.isConstructor = isConstructor; - this.maxFeePerGas = ""; - this.maxPriorityFee = ""; - } - - public Transaction(Web3Transaction tx, long chainId, String wallet) - { - this.hash = null; - this.error = null; - this.blockNumber = null; - this.timeStamp = System.currentTimeMillis()/1000; - this.nonce = -1; - this.from = wallet; - this.to = tx.recipient.toString(); - this.value = tx.value.toString(); - this.gas = tx.gasLimit.toString(); - this.gasPrice = tx.gasPrice.toString(); - this.input = tx.payload; - this.gasUsed = tx.gasLimit.toString(); - this.chainId = chainId; - this.isConstructor = tx.isConstructor(); - this.maxFeePerGas = tx.maxFeePerGas.toString(); - this.maxPriorityFee = tx.maxPriorityFeePerGas.toString(); - } - - public Transaction(CovalentTransaction cTx, long chainId, long transactionTime) - { - if (cTx.to_address == null || cTx.to_address.equals("null")) - { - isConstructor = true; - input = CONSTRUCTOR; - //determine creation address from events - to = cTx.determineContractAddress(); - } - else - { - to = cTx.to_address; - input = "0x"; - } - - this.hash = cTx.tx_hash; - this.blockNumber = cTx.block_height; - this.timeStamp = transactionTime; - this.error = cTx.successful ? "0" : "1"; - this.nonce = 0; //don't know this - this.from = cTx.from_address; - this.value = cTx.value; - this.gas = String.valueOf(cTx.gas_offered); - this.gasPrice = cTx.gas_price; - this.gasUsed = cTx.gas_spent; - this.chainId = chainId; - this.maxFeePerGas = ""; - this.maxPriorityFee = ""; - } - - public Transaction(org.web3j.protocol.core.methods.response.Transaction ethTx, long chainId, boolean isSuccess, long timeStamp) - { - // Get contract address if constructor - String contractAddress = ethTx.getCreates() != null ? ethTx.getCreates() : ""; - int nonce = ethTx.getNonceRaw() != null ? Numeric.toBigInt(ethTx.getNonceRaw()).intValue() : 0; - - if (!TextUtils.isEmpty(contractAddress)) //must be a constructor - { - to = contractAddress; - isConstructor = true; - input = CONSTRUCTOR; - } - else if (ethTx.getTo() == null && ethTx.getInput() != null && ethTx.getInput().startsWith("0x60")) - { - // some clients don't populate the 'creates' data for constructors. Note: Ethereum constructor always starts with a 'PUSH' 0x60 instruction - input = CONSTRUCTOR; - isConstructor = true; - to = calculateContractAddress(ethTx.getFrom(), nonce); - } - else - { - this.to = ethTx.getTo() != null ? ethTx.getTo() : ""; - this.input = ethTx.getInput(); - } - - this.hash = ethTx.getHash(); - this.blockNumber = ethTx.getBlockNumber().toString(); - this.timeStamp = timeStamp; - this.error = isSuccess ? "0" : "1"; - this.nonce = nonce; - this.from = ethTx.getFrom(); - this.value = ethTx.getValue().toString(); - this.gas = ethTx.getGas().toString(); - this.gasPrice = ethTx.getGasPrice().toString(); - this.gasUsed = ethTx.getGas().toString(); - this.chainId = chainId; - this.maxFeePerGas = ethTx.getMaxFeePerGas(); - this.maxPriorityFee = ethTx.getMaxPriorityFeePerGas(); - } - - public Transaction(String hash, String isError, String blockNumber, long timeStamp, int nonce, String from, String to, - String value, String gas, String gasPrice, String input, String gasUsed, long chainId, String contractAddress) - { - //Is it a constructor? - if (!TextUtils.isEmpty(contractAddress)) - { - String testContractDeploymentAddress = Utils.calculateContractAddress(from, nonce); - if (testContractDeploymentAddress.equalsIgnoreCase(contractAddress)) - { - to = contractAddress; - isConstructor = true; - input = CONSTRUCTOR; - } - } - - this.to = to; - this.hash = hash; - this.error = isError; - this.blockNumber = blockNumber; - this.timeStamp = timeStamp; - this.nonce = nonce; - this.from = from; - this.value = value; - this.gas = gas; - this.gasPrice = gasPrice; - this.input = input; - this.gasUsed = gasUsed; - this.chainId = chainId; - this.maxFeePerGas = ""; - this.maxPriorityFee = ""; - } - - public Transaction(String hash, String isError, String blockNumber, long timeStamp, int nonce, String from, String to, - String value, String gas, String gasPrice, String maxFeePerGas, String maxPriorityFee, String input, String gasUsed, long chainId, String contractAddress) - { - if (!TextUtils.isEmpty(contractAddress)) - { - String testContractDeploymentAddress = Utils.calculateContractAddress(from, nonce); - if (testContractDeploymentAddress.equalsIgnoreCase(contractAddress)) - { - to = contractAddress; - isConstructor = true; - input = CONSTRUCTOR; - } - } - - this.to = to; - this.hash = hash; - this.error = isError; - this.blockNumber = blockNumber; - this.timeStamp = timeStamp; - this.nonce = nonce; - this.from = from; - this.value = value; - this.gas = gas; - this.maxFeePerGas = maxFeePerGas; - this.maxPriorityFee = maxPriorityFee; - this.gasPrice = gasPrice; - this.input = input; - this.gasUsed = gasUsed; - this.chainId = chainId; - } - - protected Transaction(Parcel in) - { - hash = in.readString(); - error = in.readString(); - blockNumber = in.readString(); - timeStamp = in.readLong(); - nonce = in.readInt(); - from = in.readString(); - to = in.readString(); - value = in.readString(); - gas = in.readString(); - gasPrice = in.readString(); - input = in.readString(); - gasUsed = in.readString(); - chainId = in.readLong(); - maxFeePerGas = in.readString(); - maxPriorityFee = in.readString(); - } - - public static final Creator CREATOR = new Creator() { - @Override - public Transaction createFromParcel(Parcel in) { - return new Transaction(in); - } - - @Override - public Transaction[] newArray(int size) { - return new Transaction[size]; - } - }; - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { + this.nonce = nonce; + this.from = from; + this.to = to; + this.value = value; + this.gas = gas; + this.gasPrice = gasPrice; + this.input = input; + this.gasUsed = gasUsed; + this.chainId = chainId; + this.isConstructor = isConstructor; + this.maxFeePerGas = ""; + this.maxPriorityFee = ""; + } + + public Transaction(Web3Transaction tx, long chainId, String wallet) + { + this.hash = null; + this.error = null; + this.blockNumber = null; + this.timeStamp = System.currentTimeMillis() / 1000; + this.nonce = -1; + this.from = wallet; + this.to = tx.recipient.toString(); + this.value = tx.value.toString(); + this.gas = tx.gasLimit.toString(); + this.gasPrice = tx.gasPrice.toString(); + this.input = tx.payload; + this.gasUsed = tx.gasLimit.toString(); + this.chainId = chainId; + this.isConstructor = tx.isConstructor(); + this.maxFeePerGas = tx.maxFeePerGas.toString(); + this.maxPriorityFee = tx.maxPriorityFeePerGas.toString(); + } + + public Transaction(CovalentTransaction cTx, long chainId, long transactionTime) + { + if (cTx.to_address == null || cTx.to_address.equals("null")) + { + isConstructor = true; + input = CONSTRUCTOR; + //determine creation address from events + to = cTx.determineContractAddress(); + } + else + { + to = cTx.to_address; + input = "0x"; + } + + this.hash = cTx.tx_hash; + this.blockNumber = cTx.block_height; + this.timeStamp = transactionTime; + this.error = cTx.successful ? "0" : "1"; + this.nonce = 0; //don't know this + this.from = cTx.from_address; + this.value = cTx.value; + this.gas = String.valueOf(cTx.gas_offered); + this.gasPrice = cTx.gas_price; + this.gasUsed = cTx.gas_spent; + this.chainId = chainId; + this.maxFeePerGas = ""; + this.maxPriorityFee = ""; + } + + public Transaction(org.web3j.protocol.core.methods.response.Transaction ethTx, long chainId, boolean isSuccess, long timeStamp) + { + // Get contract address if constructor + String contractAddress = ethTx.getCreates() != null ? ethTx.getCreates() : ""; + int nonce = ethTx.getNonceRaw() != null ? Numeric.toBigInt(ethTx.getNonceRaw()).intValue() : 0; + + if (!TextUtils.isEmpty(contractAddress)) //must be a constructor + { + to = contractAddress; + isConstructor = true; + input = CONSTRUCTOR; + } + else if (ethTx.getTo() == null && ethTx.getInput() != null && ethTx.getInput().startsWith("0x60")) + { + // some clients don't populate the 'creates' data for constructors. Note: Ethereum constructor always starts with a 'PUSH' 0x60 instruction + input = CONSTRUCTOR; + isConstructor = true; + to = calculateContractAddress(ethTx.getFrom(), nonce); + } + else + { + this.to = ethTx.getTo() != null ? ethTx.getTo() : ""; + this.input = ethTx.getInput(); + } + + this.hash = ethTx.getHash(); + this.blockNumber = ethTx.getBlockNumber().toString(); + this.timeStamp = timeStamp; + this.error = isSuccess ? "0" : "1"; + this.nonce = nonce; + this.from = ethTx.getFrom(); + this.value = ethTx.getValue().toString(); + this.gas = ethTx.getGas().toString(); + this.gasPrice = ethTx.getGasPrice().toString(); + this.gasUsed = ethTx.getGas().toString(); + this.chainId = chainId; + this.maxFeePerGas = ethTx.getMaxFeePerGas(); + this.maxPriorityFee = ethTx.getMaxPriorityFeePerGas(); + } + + public Transaction(String hash, String isError, String blockNumber, long timeStamp, int nonce, String from, String to, + String value, String gas, String gasPrice, String input, String gasUsed, long chainId, String contractAddress) + { + //Is it a constructor? + if (!TextUtils.isEmpty(contractAddress)) + { + String testContractDeploymentAddress = Utils.calculateContractAddress(from, nonce); + if (testContractDeploymentAddress.equalsIgnoreCase(contractAddress)) + { + to = contractAddress; + isConstructor = true; + input = CONSTRUCTOR; + } + } + + this.to = to; + this.hash = hash; + this.error = isError; + this.blockNumber = blockNumber; + this.timeStamp = timeStamp; + this.nonce = nonce; + this.from = from; + this.value = value; + this.gas = gas; + this.gasPrice = gasPrice; + this.input = input; + this.gasUsed = gasUsed; + this.chainId = chainId; + this.maxFeePerGas = ""; + this.maxPriorityFee = ""; + } + + public Transaction(String hash, String isError, String blockNumber, long timeStamp, int nonce, String from, String to, + String value, String gas, String gasPrice, String maxFeePerGas, String maxPriorityFee, String input, String gasUsed, long chainId, String contractAddress) + { + if (!TextUtils.isEmpty(contractAddress)) + { + String testContractDeploymentAddress = Utils.calculateContractAddress(from, nonce); + if (testContractDeploymentAddress.equalsIgnoreCase(contractAddress)) + { + to = contractAddress; + isConstructor = true; + input = CONSTRUCTOR; + } + } + + this.to = to; + this.hash = hash; + this.error = isError; + this.blockNumber = blockNumber; + this.timeStamp = timeStamp; + this.nonce = nonce; + this.from = from; + this.value = value; + this.gas = gas; + this.maxFeePerGas = maxFeePerGas; + this.maxPriorityFee = maxPriorityFee; + this.gasPrice = gasPrice; + this.input = input; + this.gasUsed = gasUsed; + this.chainId = chainId; + } + + protected Transaction(Parcel in) + { + hash = in.readString(); + error = in.readString(); + blockNumber = in.readString(); + timeStamp = in.readLong(); + nonce = in.readInt(); + from = in.readString(); + to = in.readString(); + value = in.readString(); + gas = in.readString(); + gasPrice = in.readString(); + input = in.readString(); + gasUsed = in.readString(); + chainId = in.readLong(); + maxFeePerGas = in.readString(); + maxPriorityFee = in.readString(); + } + + public static final Creator CREATOR = new Creator() + { + @Override + public Transaction createFromParcel(Parcel in) + { + return new Transaction(in); + } + + @Override + public Transaction[] newArray(int size) + { + return new Transaction[size]; + } + }; + + @Override + public int describeContents() + { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) + { dest.writeString(hash); dest.writeString(error); dest.writeString(blockNumber); dest.writeLong(timeStamp); - dest.writeInt(nonce); - dest.writeString(from); - dest.writeString(to); - dest.writeString(value); - dest.writeString(gas); - dest.writeString(gasPrice); - dest.writeString(input); - dest.writeString(gasUsed); - dest.writeLong(chainId); - dest.writeString(maxFeePerGas); - dest.writeString(maxPriorityFee); - } - - public boolean isRelated(String contractAddress, String walletAddress) - { - if (contractAddress.equals("eth")) - { - return (input.equals("0x") || from.equalsIgnoreCase(walletAddress)); - } - else if (walletAddress.equalsIgnoreCase(contractAddress)) //transactions sent from or sent to the main currency account - { - return from.equalsIgnoreCase(walletAddress) || to.equalsIgnoreCase(walletAddress); - } - else if (to.equalsIgnoreCase(contractAddress)) - { - return true; - } - else - { - return getWalletInvolvedInTransaction(walletAddress); - } - } - - /** - * Fetch result of transaction operation. - * This is very much a WIP - * @param token - * @return - */ - public String getOperationResult(Token token, int precision) - { - //get amount here. will be amount + symbol if appropriate - if (hasInput()) - { - decodeTransactionInput(token.getWallet()); - String value = transactionInput.getOperationValue(token, this); - boolean isSendOrReceive = !from.equalsIgnoreCase(to) && transactionInput.isSendOrReceive(this); - String prefix = (value.length() == 0 || (value.startsWith("#") || !isSendOrReceive)) ? "" : - (token.getIsSent(this) ? "- " : "+ "); - return prefix + value; - } - else - { - return token.getTransactionValue(this, precision); - } - } - - /** - * Can the contract call be valid if the operation token is Ethereum? - * @param token - * @return - */ - public boolean shouldShowSymbol(Token token) - { - if (hasInput()) - { - decodeTransactionInput(token.getWallet()); - return transactionInput.shouldShowSymbol(token); - } - else - { - return true; - } - } - - public String getOperationTokenAddress() - { - if (hasInput()) - { - return to; - } - else - { - return ""; - } - } - - public boolean isLegacyTransaction() - { - try - { - return !TextUtils.isEmpty(gasPrice) && new BigInteger(gasPrice).compareTo(BigInteger.ZERO) > 0; - } - catch (Exception e) - { - return true; - } - } - - public String getOperationName(Context ctx, Token token, String walletAddress) - { - String txName = null; - if (isPending()) - { - txName = ctx.getString(R.string.status_pending); - } - else if (hasInput()) - { - decodeTransactionInput(walletAddress); - if (token.isEthereum() && shouldShowSymbol(token)) - { - transactionInput.type = TransactionType.CONTRACT_CALL; - } - - return transactionInput.getOperationTitle(ctx); - } - - return txName; - } - - public boolean hasInput() - { - return input != null && input.length() >= 10; - } - - public int getOperationToFrom(String walletAddress) - { - if (hasInput()) - { - decodeTransactionInput(walletAddress); - return transactionInput.getOperationToFrom(); - } - else - { - return 0; - } - } - - public StatusType getOperationImage(Token token) - { - if (hasError()) - { - return StatusType.FAILED; - } - else if (hasInput()) - { - decodeTransactionInput(token.getWallet()); - return transactionInput.getOperationImage(this, token.getWallet()); - } - else - { - return from.equalsIgnoreCase(token.getWallet()) ? StatusType.SENT : StatusType.RECEIVE; - } - } - - 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 - * for the 'breeding fee'. That fee is later released to the caller of the 'birth' function. - * Supplemental info for these transaction would appear as -0.031 for the 'breedWithAuto' and +0.031 on the 'birth' call - * However it's not that simple - the 'breeding fee' will be in the value attached to the transaction, however the 'midwife' reward appears - * as an internal transaction, so won't be in the 'value' property. - * - * @return - */ - public String getSupplementalInfo(String walletAddress, String networkName) - { - if (hasInput()) - { - decodeTransactionInput(walletAddress); - return transactionInput.getSupplimentalInfo(this, walletAddress, networkName); - } - else - { - return ""; - } - } - - public String getPrefix(Token token) - { - if (hasInput()) - { - decodeTransactionInput(token.getWallet()); - if (!transactionInput.isSendOrReceive(this) || token.isEthereum()) - { - return ""; - } - else if (token.isERC721()) - { - return ""; - } - } - - boolean isSent = token.getIsSent(this); - boolean isSelf = from.equalsIgnoreCase(to); - if (isSelf) return ""; - else if (isSent) return "- "; - else return "+ "; - } + dest.writeInt(nonce); + dest.writeString(from); + dest.writeString(to); + dest.writeString(value); + dest.writeString(gas); + dest.writeString(gasPrice); + dest.writeString(input); + dest.writeString(gasUsed); + dest.writeLong(chainId); + dest.writeString(maxFeePerGas); + dest.writeString(maxPriorityFee); + } + + public boolean isRelated(String contractAddress, String walletAddress) + { + if (contractAddress.equals("eth")) + { + return (input.equals("0x") || from.equalsIgnoreCase(walletAddress)); + } + else if (walletAddress.equalsIgnoreCase(contractAddress)) //transactions sent from or sent to the main currency account + { + return from.equalsIgnoreCase(walletAddress) || to.equalsIgnoreCase(walletAddress); + } + else if (to.equalsIgnoreCase(contractAddress)) + { + return true; + } + else + { + return getWalletInvolvedInTransaction(walletAddress); + } + } + + /** + * Fetch result of transaction operation. + * This is very much a WIP + * + * @param token + * @return + */ + public String getOperationResult(Token token, int precision) + { + //get amount here. will be amount + symbol if appropriate + if (hasInput()) + { + decodeTransactionInput(token.getWallet()); + String value = transactionInput.getOperationValue(token, this); + boolean isSendOrReceive = !from.equalsIgnoreCase(to) && transactionInput.isSendOrReceive(this); + String prefix = (value.length() == 0 || (value.startsWith("#") || !isSendOrReceive)) ? "" : + (token.getIsSent(this) ? "- " : "+ "); + return prefix + value; + } + else + { + return token.getTransactionValue(this, precision); + } + } + + /** + * Can the contract call be valid if the operation token is Ethereum? + * + * @param token + * @return + */ + public boolean shouldShowSymbol(Token token) + { + if (hasInput()) + { + decodeTransactionInput(token.getWallet()); + return transactionInput.shouldShowSymbol(token); + } + else + { + return true; + } + } + + public String getOperationTokenAddress() + { + if (hasInput()) + { + return to; + } + else + { + return ""; + } + } + + public boolean isLegacyTransaction() + { + try + { + return !TextUtils.isEmpty(gasPrice) && new BigInteger(gasPrice).compareTo(BigInteger.ZERO) > 0; + } + catch (Exception e) + { + return true; + } + } + + public String getOperationName(Context ctx, Token token, String walletAddress) + { + String txName = null; + if (isPending()) + { + txName = ctx.getString(R.string.status_pending); + } + else if (hasInput()) + { + decodeTransactionInput(walletAddress); + if (token.isEthereum() && shouldShowSymbol(token)) + { + transactionInput.type = TransactionType.CONTRACT_CALL; + } + + return transactionInput.getOperationTitle(ctx); + } + + return txName; + } + + public boolean hasInput() + { + return input != null && input.length() >= 10; + } + + public int getOperationToFrom(String walletAddress) + { + if (hasInput()) + { + decodeTransactionInput(walletAddress); + return transactionInput.getOperationToFrom(); + } + else + { + return 0; + } + } + + public StatusType getOperationImage(Token token) + { + if (hasError()) + { + return StatusType.FAILED; + } + else if (hasInput()) + { + decodeTransactionInput(token.getWallet()); + return transactionInput.getOperationImage(this, token.getWallet()); + } + else + { + return from.equalsIgnoreCase(token.getWallet()) ? StatusType.SENT : StatusType.RECEIVE; + } + } + + 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 + * for the 'breeding fee'. That fee is later released to the caller of the 'birth' function. + * Supplemental info for these transaction would appear as -0.031 for the 'breedWithAuto' and +0.031 on the 'birth' call + * However it's not that simple - the 'breeding fee' will be in the value attached to the transaction, however the 'midwife' reward appears + * as an internal transaction, so won't be in the 'value' property. + * + * @return + */ + public String getSupplementalInfo(String walletAddress, String networkName) + { + if (hasInput()) + { + decodeTransactionInput(walletAddress); + return transactionInput.getSupplimentalInfo(this, walletAddress, networkName); + } + else + { + return ""; + } + } + + public String getPrefix(Token token) + { + if (hasInput()) + { + decodeTransactionInput(token.getWallet()); + if (!transactionInput.isSendOrReceive(this) || token.isEthereum()) + { + return ""; + } + else if (token.isERC721()) + { + return ""; + } + } + + boolean isSent = token.getIsSent(this); + boolean isSelf = from.equalsIgnoreCase(to); + if (isSelf) return ""; + else if (isSent) return "- "; + else return "+ "; + } public BigDecimal getRawValue(String walletAddress) throws Exception { - if (hasInput()) - { - decodeTransactionInput(walletAddress); - return transactionInput.getRawValue(); - } - else - { - return new BigDecimal(value); - } - } - - public StatusType getTransactionStatus() - { - if (hasError()) - { - return StatusType.FAILED; - } - else if (blockNumber.equals("-1")) - { - return StatusType.REJECTED; - } - else if (isPending()) - { - return StatusType.PENDING; - } - else - { - return null; - } - } + if (hasInput()) + { + decodeTransactionInput(walletAddress); + return transactionInput.getRawValue(); + } + else + { + return new BigDecimal(value); + } + } + + public StatusType getTransactionStatus() + { + if (hasError()) + { + return StatusType.FAILED; + } + else if (blockNumber.equals("-1")) + { + return StatusType.REJECTED; + } + else if (isPending()) + { + return StatusType.PENDING; + } + else + { + return null; + } + } public void addTransactionElements(Map resultMap) { - resultMap.put("__hash", new EventResult("", hash)); - resultMap.put("__to", new EventResult("", to)); - resultMap.put("__from", new EventResult("", from)); - resultMap.put("__value", new EventResult("", value)); - resultMap.put("__chainId", new EventResult("", String.valueOf(chainId))); - } - - public String getEventName(String walletAddress) - { - String eventName = ""; - if (hasInput()) - { - decodeTransactionInput(walletAddress); - eventName = transactionInput.getOperationEvent(walletAddress); - } - - return eventName; - } - - public int getSupplementalColour(String supplementalTxt) - { - if (!TextUtils.isEmpty(supplementalTxt)) - { - switch (supplementalTxt.charAt(1)) - { - case '-': - return R.color.negative; - case '+': - return R.color.positive; - default: - break; - } - } - - return R.color.text_primary; - } - - public String getDestination(Token token) - { - if (hasInput()) - { - decodeTransactionInput(token.getWallet()); - return transactionInput.getOperationAddress(this, token); - } - else - { - return token.getAddress(); - } - } - - public String getOperationDetail(Context ctx, Token token, TokensService tService) - { - if (hasInput()) - { - decodeTransactionInput(token.getWallet()); - return transactionInput.getOperationDescription (ctx, this, token, tService); - } - else - { - return ctx.getString(R.string.operation_definition, ctx.getString(R.string.to), ENSHandler.matchENSOrFormat(ctx, to)); - } - } - - private void decodeTransactionInput(String walletAddress) - { - if (transactionInput == null && hasInput() && Utils.isAddressValid(walletAddress)) - { - transactionInput = decoder.decodeInput(this, walletAddress); - } - } - - public boolean getWalletInvolvedInTransaction(String walletAddr) - { - decodeTransactionInput(walletAddr); - if ((transactionInput != null && transactionInput.functionData != null) && transactionInput.containsAddress(walletAddr)) return true; - else if (from.equalsIgnoreCase(walletAddr)) return true; - else if (to.equalsIgnoreCase(walletAddr)) return true; - else return input != null && input.length() > 40 && input.contains(Numeric.cleanHexPrefix(walletAddr.toLowerCase())); - } - - public boolean isNFTSent(String walletAddress) - { - if (hasInput()) - { - decodeTransactionInput(walletAddress); - return transactionInput.isSent(); - } - else - { - return true; - } - } - - public boolean getIsSent(String walletAddress) - { - if (hasInput()) - { - decodeTransactionInput(walletAddress); - return transactionInput.isSent(); - } - else - { - return from.equalsIgnoreCase(walletAddress); - } - } - - public boolean isValueChange(String walletAddress) - { - if (hasInput()) - { - decodeTransactionInput(walletAddress); - return transactionInput.isSendOrReceive(this); - } - else - { - return true; - } - } - - private String calculateContractAddress(String account, long nonce){ - byte[] addressAsBytes = Numeric.hexStringToByteArray(account); - byte[] calculatedAddressAsBytes = - Hash.sha3(RlpEncoder.encode( - new RlpList( - RlpString.create(addressAsBytes), - RlpString.create((nonce))))); - - calculatedAddressAsBytes = Arrays.copyOfRange(calculatedAddressAsBytes, - 12, calculatedAddressAsBytes.length); - return Numeric.toHexString(calculatedAddressAsBytes); - } + resultMap.put("__hash", new EventResult("", hash)); + resultMap.put("__to", new EventResult("", to)); + resultMap.put("__from", new EventResult("", from)); + resultMap.put("__value", new EventResult("", value)); + resultMap.put("__chainId", new EventResult("", String.valueOf(chainId))); + } + + public String getEventName(String walletAddress) + { + String eventName = ""; + if (hasInput()) + { + decodeTransactionInput(walletAddress); + eventName = transactionInput.getOperationEvent(walletAddress); + } + + return eventName; + } + + public int getSupplementalColour(String supplementalTxt) + { + if (!TextUtils.isEmpty(supplementalTxt)) + { + switch (supplementalTxt.charAt(1)) + { + case '-': + return R.color.negative; + case '+': + return R.color.positive; + default: + break; + } + } + + return R.color.text_primary; + } + + public String getDestination(Token token) + { + if (token == null) return ""; + if (hasInput()) + { + decodeTransactionInput(token.getWallet()); + return transactionInput.getOperationAddress(this, token); + } + else + { + return token.getAddress(); + } + } + + public String getOperationDetail(Context ctx, Token token, TokensService tService) + { + if (hasInput()) + { + decodeTransactionInput(token.getWallet()); + return transactionInput.getOperationDescription(ctx, this, token, tService); + } + else + { + return ctx.getString(R.string.operation_definition, ctx.getString(R.string.to), ENSHandler.matchENSOrFormat(ctx, to)); + } + } + + private void decodeTransactionInput(String walletAddress) + { + if (transactionInput == null && hasInput() && Utils.isAddressValid(walletAddress)) + { + transactionInput = decoder.decodeInput(this, walletAddress); + } + } + + public boolean getWalletInvolvedInTransaction(String walletAddr) + { + decodeTransactionInput(walletAddr); + if ((transactionInput != null && transactionInput.functionData != null) && transactionInput.containsAddress(walletAddr)) + return true; + else if (from.equalsIgnoreCase(walletAddr)) return true; + else if (to.equalsIgnoreCase(walletAddr)) return true; + else + return input != null && input.length() > 40 && input.contains(Numeric.cleanHexPrefix(walletAddr.toLowerCase())); + } + + public boolean isNFTSent(String walletAddress) + { + if (hasInput()) + { + decodeTransactionInput(walletAddress); + return transactionInput.isSent(); + } + else + { + return true; + } + } + + public boolean getIsSent(String walletAddress) + { + if (hasInput()) + { + decodeTransactionInput(walletAddress); + return transactionInput.isSent(); + } + else + { + return from.equalsIgnoreCase(walletAddress); + } + } + + public boolean isValueChange(String walletAddress) + { + if (hasInput()) + { + decodeTransactionInput(walletAddress); + return transactionInput.isSendOrReceive(this); + } + else + { + return true; + } + } + + private String calculateContractAddress(String account, long nonce) + { + byte[] addressAsBytes = Numeric.hexStringToByteArray(account); + byte[] calculatedAddressAsBytes = + Hash.sha3(RlpEncoder.encode( + new RlpList( + RlpString.create(addressAsBytes), + RlpString.create((nonce))))); + + calculatedAddressAsBytes = Arrays.copyOfRange(calculatedAddressAsBytes, + 12, calculatedAddressAsBytes.length); + return Numeric.toHexString(calculatedAddressAsBytes); + } } diff --git a/app/src/main/java/com/alphawallet/app/entity/lifi/Action.java b/app/src/main/java/com/alphawallet/app/entity/lifi/Action.java new file mode 100644 index 0000000000..110be10c1a --- /dev/null +++ b/app/src/main/java/com/alphawallet/app/entity/lifi/Action.java @@ -0,0 +1,50 @@ +package com.alphawallet.app.entity.lifi; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +public class Action +{ + @SerializedName("fromChainId") + @Expose + public long fromChainId; + + @SerializedName("toChainId") + @Expose + public long toChainId; + + @SerializedName("fromToken") + @Expose + public Token fromToken; + + @SerializedName("toToken") + @Expose + public Token toToken; + + @SerializedName("fromAmount") + @Expose + public String fromAmount; + + @SerializedName("slippage") + @Expose + public double slippage; + + @SerializedName("fromAddress") + @Expose + public String fromAddress; + + @SerializedName("toAddress") + @Expose + public String toAddress; + + public String getCurrentPrice() + { + return new BigDecimal(fromToken.priceUSD) + .divide(new BigDecimal(toToken.priceUSD), 4, RoundingMode.DOWN) + .stripTrailingZeros() + .toPlainString(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/alphawallet/app/entity/lifi/Connection.java b/app/src/main/java/com/alphawallet/app/entity/lifi/Connection.java index 9d5166d1b6..01fe4a324c 100644 --- a/app/src/main/java/com/alphawallet/app/entity/lifi/Connection.java +++ b/app/src/main/java/com/alphawallet/app/entity/lifi/Connection.java @@ -4,7 +4,6 @@ import com.google.gson.annotations.SerializedName; import java.util.List; -import java.util.Objects; public class Connection { @@ -18,83 +17,9 @@ public class Connection @SerializedName("fromTokens") @Expose - public List fromTokens; + public List fromTokens; @SerializedName("toTokens") @Expose - public List toTokens; - - public static class LToken - { - @SerializedName("address") - @Expose - public String address; - - @SerializedName("symbol") - @Expose - public String symbol; - - @SerializedName("decimals") - @Expose - public long decimals; - - @SerializedName("chainId") - @Expose - public long chainId; - - @SerializedName("name") - @Expose - public String name; - - @SerializedName("coinKey") - @Expose - public String coinKey; - - @SerializedName("priceUSD") - @Expose - public String priceUSD; - - @SerializedName("logoURI") - @Expose - public String logoURI; - - public String balance; - public double fiatEquivalent; - - @Override - public boolean equals(Object o) - { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - LToken lToken = (LToken) o; - return address.equals(lToken.address) && symbol.equals(lToken.symbol); - } - - @Override - public int hashCode() - { - return Objects.hash(address, symbol); - } - - // Note: In the LIFI API, the native token has either of these two addresses. - public boolean isNativeToken() - { - return address.equalsIgnoreCase("0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee") || - address.equalsIgnoreCase("0x0000000000000000000000000000000000000000"); - } - - public double getFiatValue() - { - try - { - double value = Double.parseDouble(balance); - double priceUSD = Double.parseDouble(this.priceUSD); - return value * priceUSD; - } - catch (NumberFormatException | NullPointerException e) - { - return 0.0; - } - } - } + public List toTokens; } diff --git a/app/src/main/java/com/alphawallet/app/entity/lifi/Estimate.java b/app/src/main/java/com/alphawallet/app/entity/lifi/Estimate.java new file mode 100644 index 0000000000..ab63b81844 --- /dev/null +++ b/app/src/main/java/com/alphawallet/app/entity/lifi/Estimate.java @@ -0,0 +1,100 @@ +package com.alphawallet.app.entity.lifi; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +import java.util.ArrayList; + +public class Estimate +{ + @SerializedName("fromAmount") + @Expose + public String fromAmount; + + @SerializedName("toAmount") + @Expose + public String toAmount; + + @SerializedName("toAmountMin") + @Expose + public String toAmountMin; + + @SerializedName("approvalAddress") + @Expose + public String approvalAddress; + + @SerializedName("executionDuration") + @Expose + public long executionDuration; + + @SerializedName("feeCosts") + @Expose + public ArrayList feeCosts; + + @SerializedName("gasCosts") + @Expose + public ArrayList gasCosts; + + @SerializedName("data") + @Expose + public Data data; + + @SerializedName("fromAmountUSD") + @Expose + public String fromAmountUSD; + + @SerializedName("toAmountUSD") + @Expose + public String toAmountUSD; + + public static class Data + { + @SerializedName("blockNumber") + @Expose + public long blockNumber; + + @SerializedName("network") + @Expose + public long network; + + @SerializedName("srcToken") + @Expose + public String srcToken; + + @SerializedName("srcDecimals") + @Expose + public long srcDecimals; + + @SerializedName("srcAmount") + @Expose + public String srcAmount; + + @SerializedName("destToken") + @Expose + public String destToken; + + @SerializedName("destDecimals") + @Expose + public long destDecimals; + + @SerializedName("destAmount") + @Expose + public String destAmount; + + @SerializedName("gasCostUSD") + @Expose + public String gasCostUSD; + + @SerializedName("gasCost") + @Expose + public String gasCost; + + @SerializedName("buyAmount") + @Expose + public String buyAmount; + + @SerializedName("sellAmount") + @Expose + public String sellAmount; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/alphawallet/app/entity/lifi/FeeCost.java b/app/src/main/java/com/alphawallet/app/entity/lifi/FeeCost.java new file mode 100644 index 0000000000..bbbd5cd645 --- /dev/null +++ b/app/src/main/java/com/alphawallet/app/entity/lifi/FeeCost.java @@ -0,0 +1,25 @@ +package com.alphawallet.app.entity.lifi; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +import java.util.ArrayList; + +public class FeeCost +{ + @SerializedName("name") + @Expose + public String name; + + @SerializedName("percentage") + @Expose + public String percentage; + + @SerializedName("token") + @Expose + public Token token; + + @SerializedName("amount") + @Expose + public String amount; +} \ No newline at end of file diff --git a/app/src/main/java/com/alphawallet/app/entity/lifi/GasCost.java b/app/src/main/java/com/alphawallet/app/entity/lifi/GasCost.java new file mode 100644 index 0000000000..d2ccd5b39b --- /dev/null +++ b/app/src/main/java/com/alphawallet/app/entity/lifi/GasCost.java @@ -0,0 +1,19 @@ +package com.alphawallet.app.entity.lifi; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class GasCost +{ + @SerializedName("amount") + @Expose + public String amount; + + @SerializedName("amountUSD") + @Expose + public String amountUSD; + + @SerializedName("token") + @Expose + public Token token; +} \ No newline at end of file diff --git a/app/src/main/java/com/alphawallet/app/entity/lifi/Quote.java b/app/src/main/java/com/alphawallet/app/entity/lifi/Quote.java index 2e0d1cf6d2..fc2d80e4f1 100644 --- a/app/src/main/java/com/alphawallet/app/entity/lifi/Quote.java +++ b/app/src/main/java/com/alphawallet/app/entity/lifi/Quote.java @@ -3,9 +3,6 @@ import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; -import java.math.BigDecimal; -import java.util.ArrayList; - public class Quote { @SerializedName("id") @@ -22,186 +19,16 @@ public class Quote @SerializedName("toolDetails") @Expose - public ToolDetails toolDetails; - - public static class ToolDetails - { - @SerializedName("key") - @Expose - public String key; - - @SerializedName("name") - @Expose - public String name; - - @SerializedName("logoURI") - @Expose - public String logoURI; - } + public SwapProvider swapProvider; @SerializedName("action") @Expose public Action action; - public static class Action - { - @SerializedName("fromChainId") - @Expose - public long fromChainId; - - @SerializedName("toChainId") - @Expose - public long toChainId; - - @SerializedName("fromToken") - @Expose - public Connection.LToken fromToken; - - @SerializedName("toToken") - @Expose - public Connection.LToken toToken; - - @SerializedName("fromAmount") - @Expose - public String fromAmount; - - @SerializedName("slippage") - @Expose - public double slippage; - - @SerializedName("fromAddress") - @Expose - public String fromAddress; - - @SerializedName("toAddress") - @Expose - public String toAddress; - } - @SerializedName("estimate") @Expose public Estimate estimate; - public static class Estimate - { - @SerializedName("fromAmount") - @Expose - public String fromAmount; - - @SerializedName("toAmount") - @Expose - public String toAmount; - - @SerializedName("toAmountMin") - @Expose - public String toAmountMin; - - @SerializedName("approvalAddress") - @Expose - public String approvalAddress; - - @SerializedName("executionDuration") - @Expose - public long executionDuration; - -// @SerializedName("feeCosts") -// @Expose -// public JSONArray feeCosts; - - @SerializedName("gasCosts") - @Expose - public ArrayList gasCosts; - - public static class GasCost - { - @SerializedName("amount") - @Expose - public String amount; - - @SerializedName("amountUSD") - @Expose - public String amountUSD; - - @SerializedName("token") - @Expose - public Token token; - - public static class Token - { - @SerializedName("symbol") - @Expose - public String symbol; - - @SerializedName("decimals") - @Expose - public long decimals; - } - } - - @SerializedName("data") - @Expose - public Data data; - - public static class Data - { - @SerializedName("blockNumber") - @Expose - public long blockNumber; - - @SerializedName("network") - @Expose - public long network; - - @SerializedName("srcToken") - @Expose - public String srcToken; - - @SerializedName("srcDecimals") - @Expose - public long srcDecimals; - - @SerializedName("srcAmount") - @Expose - public String srcAmount; - - @SerializedName("destToken") - @Expose - public String destToken; - - @SerializedName("destDecimals") - @Expose - public long destDecimals; - - @SerializedName("destAmount") - @Expose - public String destAmount; - - @SerializedName("gasCostUSD") - @Expose - public String gasCostUSD; - - @SerializedName("gasCost") - @Expose - public String gasCost; - - @SerializedName("buyAmount") - @Expose - public String buyAmount; - - @SerializedName("sellAmount") - @Expose - public String sellAmount; - } - - @SerializedName("fromAmountUSD") - @Expose - public String fromAmountUSD; - - @SerializedName("toAmountUSD") - @Expose - public String toAmountUSD; - } - @SerializedName("transactionRequest") @Expose public TransactionRequest transactionRequest; @@ -236,10 +63,4 @@ public static class TransactionRequest @Expose public String gasPrice; } - - public String getCurrentPrice() - { - return new BigDecimal(action.fromToken.priceUSD) - .multiply(new BigDecimal(action.toToken.priceUSD)).toString(); - } } diff --git a/app/src/main/java/com/alphawallet/app/entity/lifi/Route.java b/app/src/main/java/com/alphawallet/app/entity/lifi/Route.java new file mode 100644 index 0000000000..97719ea00c --- /dev/null +++ b/app/src/main/java/com/alphawallet/app/entity/lifi/Route.java @@ -0,0 +1,36 @@ +package com.alphawallet.app.entity.lifi; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +import java.util.List; + +public class Route +{ + @SerializedName("gasCostUSD") + @Expose + public String gasCostUSD; + + @SerializedName("steps") + @Expose + public List steps; + + @SerializedName("tags") + @Expose + public List tags; + + public static class Step + { + @SerializedName("toolDetails") + @Expose + public SwapProvider swapProvider; + + @SerializedName("action") + @Expose + public Action action; + + @SerializedName("estimate") + @Expose + public Estimate estimate; + } +} diff --git a/app/src/main/java/com/alphawallet/app/entity/lifi/RouteError.java b/app/src/main/java/com/alphawallet/app/entity/lifi/RouteError.java new file mode 100644 index 0000000000..aa6135d733 --- /dev/null +++ b/app/src/main/java/com/alphawallet/app/entity/lifi/RouteError.java @@ -0,0 +1,23 @@ +package com.alphawallet.app.entity.lifi; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class RouteError +{ + @SerializedName("tool") + @Expose + public String tool; + + @SerializedName("message") + @Expose + public String message; + + @SerializedName("errorType") + @Expose + public String errorType; + + @SerializedName("code") + @Expose + public String code; +} diff --git a/app/src/main/java/com/alphawallet/app/entity/lifi/RouteOptions.java b/app/src/main/java/com/alphawallet/app/entity/lifi/RouteOptions.java new file mode 100644 index 0000000000..99882f661a --- /dev/null +++ b/app/src/main/java/com/alphawallet/app/entity/lifi/RouteOptions.java @@ -0,0 +1,33 @@ +package com.alphawallet.app.entity.lifi; + +import com.google.gson.Gson; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +public class RouteOptions +{ + public String integrator; + public String slippage; + public Exchanges exchanges; + public String order; + + public RouteOptions() + { + this.exchanges = new Exchanges(); + } + + public static class Exchanges + { + public List allow = new ArrayList<>(); + } + + public JSONObject getJson() throws JSONException + { + String json = new Gson().toJson(this); + return new JSONObject(json); + } +} diff --git a/app/src/main/java/com/alphawallet/app/entity/lifi/SwapProvider.java b/app/src/main/java/com/alphawallet/app/entity/lifi/SwapProvider.java new file mode 100644 index 0000000000..6b01e6a292 --- /dev/null +++ b/app/src/main/java/com/alphawallet/app/entity/lifi/SwapProvider.java @@ -0,0 +1,25 @@ +package com.alphawallet.app.entity.lifi; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class SwapProvider +{ + @SerializedName("key") + @Expose + public String key; + + @SerializedName("name") + @Expose + public String name; + + @SerializedName("logoURI") + @Expose + public String logoURI; + + @SerializedName("url") + @Expose + public String url; + + public boolean isChecked; +} \ No newline at end of file diff --git a/app/src/main/java/com/alphawallet/app/entity/lifi/Token.java b/app/src/main/java/com/alphawallet/app/entity/lifi/Token.java new file mode 100644 index 0000000000..83ec1225a6 --- /dev/null +++ b/app/src/main/java/com/alphawallet/app/entity/lifi/Token.java @@ -0,0 +1,91 @@ +package com.alphawallet.app.entity.lifi; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +import java.util.Objects; + +public class Token +{ + @SerializedName("address") + @Expose + public String address; + + @SerializedName("symbol") + @Expose + public String symbol; + + @SerializedName("decimals") + @Expose + public long decimals; + + @SerializedName("chainId") + @Expose + public long chainId; + + @SerializedName("name") + @Expose + public String name; + + @SerializedName("coinKey") + @Expose + public String coinKey; + + @SerializedName("priceUSD") + @Expose + public String priceUSD; + + @SerializedName("logoURI") + @Expose + public String logoURI; + + public String balance; + public double fiatEquivalent; + + @Override + public boolean equals(Object o) + { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Token lToken = (Token) o; + return address.equals(lToken.address) && symbol.equals(lToken.symbol); + } + + @Override + public int hashCode() + { + return Objects.hash(address, symbol); + } + + // Note: In the LIFI API, the native token has either of these two addresses. + public boolean isNativeToken() + { + return address.equalsIgnoreCase("0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee") || + address.equalsIgnoreCase("0x0000000000000000000000000000000000000000"); + } + + public double getFiatValue() + { + try + { + double value = Double.parseDouble(balance); + double priceUSD = Double.parseDouble(this.priceUSD); + return value * priceUSD; + } + catch (NumberFormatException | NullPointerException e) + { + return 0.0; + } + } + + public boolean isSimilarTo(com.alphawallet.app.entity.tokens.Token aToken, String walletAddress) + { + if (this.chainId == aToken.tokenInfo.chainId + && this.address.equalsIgnoreCase(aToken.getAddress())) + { + return true; + } + + return aToken.getAddress().equalsIgnoreCase(walletAddress) && isNativeToken(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/alphawallet/app/entity/opensea/OpenSeaAsset.java b/app/src/main/java/com/alphawallet/app/entity/opensea/OpenSeaAsset.java index 954e2fdb27..635de75260 100644 --- a/app/src/main/java/com/alphawallet/app/entity/opensea/OpenSeaAsset.java +++ b/app/src/main/java/com/alphawallet/app/entity/opensea/OpenSeaAsset.java @@ -88,6 +88,10 @@ public class OpenSeaAsset @Expose public LastSale lastSale; + @SerializedName("rarity_data") + @Expose + public Rarity rarity; + public static class Collection { @SerializedName("stats") diff --git a/app/src/main/java/com/alphawallet/app/entity/opensea/Rarity.java b/app/src/main/java/com/alphawallet/app/entity/opensea/Rarity.java new file mode 100644 index 0000000000..5160fcaec5 --- /dev/null +++ b/app/src/main/java/com/alphawallet/app/entity/opensea/Rarity.java @@ -0,0 +1,31 @@ +package com.alphawallet.app.entity.opensea; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class Rarity +{ + @SerializedName("strategy_id") + @Expose + public String strategyId; + + @SerializedName("strategy_version") + @Expose + public String strategyVersion; + + @SerializedName("rank") + @Expose + public long rank; + + @SerializedName("score") + @Expose + public double score; + + @SerializedName("max_rank") + @Expose + public long maxRank; + + @SerializedName("tokens_scored") + @Expose + public long tokensScored; +} diff --git a/app/src/main/java/com/alphawallet/app/entity/tokenscript/TokenScriptFile.java b/app/src/main/java/com/alphawallet/app/entity/tokenscript/TokenScriptFile.java index 0dac3b5df9..a7a9689839 100644 --- a/app/src/main/java/com/alphawallet/app/entity/tokenscript/TokenScriptFile.java +++ b/app/src/main/java/com/alphawallet/app/entity/tokenscript/TokenScriptFile.java @@ -125,6 +125,10 @@ public String calcMD5() String rand = String.valueOf(new Random(System.currentTimeMillis()).nextInt()); sb.append(rand); //never matches } + catch (Exception e) + { + Timber.w(e); + } //return complete hash return sb.toString(); diff --git a/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java b/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java index 6219475e05..2c386047bc 100644 --- a/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java +++ b/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java @@ -3,12 +3,16 @@ /* Please don't add import android at this point. Later this file will be shared * between projects including non-Android projects */ +import static com.alphawallet.ethereum.EthereumNetworkBase.ARBITRUM_GOERLI_TESTNET_FALLBACK_RPC_URL; +import static com.alphawallet.ethereum.EthereumNetworkBase.ARBITRUM_GOERLI_TEST_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.ARBITRUM_MAIN_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.ARBITRUM_TEST_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.ARTIS_SIGMA1_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.ARTIS_TAU1_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.AURORA_MAINNET_ID; +import static com.alphawallet.ethereum.EthereumNetworkBase.AURORA_MAINNET_RPC_URL; import static com.alphawallet.ethereum.EthereumNetworkBase.AURORA_TESTNET_ID; +import static com.alphawallet.ethereum.EthereumNetworkBase.AURORA_TESTNET_RPC_URL; import static com.alphawallet.ethereum.EthereumNetworkBase.AVALANCHE_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.AVALANCHE_RPC_URL; import static com.alphawallet.ethereum.EthereumNetworkBase.BINANCE_MAIN_ID; @@ -24,16 +28,25 @@ import static com.alphawallet.ethereum.EthereumNetworkBase.FUJI_TEST_RPC_URL; import static com.alphawallet.ethereum.EthereumNetworkBase.GOERLI_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.HECO_ID; +import static com.alphawallet.ethereum.EthereumNetworkBase.HECO_RPC_URL; import static com.alphawallet.ethereum.EthereumNetworkBase.HECO_TEST_ID; +import static com.alphawallet.ethereum.EthereumNetworkBase.HECO_TEST_RPC_URL; import static com.alphawallet.ethereum.EthereumNetworkBase.IOTEX_MAINNET_ID; +import static com.alphawallet.ethereum.EthereumNetworkBase.IOTEX_MAINNET_RPC_URL; import static com.alphawallet.ethereum.EthereumNetworkBase.IOTEX_TESTNET_ID; +import static com.alphawallet.ethereum.EthereumNetworkBase.IOTEX_TESTNET_RPC_URL; import static com.alphawallet.ethereum.EthereumNetworkBase.KLAYTN_BAOBAB_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.KLAYTN_BAOBAB_RPC; import static com.alphawallet.ethereum.EthereumNetworkBase.KLAYTN_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.KLAYTN_RPC; import static com.alphawallet.ethereum.EthereumNetworkBase.KOVAN_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.MAINNET_ID; +import static com.alphawallet.ethereum.EthereumNetworkBase.OPTIMISM_GOERLI_TESTNET_FALLBACK_RPC_URL; +import static com.alphawallet.ethereum.EthereumNetworkBase.OPTIMISM_GOERLI_TEST_ID; +import static com.alphawallet.ethereum.EthereumNetworkBase.OPTIMISTIC_MAIN_FALLBACK_URL; +import static com.alphawallet.ethereum.EthereumNetworkBase.OPTIMISTIC_TEST_FALLBACK_URL; import static com.alphawallet.ethereum.EthereumNetworkBase.PHI_MAIN_ID; +import static com.alphawallet.ethereum.EthereumNetworkBase.PHI_MAIN_RPC_URL; import static com.alphawallet.ethereum.EthereumNetworkBase.PHI_NETWORK_V2_RPC; import static com.alphawallet.ethereum.EthereumNetworkBase.PHI_V2_MAIN_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.POLYGON_ID; @@ -49,8 +62,11 @@ import static com.alphawallet.ethereum.EthereumNetworkBase.POA_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.RINKEBY_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.ROPSTEN_ID; +import static com.alphawallet.ethereum.EthereumNetworkBase.SEPOLIA_TESTNET_ID; +import static com.alphawallet.ethereum.EthereumNetworkBase.SEPOLIA_TESTNET_RPC_URL; import static com.alphawallet.ethereum.EthereumNetworkBase.SOKOL_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.GNOSIS_ID; +import static com.alphawallet.ethereum.EthereumNetworkBase.XDAI_RPC_URL; import android.text.TextUtils; import android.util.LongSparseArray; @@ -106,24 +122,16 @@ public abstract class EthereumNetworkBase implements EthereumNetworkRepositoryTy public static final String FREE_MAINNET_RPC_URL = "https://rpc.ankr.com/eth"; public static final String FREE_POLYGON_RPC_URL = "https://polygon-rpc.com"; public static final String FREE_ARBITRUM_RPC_URL = "https://arbitrum.public-rpc.com"; - public static final String FREE_RINKEBY_RPC_URL = "https://rpc.ankr.com/eth_rinkeby"; public static final String FREE_GOERLI_RPC_URL = "https://rpc.ankr.com/eth_goerli"; public static final String FREE_MUMBAI_RPC_URL = "https://rpc-mumbai.maticvigil.com"; - public static final String FREE_OPTIMISM_RPC_URL = "https://mainnet.optimism.io"; public static final String FREE_ARBITRUM_TEST_RPC_URL = "https://rinkeby.arbitrum.io/rpc"; - public static final String FREE_KOVAN_RPC_URL = "https://kovan.poa.network"; - public static final String FREE_OPTIMISM_TESTRPC_URL = "https://kovan.optimism.io"; public static final String FREE_PALM_RPC_URL = "https://palm-mainnet.infura.io/v3/3a961d6501e54add9a41aa53f15de99b"; public static final String FREE_PALM_TEST_RPC_URL = "https://palm-testnet.infura.io/v3/3a961d6501e54add9a41aa53f15de99b"; public static final String FREE_CRONOS_MAIN_BETA_RPC_URL = "https://evm.cronos.org"; public static final String MAINNET_RPC_URL = usesProductionKey ? "https://mainnet.infura.io/v3/" + keyProvider.getInfuraKey() : FREE_MAINNET_RPC_URL; - public static final String RINKEBY_RPC_URL = usesProductionKey ? "https://rinkeby.infura.io/v3/" + keyProvider.getInfuraKey() - : FREE_RINKEBY_RPC_URL; - public static final String KOVAN_RPC_URL = usesProductionKey ? "https://kovan.infura.io/v3/" + keyProvider.getInfuraKey() - : FREE_KOVAN_RPC_URL; - public static final String GOERLI_RPC_URL = usesProductionKey ? "https://goerli.infura.io/v3/" + keyProvider.getInfuraKey() + public static final String GOERLI_RPC_URL = usesProductionKey ? "https://goerli.infura.io/v3/" + keyProvider.getInfuraKey() : FREE_GOERLI_RPC_URL; public static final String POLYGON_RPC_URL = usesProductionKey ? "https://polygon-mainnet.infura.io/v3/" + keyProvider.getInfuraKey() : FREE_POLYGON_RPC_URL; @@ -132,11 +140,7 @@ public abstract class EthereumNetworkBase implements EthereumNetworkRepositoryTy public static final String MUMBAI_TEST_RPC_URL = usesProductionKey ? "https://polygon-mumbai.infura.io/v3/" + keyProvider.getInfuraKey() : FREE_MUMBAI_RPC_URL; public static final String OPTIMISTIC_MAIN_URL = usesProductionKey ? "https://optimism-mainnet.infura.io/v3/" + keyProvider.getInfuraKey() - : FREE_OPTIMISM_RPC_URL; - public static final String OPTIMISTIC_TEST_URL = usesProductionKey ? "https://optimism-kovan.infura.io/v3/" + keyProvider.getInfuraKey() - : FREE_OPTIMISM_TESTRPC_URL; - public static final String ARBITRUM_TESTNET_RPC = usesProductionKey ? "https://arbitrum-rinkeby.infura.io/v3/" + keyProvider.getInfuraKey() - : FREE_ARBITRUM_TEST_RPC_URL; + : OPTIMISTIC_MAIN_FALLBACK_URL; public static final String PALM_RPC_URL = usesProductionKey ? "https://palm-mainnet.infura.io/v3/" + keyProvider.getInfuraKey() : FREE_PALM_RPC_URL; public static final String PALM_TEST_RPC_URL = usesProductionKey ? "https://palm-testnet.infura.io/v3/" + keyProvider.getInfuraKey() @@ -149,44 +153,41 @@ public abstract class EthereumNetworkBase implements EthereumNetworkRepositoryTy // Use the "Free" routes as backup in order to diversify node usage; to avoid single point of failure public static final String MAINNET_FALLBACK_RPC_URL = usesProductionKey ? FREE_MAINNET_RPC_URL : "https://mainnet.infura.io/v3/" + keyProvider.getSecondaryInfuraKey(); - public static final String RINKEBY_FALLBACK_RPC_URL = usesProductionKey ? FREE_RINKEBY_RPC_URL : "https://rinkeby.infura.io/v3/" + keyProvider.getSecondaryInfuraKey(); - public static final String KOVAN_FALLBACK_RPC_URL = usesProductionKey ? FREE_KOVAN_RPC_URL : "https://kovan.infura.io/v3/" + keyProvider.getSecondaryInfuraKey(); public static final String GOERLI_FALLBACK_RPC_URL = usesProductionKey ? FREE_GOERLI_RPC_URL : "https://goerli.infura.io/v3/" + keyProvider.getSecondaryInfuraKey(); public static final String ARBITRUM_FALLBACK_MAINNET_RPC = usesProductionKey ? FREE_ARBITRUM_RPC_URL : "https://arbitrum-mainnet.infura.io/v3/" + keyProvider.getSecondaryInfuraKey(); public static final String PALM_RPC_FALLBACK_URL = usesProductionKey ? FREE_PALM_RPC_URL : "https://palm-mainnet.infura.io/v3/" + keyProvider.getSecondaryInfuraKey(); public static final String PALM_TEST_RPC_FALLBACK_URL = usesProductionKey ? FREE_PALM_RPC_URL : "https://palm-testnet.infura.io/v3/" + keyProvider.getSecondaryInfuraKey(); + //Deprecated: for now these RPCs still work + public static final String ROPSTEN_RPC_URL = "https://rpc.ankr.com/eth_ropsten"; + public static final String RINKEBY_RPC_URL = "https://rpc.ankr.com/eth_rinkeby"; + public static final String ARBITRUM_TESTNET_RPC = FREE_ARBITRUM_TEST_RPC_URL; + public static final String SOKOL_RPC_URL = "https://sokol.poa.network"; + + //These Networks are no longer running + public static final String KOVAN_RPC_URL = "https://kovan.poa.network"; + public static final String OPTIMISTIC_TEST_URL = OPTIMISTIC_TEST_FALLBACK_URL; + //Note that AlphaWallet now uses a double node configuration. See class AWHttpService comment 'try primary node'. //If you supply a main RPC and secondary it will try the secondary if the primary node times out after 10 seconds. //See the declaration of NetworkInfo - it has a member backupNodeUrl. Put your secondary node here. - public static final String ROPSTEN_FALLBACK_RPC_URL = "https://ropsten.infura.io/v3/" + keyProvider.getSecondaryInfuraKey(); public static final String CLASSIC_RPC_URL = "https://www.ethercluster.com/etc"; - public static final String XDAI_RPC_URL = com.alphawallet.ethereum.EthereumNetworkBase.XDAI_RPC_URL; public static final String POA_RPC_URL = "https://core.poa.network/"; - public static final String ROPSTEN_RPC_URL = "https://ropsten.infura.io/v3/" + keyProvider.getInfuraKey(); - public static final String SOKOL_RPC_URL = "https://sokol.poa.network"; public static final String ARTIS_SIGMA1_RPC_URL = "https://rpc.sigma1.artis.network"; public static final String ARTIS_TAU1_RPC_URL = "https://rpc.tau1.artis.network"; public static final String BINANCE_TEST_RPC_URL = "https://data-seed-prebsc-1-s3.binance.org:8545"; public static final String BINANCE_TEST_FALLBACK_RPC_URL = "https://data-seed-prebsc-2-s1.binance.org:8545"; public static final String BINANCE_MAIN_RPC_URL = "https://bsc-dataseed.binance.org"; public static final String BINANCE_MAIN_FALLBACK_RPC_URL = "https://bsc-dataseed2.ninicoin.io:443"; - public static final String HECO_RPC_URL = "https://http-mainnet.hecochain.com"; - public static final String HECO_TEST_RPC_URL = "https://http-testnet.hecochain.com"; public static final String POLYGON_FALLBACK_RPC_URL = "https://matic-mainnet.chainstacklabs.com"; public static final String MUMBAI_FALLBACK_RPC_URL = "https://matic-mumbai.chainstacklabs.com"; - public static final String OPTIMISTIC_MAIN_FALLBACK_URL = "https://mainnet.optimism.io"; - public static final String OPTIMISTIC_TEST_FALLBACK_URL = "https://kovan.optimism.io"; public static final String CRONOS_TEST_URL = "https://evm-t3.cronos.org"; public static final String ARBITRUM_FALLBACK_TESTNET_RPC = "https://rinkeby.arbitrum.io/rpc"; - public static final String IOTEX_MAINNET_RPC_URL = "https://babel-api.mainnet.iotex.io"; public static final String IOTEX_MAINNET_RPC_FALLBACK_URL = "https://rpc.ankr.com/iotex"; - public static final String IOTEX_TESTNET_RPC_URL = "https://babel-api.testnet.iotex.io"; - public static final String AURORA_MAINNET_RPC_URL = "https://mainnet.aurora.dev"; - public static final String AURORA_TESTNET_RPC_URL = "https://testnet.aurora.dev"; - public static final String PHI_NETWORK_RPC = "https://rpc1.phi.network"; + public static final String OPTIMISM_GOERLI_TESTNET_RPC_URL = "https://optimism-goerli.infura.io/v3/" + keyProvider.getInfuraKey(); + public static final String ARBITRUM_GOERLI_TESTNET_RPC_URL = "https://arbitrum-goerli.infura.io/v3/" + keyProvider.getInfuraKey(); //All chains that have fiat/real value (not testnet) must be put here //Note: This list also determines the order of display for main net chains in the wallet. @@ -197,8 +198,19 @@ public abstract class EthereumNetworkBase implements EthereumNetworkRepositoryTy FANTOM_ID, OPTIMISTIC_MAIN_ID, CRONOS_MAIN_ID, ARBITRUM_MAIN_ID, PALM_ID, KLAYTN_ID, IOTEX_MAINNET_ID, AURORA_MAINNET_ID, MILKOMEDA_C1_ID, PHI_V2_MAIN_ID, PHI_MAIN_ID)); + private static final List testnetList = new ArrayList<>(Arrays.asList( + GOERLI_ID, BINANCE_TEST_ID, HECO_TEST_ID, CRONOS_TEST_ID, OPTIMISM_GOERLI_TEST_ID, ARBITRUM_GOERLI_TEST_ID, KLAYTN_BAOBAB_ID, + FANTOM_TEST_ID, IOTEX_TESTNET_ID, FUJI_TEST_ID, POLYGON_TEST_ID, MILKOMEDA_C1_TEST_ID, ARTIS_TAU1_ID, + SEPOLIA_TESTNET_ID, AURORA_TESTNET_ID, PALM_TEST_ID, + //Deprecated networks + ROPSTEN_ID, RINKEBY_ID, KOVAN_ID, OPTIMISTIC_TEST_ID, SOKOL_ID, ARBITRUM_TEST_ID)); + + private static final List deprecatedNetworkList = new ArrayList<>(Arrays.asList( + ROPSTEN_ID, RINKEBY_ID, KOVAN_ID, OPTIMISTIC_TEST_ID, SOKOL_ID, ARBITRUM_TEST_ID)); + // for reset built-in network - private static final LongSparseArray builtinNetworkMap = new LongSparseArray() { + private static final LongSparseArray builtinNetworkMap = new LongSparseArray() + { { put(MAINNET_ID, new NetworkInfo(C.ETHEREUM_NETWORK_NAME, C.ETH_SYMBOL, MAINNET_RPC_URL, @@ -220,22 +232,6 @@ public abstract class EthereumNetworkBase implements EthereumNetworkRepositoryTy ARTIS_SIGMA1_RPC_URL, "https://explorer.sigma1.artis.network/tx/", ARTIS_SIGMA1_ID, ARTIS_SIGMA1_RPC_URL, "https://explorer.sigma1.artis.network/api?")); - put(KOVAN_ID, new NetworkInfo(C.KOVAN_NETWORK_NAME, C.ETH_SYMBOL, - KOVAN_RPC_URL, - "https://kovan.etherscan.io/tx/", KOVAN_ID, - KOVAN_FALLBACK_RPC_URL, "https://api-kovan.etherscan.io/api?")); - put(ROPSTEN_ID, new NetworkInfo(C.ROPSTEN_NETWORK_NAME, C.ETH_SYMBOL, - ROPSTEN_RPC_URL, - "https://ropsten.etherscan.io/tx/", ROPSTEN_ID, - ROPSTEN_FALLBACK_RPC_URL, "https://api-ropsten.etherscan.io/api?")); - put(SOKOL_ID, new NetworkInfo(C.SOKOL_NETWORK_NAME, C.POA_SYMBOL, - SOKOL_RPC_URL, - "https://blockscout.com/poa/sokol/tx/", SOKOL_ID, - SOKOL_RPC_URL, "https://blockscout.com/poa/sokol/api?")); - put(RINKEBY_ID, new NetworkInfo(C.RINKEBY_NETWORK_NAME, C.ETH_SYMBOL, - RINKEBY_RPC_URL, - "https://rinkeby.etherscan.io/tx/", RINKEBY_ID, - RINKEBY_FALLBACK_RPC_URL, "https://api-rinkeby.etherscan.io/api?")); put(GOERLI_ID, new NetworkInfo(C.GOERLI_NETWORK_NAME, C.GOERLI_SYMBOL, GOERLI_RPC_URL, "https://goerli.etherscan.io/tx/", GOERLI_ID, @@ -287,10 +283,6 @@ public abstract class EthereumNetworkBase implements EthereumNetworkRepositoryTy OPTIMISTIC_MAIN_URL, "https://optimistic.etherscan.io/tx/", OPTIMISTIC_MAIN_ID, OPTIMISTIC_MAIN_FALLBACK_URL, "https://api-optimistic.etherscan.io/api?")); - put(OPTIMISTIC_TEST_ID, new NetworkInfo(C.OPTIMISTIC_TEST_NETWORK, C.ETH_SYMBOL, - OPTIMISTIC_TEST_URL, - "https://kovan-optimistic.etherscan.io/tx/", OPTIMISTIC_TEST_ID, OPTIMISTIC_TEST_FALLBACK_URL, - "https://api-kovan-optimistic.etherscan.io/api?")); put(CRONOS_MAIN_ID, new NetworkInfo(C.CRONOS_MAIN_NETWORK, C.CRONOS_SYMBOL, CRONOS_MAIN_RPC_URL, "https://cronoscan.com/tx/", CRONOS_MAIN_ID, CRONOS_MAIN_RPC_URL, @@ -303,10 +295,6 @@ public abstract class EthereumNetworkBase implements EthereumNetworkRepositoryTy ARBITRUM_MAINNET_RPC, "https://arbiscan.io/tx/", ARBITRUM_MAIN_ID, ARBITRUM_FALLBACK_MAINNET_RPC, "https://api.arbiscan.io/api?")); - put(ARBITRUM_TEST_ID, new NetworkInfo(C.ARBITRUM_TEST_NETWORK, C.ARBITRUM_TEST_SYMBOL, - ARBITRUM_TESTNET_RPC, - "https://testnet.arbiscan.io/tx/", ARBITRUM_TEST_ID, ARBITRUM_FALLBACK_TESTNET_RPC, - "https://testnet.arbiscan.io/api?")); //no transaction API put(PALM_ID, new NetworkInfo(C.PALM_NAME, C.PALM_SYMBOL, PALM_RPC_URL, "https://explorer.palm.io/tx/", PALM_ID, PALM_RPC_FALLBACK_URL, @@ -315,7 +303,6 @@ public abstract class EthereumNetworkBase implements EthereumNetworkRepositoryTy PALM_TEST_RPC_URL, "https://explorer.palm-uat.xyz/tx/", PALM_TEST_ID, PALM_TEST_RPC_FALLBACK_URL, "https://explorer.palm-uat.xyz/api?")); - put(KLAYTN_ID, new NetworkInfo(C.KLAYTN_NAME, C.KLAYTN_SYMBOL, USE_KLAYTN_RPC, "https://scope.klaytn.com/tx/", KLAYTN_ID, KLAYTN_RPC, @@ -338,7 +325,6 @@ public abstract class EthereumNetworkBase implements EthereumNetworkRepositoryTy put(AURORA_TESTNET_ID, new NetworkInfo(C.AURORA_TESTNET_NAME, C.ETH_SYMBOL, AURORA_TESTNET_RPC_URL, "https://testnet.aurorascan.dev/tx/", AURORA_TESTNET_ID, "", "https://api-testnet.aurorascan.dev/api?")); - put(MILKOMEDA_C1_ID, new NetworkInfo(C.MILKOMEDA_NAME, C.MILKOMEDA_SYMBOL, MILKOMEDA_C1_RPC, "https://explorer-mainnet-cardano-evm.c1.milkomeda.com/tx/", MILKOMEDA_C1_ID, "", @@ -348,13 +334,51 @@ public abstract class EthereumNetworkBase implements EthereumNetworkRepositoryTy "https://explorer-devnet-cardano-evm.c1.milkomeda.com/tx/", MILKOMEDA_C1_TEST_ID, "", "https://explorer-devnet-cardano-evm.c1.milkomeda.com/api?")); put(PHI_MAIN_ID, new NetworkInfo(C.PHI_NETWORK_NAME, C.PHI_NETWORK_SYMBOL, - PHI_NETWORK_RPC, + PHI_MAIN_RPC_URL, "https://explorer.phi.network/tx/", PHI_MAIN_ID, "https://rpc2.phi.network", "")); put(PHI_V2_MAIN_ID, new NetworkInfo(C.PHI_V2_NETWORK_NAME, C.PHI_NETWORK_SYMBOL, PHI_NETWORK_V2_RPC, "https://phiscan.com/tx/", PHI_V2_MAIN_ID, "", "https://phiscan.com/api?")); + put(SEPOLIA_TESTNET_ID, new NetworkInfo(C.SEPOLIA_TESTNET_NAME, C.SEPOLIA_SYMBOL, + SEPOLIA_TESTNET_RPC_URL, + "https://sepolia.etherscan.io/tx/", SEPOLIA_TESTNET_ID, "https://rpc2.sepolia.org", + "https://api-sepolia.etherscan.io/api?")); + put(OPTIMISM_GOERLI_TEST_ID, new NetworkInfo(C.OPTIMISM_GOERLI_TESTNET_NAME, C.OPTIMISM_GOERLI_TEST_SYMBOL, + OPTIMISM_GOERLI_TESTNET_RPC_URL, + "https://blockscout.com/optimism/goerli/tx/", OPTIMISM_GOERLI_TEST_ID, OPTIMISM_GOERLI_TESTNET_FALLBACK_RPC_URL, + "https://blockscout.com/optimism/goerli/api?")); + put(ARBITRUM_GOERLI_TEST_ID, new NetworkInfo(C.ARBITRUM_GOERLI_TESTNET_NAME, C.ARBITRUM_SYMBOL, + ARBITRUM_GOERLI_TESTNET_RPC_URL, + "https://goerli-rollup-explorer.arbitrum.io/tx/", ARBITRUM_GOERLI_TEST_ID, ARBITRUM_GOERLI_TESTNET_FALLBACK_RPC_URL, + "https://goerli-rollup-explorer.arbitrum.io/api?")); + + // Deprecated Networks + put(ROPSTEN_ID, new NetworkInfo(C.ROPSTEN_NETWORK_NAME, C.ETH_SYMBOL, + ROPSTEN_RPC_URL, + "https://ropsten.etherscan.io/tx/", ROPSTEN_ID, + ROPSTEN_RPC_URL, "https://api-ropsten.etherscan.io/api?")); + put(RINKEBY_ID, new NetworkInfo(C.RINKEBY_NETWORK_NAME, C.ETH_SYMBOL, + RINKEBY_RPC_URL, + "https://rinkeby.etherscan.io/tx/", RINKEBY_ID, + RINKEBY_RPC_URL, "https://api-rinkeby.etherscan.io/api?")); + put(KOVAN_ID, new NetworkInfo(C.KOVAN_NETWORK_NAME, C.ETH_SYMBOL, + KOVAN_RPC_URL, + "https://kovan.etherscan.io/tx/", KOVAN_ID, + KOVAN_RPC_URL, "https://api-kovan.etherscan.io/api?")); + put(SOKOL_ID, new NetworkInfo(C.SOKOL_NETWORK_NAME, C.POA_SYMBOL, + SOKOL_RPC_URL, + "https://blockscout.com/poa/sokol/tx/", SOKOL_ID, + SOKOL_RPC_URL, "https://blockscout.com/poa/sokol/api?")); + put(OPTIMISTIC_TEST_ID, new NetworkInfo(C.OPTIMISTIC_TEST_NETWORK, C.ETH_SYMBOL, + OPTIMISTIC_TEST_URL, + "https://kovan-optimistic.etherscan.io/tx/", OPTIMISTIC_TEST_ID, OPTIMISTIC_TEST_FALLBACK_URL, + "https://api-kovan-optimistic.etherscan.io/api?")); + put(ARBITRUM_TEST_ID, new NetworkInfo(C.ARBITRUM_TEST_NETWORK, C.ARBITRUM_TEST_SYMBOL, + ARBITRUM_TESTNET_RPC, + "https://testnet.arbiscan.io/tx/", ARBITRUM_TEST_ID, ARBITRUM_FALLBACK_TESTNET_RPC, + "https://testnet.arbiscan.io/api?")); //no transaction API } }; @@ -362,7 +386,8 @@ public abstract class EthereumNetworkBase implements EthereumNetworkRepositoryTy //the entries are automatically sorted into numerical order private static final LongSparseArray networkMap = builtinNetworkMap.clone(); - private static final LongSparseArray chainLogos = new LongSparseArray() { + private static final LongSparseArray chainLogos = new LongSparseArray() + { { put(MAINNET_ID, R.drawable.ic_token_eth); put(KOVAN_ID, R.drawable.ic_kovan); @@ -403,10 +428,14 @@ public abstract class EthereumNetworkBase implements EthereumNetworkRepositoryTy put(MILKOMEDA_C1_TEST_ID, R.drawable.ic_milkomeda_test); put(PHI_MAIN_ID, R.drawable.ic_phi_network); put(PHI_V2_MAIN_ID, R.drawable.ic_phi_network); + put(SEPOLIA_TESTNET_ID, R.drawable.ic_sepolia_test); + put(OPTIMISM_GOERLI_TEST_ID, R.drawable.ic_optimism_testnet_logo); + put(ARBITRUM_GOERLI_TEST_ID, R.drawable.ic_icons_arbitrum_test); } }; - private static final LongSparseArray smallChainLogos = new LongSparseArray() { + private static final LongSparseArray smallChainLogos = new LongSparseArray() + { { put(MAINNET_ID, R.drawable.ic_icons_network_eth); put(KOVAN_ID, R.drawable.ic_kovan); @@ -447,10 +476,14 @@ public abstract class EthereumNetworkBase implements EthereumNetworkRepositoryTy put(MILKOMEDA_C1_TEST_ID, R.drawable.ic_milkomeda_test); put(PHI_MAIN_ID, R.drawable.ic_phi_network); put(PHI_V2_MAIN_ID, R.drawable.ic_phi_network); + put(SEPOLIA_TESTNET_ID, R.drawable.ic_sepolia_test); + put(OPTIMISM_GOERLI_TEST_ID, R.drawable.ic_optimism_testnet_logo); + put(ARBITRUM_GOERLI_TEST_ID, R.drawable.ic_icons_arbitrum_test); } }; - private static final LongSparseArray chainColours = new LongSparseArray() { + private static final LongSparseArray chainColours = new LongSparseArray() + { { put(MAINNET_ID, R.color.mainnet); put(KOVAN_ID, R.color.kovan); @@ -491,6 +524,9 @@ public abstract class EthereumNetworkBase implements EthereumNetworkRepositoryTy put(MILKOMEDA_C1_TEST_ID, R.color.milkomeda_test); put(PHI_MAIN_ID, R.color.phi_network); put(PHI_V2_MAIN_ID, R.color.phi_network); + put(SEPOLIA_TESTNET_ID, R.color.sepolia); + put(OPTIMISM_GOERLI_TEST_ID, R.color.optimistic_test); + put(ARBITRUM_GOERLI_TEST_ID, R.color.arbitrum_test); } }; @@ -538,7 +574,7 @@ else if (networkMap.indexOfKey(chainId) >= 0) } else { - return 500 + (int)chainId%500; //fixed ID above 500 + return 500 + (int) chainId % 500; //fixed ID above 500 } } @@ -547,8 +583,9 @@ public boolean hasLockedGas(long chainId) { return hasLockedGas.contains(chainId); } - - static final Map addressOverride = new HashMap() { + + static final Map addressOverride = new HashMap() + { { put(OPTIMISTIC_MAIN_ID, "0x4200000000000000000000000000000000000006"); put(OPTIMISTIC_TEST_ID, "0x4200000000000000000000000000000000000006"); @@ -561,40 +598,53 @@ public boolean hasLockedGas(long chainId) final NetworkInfo[] additionalNetworks; - static class CustomNetworks { + static class CustomNetworks + { private ArrayList list = new ArrayList<>(); private Map mapToTestNet = new HashMap<>(); final transient private PreferenceRepositoryType preferences; - public CustomNetworks(PreferenceRepositoryType preferences) { + public CustomNetworks(PreferenceRepositoryType preferences) + { this.preferences = preferences; restore(); } - public void restore() { + public void restore() + { String networks = preferences.getCustomRPCNetworks(); - if (!TextUtils.isEmpty(networks)) { + if (!TextUtils.isEmpty(networks)) + { CustomNetworks cn = new Gson().fromJson(networks, CustomNetworks.class); this.list = cn.list; this.mapToTestNet = cn.mapToTestNet; checkCustomNetworkSetting(); - for (NetworkInfo info : list) { + for (NetworkInfo info : list) + { networkMap.put(info.chainId, info); Boolean value = mapToTestNet.get(info.chainId); boolean isTestnet = value != null && value; - if (!isTestnet && !hasValue.contains(info.chainId)) { + if (!isTestnet && !hasValue.contains(info.chainId)) + { hasValue.add(info.chainId); } + else if (isTestnet && !testnetList.contains(info.chainId)) + { + testnetList.add(info.chainId); + } } } } - private void checkCustomNetworkSetting() { - if (list.size() > 0 && !list.get(0).isCustom) { //need to update the list + private void checkCustomNetworkSetting() + { + if (list.size() > 0 && !list.get(0).isCustom) + { //need to update the list List copyList = new ArrayList<>(list); list.clear(); - for (NetworkInfo n : copyList) { + for (NetworkInfo n : copyList) + { boolean isCustom = builtinNetworkMap.indexOfKey(n.chainId) == -1; NetworkInfo newInfo = new NetworkInfo(n.name, n.symbol, n.rpcServerUrl, n.etherscanUrl, n.chainId, n.backupNodeUrl, n.etherscanAPI, isCustom); list.add(newInfo); @@ -606,9 +656,12 @@ private void checkCustomNetworkSetting() { public void save(NetworkInfo info, boolean isTestnet, Long oldChainId) { - if (oldChainId != null) { + if (oldChainId != null) + { updateNetwork(info, isTestnet, oldChainId); - } else { + } + else + { addNetwork(info, isTestnet); } @@ -620,11 +673,14 @@ private void updateNetwork(NetworkInfo info, boolean isTestnet, long oldChainId) { removeNetwork(oldChainId); list.add(info); - - if (!isTestnet) { + if (!isTestnet) + { hasValue.add(info.chainId); } - + else + { + testnetList.add(info.chainId); + } mapToTestNet.put(info.chainId, isTestnet); networkMap.put(info.chainId, info); } @@ -632,14 +688,20 @@ private void updateNetwork(NetworkInfo info, boolean isTestnet, long oldChainId) private void addNetwork(NetworkInfo info, boolean isTestnet) { list.add(info); - if (!isTestnet) { + if (!isTestnet) + { hasValue.add(info.chainId); } + else + { + testnetList.add(info.chainId); + } mapToTestNet.put(info.chainId, isTestnet); networkMap.put(info.chainId, info); } - public void remove(long chainId) { + public void remove(long chainId) + { removeNetwork(chainId); String networks = new Gson().toJson(this); @@ -688,24 +750,42 @@ private void addNetworks(List result, boolean withValue) { for (long networkId : hasValue) { - result.add(networkMap.get(networkId)); + if (!deprecatedNetworkList.contains(networkId)) + { + result.add(networkMap.get(networkId)); + } + } + + for (long networkId : hasValue) + { + if (deprecatedNetworkList.contains(networkId)) + { + result.add(networkMap.get(networkId)); + } } } else { - //sorted array - for (int i = 0; i < networkMap.size(); i++) + for (long networkId : testnetList) { - NetworkInfo info = networkMap.valueAt(i); - if (!hasValue.contains(info.chainId) && !result.contains(info)) + if (!deprecatedNetworkList.contains(networkId)) { - result.add(info); + result.add(networkMap.get(networkId)); + } + } + + for (long networkId : testnetList) + { + if (deprecatedNetworkList.contains(networkId)) + { + result.add(networkMap.get(networkId)); } } } } - public static String getChainOverrideAddress(long chainId) { + public static String getChainOverrideAddress(long chainId) + { return addressOverride.containsKey(chainId) ? addressOverride.get(chainId) : ""; } @@ -734,7 +814,8 @@ public NetworkInfo getNetworkByChain(long chainId) @Override public Single getLastTransactionNonce(Web3j web3j, String walletAddress) { - return Single.fromCallable(() -> { + return Single.fromCallable(() -> + { try { EthGetTransactionCount ethGetTransactionCount = web3j @@ -782,7 +863,7 @@ public List getSelectedFilters(boolean isMainNet) @Override public Long getDefaultNetwork(boolean isMainNet) { - return isMainNet ? CustomViewSettings.primaryChain : RINKEBY_ID; + return isMainNet ? CustomViewSettings.primaryChain : GOERLI_ID; } @Override @@ -837,7 +918,8 @@ public NetworkInfo[] getAllActiveNetworks() } @Override - public void addOnChangeDefaultNetwork(OnNetworkChangeListener onNetworkChanged) { + public void addOnChangeDefaultNetwork(OnNetworkChangeListener onNetworkChanged) + { onNetworkChangedListeners.add(onNetworkChanged); } @@ -854,8 +936,12 @@ public static List getAllMainNetworks() public static String getSecondaryNodeURL(long networkId) { NetworkInfo info = networkMap.get(networkId); - if (info != null) { return info.backupNodeUrl; } - else { + if (info != null) + { + return info.backupNodeUrl; + } + else + { return ""; } } @@ -905,16 +991,24 @@ public static BigInteger getMaxGasLimit(long chainId) public static String getNodeURLByNetworkId(long networkId) { NetworkInfo info = networkMap.get(networkId); - if (info != null) { return info.rpcServerUrl; } - else { return MAINNET_RPC_URL; } + if (info != null) + { + return info.rpcServerUrl; + } + else + { + return MAINNET_RPC_URL; + } } /** * This is used so as not to leak API credentials to web3; XInfuraAPI is the backup API key checked into github + * * @param networkId * @return */ - public static String getDefaultNodeURL(long networkId) { + public static String getDefaultNodeURL(long networkId) + { NetworkInfo info = networkMap.get(networkId); if (info != null) return info.rpcServerUrl; else return ""; @@ -922,9 +1016,12 @@ public static String getDefaultNodeURL(long networkId) { public static long getNetworkIdFromName(String name) { - if (!TextUtils.isEmpty(name)) { - for (int i = 0; i < networkMap.size(); i++) { - if (name.equals(networkMap.valueAt(i).name)) { + if (!TextUtils.isEmpty(name)) + { + for (int i = 0; i < networkMap.size(); i++) + { + if (name.equals(networkMap.valueAt(i).name)) + { return networkMap.valueAt(i).chainId; } } @@ -994,7 +1091,8 @@ public Token getBlankOverrideToken(NetworkInfo networkInfo) public Single getBlankOverrideTokens(Wallet wallet) { - return Single.fromCallable(() -> { + return Single.fromCallable(() -> + { if (getBlankOverrideToken() == null) { return new Token[0]; @@ -1051,7 +1149,8 @@ public void setActiveMainnet(boolean isMainNet) preferences.setActiveMainnet(isMainNet); } - public void saveCustomRPCNetwork(String networkName, String rpcUrl, long chainId, String symbol, String blockExplorerUrl, String explorerApiUrl, boolean isTestnet, Long oldChainId) { + public void saveCustomRPCNetwork(String networkName, String rpcUrl, long chainId, String symbol, String blockExplorerUrl, String explorerApiUrl, boolean isTestnet, Long oldChainId) + { NetworkInfo builtInNetwork = builtinNetworkMap.get(chainId); boolean isCustom = builtInNetwork == null; @@ -1059,11 +1158,13 @@ public void saveCustomRPCNetwork(String networkName, String rpcUrl, long chainId customNetworks.save(info, isTestnet, oldChainId); } - public void removeCustomRPCNetwork(long chainId) { + public void removeCustomRPCNetwork(long chainId) + { customNetworks.remove(chainId); } - public static NetworkInfo getNetworkInfo(long chainId) { + public static NetworkInfo getNetworkInfo(long chainId) + { return networkMap.get(chainId); } @@ -1118,4 +1219,8 @@ public NetworkInfo getBuiltInNetwork(long chainId) return builtinNetworkMap.get(chainId); } -} + public static boolean isNetworkDeprecated(long chainId) + { + return deprecatedNetworkList.contains(chainId); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/alphawallet/app/repository/PreferenceRepositoryType.java b/app/src/main/java/com/alphawallet/app/repository/PreferenceRepositoryType.java index 8dc04155fe..0f3bfe3d82 100644 --- a/app/src/main/java/com/alphawallet/app/repository/PreferenceRepositoryType.java +++ b/app/src/main/java/com/alphawallet/app/repository/PreferenceRepositoryType.java @@ -2,6 +2,8 @@ import com.alphawallet.app.entity.CurrencyItem; +import java.util.Set; + public interface PreferenceRepositoryType { String getCurrentWalletAddress(); @@ -98,4 +100,7 @@ public interface PreferenceRepositoryType { boolean isNewWallet(String address); void setNewWallet(String address, boolean isNewWallet); + + Set getSelectedSwapProviders(); + void setSelectedSwapProviders(Set swapProviders); } diff --git a/app/src/main/java/com/alphawallet/app/repository/SharedPreferenceRepository.java b/app/src/main/java/com/alphawallet/app/repository/SharedPreferenceRepository.java index 654c301027..b2eaa22a12 100644 --- a/app/src/main/java/com/alphawallet/app/repository/SharedPreferenceRepository.java +++ b/app/src/main/java/com/alphawallet/app/repository/SharedPreferenceRepository.java @@ -10,7 +10,9 @@ import com.alphawallet.app.C; import com.alphawallet.app.entity.CurrencyItem; +import java.util.HashSet; import java.util.Locale; +import java.util.Set; public class SharedPreferenceRepository implements PreferenceRepositoryType { private static final String CURRENT_ACCOUNT_ADDRESS_KEY = "current_account_address"; @@ -41,6 +43,7 @@ public class SharedPreferenceRepository implements PreferenceRepositoryType { public static final String MARSHMALLOW_SUPPORT_WARNING = "marshmallow_version_support_warning_shown"; private static final String LAST_FRAGMENT_ID = "lastfrag_id"; private static final String LAST_VERSION_CODE = "last_version_code"; + private static final String SELECTED_SWAP_PROVIDERS_KEY = "selected_exchanges"; private static final String RATE_APP_SHOWN = "rate_us_shown"; private static final String LAUNCH_COUNT = "launch_count"; @@ -392,6 +395,18 @@ public void setNewWallet(String address, boolean isNewWallet) pref.edit().putBoolean(keyOf(address), isNewWallet).apply(); } + @Override + public Set getSelectedSwapProviders() + { + return pref.getStringSet(SELECTED_SWAP_PROVIDERS_KEY, new HashSet<>()); + } + + @Override + public void setSelectedSwapProviders(Set swapProviders) + { + pref.edit().putStringSet(SELECTED_SWAP_PROVIDERS_KEY, swapProviders).apply(); + } + @NonNull private String keyOf(String address) { diff --git a/app/src/main/java/com/alphawallet/app/repository/SwapRepository.java b/app/src/main/java/com/alphawallet/app/repository/SwapRepository.java new file mode 100644 index 0000000000..155aa473fb --- /dev/null +++ b/app/src/main/java/com/alphawallet/app/repository/SwapRepository.java @@ -0,0 +1,36 @@ +package com.alphawallet.app.repository; + +import android.content.Context; + +import com.alphawallet.app.entity.lifi.SwapProvider; +import com.alphawallet.app.util.Utils; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import java.util.List; + +public class SwapRepository implements SwapRepositoryType +{ + public static final String FETCH_CHAINS = "https://li.quest/v1/chains"; + public static final String FETCH_TOKENS = "https://li.quest/v1/connections"; + public static final String FETCH_QUOTE = "https://li.quest/v1/quote"; + public static final String FETCH_TOOLS = "https://li.quest/v1/tools"; + public static final String FETCH_ROUTES = "https://li.quest/v1/advanced/routes"; + private static final String SWAP_PROVIDERS_FILENAME = "swap_providers_list.json"; + + private final Context context; + + public SwapRepository(Context context) + { + this.context = context; + } + + @Override + public List getProviders() + { + return new Gson().fromJson(Utils.loadJSONFromAsset(context, SWAP_PROVIDERS_FILENAME), + new TypeToken>() + { + }.getType()); + } +} diff --git a/app/src/main/java/com/alphawallet/app/repository/SwapRepositoryType.java b/app/src/main/java/com/alphawallet/app/repository/SwapRepositoryType.java new file mode 100644 index 0000000000..978babf52b --- /dev/null +++ b/app/src/main/java/com/alphawallet/app/repository/SwapRepositoryType.java @@ -0,0 +1,10 @@ +package com.alphawallet.app.repository; + +import com.alphawallet.app.entity.lifi.SwapProvider; + +import java.util.List; + +public interface SwapRepositoryType +{ + public List getProviders(); +} diff --git a/app/src/main/java/com/alphawallet/app/service/SwapService.java b/app/src/main/java/com/alphawallet/app/service/SwapService.java index 512947c6dd..fab5804e2e 100644 --- a/app/src/main/java/com/alphawallet/app/service/SwapService.java +++ b/app/src/main/java/com/alphawallet/app/service/SwapService.java @@ -3,24 +3,29 @@ import android.net.Uri; import com.alphawallet.app.C; -import com.alphawallet.app.entity.lifi.Connection; +import com.alphawallet.app.entity.lifi.RouteOptions; +import com.alphawallet.app.entity.lifi.Token; +import com.alphawallet.app.repository.SwapRepository; import com.alphawallet.app.util.BalanceUtils; import com.alphawallet.app.util.JsonUtils; +import org.json.JSONException; +import org.json.JSONObject; + import java.util.Objects; +import java.util.Set; import java.util.concurrent.TimeUnit; import io.reactivex.Single; +import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; +import okhttp3.RequestBody; import okhttp3.ResponseBody; import timber.log.Timber; public class SwapService { - private static final String FETCH_CHAINS = "https://li.quest/v1/chains"; - private static final String FETCH_TOKENS = "https://li.quest/v1/connections"; - private static final String SWAP_TOKEN = "https://li.quest/v1/quote"; private static OkHttpClient httpClient; public SwapService() @@ -38,8 +43,18 @@ private Request buildRequest(String api) Request.Builder requestB = new Request.Builder() .url(api) .header("User-Agent", "Chrome/74.0.3729.169") - .method("GET", null) - .addHeader("Content-Type", "application/json"); + .addHeader("Content-Type", "application/json") + .get(); + return requestB.build(); + } + + private Request buildPostRequest(String api, RequestBody requestBody) + { + Request.Builder requestB = new Request.Builder() + .url(api) + .header("User-Agent", "Chrome/74.0.3729.169") + .addHeader("Content-Type", "application/json") + .post(requestBody); return requestB.build(); } @@ -69,49 +84,185 @@ private String executeRequest(String api) return JsonUtils.EMPTY_RESULT; } + private String executePostRequest(String api, RequestBody requestBody) + { + try (okhttp3.Response response = httpClient.newCall(buildPostRequest(api, requestBody)).execute()) + { + if (response.isSuccessful()) + { + ResponseBody responseBody = response.body(); + if (responseBody != null) + { + return responseBody.string(); + } + } + else + { + return Objects.requireNonNull(response.body()).string(); + } + } + catch (Exception e) + { + Timber.e(e); + return e.getMessage(); + } + + return JsonUtils.EMPTY_RESULT; + } + public Single getChains() { return Single.fromCallable(this::fetchChains); } + public Single getTools() + { + return Single.fromCallable(this::fetchTools); + } + public Single getConnections(long from, long to) { return Single.fromCallable(() -> fetchPairs(from, to)); } - public Single getQuote(Connection.LToken source, Connection.LToken dest, String address, String amount, String slippage) + public Single getQuote(Token source, + Token dest, + String address, + String amount, + String slippage, + String allowExchanges) + { + return Single.fromCallable(() -> fetchQuote(source, dest, address, amount, slippage, allowExchanges)); + } + + public Single getRoutes(Token source, + Token dest, + String address, + String amount, + String slippage, + Set exchanges) { - return Single.fromCallable(() -> fetchQuote(source, dest, address, amount, slippage)); + return Single.fromCallable(() -> fetchRoutes(source, dest, address, amount, slippage, exchanges)); + } + + public Single getRoutes(String fromChainId, + String toChainId, + String fromTokenAddress, + String toTokenAddress, + String fromAddress, + String fromAmount, + String slippage, + Set exchanges) + { + return Single.fromCallable(() -> fetchRoutes(fromChainId, toChainId, fromTokenAddress, toTokenAddress, fromAddress, fromAmount, slippage, exchanges)); } public String fetchChains() { Uri.Builder builder = new Uri.Builder(); - builder.encodedPath(FETCH_CHAINS); + builder.encodedPath(SwapRepository.FETCH_CHAINS); + return executeRequest(builder.build().toString()); + } + + public String fetchTools() + { + Uri.Builder builder = new Uri.Builder(); + builder.encodedPath(SwapRepository.FETCH_TOOLS); return executeRequest(builder.build().toString()); } public String fetchPairs(long fromChain, long toChain) { Uri.Builder builder = new Uri.Builder(); - builder.encodedPath(FETCH_TOKENS) + builder.encodedPath(SwapRepository.FETCH_TOKENS) .appendQueryParameter("fromChain", String.valueOf(fromChain)) .appendQueryParameter("toChain", String.valueOf(toChain)); return executeRequest(builder.build().toString()); } - public String fetchQuote(Connection.LToken source, Connection.LToken dest, String address, String amount, String slippage) + public String fetchQuote(Token source, + Token dest, + String address, + String amount, + String slippage, + String allowExchanges) { Uri.Builder builder = new Uri.Builder(); - builder.encodedPath(SWAP_TOKEN) + builder.encodedPath(SwapRepository.FETCH_QUOTE) .appendQueryParameter("fromChain", String.valueOf(source.chainId)) .appendQueryParameter("toChain", String.valueOf(dest.chainId)) .appendQueryParameter("fromToken", source.address) .appendQueryParameter("toToken", dest.address) .appendQueryParameter("fromAddress", address) .appendQueryParameter("fromAmount", BalanceUtils.getRawFormat(amount, source.decimals)) -// .appendQueryParameter("order", "RECOMMENDED") + .appendQueryParameter("allowExchanges", allowExchanges) .appendQueryParameter("slippage", slippage); return executeRequest(builder.build().toString()); } + + public String fetchRoutes(Token source, + Token dest, + String address, + String amount, + String slippage, + Set exchanges) + { + RouteOptions options = new RouteOptions(); + options.slippage = slippage; + options.exchanges.allow.addAll(exchanges); + + RequestBody body = null; + try + { + JSONObject json = new JSONObject(); + json.put("fromChainId", String.valueOf(source.chainId)); + json.put("toChainId", String.valueOf(dest.chainId)); + json.put("fromTokenAddress", source.address); + json.put("toTokenAddress", dest.address); + json.put("fromAddress", address); + json.put("fromAmount", BalanceUtils.getRawFormat(amount, source.decimals)); + json.put("options", options.getJson()); + body = RequestBody.create(json.toString(), MediaType.parse("application/json")); + } + catch (JSONException e) + { + Timber.e(e); + } + + return executePostRequest(SwapRepository.FETCH_ROUTES, body); + } + + public String fetchRoutes(String fromChainId, + String toChainId, + String fromTokenAddress, + String toTokenAddress, + String fromAddress, + String fromAmount, + String slippage, + Set exchanges) + { + RouteOptions options = new RouteOptions(); + options.slippage = slippage; + options.exchanges.allow.addAll(exchanges); + + RequestBody body = null; + try + { + JSONObject json = new JSONObject(); + json.put("fromChainId", fromChainId); + json.put("toChainId", toChainId); + json.put("fromTokenAddress", fromTokenAddress); + json.put("toTokenAddress", toTokenAddress); + json.put("fromAddress", fromAddress); + json.put("fromAmount", fromAmount); + json.put("options", options.getJson()); + body = RequestBody.create(json.toString(), MediaType.parse("application/json")); + } + catch (JSONException e) + { + Timber.e(e); + } + + return executePostRequest(SwapRepository.FETCH_ROUTES, body); + } } diff --git a/app/src/main/java/com/alphawallet/app/service/TickerService.java b/app/src/main/java/com/alphawallet/app/service/TickerService.java index eda5013178..152db1d135 100644 --- a/app/src/main/java/com/alphawallet/app/service/TickerService.java +++ b/app/src/main/java/com/alphawallet/app/service/TickerService.java @@ -19,7 +19,7 @@ import static com.alphawallet.ethereum.EthereumNetworkBase.PHI_V2_MAIN_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.POA_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.POLYGON_ID; -import static com.alphawallet.ethereum.EthereumNetworkBase.RINKEBY_ID; +import static com.alphawallet.ethereum.EthereumNetworkBase.POLYGON_TEST_ID; import static org.web3j.protocol.core.methods.request.Transaction.createEthCallTransaction; import android.text.TextUtils; @@ -80,7 +80,7 @@ public class TickerService { private static final int UPDATE_TICKER_CYCLE = 5; //5 Minutes private static final String MEDIANIZER = "0x729D19f657BD0614b4985Cf1D82531c67569197B"; - private static final String MARKET_ORACLE_CONTRACT = "0xf155a7eb4a2993c8cf08a76bca137ee9ac0a01d8"; + private static final String MARKET_ORACLE_CONTRACT = "0xdAcAf435f241B1a062B021abEED9CA2F76F22F8D"; private static final String CONTRACT_ADDR = "[CONTRACT_ADDR]"; private static final String CHAIN_IDS = "[CHAIN_ID]"; private static final String CURRENCY_TOKEN = "[CURRENCY]"; @@ -91,7 +91,7 @@ public class TickerService private static final String CURRENCY_CONV = "currency"; private static final boolean ALLOW_UNVERIFIED_TICKERS = false; //allows verified:false tickers from DEX.GURU. Not recommended public static final long TICKER_TIMEOUT = DateUtils.WEEK_IN_MILLIS; //remove ticker if not seen in one week - public static final long TICKER_STALE_TIMEOUT = 15 * DateUtils.MINUTE_IN_MILLIS; //try to use market API if AlphaWallet market oracle not updating + public static final long TICKER_STALE_TIMEOUT = 30 * DateUtils.MINUTE_IN_MILLIS; //Use market API if AlphaWallet market oracle not updating private final OkHttpClient httpClient; private final PreferenceRepositoryType sharedPrefs; @@ -228,7 +228,7 @@ private Single updateTickersFromOracle(double conversionRate) currentConversionRate = conversionRate; return Single.fromCallable(() -> { int tickerSize = 0; - final Web3j web3j = TokenRepository.getWeb3jService(RINKEBY_ID); + final Web3j web3j = TokenRepository.getWeb3jService(POLYGON_TEST_ID); //fetch current tickers Function function = getTickers(); String responseValue = callSmartContractFunction(web3j, function, MARKET_ORACLE_CONTRACT); diff --git a/app/src/main/java/com/alphawallet/app/ui/FunctionActivity.java b/app/src/main/java/com/alphawallet/app/ui/FunctionActivity.java index dc81d9688b..0876ed35ce 100644 --- a/app/src/main/java/com/alphawallet/app/ui/FunctionActivity.java +++ b/app/src/main/java/com/alphawallet/app/ui/FunctionActivity.java @@ -304,6 +304,7 @@ public boolean onOptionsItemSelected(MenuItem item) { private void completeTokenScriptFunction(String function) { Map functions = viewModel.getAssetDefinitionService().getTokenFunctionMap(token.tokenInfo.chainId, token.getAddress()); + if (functions == null) return; action = functions.get(function); if (action != null && action.function != null) //if no function then it's handled by the token view diff --git a/app/src/main/java/com/alphawallet/app/ui/HomeActivity.java b/app/src/main/java/com/alphawallet/app/ui/HomeActivity.java index 81e9fb3041..8d19e874f4 100644 --- a/app/src/main/java/com/alphawallet/app/ui/HomeActivity.java +++ b/app/src/main/java/com/alphawallet/app/ui/HomeActivity.java @@ -39,7 +39,6 @@ import androidx.annotation.Nullable; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; -import androidx.core.content.FileProvider; import androidx.core.view.WindowCompat; import androidx.core.view.WindowInsetsCompat; import androidx.core.view.WindowInsetsControllerCompat; @@ -52,7 +51,6 @@ import androidx.viewpager2.adapter.FragmentStateAdapter; import androidx.viewpager2.widget.ViewPager2; -import com.alphawallet.app.BuildConfig; import com.alphawallet.app.C; import com.alphawallet.app.R; import com.alphawallet.app.api.v1.entity.request.ApiV1Request; @@ -87,7 +85,6 @@ import net.yslibrary.android.keyboardvisibilityevent.KeyboardVisibilityEvent; -import java.io.File; import java.lang.reflect.Method; import java.net.URLDecoder; import java.util.List; @@ -242,7 +239,6 @@ public void onPageScrollStateChanged(int state) dissableDisplayHomeAsUp(); viewModel.error().observe(this, this::onError); - viewModel.installIntent().observe(this, this::onInstallIntent); viewModel.walletName().observe(this, this::onWalletName); viewModel.backUpMessage().observe(this, this::onBackup); viewModel.splashReset().observe(this, this::onRequireInit); @@ -278,6 +274,7 @@ public void onPageScrollStateChanged(int state) else { //TODO: Check we are using latest version on github, since we're using a downloaded/manually installed version + //TODO: Also add a build exclusion so this code only appears if it's a noAnalytics build. //First check that this the package name is "io.stormbird.wallet" - it could be a fork } @@ -925,31 +922,6 @@ public void onRequestPermissionsResult(int requestCode, String[] permissions, in } } - private void onInstallIntent(File installFile) - { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - { - String authority = BuildConfig.APPLICATION_ID + ".fileprovider"; - Uri apkUri = FileProvider.getUriForFile(getApplicationContext(), authority, installFile); - Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE); - intent.setData(apkUri); - intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - startActivity(intent); - } - else - { - Uri apkUri = Uri.fromFile(installFile); - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(apkUri, "application/vnd.android.package-archive"); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(intent); - } - - //Blank install time here so that next time the app runs the install time will be correctly set up - viewModel.setInstallTime(0); - finish(); - } - @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { diff --git a/app/src/main/java/com/alphawallet/app/ui/NFTAssetDetailActivity.java b/app/src/main/java/com/alphawallet/app/ui/NFTAssetDetailActivity.java index ea55e0c0c0..a7750bbfcb 100644 --- a/app/src/main/java/com/alphawallet/app/ui/NFTAssetDetailActivity.java +++ b/app/src/main/java/com/alphawallet/app/ui/NFTAssetDetailActivity.java @@ -35,7 +35,6 @@ import com.alphawallet.app.service.GasService; import com.alphawallet.app.ui.widget.entity.ActionSheetCallback; import com.alphawallet.app.ui.widget.entity.NFTAttributeLayout; -import com.alphawallet.app.util.Utils; import com.alphawallet.app.viewmodel.TokenFunctionViewModel; import com.alphawallet.app.web3.entity.Web3Transaction; import com.alphawallet.app.widget.AWalletAlertDialog; @@ -90,6 +89,7 @@ public class NFTAssetDetailActivity extends BaseActivity implements StandardFunc private TokenInfoView tivLastSale; private TokenInfoView tivAveragePrice; private TokenInfoView tivFloorPrice; + private TokenInfoView tivRarityData; private Animation rotation; private ActivityResultLauncher handleTransactionSuccess; private ActivityResultLauncher getGasSettings; @@ -196,6 +196,7 @@ private void initViews() tivLastSale = findViewById(R.id.last_sale); tivAveragePrice = findViewById(R.id.average_price); tivFloorPrice = findViewById(R.id.floor_price); + tivRarityData = findViewById(R.id.rarity); rotation = AnimationUtils.loadAnimation(this, R.anim.rotate_refresh); rotation.setRepeatCount(Animation.INFINITE); @@ -308,7 +309,7 @@ private void updateDefaultTokenData() tivNetwork.setValue(token.getNetworkName()); - tivContractAddress.setValue(Utils.formatAddress(token.tokenInfo.address)); + tivContractAddress.setCopyableValue(token.tokenInfo.address); } private void loadAssetFromMetadata(NFTAsset asset) @@ -407,6 +408,11 @@ private void loadFromOpenSeaData(OpenSeaAsset openSeaAsset) nftAttributeLayout.bind(token, openSeaAsset.traits, 0); } + if (openSeaAsset.rarity != null && openSeaAsset.rarity.rank > 0) + { + tivRarityData.setValue("#" + openSeaAsset.rarity.rank); + } + if (openSeaAsset.owner != null && openSeaAsset.owner.user != null) { diff --git a/app/src/main/java/com/alphawallet/app/ui/NewSettingsFragment.java b/app/src/main/java/com/alphawallet/app/ui/NewSettingsFragment.java index b2e62b9a7d..aca05ec7d1 100644 --- a/app/src/main/java/com/alphawallet/app/ui/NewSettingsFragment.java +++ b/app/src/main/java/com/alphawallet/app/ui/NewSettingsFragment.java @@ -43,6 +43,7 @@ import com.alphawallet.app.interact.GenericWalletInteract; import com.alphawallet.app.util.LocaleUtils; import com.alphawallet.app.util.UpdateUtils; +import com.alphawallet.app.util.Utils; import com.alphawallet.app.viewmodel.NewSettingsViewModel; import com.alphawallet.app.widget.NotificationView; import com.alphawallet.app.widget.SettingsItemView; @@ -412,14 +413,10 @@ private void onDefaultWallet(Wallet wallet) this.wallet = wallet; if (wallet.address != null) { - if (!wallet.ENSname.isEmpty()) - { - changeWalletSetting.setSubtitle(wallet.ENSname + " | " + wallet.address); - } - else - { - changeWalletSetting.setSubtitle(wallet.address); - } + String walletAddressDisplay = wallet.ENSname.isEmpty() ? wallet.address + : wallet.ENSname + " | " + Utils.formatAddress(wallet.address); + + changeWalletSetting.setSubtitle(walletAddressDisplay); } switch (wallet.authLevel) diff --git a/app/src/main/java/com/alphawallet/app/ui/SelectRouteActivity.java b/app/src/main/java/com/alphawallet/app/ui/SelectRouteActivity.java new file mode 100644 index 0000000000..c29c1bfed2 --- /dev/null +++ b/app/src/main/java/com/alphawallet/app/ui/SelectRouteActivity.java @@ -0,0 +1,201 @@ +package com.alphawallet.app.ui; + +import android.content.Intent; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.Nullable; +import androidx.lifecycle.ViewModelProvider; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.alphawallet.app.R; +import com.alphawallet.app.entity.lifi.Route; +import com.alphawallet.app.ui.widget.adapter.RouteAdapter; +import com.alphawallet.app.ui.widget.entity.ProgressInfo; +import com.alphawallet.app.util.BalanceUtils; +import com.alphawallet.app.util.SwapUtils; +import com.alphawallet.app.viewmodel.SelectRouteViewModel; +import com.alphawallet.app.widget.AWalletAlertDialog; +import com.alphawallet.app.widget.AddressIcon; +import com.google.android.material.button.MaterialButton; + +import java.util.List; +import java.util.Locale; + +import dagger.hilt.android.AndroidEntryPoint; + +@AndroidEntryPoint +public class SelectRouteActivity extends BaseActivity +{ + private static final long GET_ROUTES_INTERVAL_MS = 30000; + private static final long COUNTDOWN_INTERVAL_MS = 1000; + private SelectRouteViewModel viewModel; + private RecyclerView recyclerView; + private TextView fromAmount; + private TextView fromSymbol; + private TextView currentPrice; + private TextView countdownText; + private LinearLayout noRoutesLayout; + private MaterialButton selectExchangesBtn; + private AddressIcon fromTokenIcon; + private AWalletAlertDialog progressDialog; + private CountDownTimer getRoutesTimer; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_select_route); + + toolbar(); + + setTitle(getString(R.string.title_select_route)); + + initViews(); + + initViewModel(); + + initTimer(); + } + + @Override + protected void onResume() + { + getRoutes(); + super.onResume(); + } + + @Override + protected void onPause() + { + if (getRoutesTimer != null) + { + getRoutesTimer.cancel(); + } + super.onPause(); + } + + private void initViews() + { + recyclerView = findViewById(R.id.list_routes); + fromAmount = findViewById(R.id.from_amount); + fromSymbol = findViewById(R.id.from_symbol); + fromTokenIcon = findViewById(R.id.from_token_icon); + currentPrice = findViewById(R.id.current_price); + countdownText = findViewById(R.id.text_countdown); + noRoutesLayout = findViewById(R.id.layout_no_routes_found); + selectExchangesBtn = findViewById(R.id.btn_select_exchanges); + selectExchangesBtn.setOnClickListener(v -> { + Intent intent = new Intent(this, SelectSwapProvidersActivity.class); + startActivity(intent); + }); + + progressDialog = new AWalletAlertDialog(this); + progressDialog.setCancelable(false); + progressDialog.setProgressMode(); + } + + private void initViewModel() + { + viewModel = new ViewModelProvider(this) + .get(SelectRouteViewModel.class); + viewModel.routes().observe(this, this::onRoutes); + viewModel.progressInfo().observe(this, this::onProgressInfo); + } + + private void initTimer() + { + getRoutesTimer = new CountDownTimer(GET_ROUTES_INTERVAL_MS, COUNTDOWN_INTERVAL_MS) + { + @Override + public void onTick(long millisUntilFinished) + { + String format = millisUntilFinished < 10000 ? "0:0%d" : "0:%d"; + String time = String.format(Locale.ENGLISH, format, millisUntilFinished / 1000); + countdownText.setText(getString(R.string.label_available_routes, time)); + } + + @Override + public void onFinish() + { + getRoutes(); + } + }; + } + + private void getRoutes() + { + String fromChainId = getIntent().getStringExtra("fromChainId"); + String toChainId = getIntent().getStringExtra("toChainId"); + String fromTokenAddress = getIntent().getStringExtra("fromTokenAddress"); + String toTokenAddress = getIntent().getStringExtra("toTokenAddress"); + String fromAddress = getIntent().getStringExtra("fromAddress"); + String fromAmount = getIntent().getStringExtra("fromAmount"); + long fromTokenDecimals = getIntent().getLongExtra("fromTokenDecimals", -1); + String slippage = getIntent().getStringExtra("slippage"); + String fromSymbol = getIntent().getStringExtra("fromTokenSymbol"); + String fromTokenLogoUri = getIntent().getStringExtra("fromTokenLogoUri"); + + this.fromAmount.setText(BalanceUtils.getShortFormat(fromAmount, fromTokenDecimals)); + this.fromSymbol.setText(fromSymbol); + this.fromTokenIcon.bindData(fromTokenLogoUri, Long.parseLong(fromChainId), fromTokenAddress, fromSymbol); + + viewModel.getRoutes(fromChainId, toChainId, fromTokenAddress, toTokenAddress, fromAddress, fromAmount, slippage, viewModel.getPreferredExchanges()); + } + + private void onRoutes(List routes) + { + processRoutes(routes); + + getRoutesTimer.start(); + } + + private void processRoutes(List routeList) + { + RouteAdapter adapter = new RouteAdapter(this, routeList, provider -> { + Intent intent = new Intent(); + intent.putExtra("provider", provider); + setResult(RESULT_OK, intent); + finish(); + }); + recyclerView.setLayoutManager(new LinearLayoutManager(this)); + recyclerView.setAdapter(adapter); + + if (!routeList.isEmpty()) + { + Route route = routeList.get(0); + currentPrice.setText(SwapUtils.getFormattedCurrentPrice(route.steps.get(0).action)); + noRoutesLayout.setVisibility(View.GONE); + } + else + { + currentPrice.setText(R.string.NA); + noRoutesLayout.setVisibility(View.VISIBLE); + } + } + + private void onProgressInfo(ProgressInfo progressInfo) + { + if (progressInfo.shouldShow()) + { + progressDialog.setMessage(progressInfo.getMessage()); + progressDialog.show(); + } + else + { + progressDialog.dismiss(); + } + } + + @Override + public void onBackPressed() + { + setResult(RESULT_CANCELED); + super.onBackPressed(); + } +} diff --git a/app/src/main/java/com/alphawallet/app/ui/SelectSwapProvidersActivity.java b/app/src/main/java/com/alphawallet/app/ui/SelectSwapProvidersActivity.java new file mode 100644 index 0000000000..c70087e814 --- /dev/null +++ b/app/src/main/java/com/alphawallet/app/ui/SelectSwapProvidersActivity.java @@ -0,0 +1,78 @@ +package com.alphawallet.app.ui; + +import android.os.Bundle; +import android.view.MenuItem; +import android.widget.Toast; + +import androidx.annotation.Nullable; +import androidx.lifecycle.ViewModelProvider; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.alphawallet.app.R; +import com.alphawallet.app.ui.widget.adapter.SwapProviderAdapter; +import com.alphawallet.app.viewmodel.SelectSwapProvidersViewModel; + +import dagger.hilt.android.AndroidEntryPoint; + +@AndroidEntryPoint +public class SelectSwapProvidersActivity extends BaseActivity +{ + private SelectSwapProvidersViewModel viewModel; + private SwapProviderAdapter adapter; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + setContentView(R.layout.basic_list_activity); + + toolbar(); + + setTitle(getString(R.string.title_select_exchanges)); + + initViewModel(); + + initViews(); + } + + private void initViewModel() + { + viewModel = new ViewModelProvider(this) + .get(SelectSwapProvidersViewModel.class); + } + + private void initViews() + { + RecyclerView recyclerView = findViewById(R.id.list); + recyclerView.setLayoutManager(new LinearLayoutManager(this)); + adapter = new SwapProviderAdapter(viewModel.getSwapProviders()); + recyclerView.setAdapter(adapter); + } + + @Override + public void onBackPressed() + { + if (viewModel.savePreferences(adapter.getExchanges())) + { + setResult(RESULT_OK); + super.onBackPressed(); + } + else + { + Toast.makeText(this, getString(R.string.message_select_one_exchange), Toast.LENGTH_SHORT).show(); + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) + { + if (item.getItemId() == android.R.id.home) + { + onBackPressed(); + return true; + } + return super.onOptionsItemSelected(item); + } +} diff --git a/app/src/main/java/com/alphawallet/app/ui/SwapActivity.java b/app/src/main/java/com/alphawallet/app/ui/SwapActivity.java index f066cee50b..fe122797df 100644 --- a/app/src/main/java/com/alphawallet/app/ui/SwapActivity.java +++ b/app/src/main/java/com/alphawallet/app/ui/SwapActivity.java @@ -2,7 +2,7 @@ import android.content.Intent; import android.os.Bundle; -import android.os.Handler; +import android.os.CountDownTimer; import android.text.TextUtils; import android.view.Menu; import android.view.MenuItem; @@ -12,6 +12,7 @@ import android.widget.TextView; import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.Nullable; import androidx.lifecycle.ViewModelProvider; @@ -25,8 +26,9 @@ import com.alphawallet.app.entity.lifi.Chain; import com.alphawallet.app.entity.lifi.Connection; import com.alphawallet.app.entity.lifi.Quote; -import com.alphawallet.app.entity.tokens.Token; +import com.alphawallet.app.entity.lifi.Token; import com.alphawallet.app.ui.widget.entity.ActionSheetCallback; +import com.alphawallet.app.ui.widget.entity.ProgressInfo; import com.alphawallet.app.util.BalanceUtils; import com.alphawallet.app.util.SwapUtils; import com.alphawallet.app.viewmodel.SwapViewModel; @@ -35,6 +37,7 @@ import com.alphawallet.app.widget.AWalletAlertDialog; import com.alphawallet.app.widget.ActionSheetDialog; import com.alphawallet.app.widget.SelectTokenDialog; +import com.alphawallet.app.widget.StandardHeader; import com.alphawallet.app.widget.SwapSettingsDialog; import com.alphawallet.app.widget.TokenInfoView; import com.alphawallet.app.widget.TokenSelector; @@ -51,6 +54,7 @@ public class SwapActivity extends BaseActivity implements StandardFunctionInterface, ActionSheetCallback { private static final long GET_QUOTE_INTERVAL_MS = 30000; + private static final long COUNTDOWN_INTERVAL_MS = 1000; private SwapViewModel viewModel; private TokenSelector sourceSelector; private TokenSelector destSelector; @@ -62,39 +66,26 @@ public class SwapActivity extends BaseActivity implements StandardFunctionInterf private AWalletAlertDialog errorDialog; private RelativeLayout tokenLayout; private LinearLayout infoLayout; + private StandardHeader quoteHeader; private TokenInfoView provider; - private TokenInfoView fees; + private TokenInfoView providerWebsite; + private TokenInfoView gasFees; + private TokenInfoView otherFees; private TokenInfoView currentPrice; private TokenInfoView minReceived; private LinearLayout noConnectionsLayout; private MaterialButton continueBtn; private MaterialButton openSettingsBtn; private TextView chainName; - private Token token; + private com.alphawallet.app.entity.tokens.Token token; private Wallet wallet; - private Connection.LToken sourceToken; + private Token sourceToken; private List chains; - private final Handler getQuoteHandler = new Handler(); - private final Runnable getQuoteRunnable = new Runnable() - { - @Override - public void run() - { - if (confirmationDialog == null || !confirmationDialog.isShowing()) - { - viewModel.getQuote( - sourceSelector.getToken(), - destSelector.getToken(), - wallet.address, - sourceSelector.getAmount(), - settingsDialog.getSlippage()); - } - else - { - startQuoteTask(GET_QUOTE_INTERVAL_MS); - } - } - }; + private String selectedRouteProvider; + private CountDownTimer getQuoteTimer; + private ActivityResultLauncher selectSwapProviderLauncher; + private ActivityResultLauncher gasSettingsLauncher; + private ActivityResultLauncher getRoutesLauncher; @Override protected void onCreate(@Nullable Bundle savedInstanceState) @@ -113,7 +104,42 @@ protected void onCreate(@Nullable Bundle savedInstanceState) initViews(); - viewModel.getChains(); + initTimer(); + + registerActivityResultLaunchers(); + + viewModel.prepare(this, selectSwapProviderLauncher); + } + + private void registerActivityResultLaunchers() + { + selectSwapProviderLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), + result -> { + if (result.getResultCode() == RESULT_OK) + { + viewModel.getChains(); + } + }); + + gasSettingsLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), + result -> confirmationDialog.setCurrentGasIndex(result)); + + getRoutesLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), + result -> { + if (result.getResultCode() == RESULT_OK) + { + Intent data = result.getData(); + if (data != null) + { + selectedRouteProvider = data.getStringExtra("provider"); + getQuote(); + } + } + else if (result.getResultCode() == RESULT_CANCELED) + { + continueBtn.setEnabled(!TextUtils.isEmpty(selectedRouteProvider)); + } + }); } private void initViewModel() @@ -131,6 +157,24 @@ private void initViewModel() viewModel.transactionError().observe(this, this::txError); } + private void initTimer() + { + getQuoteTimer = new CountDownTimer(GET_QUOTE_INTERVAL_MS, COUNTDOWN_INTERVAL_MS) + { + @Override + public void onTick(long millisUntilFinished) + { + // TODO: Display countdown timer? + } + + @Override + public void onFinish() + { + getQuote(); + } + }; + } + private void getIntentData() { long chainId = getIntent().getLongExtra(C.EXTRA_CHAIN_ID, EthereumNetworkBase.MAINNET_ID); @@ -145,14 +189,21 @@ private void initViews() destSelector = findViewById(R.id.to_input); tokenLayout = findViewById(R.id.layout_tokens); infoLayout = findViewById(R.id.layout_info); + quoteHeader = findViewById(R.id.header_quote); provider = findViewById(R.id.tiv_provider); - fees = findViewById(R.id.tiv_fees); + providerWebsite = findViewById(R.id.tiv_provider_website); + gasFees = findViewById(R.id.tiv_gas_fees); + otherFees = findViewById(R.id.tiv_other_fees); currentPrice = findViewById(R.id.tiv_current_price); minReceived = findViewById(R.id.tiv_min_received); noConnectionsLayout = findViewById(R.id.layout_no_connections); continueBtn = findViewById(R.id.btn_continue); openSettingsBtn = findViewById(R.id.btn_open_settings); + quoteHeader.getImageControl().setOnClickListener(v -> { + getAvailableRoutes(); + }); + progressDialog = new AWalletAlertDialog(this); progressDialog.setCancelable(false); progressDialog.setProgressMode(); @@ -186,11 +237,11 @@ public void onSelectorClicked() @Override public void onAmountChanged(String amount) { - startQuoteTask(0); + getAvailableRoutes(); } @Override - public void onSelectionChanged(Connection.LToken token) + public void onSelectionChanged(Token token) { sourceTokenChanged(token); } @@ -221,7 +272,7 @@ public void onAmountChanged(String amount) } @Override - public void onSelectionChanged(Connection.LToken token) + public void onSelectionChanged(Token token) { destTokenChanged(token); } @@ -248,11 +299,11 @@ private ActionSheetDialog createConfirmationAction(Quote quote) ActionSheetDialog confDialog = null; try { - Token activeToken = viewModel.getTokensService().getTokenOrBase(sourceToken.chainId, sourceToken.address); + com.alphawallet.app.entity.tokens.Token activeToken = viewModel.getTokensService().getTokenOrBase(sourceToken.chainId, sourceToken.address); Web3Transaction w3Tx = viewModel.buildWeb3Transaction(quote); confDialog = new ActionSheetDialog(this, w3Tx, activeToken, "", w3Tx.recipient.toString(), viewModel.getTokensService(), this); - confDialog.setURL(quote.toolDetails.name); + confDialog.setURL(quote.swapProvider.name); confDialog.setCanceledOnTouchOutside(false); confDialog.setGasEstimate(Numeric.toBigInt(quote.transactionRequest.gasLimit)); } @@ -264,7 +315,7 @@ private ActionSheetDialog createConfirmationAction(Quote quote) return confDialog; } - private void destTokenChanged(Connection.LToken token) + private void destTokenChanged(Token token) { destSelector.setBalance(viewModel.getBalance(token)); @@ -272,10 +323,10 @@ private void destTokenChanged(Connection.LToken token) destTokenDialog.setSelectedToken(token.address); - startQuoteTask(0); + getAvailableRoutes(); } - private void sourceTokenChanged(Connection.LToken token) + private void sourceTokenChanged(Token token) { if (destSelector.getToken() == null) { @@ -294,17 +345,31 @@ private void sourceTokenChanged(Connection.LToken token) sourceToken = token; - startQuoteTask(0); + getAvailableRoutes(); } @Override protected void onResume() { super.onResume(); + if (settingsDialog != null) + { + settingsDialog.setSwapProviders(viewModel.getPreferredSwapProviders()); + } + } + + @Override + protected void onPause() + { + if (getQuoteTimer != null) + { + getQuoteTimer.cancel(); + } + super.onPause(); } // The source token should default to the token selected in the main wallet dialog (ie the token from the intent). - private void initSourceToken(Connection.LToken selectedToken) + private void initSourceToken(Token selectedToken) { if (selectedToken != null) { @@ -318,7 +383,7 @@ private void initSourceToken(Connection.LToken selectedToken) } } - private void initFromDialog(List fromTokens) + private void initFromDialog(List fromTokens) { Tokens.sortValue(fromTokens); sourceTokenDialog = new SelectTokenDialog(fromTokens, this, tokenItem -> { @@ -327,7 +392,7 @@ private void initFromDialog(List fromTokens) }); } - private void initToDialog(List toTokens) + private void initToDialog(List toTokens) { Tokens.sortName(toTokens); Tokens.sortValue(toTokens); @@ -337,30 +402,39 @@ private void initToDialog(List toTokens) }); } - private void startQuoteTask(long delay) + private void getAvailableRoutes() { - stopQuoteTask(); - - continueBtn.setEnabled(false); + if (getQuoteTimer != null) + { + getQuoteTimer.cancel(); + } if (sourceSelector.getToken() != null && destSelector.getToken() != null + && !sourceSelector.getToken().equals(destSelector.getToken()) && !TextUtils.isEmpty(sourceSelector.getAmount())) { - getQuoteHandler.postDelayed(getQuoteRunnable, delay); + viewModel.getRoutes( + this, + getRoutesLauncher, + sourceSelector.getToken(), + destSelector.getToken(), + wallet.address, + sourceSelector.getAmount(), + settingsDialog.getSlippage() + ); } } - private void stopQuoteTask() - { - getQuoteHandler.removeCallbacks(getQuoteRunnable); - } - private void onChains(List chains) { this.chains = chains; - settingsDialog = new SwapSettingsDialog(this, chains, + settingsDialog = new SwapSettingsDialog( + this, + chains, + viewModel.getSwapProviders(), + viewModel.getPreferredSwapProviders(), chain -> { chainName.setText(chain.name); viewModel.setChain(chain); @@ -400,13 +474,13 @@ private void onConnections(List connections) { if (!connections.isEmpty()) { - List fromTokens = new ArrayList<>(); - List toTokens = new ArrayList<>(); - Connection.LToken selectedToken = null; + List fromTokens = new ArrayList<>(); + List toTokens = new ArrayList<>(); + Token selectedToken = null; for (Connection c : connections) { - for (Connection.LToken t : c.fromTokens) + for (Token t : c.fromTokens) { if (!fromTokens.contains(t)) { @@ -417,7 +491,7 @@ private void onConnections(List connections) { fromTokens.add(t); - if (t.chainId == token.tokenInfo.chainId && t.address.equalsIgnoreCase(token.getAddress())) + if (t.isSimilarTo(token, wallet.address)) { selectedToken = t; } @@ -425,7 +499,7 @@ private void onConnections(List connections) } } - for (Connection.LToken t : c.toTokens) + for (Token t : c.toTokens) { if (!toTokens.contains(t)) { @@ -451,7 +525,21 @@ private void onConnections(List connections) infoLayout.setVisibility(View.GONE); noConnectionsLayout.setVisibility(View.VISIBLE); } + } + private void getQuote() + { + if (!TextUtils.isEmpty(selectedRouteProvider)) + { + viewModel.getQuote( + sourceSelector.getToken(), + destSelector.getToken(), + wallet.address, + sourceSelector.getAmount(), + settingsDialog.getSlippage(), + selectedRouteProvider + ); + } } private void onQuote(Quote quote) @@ -467,7 +555,7 @@ private void onQuote(Quote quote) continueBtn.setEnabled(true); - getQuoteHandler.postDelayed(getQuoteRunnable, GET_QUOTE_INTERVAL_MS); + getQuoteTimer.start(); } private void updateDestAmount(Quote quote) @@ -484,32 +572,31 @@ private void updateDestAmount(Quote quote) private void updateInfoSummary(Quote quote) { - provider.setValue(quote.toolDetails.name); - fees.setValue(SwapUtils.getTotalGasFees(quote.estimate.gasCosts)); - currentPrice.setValue(SwapUtils.getFormattedCurrentPrice(quote).trim()); - minReceived.setValue(SwapUtils.getMinimumAmountReceived(quote)); + provider.setValue(quote.swapProvider.name); + String url = viewModel.getSwapProviderUrl(quote.swapProvider.key); + if (!TextUtils.isEmpty(url)) + { + providerWebsite.setValue(url); + providerWebsite.setLink(); + } + gasFees.setValue(SwapUtils.getTotalGasFees(quote.estimate.gasCosts)); + otherFees.setValue(SwapUtils.getOtherFees(quote.estimate.feeCosts)); + currentPrice.setValue(SwapUtils.getFormattedCurrentPrice(quote.action).trim()); + minReceived.setValue(SwapUtils.getFormattedMinAmount(quote.estimate, quote.action)); infoLayout.setVisibility(View.VISIBLE); } - private void onProgressInfo(int code) + private void onProgressInfo(ProgressInfo progressInfo) { - String message; - switch (code) + if (progressInfo.shouldShow()) { - case C.ProgressInfo.FETCHING_CHAINS: - message = getString(R.string.message_fetching_chains); - break; - case C.ProgressInfo.FETCHING_CONNECTIONS: - message = getString(R.string.message_fetching_connections); - break; - case C.ProgressInfo.FETCHING_QUOTE: - message = getString(R.string.message_fetching_quote); - break; - default: - message = getString(R.string.title_dialog_handling); - break; + progressDialog.setTitle(progressInfo.getMessage()); + progressDialog.show(); + } + else + { + progressDialog.dismiss(); } - progressDialog.setTitle(message); } private void onProgress(Boolean shouldShowProgress) @@ -548,7 +635,7 @@ private void onError(ErrorEnvelope errorEnvelope) sourceSelector.setError(getString(R.string.error_insufficient_balance, sourceSelector.getToken().symbol)); break; case C.ErrorCode.SWAP_TIMEOUT_ERROR: - startQuoteTask(0); + getAvailableRoutes(); break; case C.ErrorCode.SWAP_CONNECTIONS_ERROR: case C.ErrorCode.SWAP_CHAIN_ERROR: @@ -567,7 +654,7 @@ private void onError(ErrorEnvelope errorEnvelope) errorDialog.setTitle(R.string.title_dialog_error); errorDialog.setMessage(errorEnvelope.message); errorDialog.setButton(R.string.try_again, v -> { - startQuoteTask(0); + getAvailableRoutes(); errorDialog.dismiss(); }); errorDialog.setSecondaryButton(R.string.action_cancel, v -> errorDialog.dismiss()); @@ -630,6 +717,6 @@ public void notifyConfirm(String mode) @Override public ActivityResultLauncher gasSelectLauncher() { - return null; + return gasSettingsLauncher; } } diff --git a/app/src/main/java/com/alphawallet/app/ui/widget/adapter/MultiSelectNetworkAdapter.java b/app/src/main/java/com/alphawallet/app/ui/widget/adapter/MultiSelectNetworkAdapter.java index 2934e49374..2e9c761387 100644 --- a/app/src/main/java/com/alphawallet/app/ui/widget/adapter/MultiSelectNetworkAdapter.java +++ b/app/src/main/java/com/alphawallet/app/ui/widget/adapter/MultiSelectNetworkAdapter.java @@ -9,6 +9,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.alphawallet.app.R; +import com.alphawallet.app.repository.EthereumNetworkBase; import com.alphawallet.app.ui.widget.entity.NetworkItem; import com.alphawallet.app.widget.TokenIcon; import com.google.android.material.checkbox.MaterialCheckBox; @@ -76,6 +77,14 @@ public void onBindViewHolder(MultiSelectNetworkAdapter.ViewHolder holder, int po holder.manageView.setOnClickListener(v -> editListener.onEditNetwork(networkList.get(position).getChainId(), holder.manageView)); holder.checkbox.setChecked(item.isSelected()); holder.tokenIcon.bindData(item.getChainId()); + + if (EthereumNetworkBase.isNetworkDeprecated(item.getChainId())) + { + holder.deprecatedIndicator.setVisibility(View.VISIBLE); + holder.tokenIcon.setGrayscale(true); + holder.name.setAlpha(0.7f); + holder.chainId.setAlpha(0.7f); + } } } @@ -99,6 +108,7 @@ class ViewHolder extends RecyclerView.ViewHolder { View manageView; TokenIcon tokenIcon; TextView chainId; + TextView deprecatedIndicator; ViewHolder(View view) { @@ -109,6 +119,7 @@ class ViewHolder extends RecyclerView.ViewHolder { manageView = view.findViewById(R.id.manage_btn); tokenIcon = view.findViewById(R.id.token_icon); chainId = view.findViewById(R.id.chain_id); + deprecatedIndicator = view.findViewById(R.id.deprecated); } } } \ No newline at end of file diff --git a/app/src/main/java/com/alphawallet/app/ui/widget/adapter/RouteAdapter.java b/app/src/main/java/com/alphawallet/app/ui/widget/adapter/RouteAdapter.java new file mode 100644 index 0000000000..0dd563796b --- /dev/null +++ b/app/src/main/java/com/alphawallet/app/ui/widget/adapter/RouteAdapter.java @@ -0,0 +1,105 @@ +package com.alphawallet.app.ui.widget.adapter; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.alphawallet.app.R; +import com.alphawallet.app.entity.lifi.Route; +import com.alphawallet.app.ui.widget.entity.OnRouteSelectedListener; +import com.alphawallet.app.util.SwapUtils; +import com.alphawallet.app.widget.AddressIcon; +import com.google.android.material.card.MaterialCardView; + +import java.util.List; + +public class RouteAdapter extends RecyclerView.Adapter +{ + private final Context context; + private final List data; + private final OnRouteSelectedListener listener; + + public RouteAdapter(Context context, List data, OnRouteSelectedListener listener) + { + this.context = context; + this.data = data; + this.listener = listener; + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) + { + int buttonTypeId = R.layout.item_route; + View itemView = LayoutInflater.from(parent.getContext()) + .inflate(buttonTypeId, parent, false); + return new ViewHolder(itemView); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) + { + Route item = data.get(position); + if (item != null) + { + Route.Step step = item.steps.get(0); + + holder.provider.setText(context.getString(R.string.label_swap_via, step.swapProvider.name)); + + for (String tag : item.tags) + { + if (tag.equalsIgnoreCase("RECOMMENDED")) + { + holder.tag.setVisibility(View.VISIBLE); + holder.tag.setText(tag); + } + } + + holder.value.setText(SwapUtils.getFormattedMinAmount(step.estimate, step.action)); + holder.icon.bindData(step.action.toToken.logoURI, step.action.toToken.chainId, step.action.toToken.address, step.action.toToken.symbol); +// holder.symbol.setText(step.action.toToken.symbol); + holder.gas.setText(context.getString(R.string.info_gas_fee, SwapUtils.getTotalGasFees(step.estimate.gasCosts))); + holder.fees.setVisibility(step.estimate.feeCosts.isEmpty() ? View.GONE : View.VISIBLE); + holder.fees.setText(SwapUtils.getOtherFees(step.estimate.feeCosts)); + holder.layout.setOnClickListener(v -> listener.onRouteSelected(step.swapProvider.key)); + } + } + + @Override + public int getItemCount() + { + return data.size(); + } + + static class ViewHolder extends RecyclerView.ViewHolder + { + MaterialCardView layout; + TextView tag; + TextView provider; + TextView value; + TextView symbol; + TextView gas; + TextView fees; + TextView price; + AddressIcon icon; + + ViewHolder(View view) + { + super(view); + layout = view.findViewById(R.id.layout); + tag = view.findViewById(R.id.tag); + provider = view.findViewById(R.id.provider); + value = view.findViewById(R.id.value); + symbol = view.findViewById(R.id.symbol); + gas = view.findViewById(R.id.gas); + fees = view.findViewById(R.id.fees); + price = view.findViewById(R.id.price); + icon = view.findViewById(R.id.token_icon); + } + } +} diff --git a/app/src/main/java/com/alphawallet/app/ui/widget/adapter/SelectChainAdapter.java b/app/src/main/java/com/alphawallet/app/ui/widget/adapter/SelectChainAdapter.java index b7e210f0fa..3f8f502b74 100644 --- a/app/src/main/java/com/alphawallet/app/ui/widget/adapter/SelectChainAdapter.java +++ b/app/src/main/java/com/alphawallet/app/ui/widget/adapter/SelectChainAdapter.java @@ -1,11 +1,9 @@ package com.alphawallet.app.ui.widget.adapter; - import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ImageView; import android.widget.TextView; import androidx.annotation.NonNull; @@ -14,7 +12,7 @@ import com.alphawallet.app.R; import com.alphawallet.app.entity.lifi.Chain; import com.alphawallet.app.widget.SwapSettingsDialog; -import com.bumptech.glide.Glide; +import com.alphawallet.app.widget.TokenIcon; import com.google.android.material.radiobutton.MaterialRadioButton; import java.util.List; @@ -51,11 +49,7 @@ public void onBindViewHolder(ViewHolder holder, int position) { holder.name.setText(item.metamask.chainName); holder.chainId.setText(context.getString(R.string.chain_id, item.id)); - - Glide.with(context) - .load(item.logoURI) - .circleCrop() - .into(holder.chainIcon); + holder.chainIcon.bindData(item.id); if (item.id == selectedChainId) { @@ -75,18 +69,18 @@ public int getItemCount() public void setChains(List chains) { this.chains = chains; - notifyDataSetChanged(); + notifyItemRangeChanged(0, getItemCount()); } - public void setSelectedChain(long selectedChainId) + public long getSelectedChain() { - this.selectedChainId = selectedChainId; - notifyDataSetChanged(); + return this.selectedChainId; } - public long getSelectedChain() + public void setSelectedChain(long selectedChainId) { - return this.selectedChainId; + this.selectedChainId = selectedChainId; + notifyItemRangeChanged(0, getItemCount()); } static class ViewHolder extends RecyclerView.ViewHolder @@ -95,7 +89,7 @@ static class ViewHolder extends RecyclerView.ViewHolder TextView name; TextView chainId; View itemLayout; - ImageView chainIcon; + TokenIcon chainIcon; ViewHolder(View view) { diff --git a/app/src/main/java/com/alphawallet/app/ui/widget/adapter/SelectTokenAdapter.java b/app/src/main/java/com/alphawallet/app/ui/widget/adapter/SelectTokenAdapter.java index 0118a9bc30..c5f32d6305 100644 --- a/app/src/main/java/com/alphawallet/app/ui/widget/adapter/SelectTokenAdapter.java +++ b/app/src/main/java/com/alphawallet/app/ui/widget/adapter/SelectTokenAdapter.java @@ -1,6 +1,5 @@ package com.alphawallet.app.ui.widget.adapter; - import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; @@ -11,7 +10,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.alphawallet.app.R; -import com.alphawallet.app.entity.lifi.Connection; +import com.alphawallet.app.entity.lifi.Token; import com.alphawallet.app.widget.AddressIcon; import com.alphawallet.app.widget.SelectTokenDialog; import com.google.android.material.radiobutton.MaterialRadioButton; @@ -21,12 +20,12 @@ public class SelectTokenAdapter extends RecyclerView.Adapter { - private final List displayData; + private final List displayData; private final SelectTokenDialog.SelectTokenDialogEventListener callback; - private String selectedTokenAddress; private final TokenFilter tokenFilter; + private String selectedTokenAddress; - public SelectTokenAdapter(List tokens, SelectTokenDialog.SelectTokenDialogEventListener callback) + public SelectTokenAdapter(List tokens, SelectTokenDialog.SelectTokenDialogEventListener callback) { tokenFilter = new TokenFilter(tokens); this.callback = callback; @@ -47,7 +46,7 @@ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { - Connection.LToken item = displayData.get(position); + Token item = displayData.get(position); if (item != null) { holder.name.setText(item.name); @@ -56,7 +55,7 @@ public void onBindViewHolder(@NonNull ViewHolder holder, int position) holder.name.append(")"); holder.tokenIcon.bindData(item.logoURI, item.chainId, selectedTokenAddress, item.symbol); - + String balance = item.balance; if (!TextUtils.isEmpty(balance)) { @@ -80,7 +79,7 @@ public void filter(String keyword) updateList(tokenFilter.filterBy(keyword)); } - public void updateList(List filteredList) + public void updateList(List filteredList) { displayData.clear(); displayData.addAll(filteredList); diff --git a/app/src/main/java/com/alphawallet/app/ui/widget/adapter/SwapProviderAdapter.java b/app/src/main/java/com/alphawallet/app/ui/widget/adapter/SwapProviderAdapter.java new file mode 100644 index 0000000000..724af0fdca --- /dev/null +++ b/app/src/main/java/com/alphawallet/app/ui/widget/adapter/SwapProviderAdapter.java @@ -0,0 +1,87 @@ +package com.alphawallet.app.ui.widget.adapter; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.alphawallet.app.R; +import com.alphawallet.app.entity.lifi.SwapProvider; +import com.alphawallet.app.widget.AddressIcon; +import com.google.android.material.checkbox.MaterialCheckBox; + +import java.util.List; + +public class SwapProviderAdapter extends RecyclerView.Adapter +{ + private final List data; + + public SwapProviderAdapter(List data) + { + this.data = data; + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) + { + int buttonTypeId = R.layout.item_exchange; + View itemView = LayoutInflater.from(parent.getContext()) + .inflate(buttonTypeId, parent, false); + return new ViewHolder(itemView); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) + { + SwapProvider item = data.get(position); + if (item != null) + { + holder.title.setText(item.name); + + holder.subtitle.setText(item.url); + + holder.icon.bindData(item.logoURI, -1, "", ""); + + holder.layout.setOnClickListener(v -> holder.checkBox.setChecked(!item.isChecked)); + + holder.checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> item.isChecked = isChecked); + + holder.checkBox.setChecked(item.isChecked); + } + } + + public List getExchanges() + { + return data; + } + + @Override + public int getItemCount() + { + return data.size(); + } + + static class ViewHolder extends RecyclerView.ViewHolder + { + RelativeLayout layout; + AddressIcon icon; + TextView title; + TextView subtitle; + MaterialCheckBox checkBox; + + ViewHolder(View view) + { + super(view); + layout = view.findViewById(R.id.layout_list_item); + icon = view.findViewById(R.id.token_icon); + title = view.findViewById(R.id.provider); + subtitle = view.findViewById(R.id.subtitle); + checkBox = view.findViewById(R.id.checkbox); + } + } +} diff --git a/app/src/main/java/com/alphawallet/app/ui/widget/adapter/TokenFilter.java b/app/src/main/java/com/alphawallet/app/ui/widget/adapter/TokenFilter.java index dd57ff6a6d..1e9fb39653 100644 --- a/app/src/main/java/com/alphawallet/app/ui/widget/adapter/TokenFilter.java +++ b/app/src/main/java/com/alphawallet/app/ui/widget/adapter/TokenFilter.java @@ -1,29 +1,46 @@ package com.alphawallet.app.ui.widget.adapter; +import android.text.TextUtils; + import androidx.annotation.NonNull; -import com.alphawallet.app.entity.lifi.Connection; +import com.alphawallet.app.entity.lifi.Token; import java.util.ArrayList; import java.util.List; +import java.util.ListIterator; import java.util.Locale; public class TokenFilter { - private final List tokens; + private final List tokens; - public TokenFilter(List tokens) + public TokenFilter(List tokens) { this.tokens = tokens; + removeBadTokens(); + } + + private void removeBadTokens() + { + ListIterator iterator = this.tokens.listIterator(); + while (iterator.hasNext()) + { + Token t = iterator.next(); + if (TextUtils.isEmpty(t.name) || TextUtils.isEmpty(t.symbol)) + { + iterator.remove(); + } + } } - public List filterBy(String keyword) + public List filterBy(String keyword) { String lowerCaseKeyword = lowerCase(keyword); - List result = new ArrayList<>(); + List result = new ArrayList<>(); // First filter: Add all entries that start with the keyword on top of the list. - for (Connection.LToken lToken : this.tokens) + for (Token lToken : this.tokens) { String name = lowerCase(lToken.name); String symbol = lowerCase(lToken.symbol); @@ -35,7 +52,7 @@ public List filterBy(String keyword) } // Second filter: Add the rest of the entries that contain the keyword on top of the list. - for (Connection.LToken lToken : this.tokens) + for (Token lToken : this.tokens) { String name = lowerCase(lToken.name); String symbol = lowerCase(lToken.symbol); diff --git a/app/src/main/java/com/alphawallet/app/ui/widget/entity/OnRouteSelectedListener.java b/app/src/main/java/com/alphawallet/app/ui/widget/entity/OnRouteSelectedListener.java new file mode 100644 index 0000000000..2592a3bb57 --- /dev/null +++ b/app/src/main/java/com/alphawallet/app/ui/widget/entity/OnRouteSelectedListener.java @@ -0,0 +1,6 @@ +package com.alphawallet.app.ui.widget.entity; + +public interface OnRouteSelectedListener +{ + void onRouteSelected(String provider); +} diff --git a/app/src/main/java/com/alphawallet/app/ui/widget/entity/ProgressInfo.java b/app/src/main/java/com/alphawallet/app/ui/widget/entity/ProgressInfo.java new file mode 100644 index 0000000000..e5523168e5 --- /dev/null +++ b/app/src/main/java/com/alphawallet/app/ui/widget/entity/ProgressInfo.java @@ -0,0 +1,28 @@ +package com.alphawallet.app.ui.widget.entity; + +public class ProgressInfo +{ + private boolean shouldShow; + private int messageRes; + + public ProgressInfo(boolean shouldShow, int messageRes) + { + this.shouldShow = shouldShow; + this.messageRes = messageRes; + } + + public ProgressInfo(boolean shouldShow) + { + this.shouldShow = shouldShow; + } + + public boolean shouldShow() + { + return shouldShow; + } + + public int getMessage() + { + return messageRes; + } +} diff --git a/app/src/main/java/com/alphawallet/app/util/SwapUtils.java b/app/src/main/java/com/alphawallet/app/util/SwapUtils.java index baee0d76b4..b69f0f4a64 100644 --- a/app/src/main/java/com/alphawallet/app/util/SwapUtils.java +++ b/app/src/main/java/com/alphawallet/app/util/SwapUtils.java @@ -1,5 +1,9 @@ package com.alphawallet.app.util; +import com.alphawallet.app.entity.lifi.Action; +import com.alphawallet.app.entity.lifi.Estimate; +import com.alphawallet.app.entity.lifi.FeeCost; +import com.alphawallet.app.entity.lifi.GasCost; import com.alphawallet.app.entity.lifi.Quote; import java.math.BigDecimal; @@ -7,39 +11,59 @@ public class SwapUtils { + private static final String CURRENT_PRICE_FORMAT = "1 %s ≈ %s %s"; private static final String GAS_PRICE_FORMAT = "%s %s"; + private static final String FEE_FORMAT = "%s %s"; private static final String MINIMUM_RECEIVED_FORMAT = "%s %s"; - private static final String CURRENT_PRICE_FORMAT = "1 %s ≈ %s %s"; - public static String getTotalGasFees(ArrayList gasCosts) + public static String getTotalGasFees(ArrayList gasCosts) { StringBuilder gas = new StringBuilder(); - for (Quote.Estimate.GasCost gc : gasCosts) + for (GasCost gc : gasCosts) { gas.append(SwapUtils.getGasFee(gc)).append(System.lineSeparator()); } return gas.toString().trim(); } - public static String getGasFee(Quote.Estimate.GasCost gasCost) + public static String getGasFee(GasCost gasCost) { return String.format(GAS_PRICE_FORMAT, BalanceUtils.getScaledValueFixed(new BigDecimal(gasCost.amount), gasCost.token.decimals, 4), gasCost.token.symbol); } - public static String getFormattedCurrentPrice(Quote quote) + public static String getOtherFees(ArrayList feeCosts) + { + StringBuilder fees = new StringBuilder(); + for (FeeCost fc : feeCosts) + { + fees.append(fc.name); + fees.append(": "); + fees.append(SwapUtils.getFee(fc)).append(System.lineSeparator()); + } + return fees.toString().trim(); + } + + public static String getFee(FeeCost feeCost) + { + return String.format(FEE_FORMAT, + BalanceUtils.getScaledValueFixed(new BigDecimal(feeCost.amount), feeCost.token.decimals, 4), + feeCost.token.symbol); + } + + public static String getFormattedCurrentPrice(Action action) { return String.format(CURRENT_PRICE_FORMAT, - quote.action.fromToken.symbol, - quote.getCurrentPrice(), - quote.action.toToken.symbol); + action.fromToken.symbol, + action.getCurrentPrice(), + action.toToken.symbol); } - public static String getMinimumAmountReceived(Quote quote) + public static String getFormattedMinAmount(Estimate estimate, Action action) { return String.format(MINIMUM_RECEIVED_FORMAT, - BalanceUtils.getShortFormat(quote.estimate.toAmountMin, quote.action.toToken.decimals), - quote.action.toToken.symbol); + BalanceUtils.getScaledValue(estimate.toAmountMin, action.toToken.decimals, 4), + action.toToken.symbol); } } diff --git a/app/src/main/java/com/alphawallet/app/util/Utils.java b/app/src/main/java/com/alphawallet/app/util/Utils.java index 169aeb9076..0c77f05484 100644 --- a/app/src/main/java/com/alphawallet/app/util/Utils.java +++ b/app/src/main/java/com/alphawallet/app/util/Utils.java @@ -68,18 +68,19 @@ import timber.log.Timber; -public class Utils { - +public class Utils +{ private static final String ISOLATE_NUMERIC = "(0?x?[0-9a-fA-F]+)"; private static final String ICON_REPO_ADDRESS_TOKEN = "[TOKEN]"; private static final String CHAIN_REPO_ADDRESS_TOKEN = "[CHAIN]"; private static final String TOKEN_LOGO = "/logo.png"; - public static final String ALPHAWALLET_REPO_NAME = "https://raw.githubusercontent.com/alphawallet/iconassets/lowercased/"; + public static final String ALPHAWALLET_REPO_NAME = "https://raw.githubusercontent.com/alphawallet/iconassets/master/"; private static final String TRUST_ICON_REPO_BASE = "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/"; private static final String TRUST_ICON_REPO = TRUST_ICON_REPO_BASE + CHAIN_REPO_ADDRESS_TOKEN + "/assets/" + ICON_REPO_ADDRESS_TOKEN + TOKEN_LOGO; private static final String ALPHAWALLET_ICON_REPO = ALPHAWALLET_REPO_NAME + ICON_REPO_ADDRESS_TOKEN + TOKEN_LOGO; - public static int dp2px(Context context, int dp) { + public static int dp2px(Context context, int dp) + { Resources r = context.getResources(); return (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, @@ -88,19 +89,27 @@ public static int dp2px(Context context, int dp) { ); } - public static String formatUrl(String url) { - if (URLUtil.isHttpsUrl(url) || URLUtil.isHttpUrl(url)) { + public static String formatUrl(String url) + { + if (URLUtil.isHttpsUrl(url) || URLUtil.isHttpUrl(url)) + { return url; - } else { - if (isValidUrl(url)) { + } + else + { + if (isValidUrl(url)) + { return C.HTTPS_PREFIX + url; - } else { + } + else + { return C.INTERNET_SEARCH_PREFIX + url; } } } - public static boolean isValidUrl(String url) { + public static boolean isValidUrl(String url) + { Pattern p = Patterns.WEB_URL; Matcher m = p.matcher(url.toLowerCase()); return m.matches(); @@ -146,7 +155,8 @@ public static boolean isValidValue(String testStr) return result; } - private static String getFirstWord(String text) { + private static String getFirstWord(String text) + { if (TextUtils.isEmpty(text)) return ""; text = text.trim(); int index; @@ -269,7 +279,7 @@ public static CharSequence createFormattedValue(Context ctx, String operationNam int spaceIndex = operationName.lastIndexOf(' '); if (spaceIndex > 0) { - operationName = operationName.substring(0, spaceIndex) + '\n' + operationName.substring(spaceIndex+1); + operationName = operationName.substring(0, spaceIndex) + '\n' + operationName.substring(spaceIndex + 1); } else { @@ -298,16 +308,20 @@ public static CharSequence createFormattedValue(Context ctx, String operationNam return sb; } - public static String loadJSONFromAsset(Context context, String fileName) { + public static String loadJSONFromAsset(Context context, String fileName) + { String json = null; - try { + try + { InputStream is = context.getAssets().open(fileName); int size = is.available(); byte[] buffer = new byte[size]; is.read(buffer); is.close(); json = new String(buffer, StandardCharsets.UTF_8); - } catch (IOException ex) { + } + catch (IOException ex) + { ex.printStackTrace(); return null; } @@ -374,7 +388,8 @@ public static List longListToArray(String list) public static int[] bigIntegerListToIntList(List ticketSendIndexList) { int[] indexList = new int[ticketSendIndexList.size()]; - for (int i = 0; i < ticketSendIndexList.size(); i++) indexList[i] = ticketSendIndexList.get(i).intValue(); + for (int i = 0; i < ticketSendIndexList.size(); i++) + indexList[i] = ticketSendIndexList.get(i).intValue(); return indexList; } @@ -395,6 +410,7 @@ public static BigInteger parseTokenId(String tokenIdStr) /** * Produce a string CSV of integer IDs given an input list of values + * * @param idList * @param keepZeros * @return @@ -453,7 +469,7 @@ public static String integerListToString(List intList, boolean keepZero for (Integer id : intList) { if (!keepZeros && id == 0) continue; - if (!first)sb.append(","); + if (!first) sb.append(","); sb.append(id); first = false; } @@ -478,7 +494,10 @@ public static boolean isNumeric(String numString) for (int i = 0; i < numString.length(); i++) { - if (Character.digit(numString.charAt(i), 10) == -1) { return false; } + if (Character.digit(numString.charAt(i), 10) == -1) + { + return false; + } } return true; @@ -491,7 +510,10 @@ public static boolean isHex(String hexStr) for (int i = 0; i < hexStr.length(); i++) { - if (Character.digit(hexStr.charAt(i), 16) == -1) { return false; } + if (Character.digit(hexStr.charAt(i), 16) == -1) + { + return false; + } } return true; @@ -518,7 +540,8 @@ public static String isolateNumeric(String valueFromInput) return valueFromInput; } - public static String formatAddress(String address) { + public static String formatAddress(String address) + { if (isAddressValid(address)) { address = Keys.toChecksumAddress(address); @@ -535,12 +558,15 @@ public static String formatAddress(String address) { /** * Just enough for diagnosis of most errors + * * @param s String to be HTML escaped * @return escaped string */ - public static String escapeHTML(String s) { + public static String escapeHTML(String s) + { StringBuilder out = new StringBuilder(Math.max(16, s.length())); - for (int i = 0; i < s.length(); i++) { + for (int i = 0; i < s.length(); i++) + { char c = s.charAt(i); switch (c) { @@ -565,12 +591,12 @@ public static String escapeHTML(String s) { public static String convertTimePeriodInSeconds(long pendingTimeInSeconds, Context ctx) { - long days = pendingTimeInSeconds/(60*60*24); - pendingTimeInSeconds -= (days*60*60*24); - long hours = pendingTimeInSeconds/(60*60); - pendingTimeInSeconds -= (hours*60*60); - long minutes = pendingTimeInSeconds/60; - long seconds = pendingTimeInSeconds%60; + long days = pendingTimeInSeconds / (60 * 60 * 24); + pendingTimeInSeconds -= (days * 60 * 60 * 24); + long hours = pendingTimeInSeconds / (60 * 60); + pendingTimeInSeconds -= (hours * 60 * 60); + long minutes = pendingTimeInSeconds / 60; + long seconds = pendingTimeInSeconds % 60; StringBuilder sb = new StringBuilder(); int timePoints = 0; @@ -647,12 +673,12 @@ public static String convertTimePeriodInSeconds(long pendingTimeInSeconds, Conte public static String shortConvertTimePeriodInSeconds(long pendingTimeInSeconds, Context ctx) { - long days = pendingTimeInSeconds/(60*60*24); - pendingTimeInSeconds -= (days*60*60*24); - long hours = pendingTimeInSeconds/(60*60); - pendingTimeInSeconds -= (hours*60*60); - long minutes = pendingTimeInSeconds/60; - long seconds = pendingTimeInSeconds%60; + long days = pendingTimeInSeconds / (60 * 60 * 24); + pendingTimeInSeconds -= (days * 60 * 60 * 24); + long hours = pendingTimeInSeconds / (60 * 60); + pendingTimeInSeconds -= (hours * 60 * 60); + long minutes = pendingTimeInSeconds / 60; + long seconds = pendingTimeInSeconds % 60; String timeStr; @@ -672,7 +698,7 @@ else if (hours > 0) } else { - BigDecimal hourStr = BigDecimal.valueOf(hours + (double)minutes/60.0) + BigDecimal hourStr = BigDecimal.valueOf(hours + (double) minutes / 60.0) .setScale(1, RoundingMode.HALF_DOWN); //to 1 dp timeStr = ctx.getString(R.string.hour_plural, hourStr.toString()); } @@ -685,7 +711,7 @@ else if (minutes > 0) } else { - BigDecimal minsStr = BigDecimal.valueOf(minutes + (double)seconds/60.0) + BigDecimal minsStr = BigDecimal.valueOf(minutes + (double) seconds / 60.0) .setScale(1, RoundingMode.HALF_DOWN); //to 1 dp timeStr = ctx.getString(R.string.minute_plural, minsStr.toString()); } @@ -720,7 +746,8 @@ public static String localiseUnixDate(Context ctx, long timeStampInSec) return timeFormat.format(date) + " | " + dateFormat.format(date); } - public static long randomId() { + public static long randomId() + { return new Date().getTime(); } @@ -770,7 +797,8 @@ public static String getTokenAddrFromAWUrl(String url) return ""; } - private static final Map twChainNames = new HashMap() { + private static final Map twChainNames = new HashMap() + { { put(CLASSIC_ID, "classic"); put(GNOSIS_ID, "xdai"); @@ -840,16 +868,21 @@ private static boolean shouldBeIPFS(String url) return url.startsWith("Qm") && url.length() == 46 && !url.contains(".") && !url.contains("/"); } - public static String loadFile(Context context, @RawRes int rawRes) { + public static String loadFile(Context context, @RawRes int rawRes) + { byte[] buffer = new byte[0]; - try { + try + { InputStream in = context.getResources().openRawResource(rawRes); buffer = new byte[in.available()]; int len = in.read(buffer); - if (len < 1) { + if (len < 1) + { throw new IOException("Nothing is read."); } - } catch (Exception ex) { + } + catch (Exception ex) + { Timber.tag("READ_JS_TAG").d(ex, "Ex"); } return new String(buffer); @@ -861,12 +894,14 @@ public static long timeUntil(long eventInMillis) } //TODO: detect various App Library installs and re-direct appropriately - public static boolean verifyInstallerId(Context context) { + public static boolean verifyInstallerId(Context context) + { try { PackageManager packageManager = context.getPackageManager(); String installingPackageName; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) + { final InstallSourceInfo installer = packageManager.getInstallSourceInfo(context.getPackageName()); installingPackageName = installer.getInstallingPackageName(); } @@ -891,16 +926,20 @@ public static boolean isTransactionHash(String input) if (input == null || (input.length() != 66 && input.length() != 64)) return false; String cleanInput = Numeric.cleanHexPrefix(input); - try { + try + { Numeric.toBigIntNoPrefix(cleanInput); - } catch (NumberFormatException e) { + } + catch (NumberFormatException e) + { return false; } return cleanInput.length() == 64; } - public static @ColorInt int getColorFromAttr(Context context, int resId) + public static @ColorInt + int getColorFromAttr(Context context, int resId) { TypedValue typedValue = new TypedValue(); Resources.Theme theme = context.getTheme(); @@ -980,7 +1019,8 @@ else if (context instanceof ContextWrapper) } } - public static String removeDoubleQuotes(String string) { + public static String removeDoubleQuotes(String string) + { return string != null ? string.replace("\"", "") : null; } } diff --git a/app/src/main/java/com/alphawallet/app/viewmodel/HomeViewModel.java b/app/src/main/java/com/alphawallet/app/viewmodel/HomeViewModel.java index f737f113e9..aa9e56c8c1 100644 --- a/app/src/main/java/com/alphawallet/app/viewmodel/HomeViewModel.java +++ b/app/src/main/java/com/alphawallet/app/viewmodel/HomeViewModel.java @@ -123,7 +123,6 @@ public class HomeViewModel extends BaseViewModel { private CryptoFunctions cryptoFunctions; private ParseMagicLink parser; - private final MutableLiveData installIntent = new MutableLiveData<>(); private final MutableLiveData walletName = new MutableLiveData<>(); private final MutableLiveData defaultWallet = new MutableLiveData<>(); private final MutableLiveData splashActivity = new MutableLiveData<>(); @@ -173,10 +172,6 @@ public LiveData transactions() { return transactions; } - public LiveData installIntent() { - return installIntent; - } - public LiveData backUpMessage() { return backUpMessage; } diff --git a/app/src/main/java/com/alphawallet/app/viewmodel/NewSettingsViewModel.java b/app/src/main/java/com/alphawallet/app/viewmodel/NewSettingsViewModel.java index 4505c2abdb..3ae8cb2ec7 100644 --- a/app/src/main/java/com/alphawallet/app/viewmodel/NewSettingsViewModel.java +++ b/app/src/main/java/com/alphawallet/app/viewmodel/NewSettingsViewModel.java @@ -1,11 +1,11 @@ package com.alphawallet.app.viewmodel; -import android.content.Context; - import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; +import android.content.Context; + import com.alphawallet.app.entity.CurrencyItem; import com.alphawallet.app.entity.LocaleItem; import com.alphawallet.app.entity.Transaction; @@ -16,6 +16,7 @@ import com.alphawallet.app.repository.PreferenceRepositoryType; import com.alphawallet.app.router.ManageWalletsRouter; import com.alphawallet.app.router.MyAddressRouter; +import com.alphawallet.app.service.TickerService; import com.alphawallet.app.service.TransactionsService; import com.alphawallet.app.util.LocaleUtils; @@ -27,7 +28,8 @@ import io.reactivex.Single; @HiltViewModel -public class NewSettingsViewModel extends BaseViewModel { +public class NewSettingsViewModel extends BaseViewModel +{ private final MutableLiveData defaultWallet = new MutableLiveData<>(); private final MutableLiveData transactions = new MutableLiveData<>(); @@ -39,6 +41,7 @@ public class NewSettingsViewModel extends BaseViewModel { private final LocaleRepositoryType localeRepository; private final CurrencyRepositoryType currencyRepository; private final TransactionsService transactionsService; + private final TickerService tickerService; @Inject NewSettingsViewModel( @@ -48,7 +51,9 @@ public class NewSettingsViewModel extends BaseViewModel { PreferenceRepositoryType preferenceRepository, LocaleRepositoryType localeRepository, CurrencyRepositoryType currencyRepository, - TransactionsService transactionsService) { + TransactionsService transactionsService, + TickerService tickerService) + { this.genericWalletInteract = genericWalletInteract; this.myAddressRouter = myAddressRouter; this.manageWalletsRouter = manageWalletsRouter; @@ -56,32 +61,40 @@ public class NewSettingsViewModel extends BaseViewModel { this.localeRepository = localeRepository; this.currencyRepository = currencyRepository; this.transactionsService = transactionsService; + this.tickerService = tickerService; } - public ArrayList getLocaleList(Context context) { + public ArrayList getLocaleList(Context context) + { return localeRepository.getLocaleList(context); } - public void setLocale(Context activity) { + public void setLocale(Context activity) + { String currentLocale = localeRepository.getActiveLocale(); LocaleUtils.setLocale(activity, currentLocale); } - public void updateLocale(String newLocale, Context context) { + public void updateLocale(String newLocale, Context context) + { localeRepository.setUserPreferenceLocale(newLocale); localeRepository.setLocale(context, newLocale); } - public String getDefaultCurrency(){ + public String getDefaultCurrency() + { return currencyRepository.getDefaultCurrency(); } - public ArrayList getCurrencyList() { + public ArrayList getCurrencyList() + { return currencyRepository.getCurrencyList(); } - public Single updateCurrency(String currencyCode){ + public Single updateCurrency(String currencyCode) + { currencyRepository.setDefaultCurrency(currencyCode); + tickerService.updateCurrencyConversion(); //delete tickers from realm return transactionsService.wipeTickerData(); } @@ -91,7 +104,8 @@ public String getActiveLocale() return localeRepository.getActiveLocale(); } - public void showManageWallets(Context context, boolean clearStack) { + public void showManageWallets(Context context, boolean clearStack) + { manageWalletsRouter.open(context, clearStack); } @@ -99,32 +113,42 @@ public boolean getNotificationState() { return preferenceRepository.getNotificationsState(); } + public void setNotificationState(boolean notificationState) { preferenceRepository.setNotificationState(notificationState); } @Override - protected void onCleared() { + protected void onCleared() + { super.onCleared(); } - public LiveData defaultWallet() { + public LiveData defaultWallet() + { return defaultWallet; } - public LiveData transactions() { + public LiveData transactions() + { return transactions; } - public LiveData backUpMessage() { return backUpMessage; } - public void prepare() { + public LiveData backUpMessage() + { + return backUpMessage; + } + + public void prepare() + { disposable = genericWalletInteract .find() .subscribe(this::onDefaultWallet, this::onError); } - private void onDefaultWallet(Wallet wallet) { + private void onDefaultWallet(Wallet wallet) + { defaultWallet.setValue(wallet); TestWalletBackup(); @@ -139,7 +163,8 @@ public void TestWalletBackup() } } - public void showMyAddress(Context context) { + public void showMyAddress(Context context) + { myAddressRouter.open(context, defaultWallet.getValue()); } diff --git a/app/src/main/java/com/alphawallet/app/viewmodel/SelectRouteViewModel.java b/app/src/main/java/com/alphawallet/app/viewmodel/SelectRouteViewModel.java new file mode 100644 index 0000000000..4e2a7c5de5 --- /dev/null +++ b/app/src/main/java/com/alphawallet/app/viewmodel/SelectRouteViewModel.java @@ -0,0 +1,119 @@ +package com.alphawallet.app.viewmodel; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import com.alphawallet.app.R; +import com.alphawallet.app.entity.lifi.Route; +import com.alphawallet.app.repository.PreferenceRepositoryType; +import com.alphawallet.app.service.SwapService; +import com.alphawallet.app.ui.widget.entity.ProgressInfo; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.List; +import java.util.Set; + +import javax.inject.Inject; + +import dagger.hilt.android.lifecycle.HiltViewModel; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; + +@HiltViewModel +public class SelectRouteViewModel extends BaseViewModel +{ + private final PreferenceRepositoryType preferenceRepository; + private final SwapService swapService; + private final MutableLiveData> routes = new MutableLiveData<>(); + private final MutableLiveData progressInfo = new MutableLiveData<>(); + private Disposable routeDisposable; + + @Inject + public SelectRouteViewModel( + PreferenceRepositoryType preferenceRepository, + SwapService swapService) + { + this.preferenceRepository = preferenceRepository; + this.swapService = swapService; + } + + public LiveData> routes() + { + return routes; + } + + public LiveData progressInfo() + { + return progressInfo; + } + + public void getRoutes(String fromChainId, + String toChainId, + String fromTokenAddress, + String toTokenAddress, + String fromAddress, + String fromAmount, + String slippage, + Set exchanges) + { + progressInfo.postValue(new ProgressInfo(true, R.string.message_fetching_routes)); + + routeDisposable = swapService + .getRoutes(fromChainId, toChainId, fromTokenAddress, toTokenAddress, fromAddress, fromAmount, slippage, exchanges) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(this::onRoutes, this::onRoutesError); + } + + private void onRoutes(String result) + { + progressInfo.postValue(new ProgressInfo(false)); + + try + { + JSONObject obj = new JSONObject(result); + if (obj.has("routes")) + { + JSONArray json = obj.getJSONArray("routes"); + List routeList = new Gson().fromJson(json.toString(), new TypeToken>() + { + }.getType()); + routes.postValue(routeList); + } + else + { +// postError(C.ErrorCode.SWAP_CONNECTIONS_ERROR, result); + } + } + catch (JSONException e) + { +// postError(C.ErrorCode.SWAP_CONNECTIONS_ERROR, Objects.requireNonNull(e.getMessage())); + } + } + + private void onRoutesError(Throwable throwable) + { + // TODO: + } + + public Set getPreferredExchanges() + { + return preferenceRepository.getSelectedSwapProviders(); + } + + @Override + protected void onCleared() + { + if (routeDisposable != null && !routeDisposable.isDisposed()) + { + routeDisposable.dispose(); + } + super.onCleared(); + } +} diff --git a/app/src/main/java/com/alphawallet/app/viewmodel/SelectSwapProvidersViewModel.java b/app/src/main/java/com/alphawallet/app/viewmodel/SelectSwapProvidersViewModel.java new file mode 100644 index 0000000000..e162683958 --- /dev/null +++ b/app/src/main/java/com/alphawallet/app/viewmodel/SelectSwapProvidersViewModel.java @@ -0,0 +1,85 @@ +package com.alphawallet.app.viewmodel; + +import android.content.Context; + +import com.alphawallet.app.entity.lifi.SwapProvider; +import com.alphawallet.app.repository.PreferenceRepositoryType; +import com.alphawallet.app.repository.SwapRepositoryType; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.inject.Inject; + +import dagger.hilt.android.lifecycle.HiltViewModel; + +@HiltViewModel +public class SelectSwapProvidersViewModel extends BaseViewModel +{ + private final PreferenceRepositoryType preferenceRepository; + private final SwapRepositoryType swapRepository; + + @Inject + public SelectSwapProvidersViewModel( + PreferenceRepositoryType preferenceRepository, + SwapRepositoryType swapRepository) + { + this.preferenceRepository = preferenceRepository; + this.swapRepository = swapRepository; + } + + public Set getPreferredExchanges(Context context) + { + Set exchanges = preferenceRepository.getSelectedSwapProviders(); + if (exchanges.isEmpty()) + { + List swapProviders = getSwapProviders(); + if (swapProviders != null) + { + for (SwapProvider provider : swapProviders) + { + exchanges.add(provider.key); + } + preferenceRepository.setSelectedSwapProviders(exchanges); + } + } + return exchanges; + } + + public List getSwapProviders() + { + List swapProviders = swapRepository.getProviders(); + + if (swapProviders != null) + { + Set preferredProviders = preferenceRepository.getSelectedSwapProviders(); + for (SwapProvider provider : swapProviders) + { + if (preferredProviders.contains(provider.key)) + { + provider.isChecked = true; + } + } + } + + return swapProviders; + } + + public boolean savePreferences(List swapProviders) + { + Set stringSet = new HashSet<>(); + for (SwapProvider providerool : swapProviders) + { + if (providerool.isChecked) + { + stringSet.add(providerool.key); + } + } + if (!stringSet.isEmpty()) + { + preferenceRepository.setSelectedSwapProviders(stringSet); + } + return !stringSet.isEmpty(); + } +} diff --git a/app/src/main/java/com/alphawallet/app/viewmodel/SwapViewModel.java b/app/src/main/java/com/alphawallet/app/viewmodel/SwapViewModel.java index 2bcfcd2812..d3c2a55b4e 100644 --- a/app/src/main/java/com/alphawallet/app/viewmodel/SwapViewModel.java +++ b/app/src/main/java/com/alphawallet/app/viewmodel/SwapViewModel.java @@ -1,11 +1,14 @@ package com.alphawallet.app.viewmodel; import android.app.Activity; +import android.content.Intent; +import androidx.activity.result.ActivityResultLauncher; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import com.alphawallet.app.C; +import com.alphawallet.app.R; import com.alphawallet.app.entity.ErrorEnvelope; import com.alphawallet.app.entity.SignAuthenticationCallback; import com.alphawallet.app.entity.TransactionData; @@ -13,12 +16,18 @@ import com.alphawallet.app.entity.lifi.Chain; import com.alphawallet.app.entity.lifi.Connection; import com.alphawallet.app.entity.lifi.Quote; -import com.alphawallet.app.entity.tokens.Token; +import com.alphawallet.app.entity.lifi.SwapProvider; +import com.alphawallet.app.entity.lifi.Token; import com.alphawallet.app.interact.CreateTransactionInteract; +import com.alphawallet.app.repository.PreferenceRepositoryType; +import com.alphawallet.app.repository.SwapRepositoryType; import com.alphawallet.app.service.AssetDefinitionService; import com.alphawallet.app.service.KeyService; import com.alphawallet.app.service.SwapService; import com.alphawallet.app.service.TokensService; +import com.alphawallet.app.ui.SelectRouteActivity; +import com.alphawallet.app.ui.SelectSwapProvidersActivity; +import com.alphawallet.app.ui.widget.entity.ProgressInfo; import com.alphawallet.app.util.BalanceUtils; import com.alphawallet.app.util.Hex; import com.alphawallet.app.web3.entity.Address; @@ -35,6 +44,7 @@ import java.util.List; import java.util.Locale; import java.util.Objects; +import java.util.Set; import javax.inject.Inject; @@ -48,6 +58,8 @@ public class SwapViewModel extends BaseViewModel { private final AssetDefinitionService assetDefinitionService; + private final PreferenceRepositoryType preferenceRepository; + private final SwapRepositoryType swapRepository; private final TokensService tokensService; private final SwapService swapService; private final CreateTransactionInteract createTransactionInteract; @@ -58,7 +70,7 @@ public class SwapViewModel extends BaseViewModel private final MutableLiveData> connections = new MutableLiveData<>(); private final MutableLiveData quote = new MutableLiveData<>(); private final MutableLiveData network = new MutableLiveData<>(); - private final MutableLiveData progressInfo = new MutableLiveData<>(); + private final MutableLiveData progressInfo = new MutableLiveData<>(); private final MutableLiveData transactionFinalised = new MutableLiveData<>(); private final MutableLiveData transactionError = new MutableLiveData<>(); @@ -70,12 +82,16 @@ public class SwapViewModel extends BaseViewModel @Inject public SwapViewModel( AssetDefinitionService assetDefinitionService, + PreferenceRepositoryType preferenceRepository, + SwapRepositoryType swapRepository, TokensService tokensService, SwapService swapService, CreateTransactionInteract createTransactionInteract, KeyService keyService) { this.assetDefinitionService = assetDefinitionService; + this.preferenceRepository = preferenceRepository; + this.swapRepository = swapRepository; this.tokensService = tokensService; this.swapService = swapService; this.createTransactionInteract = createTransactionInteract; @@ -117,7 +133,7 @@ public LiveData network() return network; } - public LiveData progressInfo() + public LiveData progressInfo() { return progressInfo; } @@ -144,8 +160,7 @@ public void setChain(Chain c) public void getChains() { - progressInfo.postValue(C.ProgressInfo.FETCHING_CHAINS); - progress.postValue(true); + progressInfo.postValue(new ProgressInfo(true, R.string.message_fetching_chains)); chainsDisposable = swapService.getChains() .subscribeOn(Schedulers.io()) @@ -153,10 +168,23 @@ public void getChains() .subscribe(this::onChains, this::onChainsError); } + public String getSwapProviderUrl(String key) + { + List tools = getSwapProviders(); + for (SwapProvider td : tools) + { + if (key.startsWith(td.key)) + { + return td.url; + } + } + + return ""; + } + public void getConnections(long from, long to) { - progressInfo.postValue(C.ProgressInfo.FETCHING_CONNECTIONS); - progress.postValue(true); + progressInfo.postValue(new ProgressInfo(true, R.string.message_fetching_connections)); connectionsDisposable = swapService.getConnections(from, to) .subscribeOn(Schedulers.io()) @@ -164,14 +192,14 @@ public void getConnections(long from, long to) .subscribe(this::onConnections, this::onConnectionsError); } - public void getQuote(Connection.LToken source, Connection.LToken dest, String address, String amount, String slippage) + public void getQuote(Token source, Token dest, String address, String amount, String slippage, String allowExchanges) { + if (!isValidAmount(amount)) return; if (hasEnoughBalance(source, amount)) { - progressInfo.postValue(C.ProgressInfo.FETCHING_QUOTE); - progress.postValue(true); + progressInfo.postValue(new ProgressInfo(true, R.string.message_fetching_quote)); - quoteDisposable = swapService.getQuote(source, dest, address, amount, slippage) + quoteDisposable = swapService.getQuote(source, dest, address, amount, slippage, allowExchanges) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(this::onQuote, this::onQuoteError); @@ -182,6 +210,19 @@ public void getQuote(Connection.LToken source, Connection.LToken dest, String ad } } + private boolean isValidAmount(String amount) + { + try + { + BigDecimal d = new BigDecimal(amount); + } + catch (Exception e) + { + return false; + } + return true; + } + private void onChainsError(Throwable t) { postError(C.ErrorCode.SWAP_CHAIN_ERROR, Objects.requireNonNull(t.getMessage())); @@ -197,7 +238,7 @@ private void onQuoteError(Throwable t) postError(C.ErrorCode.SWAP_QUOTE_ERROR, Objects.requireNonNull(t.getMessage())); } - public boolean hasEnoughBalance(Connection.LToken source, String amount) + public boolean hasEnoughBalance(Token source, String amount) { BigDecimal bal = new BigDecimal(getBalance(source)); BigDecimal reqAmount = new BigDecimal(amount); @@ -255,7 +296,7 @@ private void onConnections(String result) postError(C.ErrorCode.SWAP_CONNECTIONS_ERROR, Objects.requireNonNull(e.getMessage())); } - progress.postValue(false); + progressInfo.postValue(new ProgressInfo(false)); } private void onQuote(String result) @@ -270,7 +311,7 @@ private void onQuote(String result) quote.postValue(q); } - progress.postValue(false); + progressInfo.postValue(new ProgressInfo(false)); } private void postError(int errorCode, String errorStr) @@ -308,9 +349,9 @@ private boolean isValidQuote(String result) && result.contains("tool"); } - public String getBalance(Connection.LToken token) + public String getBalance(Token token) { - Token t; + com.alphawallet.app.entity.tokens.Token t; if (token.isNativeToken()) { t = tokensService.getServiceToken(token.chainId); @@ -360,6 +401,16 @@ public Web3Transaction buildWeb3Transaction(Quote quote) ); } + public List getSwapProviders() + { + return swapRepository.getProviders(); + } + + public Set getPreferredSwapProviders() + { + return preferenceRepository.getSelectedSwapProviders(); + } + @Override protected void onCleared() { @@ -381,4 +432,48 @@ protected void onCleared() } super.onCleared(); } + + public void getRoutes(Activity activity, + ActivityResultLauncher launcher, + Token source, + Token dest, + String address, + String amount, + String slippage) + { + if (!isValidAmount(amount)) return; + if (hasEnoughBalance(source, amount)) + { + Intent intent = new Intent(activity, SelectRouteActivity.class); + intent.putExtra("fromChainId", String.valueOf(source.chainId)); + intent.putExtra("toChainId", String.valueOf(dest.chainId)); + intent.putExtra("fromTokenAddress", String.valueOf(source.address)); + intent.putExtra("toTokenAddress", String.valueOf(dest.address)); + intent.putExtra("fromAddress", address); + intent.putExtra("fromAmount", BalanceUtils.getRawFormat(amount, source.decimals)); + intent.putExtra("fromTokenDecimals", source.decimals); + intent.putExtra("slippage", slippage); + intent.putExtra("fromTokenSymbol", source.symbol); + intent.putExtra("fromTokenIcon", source.symbol); + intent.putExtra("fromTokenLogoUri", source.logoURI); + launcher.launch(intent); + } + else + { + error.postValue(new ErrorEnvelope(C.ErrorCode.INSUFFICIENT_BALANCE, "")); + } + } + + public void prepare(Activity activity, ActivityResultLauncher launcher) + { + if (getPreferredSwapProviders().isEmpty()) + { + Intent intent = new Intent(activity, SelectSwapProvidersActivity.class); + launcher.launch(intent); + } + else + { + getChains(); + } + } } diff --git a/app/src/main/java/com/alphawallet/app/viewmodel/Tokens.java b/app/src/main/java/com/alphawallet/app/viewmodel/Tokens.java index cd4367823d..07689b8646 100644 --- a/app/src/main/java/com/alphawallet/app/viewmodel/Tokens.java +++ b/app/src/main/java/com/alphawallet/app/viewmodel/Tokens.java @@ -1,6 +1,6 @@ package com.alphawallet.app.viewmodel; -import com.alphawallet.app.entity.lifi.Connection; +import com.alphawallet.app.entity.lifi.Token; import java.math.BigDecimal; import java.util.Collections; @@ -8,7 +8,7 @@ public class Tokens { - public static void sortValue(List tokenItems) + public static void sortValue(List tokenItems) { Collections.sort(tokenItems, (l, r) -> { if (l.isNativeToken()) @@ -28,7 +28,7 @@ else if (r.isNativeToken()) }); } - public static void sortName(List tokenItems) + public static void sortName(List tokenItems) { Collections.sort(tokenItems, (l, r) -> { if (l.isNativeToken()) @@ -41,7 +41,7 @@ else if (r.isNativeToken()) } else { - return l.name.compareToIgnoreCase(r.name); + return l.name.trim().compareToIgnoreCase(r.name.trim()); } }); } diff --git a/app/src/main/java/com/alphawallet/app/walletconnect/WCClient.kt b/app/src/main/java/com/alphawallet/app/walletconnect/WCClient.kt index 0eb706ad90..53ac1bfd10 100644 --- a/app/src/main/java/com/alphawallet/app/walletconnect/WCClient.kt +++ b/app/src/main/java/com/alphawallet/app/walletconnect/WCClient.kt @@ -408,6 +408,7 @@ open class WCClient : WebSocketListener() { WCMethod.ADD_ETHEREUM_CHAIN -> { handleAddChain(request) } + else -> {} } } diff --git a/app/src/main/java/com/alphawallet/app/widget/AddressDetailView.java b/app/src/main/java/com/alphawallet/app/widget/AddressDetailView.java index c9c6c5069e..688d5de6a8 100644 --- a/app/src/main/java/com/alphawallet/app/widget/AddressDetailView.java +++ b/app/src/main/java/com/alphawallet/app/widget/AddressDetailView.java @@ -57,7 +57,8 @@ private void getAttrs(Context context, AttributeSet attrs) public void setupAddress(String address, String ensName, Token destToken) { - String destStr = (!TextUtils.isEmpty(ensName) ? ensName + " | " : "") + Utils.formatAddress(address); + boolean hasEns = !TextUtils.isEmpty(ensName); + String destStr = (hasEns ? ensName + " | " : "") + (hasEns ? Utils.formatAddress(address) : address); textAddressSummary.setText(destStr); userAvatar.bind(new Wallet(address), wallet -> { /*NOP, here to enable lookup of ENS avatar*/ }); textFullAddress.setText(address); diff --git a/app/src/main/java/com/alphawallet/app/widget/CopyTextView.java b/app/src/main/java/com/alphawallet/app/widget/CopyTextView.java index b07fdf4aae..a6ae83075d 100644 --- a/app/src/main/java/com/alphawallet/app/widget/CopyTextView.java +++ b/app/src/main/java/com/alphawallet/app/widget/CopyTextView.java @@ -14,8 +14,8 @@ import com.alphawallet.app.R; import com.google.android.material.button.MaterialButton; -public class CopyTextView extends LinearLayout { - +public class CopyTextView extends LinearLayout +{ public static final String KEY_ADDRESS = "key_address"; private final Context context; @@ -23,6 +23,7 @@ public class CopyTextView extends LinearLayout { private int textResId; private int gravity; + private int lines; private boolean showToast; private boolean boldFont; private boolean removePadding; @@ -56,6 +57,7 @@ private void getAttrs(Context context, AttributeSet attrs) boldFont = a.getBoolean(R.styleable.CopyTextView_bold, false); removePadding = a.getBoolean(R.styleable.CopyTextView_removePadding, false); marginRight = a.getDimension(R.styleable.CopyTextView_marginRight, 0.0f); + lines = a.getInt(R.styleable.CopyTextView_lines, 1); } finally { @@ -65,7 +67,17 @@ private void getAttrs(Context context, AttributeSet attrs) private void bindViews() { - button = findViewById(R.id.button); + if (lines == 2) + { + button = findViewById(R.id.button_address); + findViewById(R.id.button).setVisibility(View.GONE); + button.setVisibility(View.VISIBLE); + } + else + { + button = findViewById(R.id.button); + } + setText(getContext().getString(textResId)); button.setOnClickListener(v -> copyToClipboard()); } @@ -98,6 +110,8 @@ private void copyToClipboard() } if (showToast) + { Toast.makeText(context, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show(); + } } } diff --git a/app/src/main/java/com/alphawallet/app/widget/InputAmount.java b/app/src/main/java/com/alphawallet/app/widget/InputAmount.java index 88b5bc8bee..a5e0d957ec 100644 --- a/app/src/main/java/com/alphawallet/app/widget/InputAmount.java +++ b/app/src/main/java/com/alphawallet/app/widget/InputAmount.java @@ -1,8 +1,5 @@ package com.alphawallet.app.widget; -import static com.alphawallet.app.C.GAS_LIMIT_MIN; -import static com.alphawallet.app.repository.TokensRealmSource.databaseKey; - import android.content.Context; import android.content.res.TypedArray; import android.os.Handler; @@ -47,6 +44,9 @@ import io.realm.RealmQuery; import timber.log.Timber; +import static com.alphawallet.app.C.GAS_LIMIT_MIN; +import static com.alphawallet.app.repository.TokensRealmSource.databaseKey; + /** * Created by JB on 10/11/2020. */ @@ -387,8 +387,8 @@ private void setupAllFunds() if (token.isEthereum() && token.hasPositiveBalance()) { RealmGasSpread gasSpread = tokensService.getTickerRealmInstance().where(RealmGasSpread.class) - .equalTo("chainId", token.tokenInfo.chainId) - .findFirst(); + .equalTo("chainId", token.tokenInfo.chainId) + .findFirst(); if (gasSpread != null && gasSpread.getGasPrice().compareTo(BigInteger.ZERO) > 0) { diff --git a/app/src/main/java/com/alphawallet/app/widget/SelectTokenDialog.java b/app/src/main/java/com/alphawallet/app/widget/SelectTokenDialog.java index c98fb66881..bc2ce27ba8 100644 --- a/app/src/main/java/com/alphawallet/app/widget/SelectTokenDialog.java +++ b/app/src/main/java/com/alphawallet/app/widget/SelectTokenDialog.java @@ -19,7 +19,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.alphawallet.app.R; -import com.alphawallet.app.entity.lifi.Connection; +import com.alphawallet.app.entity.lifi.Token; import com.alphawallet.app.ui.widget.adapter.SelectTokenAdapter; import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.bottomsheet.BottomSheetDialog; @@ -56,7 +56,7 @@ public SelectTokenDialog(@NonNull Activity activity) btnClose.setOnClickListener(v -> dismiss()); } - public SelectTokenDialog(List tokenItems, Activity activity, SelectTokenDialogEventListener callback) + public SelectTokenDialog(List tokenItems, Activity activity, SelectTokenDialogEventListener callback) { this(activity); @@ -102,6 +102,6 @@ public void setSelectedToken(String address) public interface SelectTokenDialogEventListener { - void onChainSelected(Connection.LToken tokenItem); + void onChainSelected(Token tokenItem); } } diff --git a/app/src/main/java/com/alphawallet/app/widget/StandardHeader.java b/app/src/main/java/com/alphawallet/app/widget/StandardHeader.java index 0eb01a7490..2cd0a27315 100644 --- a/app/src/main/java/com/alphawallet/app/widget/StandardHeader.java +++ b/app/src/main/java/com/alphawallet/app/widget/StandardHeader.java @@ -4,6 +4,7 @@ import android.content.res.TypedArray; import android.util.AttributeSet; import android.view.View; +import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; @@ -16,6 +17,8 @@ public class StandardHeader extends LinearLayout { private TextView headerText; + private TextView textControl; + private ImageView imageControl; private ChainName chainName; private SwitchMaterial switchMaterial; private View separator; @@ -40,30 +43,41 @@ private void getAttrs(Context context, AttributeSet attrs) int headerId = a.getResourceId(R.styleable.StandardHeader_headerText, R.string.empty); boolean showSwitch = a.getBoolean(R.styleable.StandardHeader_showSwitch, false); boolean showChainName = a.getBoolean(R.styleable.StandardHeader_showChain, false); + boolean showTextControl = a.getBoolean(R.styleable.StandardHeader_showTextControl, false); + boolean showImageControl = a.getBoolean(R.styleable.StandardHeader_showImageControl, false); + int controlText = a.getResourceId(R.styleable.StandardHeader_controlText, -1); + int controlImageRes = a.getResourceId(R.styleable.StandardHeader_controlImageRes, -1); headerText = findViewById(R.id.text_header); chainName = findViewById(R.id.chain_name); switchMaterial = findViewById(R.id.switch_material); separator = findViewById(R.id.separator); + textControl = findViewById(R.id.text_control); + imageControl = findViewById(R.id.image_control); headerText.setText(headerId); - if (showSwitch) + switchMaterial.setVisibility(showSwitch ? View.VISIBLE : View.GONE); + chainName.setVisibility(showChainName ? View.VISIBLE : View.GONE); + + if (showTextControl) { - switchMaterial.setVisibility(View.VISIBLE); + textControl.setVisibility(View.VISIBLE); + textControl.setText(controlText); } else { - switchMaterial.setVisibility(View.GONE); + textControl.setVisibility(View.GONE); } - if (showChainName) + if (showImageControl) { - chainName.setVisibility(View.VISIBLE); + imageControl.setVisibility(View.VISIBLE); + imageControl.setImageResource(controlImageRes); } else { - chainName.setVisibility(View.GONE); + imageControl.setVisibility(View.GONE); } } finally @@ -92,6 +106,16 @@ public SwitchMaterial getSwitch() return switchMaterial; } + public TextView getTextControl() + { + return textControl; + } + + public ImageView getImageControl() + { + return imageControl; + } + public void hideSeparator() { separator.setVisibility(View.GONE); diff --git a/app/src/main/java/com/alphawallet/app/widget/SwapSettingsDialog.java b/app/src/main/java/com/alphawallet/app/widget/SwapSettingsDialog.java index 0f17a299f6..1ae6da13e5 100644 --- a/app/src/main/java/com/alphawallet/app/widget/SwapSettingsDialog.java +++ b/app/src/main/java/com/alphawallet/app/widget/SwapSettingsDialog.java @@ -3,9 +3,11 @@ import static com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED; import android.app.Activity; +import android.content.Intent; import android.content.res.Resources; import android.view.View; import android.widget.ImageView; +import android.widget.TextView; import androidx.annotation.NonNull; import androidx.recyclerview.widget.LinearLayoutManager; @@ -13,19 +15,25 @@ import com.alphawallet.app.R; import com.alphawallet.app.entity.lifi.Chain; +import com.alphawallet.app.entity.lifi.SwapProvider; +import com.alphawallet.app.ui.SelectSwapProvidersActivity; import com.alphawallet.app.ui.widget.adapter.ChainFilter; import com.alphawallet.app.ui.widget.adapter.SelectChainAdapter; +import com.google.android.flexbox.FlexboxLayout; import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.bottomsheet.BottomSheetDialog; import java.util.List; +import java.util.Set; public class SwapSettingsDialog extends BottomSheetDialog { private RecyclerView chainList; private SelectChainAdapter adapter; - private List chains; + private List swapProviders; private SlippageWidget slippageWidget; + private StandardHeader preferredExchangesHeader; + private FlexboxLayout preferredSwapProviders; public SwapSettingsDialog(@NonNull Activity activity) { @@ -35,7 +43,7 @@ public SwapSettingsDialog(@NonNull Activity activity) setOnShowListener(dialogInterface -> { view.setMinimumHeight(Resources.getSystem().getDisplayMetrics().heightPixels); - BottomSheetBehaviorbehavior = BottomSheetBehavior.from((View) view.getParent()); + BottomSheetBehavior behavior = BottomSheetBehavior.from((View) view.getParent()); behavior.setState(STATE_EXPANDED); behavior.setSkipCollapsed(true); }); @@ -45,15 +53,55 @@ public SwapSettingsDialog(@NonNull Activity activity) ImageView closeBtn = findViewById(R.id.image_close); closeBtn.setOnClickListener(v -> dismiss()); + + preferredExchangesHeader = findViewById(R.id.header_exchanges); + preferredExchangesHeader.getTextControl().setOnClickListener(v -> { + Intent intent = new Intent(activity, SelectSwapProvidersActivity.class); + activity.startActivity(intent); + }); + + preferredSwapProviders = findViewById(R.id.layout_exchanges); } - public SwapSettingsDialog(Activity activity, List chains, SwapSettingsInterface swapSettingsInterface) + public SwapSettingsDialog(Activity activity, + List chains, + List swapProviders, + Set preferredSwapProviders, + SwapSettingsInterface swapSettingsInterface) { this(activity); ChainFilter filter = new ChainFilter(chains); adapter = new SelectChainAdapter(activity, filter.getSupportedChains(), swapSettingsInterface); chainList.setLayoutManager(new LinearLayoutManager(getContext())); chainList.setAdapter(adapter); + this.swapProviders = swapProviders; + setSwapProviders(preferredSwapProviders); + } + + private TextView createTextView(String name) + { + int margin = (int) getContext().getResources().getDimension(R.dimen.tiny_8); + FlexboxLayout.LayoutParams params = + new FlexboxLayout.LayoutParams(FlexboxLayout.LayoutParams.WRAP_CONTENT, FlexboxLayout.LayoutParams.WRAP_CONTENT); + params.setMargins(margin, margin, margin, margin); + + TextView exchange = new TextView(getContext(), null); + exchange.setText(name); + exchange.setLayoutParams(params); + return exchange; + } + + public void setSwapProviders(Set swapProviders) + { + preferredSwapProviders.removeAllViews(); + for (SwapProvider provider : this.swapProviders) + { + if (swapProviders.contains(provider.key)) + { + preferredSwapProviders.addView(createTextView(provider.name)); + } + } + preferredSwapProviders.invalidate(); } public void setChains(List chains) diff --git a/app/src/main/java/com/alphawallet/app/widget/TokenIcon.java b/app/src/main/java/com/alphawallet/app/widget/TokenIcon.java index 1d1fb5759a..cf8d566cc3 100644 --- a/app/src/main/java/com/alphawallet/app/widget/TokenIcon.java +++ b/app/src/main/java/com/alphawallet/app/widget/TokenIcon.java @@ -4,6 +4,8 @@ import android.content.Context; import android.content.res.TypedArray; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Looper; @@ -398,4 +400,21 @@ private void loadImageFromResource(int resourceId) icon.setVisibility(View.VISIBLE); findViewById(R.id.circle).setVisibility(View.VISIBLE); } + + public void setGrayscale(boolean grayscale) + { + if (grayscale) + { + ColorMatrix matrix = new ColorMatrix(); + matrix.setSaturation(0); + ColorMatrixColorFilter cf = new ColorMatrixColorFilter(matrix); + icon.setColorFilter(cf); + icon.setImageAlpha(128); + } + else + { + icon.setColorFilter(null); + icon.setImageAlpha(255); + } + } } diff --git a/app/src/main/java/com/alphawallet/app/widget/TokenInfoView.java b/app/src/main/java/com/alphawallet/app/widget/TokenInfoView.java index 956f177321..4d13f0149f 100644 --- a/app/src/main/java/com/alphawallet/app/widget/TokenInfoView.java +++ b/app/src/main/java/com/alphawallet/app/widget/TokenInfoView.java @@ -1,5 +1,9 @@ package com.alphawallet.app.widget; +import static android.content.Context.CLIPBOARD_SERVICE; + +import android.content.ClipData; +import android.content.ClipboardManager; import android.content.Context; import android.content.Intent; import android.content.res.TypedArray; @@ -9,11 +13,13 @@ import android.view.View; import android.widget.LinearLayout; import android.widget.TextView; +import android.widget.Toast; import androidx.core.content.ContextCompat; import com.alphawallet.app.R; import com.alphawallet.app.service.TickerService; +import com.alphawallet.app.util.Utils; public class TokenInfoView extends LinearLayout { @@ -79,6 +85,33 @@ public void setValue(String text) } } + public void setCopyableValue(String text) + { + if (!TextUtils.isEmpty(text)) + { + setVisibility(View.VISIBLE); + String display = text; + // If text is an instance of an address, format it; otherwise do nothing + if (Utils.isAddressValid(text)) + { + display = Utils.formatAddress(text); + } + TextView useView = getTextView(display.length()); + useView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_copy, 0); + useView.setText(display); + setCopyListener(useView, label.getText(), text); + } + } + + private void setCopyListener(TextView textView, CharSequence clipLabel, CharSequence clipValue) + { + textView.setOnClickListener(view -> { + ClipboardManager clipboard = (ClipboardManager) getContext().getSystemService(CLIPBOARD_SERVICE); + clipboard.setPrimaryClip(ClipData.newPlainText(clipLabel, clipValue)); + Toast.makeText(getContext(), R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show(); + }); + } + public void setCurrencyValue(double v) { setVisibility(View.VISIBLE); diff --git a/app/src/main/java/com/alphawallet/app/widget/TokenSelector.java b/app/src/main/java/com/alphawallet/app/widget/TokenSelector.java index 02768154fe..4c74fb4ec2 100644 --- a/app/src/main/java/com/alphawallet/app/widget/TokenSelector.java +++ b/app/src/main/java/com/alphawallet/app/widget/TokenSelector.java @@ -10,19 +10,16 @@ import android.util.AttributeSet; import android.view.View; import android.widget.EditText; -import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import androidx.core.content.ContextCompat; import com.alphawallet.app.R; -import com.alphawallet.app.entity.lifi.Connection; +import com.alphawallet.app.entity.lifi.Token; import com.alphawallet.app.util.Utils; -import com.bumptech.glide.Glide; import com.google.android.material.button.MaterialButton; - public class TokenSelector extends LinearLayout { private final Handler handler = new Handler(Looper.getMainLooper()); @@ -38,7 +35,7 @@ public class TokenSelector extends LinearLayout private final TextView error; private Runnable runnable; private TokenSelectorEventListener callback; - private Connection.LToken tokenItem; + private Token tokenItem; public TokenSelector(Context context, AttributeSet attrs) { @@ -146,7 +143,7 @@ public void reset() setVisibility(View.VISIBLE); } - public void init(Connection.LToken tokenItem) + public void init(Token tokenItem) { this.tokenItem = tokenItem; @@ -192,7 +189,7 @@ public void afterTextChanged(Editable editable) }); } - public Connection.LToken getToken() + public Token getToken() { return this.tokenItem; } @@ -202,14 +199,14 @@ public String getAmount() return editText.getText().toString(); } - public void clearAmount() + public void setAmount(String amount) { - editText.getText().clear(); + editText.setText(amount); } - public void setAmount(String amount) + public void clearAmount() { - editText.setText(amount); + editText.getText().clear(); } public void setBalance(String amount) @@ -258,7 +255,7 @@ public interface TokenSelectorEventListener /** * Triggered when a new Token is selected. **/ - void onSelectionChanged(Connection.LToken token); + void onSelectionChanged(Token token); /** * Triggered when the `Max` button is clicked. diff --git a/app/src/main/res/drawable/ic_sepolia_test.png b/app/src/main/res/drawable/ic_sepolia_test.png new file mode 100644 index 0000000000000000000000000000000000000000..1274b0f9287ed5d184dee5eba304b4fe115b7143 GIT binary patch literal 127735 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 zΠE7L*y1K2ilx*;g^{zUSmFpPqY+M=Ig4S&`b$bn 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

4-`PVWt|k8YZ-k)iF^58GuzAM)2guF=@mg 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 z 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 Qm;e9(07*qoM6N<$g3LHbhX4Qo literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/ic_swap_horizontal.xml b/app/src/main/res/drawable/ic_swap_horizontal.xml new file mode 100644 index 0000000000..5550dac617 --- /dev/null +++ b/app/src/main/res/drawable/ic_swap_horizontal.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/select_masking_circle.xml b/app/src/main/res/drawable/select_masking_circle.xml index 11731c2d51..d461be3579 100644 --- a/app/src/main/res/drawable/select_masking_circle.xml +++ b/app/src/main/res/drawable/select_masking_circle.xml @@ -5,8 +5,7 @@ android:thicknessRatio="1" android:useLevel="false"> + android:type="radial" /> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_my_address.xml b/app/src/main/res/layout/activity_my_address.xml index 7f92a97420..835a1c2dbc 100644 --- a/app/src/main/res/layout/activity_my_address.xml +++ b/app/src/main/res/layout/activity_my_address.xml @@ -78,7 +78,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" - custom:bold="true" /> + custom:lines="2" + custom:bold="true"/> diff --git a/app/src/main/res/layout/activity_nft_asset_detail.xml b/app/src/main/res/layout/activity_nft_asset_detail.xml index c94456e42b..1c6799a04a 100644 --- a/app/src/main/res/layout/activity_nft_asset_detail.xml +++ b/app/src/main/res/layout/activity_nft_asset_detail.xml @@ -119,6 +119,13 @@ android:visibility="gone" custom:tokenInfoLabel="@string/asset_total_supply" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_swap.xml b/app/src/main/res/layout/activity_swap.xml index 031fbbbc66..266a09e616 100644 --- a/app/src/main/res/layout/activity_swap.xml +++ b/app/src/main/res/layout/activity_swap.xml @@ -119,26 +119,41 @@ android:text="@string/action_open_settings" /> + + + android:visibility="gone" + tools:visibility="visible"> + + + custom:tokenInfoLabel="@string/label_provider" + tools:visibility="visible" /> + custom:tokenInfoLabel="@string/label_provider_website" /> + + + + diff --git a/app/src/main/res/layout/dialog_swap_settings.xml b/app/src/main/res/layout/dialog_swap_settings.xml index 54be936f8d..707fc4d1f2 100644 --- a/app/src/main/res/layout/dialog_swap_settings.xml +++ b/app/src/main/res/layout/dialog_swap_settings.xml @@ -3,6 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" + xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical"> + + + + @@ -43,6 +44,12 @@ app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" tools:visibility="visible" /> + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_chain_select.xml b/app/src/main/res/layout/item_chain_select.xml index c9ef1b78ba..19cd634062 100644 --- a/app/src/main/res/layout/item_chain_select.xml +++ b/app/src/main/res/layout/item_chain_select.xml @@ -9,13 +9,13 @@ android:paddingStart="@dimen/small_12" android:paddingEnd="@dimen/tiny_8"> - + tools:src="@drawable/ic_ethereum" /> + tools:text="0xbc9a1026a4bc6f0ba8bbe486d1d09da5732b39e4"/> + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_exchange.xml b/app/src/main/res/layout/item_exchange.xml new file mode 100644 index 0000000000..07fcf11177 --- /dev/null +++ b/app/src/main/res/layout/item_exchange.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_network_check.xml b/app/src/main/res/layout/item_network_check.xml index 6c75316adb..86791fad8d 100644 --- a/app/src/main/res/layout/item_network_check.xml +++ b/app/src/main/res/layout/item_network_check.xml @@ -14,54 +14,68 @@ android:id="@+id/manage_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_gravity="center_vertical" android:background="@color/transparent" - android:src="@drawable/ic_menu" android:contentDescription="@string/manage_tokens" - android:layout_gravity="center_vertical" + android:src="@drawable/ic_menu" android:visibility="gone" - app:tint="?colorControlNormal" - tools:visibility="visible" - app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintStart_toStartOf="parent"/> + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:tint="?colorControlNormal" + tools:visibility="visible" /> + android:src="@drawable/ic_ethereum" + app:layout_constraintStart_toEndOf="@id/manage_btn" + app:layout_constraintTop_toTopOf="parent" /> - + app:layout_constraintHorizontal_bias="0" + app:layout_constraintStart_toEndOf="@id/token_icon" + app:layout_constraintTop_toTopOf="parent"> + + + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/name" + android:layout_marginHorizontal="@dimen/tiny_8" + android:layout_toEndOf="@id/chain_id" + android:text="@string/deprecated" + android:textColor="?colorError" + android:visibility="gone" + tools:visibility="visible" /> - + + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" /> \ No newline at end of file diff --git a/app/src/main/res/layout/item_route.xml b/app/src/main/res/layout/item_route.xml new file mode 100644 index 0000000000..0dc18f33ac --- /dev/null +++ b/app/src/main/res/layout/item_route.xml @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/item_standard_header.xml b/app/src/main/res/layout/item_standard_header.xml index ffe880589c..4f6d76c72c 100644 --- a/app/src/main/res/layout/item_standard_header.xml +++ b/app/src/main/res/layout/item_standard_header.xml @@ -1,5 +1,6 @@ + android:visibility="gone" /> + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_token_info.xml b/app/src/main/res/layout/item_token_info.xml index a934824cae..9ad3f9b45f 100644 --- a/app/src/main/res/layout/item_token_info.xml +++ b/app/src/main/res/layout/item_token_info.xml @@ -29,6 +29,7 @@ android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_weight="0.6" + android:drawablePadding="@dimen/tiny_8" android:ellipsize="end" android:gravity="end" android:singleLine="true" @@ -40,6 +41,7 @@ android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_weight="0.6" + android:drawablePadding="@dimen/tiny_8" android:ellipsize="end" android:gravity="end" android:maxLines="2" diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index a0bd86d60d..bec5a3ea09 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -915,4 +915,18 @@ Política de privacidad Términos de servicio Billeteras conectadas + Rareza + Intercambios preferidos + Tarifa de gasolina: %s + Fetching Routes + Obtención de rutas + Seleccionar intercambios + Nuevas rutas en %s + Cantidad a intercambiar + Sitio web del proveedor + Detalles de cotización + Intercambiar a través de %s + No se encontraron rutas para los parámetros dados. + Seleccione al menos un intercambio. + Obsoleta diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 4d8692c96e..cd1203d2c3 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -928,4 +928,18 @@ Politique de confidentialité Conditions d\'utilisation Portefeuilles connectés + Rareté + Échanges préférés + Frais de gaz: %s + Récupération d\'itinéraires + Sélectionnez l\'itinéraire + Sélectionnez les échanges + Nouvelles routes dans %s + Montant à échanger + Site Web du fournisseur + Détails du devis + Échange via %s + Aucune route trouvée pour les paramètres donnés. + Sélectionnez au moins un échange. + Obsolète diff --git a/app/src/main/res/values-id/strings.xml b/app/src/main/res/values-id/strings.xml index 1813da9709..43ea87cfa1 100644 --- a/app/src/main/res/values-id/strings.xml +++ b/app/src/main/res/values-id/strings.xml @@ -928,4 +928,18 @@ Kebijakan pribadi Ketentuan Layanan Dompet yang terhubung + Keanehan + Pertukaran Pilihan + Pertukaran Pilihan: %s + Mengambil Rute + Pilih Rute + Pilih Pertukaran + Rute Baru di %s + Jumlah Untuk Tukar + Provider Website + Detail Kutipan + Tukar melalui %s + Tidak ada rute yang ditemukan untuk parameter yang diberikan. + Pilih setidaknya satu bursa. + Tidak digunakan lagi diff --git a/app/src/main/res/values-my/strings.xml b/app/src/main/res/values-my/strings.xml index 5cbbeade8e..23deb928f5 100644 --- a/app/src/main/res/values-my/strings.xml +++ b/app/src/main/res/values-my/strings.xml @@ -949,4 +949,18 @@ %1$s တိုကင် %1$s ချိန်ခွင်လျှာမလုံလောက် ကိုယ်ရေးအချက်အလက်မူဝါဒ + ရှားပါးသည်။ + နှစ်သက်သော ဖလှယ်မှုများ + ဓာတ်ငွေ့ကြေး: %s + လမ်းကြောင်းများ ရယူခြင်း။ + လမ်းကြောင်းကို ရွေးပါ။ + Exchanges ကို ရွေးပါ။ + လမ်းကြောင်းအသစ်များ %s + လဲလှယ်ရန် ပမာဏ + ဝန်ဆောင်မှုပေးသော ဝဘ်ဆိုဒ် + ကိုးကားအသေးစိတ် + မှတဆင့်လဲလှယ်ပါ။ %s + ပေးထားသော ကန့်သတ်ဘောင်များအတွက် လမ်းကြောင်းများ ရှာမတွေ့ပါ။ + အနည်းဆုံးလဲလှယ်မှုတစ်ခုကို ရွေးပါ။ + ကန့်ကွက်ထားသည်။ diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 5ca3d08798..9fd3ec0ff7 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -928,4 +928,18 @@ Không đủ %1$s cân bằng Chuyển giao an toàn Ví kết nối + Việc hiếm có + Sở giao dịch ưu tiên + Phí xăng: %s + Tìm nạp các tuyến đường + Chọn tuyến đường + Chọn trao đổi + Các tuyến đường mới trong %s + Số tiền để hoán đổi + Trang web của nhà cung cấp + Trích dẫn Chi tiết + Hoán đổi qua %s + Không tìm thấy các tuyến đường cho các thông số đã cho. + Chọn ít nhất một sàn giao dịch. + Không được chấp nhận diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index f6076d7f29..8347dc8766 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -915,4 +915,18 @@ 隐私政策 服务条款 已连接的钱包 + 稀有度 + 首选交易所 + 汽油费: %s + 获取路线 + 选择路线 + 选择交易所 + 新航线 %s + 交换金额 + 提供者网站 + 报价详情 + 通过 %s 交换 + 没有找到给定参数的路由。 + 至少选择一个交易所。 + 已弃用 diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 13c29970b6..079fbaad27 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -36,8 +36,12 @@ + + + + @@ -72,6 +76,7 @@ + diff --git a/app/src/main/res/values/colors_misc.xml b/app/src/main/res/values/colors_misc.xml index e76582bb6b..cfae5b3a40 100644 --- a/app/src/main/res/values/colors_misc.xml +++ b/app/src/main/res/values/colors_misc.xml @@ -50,4 +50,5 @@ #222222 #292929 #8176c2 + #67b1d4 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c71e964c64..6720729071 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -932,7 +932,8 @@ Slippage Open Settings No connections found for this chain. - Fees + Gas Fee + Other Fees Current Price Minimum Received Balance: @@ -988,4 +989,18 @@ | ETH 0 + Rarity + Preferred Exchanges + Gas Fee: %s + Fetching Routes + Select Route + Select Exchanges + New Routes in %s + Amount To Swap + Provider Website + Quote Details + Swap via %s + No routes found for the given parameters. + Select at least one exchange. + Deprecated diff --git a/lib/src/main/java/com/alphawallet/ethereum/EthereumNetworkBase.java b/lib/src/main/java/com/alphawallet/ethereum/EthereumNetworkBase.java index 835cee2d0c..2aab7dd7ab 100644 --- a/lib/src/main/java/com/alphawallet/ethereum/EthereumNetworkBase.java +++ b/lib/src/main/java/com/alphawallet/ethereum/EthereumNetworkBase.java @@ -47,6 +47,9 @@ public abstract class EthereumNetworkBase { // implements EthereumNetworkReposit public static final long MILKOMEDA_C1_TEST_ID = 200101; public static final long PHI_MAIN_ID = 4181; public static final long PHI_V2_MAIN_ID = 144; + public static final long SEPOLIA_TESTNET_ID = 11155111; + public static final long OPTIMISM_GOERLI_TEST_ID = 420; + public static final long ARBITRUM_GOERLI_TEST_ID = 421613; public static final String MAINNET_RPC_URL = "https://mainnet.infura.io/v3/da3717f25f824cc1baa32d812386d93f"; @@ -62,7 +65,7 @@ public abstract class EthereumNetworkBase { // implements EthereumNetworkReposit public static final String ARTIS_TAU1_RPC_URL = "https://rpc.tau1.artis.network"; public static final String BINANCE_TEST_RPC_URL = "https://data-seed-prebsc-1-s3.binance.org:8545"; public static final String BINANCE_MAIN_RPC_URL = "https://bsc-dataseed.binance.org"; - public static final String HECO_RPC_URL = "https://http-mainnet-node.huobichain.com"; + public static final String HECO_RPC_URL = "https://http-mainnet.hecochain.com"; public static final String HECO_TEST_RPC_URL = "https://http-testnet.hecochain.com"; public static final String AVALANCHE_RPC_URL = "https://api.avax.network/ext/bc/C/rpc"; public static final String FUJI_TEST_RPC_URL = "https://api.avax-test.network/ext/bc/C/rpc"; @@ -70,8 +73,8 @@ public abstract class EthereumNetworkBase { // implements EthereumNetworkReposit public static final String FANTOM_TEST_RPC_URL = "https://rpc.testnet.fantom.network"; public static final String MATIC_RPC_URL = "https://matic-mainnet.chainstacklabs.com"; public static final String MUMBAI_TEST_RPC_URL = "https://matic-mumbai.chainstacklabs.com"; - public static final String OPTIMISTIC_MAIN_URL = "https://mainnet.optimism.io"; - public static final String OPTIMISTIC_TEST_URL = "https://kovan.optimism.io"; + public static final String OPTIMISTIC_MAIN_FALLBACK_URL = "https://mainnet.optimism.io"; + public static final String OPTIMISTIC_TEST_FALLBACK_URL = "https://kovan.optimism.io"; public static final String CRONOS_MAIN_RPC_URL = "https://evm.cronos.org"; public static final String CRONOS_TEST_URL = "https://evm-t3.cronos.org"; public static final String ARBITRUM_RPC_URL = "https://arbitrum-mainnet.infura.io/v3/da3717f25f824cc1baa32d812386d93f"; @@ -86,6 +89,11 @@ public abstract class EthereumNetworkBase { // implements EthereumNetworkReposit public static final String MILKOMEDA_C1_TEST_RPC = "https://rpc-devnet-cardano-evm.c1.milkomeda.com"; public static final String PHI_MAIN_RPC_URL = "https://rpc1.phi.network"; public static final String PHI_NETWORK_V2_RPC = "https://connect.phi.network"; + public static final String SEPOLIA_TESTNET_RPC_URL = "https://rpc.sepolia.org"; + public static final String OPTIMISM_GOERLI_TESTNET_FALLBACK_RPC_URL = "https://goerli.optimism.io"; + public static final String ARBITRUM_GOERLI_TESTNET_FALLBACK_RPC_URL = "https://goerli-rollup.arbitrum.io/rpc"; + public static final String IOTEX_MAINNET_RPC_URL = "https://babel-api.mainnet.iotex.io"; + public static final String IOTEX_TESTNET_RPC_URL = "https://babel-api.testnet.iotex.io"; static Map networkMap = new LinkedHashMap() { { @@ -135,9 +143,9 @@ public abstract class EthereumNetworkBase { // implements EthereumNetworkReposit put(POLYGON_TEST_ID, new NetworkInfo("Mumbai (Test)", "POLY", MUMBAI_TEST_RPC_URL, "https://mumbai.polygonscan.com/tx/", POLYGON_TEST_ID, false)); - put(OPTIMISTIC_MAIN_ID, new NetworkInfo("Optimistic","ETH", OPTIMISTIC_MAIN_URL, "https://optimistic.etherscan.io/tx/", + put(OPTIMISTIC_MAIN_ID, new NetworkInfo("Optimistic","ETH", OPTIMISTIC_MAIN_FALLBACK_URL, "https://optimistic.etherscan.io/tx/", OPTIMISTIC_MAIN_ID, false)); - put(OPTIMISTIC_TEST_ID, new NetworkInfo("Optimistic (Test)", "ETH", OPTIMISTIC_TEST_URL, "https://kovan-optimistic.etherscan.io/tx/", + put(OPTIMISTIC_TEST_ID, new NetworkInfo("Optimistic (Test)", "ETH", OPTIMISTIC_TEST_FALLBACK_URL, "https://kovan-optimistic.etherscan.io/tx/", OPTIMISTIC_TEST_ID, false)); put(CRONOS_MAIN_ID, new NetworkInfo("Cronos (Beta)", "CRO", CRONOS_MAIN_RPC_URL, "https://cronoscan.com/tx", CRONOS_MAIN_ID, false)); put(CRONOS_TEST_ID, new NetworkInfo("Cronos (Test)", "tCRO", CRONOS_TEST_URL, "https://testnet.cronoscan.com/tx/", CRONOS_TEST_ID, false)); @@ -168,6 +176,16 @@ public abstract class EthereumNetworkBase { // implements EthereumNetworkReposit PHI_MAIN_ID, false)); put(PHI_V2_MAIN_ID, new NetworkInfo("PHI v2", "\u03d5", PHI_NETWORK_V2_RPC, "https://phiscan.com/tx/", PHI_V2_MAIN_ID, false)); + put(SEPOLIA_TESTNET_ID, new NetworkInfo("Sepolia (Test)", "ETH", SEPOLIA_TESTNET_RPC_URL, "https://sepolia.etherscan.io/tx/", + SEPOLIA_TESTNET_ID, false)); + put(OPTIMISM_GOERLI_TEST_ID, new NetworkInfo("Optimism Goerli (Test)", "ETH", OPTIMISM_GOERLI_TESTNET_FALLBACK_RPC_URL, "https://blockscout.com/optimism/goerli/tx/", + OPTIMISM_GOERLI_TEST_ID, false)); + put(ARBITRUM_GOERLI_TEST_ID, new NetworkInfo("Arbitrum Goerli (Test)", "AGOR", OPTIMISM_GOERLI_TESTNET_FALLBACK_RPC_URL, "https://goerli-rollup-explorer.arbitrum.io/tx/", + ARBITRUM_GOERLI_TEST_ID, false)); + put(IOTEX_MAINNET_ID, new NetworkInfo("IoTeX","IOTX", IOTEX_MAINNET_RPC_URL, "https://iotexscan.io/tx/", + IOTEX_MAINNET_ID, false)); + put(IOTEX_TESTNET_ID, new NetworkInfo("IoTeX (Test)","IOTX", IOTEX_TESTNET_RPC_URL, "https://testnet.iotexscan.io/tx/", + IOTEX_TESTNET_ID, false)); } }; From d1109d2ef2f2a7e542018cead979a16b1b847fc6 Mon Sep 17 00:00:00 2001 From: James Brown Date: Thu, 3 Nov 2022 15:44:19 +1100 Subject: [PATCH 10/36] Add RPC validation fix, swap providers and bump gradle --- app/build.gradle | 4 +- app/src/main/assets/swap_providers_list.json | 110 ++++++++++++++++++ .../app/repository/EthereumNetworkBase.java | 6 + .../app/service/TickerService.java | 6 + .../app/ui/DappBrowserFragment.java | 27 ++++- .../java/com/alphawallet/app/util/Utils.java | 2 +- .../app/util/pattern/Patterns.java | 79 +++++++++++++ .../app/viewmodel/DappBrowserViewModel.java | 50 +++++++- 8 files changed, 273 insertions(+), 11 deletions(-) create mode 100644 app/src/main/assets/swap_providers_list.json create mode 100644 app/src/main/java/com/alphawallet/app/util/pattern/Patterns.java diff --git a/app/build.gradle b/app/build.gradle index fb1fd365f3..52234219b1 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -85,8 +85,8 @@ android { } } defaultConfig { - versionCode 207 - versionName "3.60" + versionCode 208 + versionName "3.60.1" applicationId "io.stormbird.wallet" minSdkVersion 23 diff --git a/app/src/main/assets/swap_providers_list.json b/app/src/main/assets/swap_providers_list.json new file mode 100644 index 0000000000..6bfd9baaf9 --- /dev/null +++ b/app/src/main/assets/swap_providers_list.json @@ -0,0 +1,110 @@ +[ + { + "key": "dodo", + "name": "DODO", + "url": "https://dodoex.io/", + "logoURI": "https://raw.githubusercontent.com/lifinance/types/main/src/assets/icons/exchanges/dodo.png" + }, + { + "key": "paraswap", + "name": "ParaSwap", + "url": "https://www.paraswap.io/", + "logoURI": "https://raw.githubusercontent.com/lifinance/types/main/src/assets/icons/exchanges/paraswap.png" + }, + { + "key": "1inch", + "name": "1inch", + "url": "https://1inch.io/", + "logoURI": "https://raw.githubusercontent.com/lifinance/types/main/src/assets/icons/exchanges/oneinch.png" + }, + { + "key": "openocean", + "name": "OpenOcean", + "url": "https://openocean.finance/", + "logoURI": "https://raw.githubusercontent.com/lifinance/types/main/src/assets/icons/exchanges/openocean.png" + }, + { + "key": "0x", + "name": "0x", + "url": "https://www.0x.org/", + "logoURI": "https://raw.githubusercontent.com/lifinance/types/main/src/assets/icons/exchanges/zerox.png" + }, + { + "key": "superfluid", + "name": "Superfluid", + "url": "https://www.superfluid.finance/", + "logoURI": "https://www.superfluid.finance/icons/icon-72x72.png" + }, + { + "key": "uniswap", + "name": "UniswapV2", + "url": "https://uniswap.org/", + "logoURI": "https://raw.githubusercontent.com/lifinance/types/main/src/assets/icons/exchanges/uniswap.png" + }, + { + "key": "quickswap", + "name": "QuickSwap", + "url": "https://quickswap.exchange/", + "logoURI": "https://raw.githubusercontent.com/lifinance/types/main/src/assets/icons/exchanges/quick.png" + }, + { + "key": "pancakeswap", + "name": "PancakeSwap", + "url": "https://pancakeswap.finance/", + "logoURI": "https://raw.githubusercontent.com/lifinance/types/main/src/assets/icons/exchanges/pancake.png" + }, + { + "key": "honeyswap", + "name": "Honeyswap", + "url": "https://honeyswap.org/", + "logoURI": "https://raw.githubusercontent.com/lifinance/types/main/src/assets/icons/exchanges/honey.png" + }, + { + "key": "spookyswap", + "name": "SpookySwap", + "url": "https://spooky.fi/", + "logoURI": "https://raw.githubusercontent.com/lifinance/types/main/src/assets/icons/exchanges/spooky.png" + }, + { + "key": "spiritswap", + "name": "SpiritSwap", + "url": "https://www.spiritswap.finance/", + "logoURI": "https://github.com/Layer3Org/spiritswap-tokens-list-icon/blob/master/token-list/images/inspirit.png?raw=true" + }, + { + "key": "solarbeam", + "name": "Solarbeam", + "url": "https://solarbeam.io/", + "logoURI": "https://raw.githubusercontent.com/lifinance/types/main/src/assets/icons/exchanges/solarbeam.png" + }, + { + "key": "jswap", + "name": "JSwap", + "url": "https://app.jswap.finance/", + "logoURI": "https://raw.githubusercontent.com/lifinance/types/main/src/assets/icons/exchanges/jswap.png" + }, + { + "key": "cronaswap", + "name": "CronaSwap", + "url": "https://app.cronaswap.org/", + "logoURI": "https://raw.githubusercontent.com/lifinance/types/main/src/assets/icons/exchanges/cronaswap.png" + }, + { + "key": "voltage", + "name": "Voltage", + "url": "https://app.voltage.finance/", + "logoURI": "https://raw.githubusercontent.com/lifinance/types/main/src/assets/icons/exchanges/voltage.png" + }, + { + "key": "ubeswap", + "name": "UbeSwap", + "url": "https://ubeswap.org/", + "logoURI": "https://raw.githubusercontent.com/lifinance/types/main/src/assets/icons/exchanges/ubeswap.png" + }, + { + "key": "sushiswap", + "name": "SushiSwap", + "url": "https://sushi.com/", + "logoURI": "https://raw.githubusercontent.com/lifinance/types/main/src/assets/icons/exchanges/sushi.png" + } +] \ No newline at end of file diff --git a/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java b/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java index 2c386047bc..3f9be9a895 100644 --- a/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java +++ b/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java @@ -3,6 +3,7 @@ /* Please don't add import android at this point. Later this file will be shared * between projects including non-Android projects */ +import static com.alphawallet.app.util.Utils.isValidUrl; import static com.alphawallet.ethereum.EthereumNetworkBase.ARBITRUM_GOERLI_TESTNET_FALLBACK_RPC_URL; import static com.alphawallet.ethereum.EthereumNetworkBase.ARBITRUM_GOERLI_TEST_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.ARBITRUM_MAIN_ID; @@ -622,6 +623,11 @@ public void restore() for (NetworkInfo info : list) { + if (!isValidUrl(info.rpcServerUrl)) //ensure RPC doesn't contain malicious code + { + continue; + } + networkMap.put(info.chainId, info); Boolean value = mapToTestNet.get(info.chainId); boolean isTestnet = value != null && value; diff --git a/app/src/main/java/com/alphawallet/app/service/TickerService.java b/app/src/main/java/com/alphawallet/app/service/TickerService.java index 152db1d135..831df164c1 100644 --- a/app/src/main/java/com/alphawallet/app/service/TickerService.java +++ b/app/src/main/java/com/alphawallet/app/service/TickerService.java @@ -16,6 +16,7 @@ import static com.alphawallet.ethereum.EthereumNetworkBase.MAINNET_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.MILKOMEDA_C1_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.OPTIMISTIC_MAIN_ID; +import static com.alphawallet.ethereum.EthereumNetworkBase.PHI_MAIN_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.PHI_V2_MAIN_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.POA_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.POLYGON_ID; @@ -434,6 +435,10 @@ private void checkPeggedTickers(long chainId, TokenTicker ticker) ethTickers.put(ARBITRUM_MAIN_ID, ticker); ethTickers.put(OPTIMISTIC_MAIN_ID, ticker); } + else if (chainId == PHI_V2_MAIN_ID) + { + ethTickers.put(PHI_MAIN_ID, ticker); + } } private void addToTokenTickers(BigInteger tickerInfo, long tickerTime) @@ -527,6 +532,7 @@ private int addPhiTickers(int tickerCount) System.currentTimeMillis()); ethTickers.put(PHI_V2_MAIN_ID, phiTicker); + ethTickers.put(PHI_MAIN_ID, phiTicker); return tickerCount + 1; } } diff --git a/app/src/main/java/com/alphawallet/app/ui/DappBrowserFragment.java b/app/src/main/java/com/alphawallet/app/ui/DappBrowserFragment.java index df3471244d..302450c77c 100644 --- a/app/src/main/java/com/alphawallet/app/ui/DappBrowserFragment.java +++ b/app/src/main/java/com/alphawallet/app/ui/DappBrowserFragment.java @@ -1238,8 +1238,14 @@ public void onWalletAddEthereumChainObject(long callbackId, WalletAddEthereumCha { // show add custom chain dialog addCustomChainDialog = new AddEthereumChainPrompt(getContext(), chainObj, chainObject -> { - viewModel.addCustomChain(chainObject); - loadNewNetwork(chainObj.getChainId()); + if (viewModel.addCustomChain(chainObject)) + { + loadNewNetwork(chainObj.getChainId()); + } + else + { + displayError(R.string.error_invalid_url, 0); + } addCustomChainDialog.dismiss(); }); addCustomChainDialog.show(); @@ -1438,6 +1444,23 @@ private void txError(Throwable throwable) confirmationDialog.dismiss(); } + private void displayError(int title, int text) + { + if (resultDialog != null && resultDialog.isShowing()) resultDialog.dismiss(); + resultDialog = new AWalletAlertDialog(requireContext()); + resultDialog.setIcon(ERROR); + resultDialog.setTitle(title); + if (text != 0) resultDialog.setMessage(text); + resultDialog.setButtonText(R.string.button_ok); + resultDialog.setButtonListener(v -> { + resultDialog.dismiss(); + }); + resultDialog.show(); + + if (confirmationDialog != null && confirmationDialog.isShowing()) + confirmationDialog.dismiss(); + } + private void showWalletWatch() { if (resultDialog != null && resultDialog.isShowing()) resultDialog.dismiss(); diff --git a/app/src/main/java/com/alphawallet/app/util/Utils.java b/app/src/main/java/com/alphawallet/app/util/Utils.java index 0c77f05484..0faf60c106 100644 --- a/app/src/main/java/com/alphawallet/app/util/Utils.java +++ b/app/src/main/java/com/alphawallet/app/util/Utils.java @@ -20,7 +20,6 @@ import android.text.TextUtils; import android.text.format.DateUtils; import android.text.style.StyleSpan; -import android.util.Patterns; import android.util.TypedValue; import android.webkit.URLUtil; @@ -31,6 +30,7 @@ import com.alphawallet.app.C; import com.alphawallet.app.R; import com.alphawallet.app.entity.tokens.Token; +import com.alphawallet.app.util.pattern.Patterns; import com.alphawallet.app.web3j.StructuredDataEncoder; import com.alphawallet.token.entity.ProviderTypedData; import com.alphawallet.token.entity.Signable; diff --git a/app/src/main/java/com/alphawallet/app/util/pattern/Patterns.java b/app/src/main/java/com/alphawallet/app/util/pattern/Patterns.java new file mode 100644 index 0000000000..cf15e07199 --- /dev/null +++ b/app/src/main/java/com/alphawallet/app/util/pattern/Patterns.java @@ -0,0 +1,79 @@ +package com.alphawallet.app.util.pattern; + +import java.util.regex.Pattern; + +/** + * Created by JB on 1/11/2022. + * + * Lifted from Android OS standard 'Patterns' file + * Reason for separation :- Android file not available for test suite + * + */ +public class Patterns +{ + private static final String UCS_CHAR = "[" + + "\u00A0-\uD7FF" + + "\uF900-\uFDCF" + + "\uFDF0-\uFFEF" + + "\uD800\uDC00-\uD83F\uDFFD" + + "\uD840\uDC00-\uD87F\uDFFD" + + "\uD880\uDC00-\uD8BF\uDFFD" + + "\uD8C0\uDC00-\uD8FF\uDFFD" + + "\uD900\uDC00-\uD93F\uDFFD" + + "\uD940\uDC00-\uD97F\uDFFD" + + "\uD980\uDC00-\uD9BF\uDFFD" + + "\uD9C0\uDC00-\uD9FF\uDFFD" + + "\uDA00\uDC00-\uDA3F\uDFFD" + + "\uDA40\uDC00-\uDA7F\uDFFD" + + "\uDA80\uDC00-\uDABF\uDFFD" + + "\uDAC0\uDC00-\uDAFF\uDFFD" + + "\uDB00\uDC00-\uDB3F\uDFFD" + + "\uDB44\uDC00-\uDB7F\uDFFD" + + "&&[^\u00A0[\u2000-\u200A]\u2028\u2029\u202F\u3000]]"; + + private static final String LABEL_CHAR = "a-zA-Z0-9" + UCS_CHAR; + + /** + * Valid characters for IRI TLD defined in RFC 3987. + */ + + private static final String WORD_BOUNDARY = "(?:\\b|$|^)"; + private static final String IRI_LABEL = + "[" + LABEL_CHAR + "](?:[" + LABEL_CHAR + "_\\-]{0,61}[" + LABEL_CHAR + "]){0,1}"; + private static final String PUNYCODE_TLD = "xn\\-\\-[\\w\\-]{0,58}\\w"; + private static final String TLD_CHAR = "a-zA-Z" + UCS_CHAR; + private static final String TLD = "(" + PUNYCODE_TLD + "|" + "[" + TLD_CHAR + "]{2,63}" +")"; + + private static final String USER_INFO = "(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)" + + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_" + + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@"; + + private static final String HOST_NAME = "(" + IRI_LABEL + "\\.)+" + TLD; + + private static final String IP_ADDRESS_STRING = + "((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]" + + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]" + + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}" + + "|[1-9][0-9]|[0-9]))"; + + private static final String DOMAIN_NAME_STR = "(" + HOST_NAME + "|" + IP_ADDRESS_STRING + ")"; + public static final Pattern DOMAIN_NAME = Pattern.compile(DOMAIN_NAME_STR); + + private static final String PROTOCOL = "(?i:http|https|rtsp|ftp)://"; + + private static final String PORT_NUMBER = "\\:\\d{1,5}"; + + private static final String PATH_AND_QUERY = "[/\\?](?:(?:[" + LABEL_CHAR + + ";/\\?:@&=#~" // plus optional query params + + "\\-\\.\\+!\\*'\\(\\),_\\$])|(?:%[a-fA-F0-9]{2}))*"; + + public static Pattern WEB_URL = Pattern.compile("(" + + "(" + + "(?:" + PROTOCOL + "(?:" + USER_INFO + ")?" + ")?" + + "(?:" + DOMAIN_NAME_STR + ")" + + "(?:" + PORT_NUMBER + ")?" + + ")" + + "(" + PATH_AND_QUERY + ")?" + + WORD_BOUNDARY + + ")"); +} diff --git a/app/src/main/java/com/alphawallet/app/viewmodel/DappBrowserViewModel.java b/app/src/main/java/com/alphawallet/app/viewmodel/DappBrowserViewModel.java index 6b52a45fe8..29e314b886 100644 --- a/app/src/main/java/com/alphawallet/app/viewmodel/DappBrowserViewModel.java +++ b/app/src/main/java/com/alphawallet/app/viewmodel/DappBrowserViewModel.java @@ -1,6 +1,7 @@ package com.alphawallet.app.viewmodel; import static com.alphawallet.app.C.Key.WALLET; +import static com.alphawallet.app.util.Utils.isValidUrl; import android.app.Activity; import android.content.Context; @@ -350,15 +351,49 @@ public String getSessionId(String url) return Uri.parse(uriString).getUserInfo(); } - public void addCustomChain(WalletAddEthereumChainObject chainObject) { - this.ethereumNetworkRepository.saveCustomRPCNetwork(chainObject.chainName, extractRpc(chainObject), chainObject.getChainId(), - chainObject.nativeCurrency.symbol, "", "", false, -1L); + public boolean addCustomChain(WalletAddEthereumChainObject chainObject) + { + String rpc = extractRpc(chainObject); + if (rpc == null) return false; + + this.ethereumNetworkRepository.saveCustomRPCNetwork(chainObject.chainName, rpc, chainObject.getChainId(), + chainObject.nativeCurrency.symbol, extractBlockExplorer(chainObject), "", false, -1L); tokensService.createBaseToken(chainObject.getChainId()) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.io()) - .subscribe(w -> { }, e -> { }) + .subscribe(w -> {}, e -> {}) .isDisposed(); + + return true; + } + + private String extractBlockExplorer(WalletAddEthereumChainObject chainObject) + { + for (String thisRpc : chainObject.blockExplorerUrls) + { + if (isValidUrl(thisRpc)) //ensure RPC doesn't contain malicious code + { + String retRpc = thisRpc; + if (thisRpc.endsWith("/tx")) + { + retRpc = thisRpc + "/"; + } + else if (!thisRpc.endsWith("/tx/")) + { + if (!thisRpc.endsWith("/")) + { + retRpc = thisRpc + "/"; + } + + retRpc = retRpc + "tx/"; + } + + return retRpc; + } + } + + return ""; } //NB Chain descriptions can contain WSS socket defs, which might come first. @@ -366,10 +401,13 @@ private String extractRpc(WalletAddEthereumChainObject chainObject) { for (String thisRpc : chainObject.rpcUrls) { - if (thisRpc.toLowerCase().startsWith("http")) { return thisRpc; } + if (isValidUrl(thisRpc)) //ensure RPC doesn't contain malicious code + { + return thisRpc; + } } - return ""; + return null; } public boolean isMainNetsSelected() From ff528b72f97a7a69aedc391197f167ffa4b252ce Mon Sep 17 00:00:00 2001 From: James Brown Date: Fri, 4 Nov 2022 19:26:22 +1100 Subject: [PATCH 11/36] test release --- app/build.gradle | 7 +++++-- .../java/com/alphawallet/app/util/RateApp.java | 2 +- .../com/alphawallet/app/util/UpdateUtils.java | 18 ++++++++++++------ app/src/main/AndroidManifest.xml | 1 + build.gradle | 2 +- 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 52234219b1..2062550ab8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -85,7 +85,7 @@ android { } } defaultConfig { - versionCode 208 + versionCode 210 versionName "3.60.1" applicationId "io.stormbird.wallet" @@ -352,7 +352,10 @@ dependencies { implementation 'androidx.work:work-runtime:2.7.1' //Analytics - analyticsImplementation 'com.google.android.play:core:1.10.3' + //analyticsImplementation 'com.google.android.play:core:1.10.3' + analyticsImplementation 'com.google.android.play:review:2.0.1' + implementation 'com.google.android.play:core-common:2.0.2' + implementation 'com.google.android.play:app-update:2.0.1' analyticsImplementation 'com.google.firebase:firebase-analytics:21.1.1' analyticsImplementation 'com.mixpanel.android:mixpanel-android:5.8.4' analyticsImplementation 'com.google.firebase:firebase-crashlytics:18.2.13' diff --git a/app/src/analytics/java/com/alphawallet/app/util/RateApp.java b/app/src/analytics/java/com/alphawallet/app/util/RateApp.java index 0bc6ff9ecd..23614bfba9 100644 --- a/app/src/analytics/java/com/alphawallet/app/util/RateApp.java +++ b/app/src/analytics/java/com/alphawallet/app/util/RateApp.java @@ -9,11 +9,11 @@ import com.alphawallet.app.R; import com.alphawallet.app.repository.PreferenceRepositoryType; +import com.google.android.gms.tasks.Task; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.play.core.review.ReviewInfo; import com.google.android.play.core.review.ReviewManager; import com.google.android.play.core.review.ReviewManagerFactory; -import com.google.android.play.core.tasks.Task; public class RateApp { // should be shown on 5th run or after the first transaction (afterTransaction == true) diff --git a/app/src/analytics/java/com/alphawallet/app/util/UpdateUtils.java b/app/src/analytics/java/com/alphawallet/app/util/UpdateUtils.java index d928006dbe..08f8d7c767 100644 --- a/app/src/analytics/java/com/alphawallet/app/util/UpdateUtils.java +++ b/app/src/analytics/java/com/alphawallet/app/util/UpdateUtils.java @@ -1,15 +1,15 @@ package com.alphawallet.app.util; import android.app.Activity; +import android.content.Intent; +import android.net.Uri; import com.alphawallet.app.entity.FragmentMessenger; +import com.google.android.gms.tasks.Task; import com.google.android.play.core.appupdate.AppUpdateInfo; import com.google.android.play.core.appupdate.AppUpdateManager; import com.google.android.play.core.appupdate.AppUpdateManagerFactory; -import com.google.android.play.core.appupdate.AppUpdateOptions; -import com.google.android.play.core.install.model.AppUpdateType; import com.google.android.play.core.install.model.UpdateAvailability; -import com.google.android.play.core.tasks.Task; public class UpdateUtils { public static void checkForUpdates(Activity context, FragmentMessenger messenger) { @@ -25,9 +25,15 @@ public static void checkForUpdates(Activity context, FragmentMessenger messenger }); } - public static void pushUpdateDialog(Activity context) + public static void pushUpdateDialog(Activity activity) { - AppUpdateManager appUpdateManager = AppUpdateManagerFactory.create(context); + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse("https://play.google.com/store/apps/details?id=" + activity.getPackageName())); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NO_ANIMATION); + + activity.startActivity(intent); + + /*AppUpdateManager appUpdateManager = AppUpdateManagerFactory.create(context); Task appUpdateInfoTask = appUpdateManager.getAppUpdateInfo(); @@ -36,6 +42,6 @@ public static void pushUpdateDialog(Activity context) { appUpdateManager.startUpdateFlow(appUpdateInfo, context, AppUpdateOptions.newBuilder(AppUpdateType.FLEXIBLE).build()); } - }); + });*/ } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 69a9ec1da4..4c934317d2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -13,6 +13,7 @@ + Date: Wed, 9 Nov 2022 12:12:44 +1100 Subject: [PATCH 12/36] Remove play library to push release through --- app/build.gradle | 7 +---- .../com/alphawallet/app/util/RateApp.java | 28 ++++++------------- .../com/alphawallet/app/util/UpdateUtils.java | 10 ++----- app/src/main/res/values-my/strings.xml | 2 +- 4 files changed, 14 insertions(+), 33 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 2062550ab8..bc50bfed02 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -85,7 +85,7 @@ android { } } defaultConfig { - versionCode 210 + versionCode 211 versionName "3.60.1" applicationId "io.stormbird.wallet" @@ -351,11 +351,6 @@ dependencies { implementation 'androidx.work:work-runtime:2.7.1' - //Analytics - //analyticsImplementation 'com.google.android.play:core:1.10.3' - analyticsImplementation 'com.google.android.play:review:2.0.1' - implementation 'com.google.android.play:core-common:2.0.2' - implementation 'com.google.android.play:app-update:2.0.1' analyticsImplementation 'com.google.firebase:firebase-analytics:21.1.1' analyticsImplementation 'com.mixpanel.android:mixpanel-android:5.8.4' analyticsImplementation 'com.google.firebase:firebase-crashlytics:18.2.13' diff --git a/app/src/analytics/java/com/alphawallet/app/util/RateApp.java b/app/src/analytics/java/com/alphawallet/app/util/RateApp.java index 23614bfba9..8118154b2b 100644 --- a/app/src/analytics/java/com/alphawallet/app/util/RateApp.java +++ b/app/src/analytics/java/com/alphawallet/app/util/RateApp.java @@ -1,6 +1,8 @@ package com.alphawallet.app.util; import android.app.Activity; +import android.content.Intent; +import android.net.Uri; import android.view.LayoutInflater; import android.view.View; import android.widget.RatingBar; @@ -9,11 +11,7 @@ import com.alphawallet.app.R; import com.alphawallet.app.repository.PreferenceRepositoryType; -import com.google.android.gms.tasks.Task; import com.google.android.material.dialog.MaterialAlertDialogBuilder; -import com.google.android.play.core.review.ReviewInfo; -import com.google.android.play.core.review.ReviewManager; -import com.google.android.play.core.review.ReviewManagerFactory; public class RateApp { // should be shown on 5th run or after the first transaction (afterTransaction == true) @@ -38,9 +36,7 @@ static public void showRateTheApp(Activity context, PreferenceRepositoryType pre preferenceRepository.setRateAppShown(); } }) - .setNegativeButton(R.string.rate_no_thanks, (dialogInterface, i) -> { - preferenceRepository.setRateAppShown(); - }); + .setNegativeButton(R.string.rate_no_thanks, (dialogInterface, i) -> preferenceRepository.setRateAppShown()); AlertDialog dialog = builder.show(); ratingBar.setOnRatingBarChangeListener((rb, rating, fromUser) -> { @@ -53,18 +49,12 @@ static public void showRateTheApp(Activity context, PreferenceRepositoryType pre } } - private static void startRateFlow(Activity context, PreferenceRepositoryType preferenceRepository) { - ReviewManager manager = ReviewManagerFactory.create(context); - Task request = manager.requestReviewFlow(); - request.addOnCompleteListener(task -> { - if (task.isSuccessful()) { - ReviewInfo reviewInfo = task.getResult(); - Task flow = manager.launchReviewFlow(context, reviewInfo); - flow.addOnCompleteListener(flowTask -> { - - }); - } - }); + private static void startRateFlow(Activity activity, PreferenceRepositoryType preferenceRepository) { + //simply take them to play store for now, until the current situation with play store libraries not being allowed is resolved + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse("https://play.google.com/store/apps/details?id=" + activity.getPackageName())); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NO_ANIMATION); + activity.startActivity(intent); // save rate ui shown preferenceRepository.setRateAppShown(); } diff --git a/app/src/analytics/java/com/alphawallet/app/util/UpdateUtils.java b/app/src/analytics/java/com/alphawallet/app/util/UpdateUtils.java index 08f8d7c767..57b5310761 100644 --- a/app/src/analytics/java/com/alphawallet/app/util/UpdateUtils.java +++ b/app/src/analytics/java/com/alphawallet/app/util/UpdateUtils.java @@ -5,15 +5,11 @@ import android.net.Uri; import com.alphawallet.app.entity.FragmentMessenger; -import com.google.android.gms.tasks.Task; -import com.google.android.play.core.appupdate.AppUpdateInfo; -import com.google.android.play.core.appupdate.AppUpdateManager; -import com.google.android.play.core.appupdate.AppUpdateManagerFactory; -import com.google.android.play.core.install.model.UpdateAvailability; public class UpdateUtils { + //Pull update check for now public static void checkForUpdates(Activity context, FragmentMessenger messenger) { - AppUpdateManager appUpdateManager = AppUpdateManagerFactory.create(context); + /*AppUpdateManager appUpdateManager = AppUpdateManagerFactory.create(context); Task appUpdateInfoTask = appUpdateManager.getAppUpdateInfo(); @@ -22,7 +18,7 @@ public static void checkForUpdates(Activity context, FragmentMessenger messenger { messenger.updateReady(appUpdateInfo.availableVersionCode()); } - }); + });*/ } public static void pushUpdateDialog(Activity activity) diff --git a/app/src/main/res/values-my/strings.xml b/app/src/main/res/values-my/strings.xml index 23deb928f5..506a909cc5 100644 --- a/app/src/main/res/values-my/strings.xml +++ b/app/src/main/res/values-my/strings.xml @@ -798,7 +798,7 @@ လုံခြုံစွာပြောင်းရွှေ့မည် ရွေးချယ်ထားသောတိုကင်များ တိုကင်များကိုပို့မည် - အသုံးပြုသည်ကိုကျေနပ်မှုရှိလျှင် ကျေးဇူးပြု၍ ကျွန်တော်တို့အားအဆင့်သတ်မှတ်ပေး၍ကူညီပါ။ + သင်သည် %1$s ကိုအသုံးပြုရသည်ကို နှစ်သက်ပါက ယင်းကို အဆင့်သတ်မှတ်ခြင်းဖြင့် ကျေးဇူးပြု၍ ကူညီပေးပါ။ နောက်မှ အဆင့်သတ်မှတ်သည် မပြုလုပ်ပါ၊ ကျေးဇူးတင်ပါသည်။ From 1762e06e11fd0d04931e95cb2cd6437547b7c872 Mon Sep 17 00:00:00 2001 From: James Brown Date: Thu, 10 Nov 2022 09:40:39 +1100 Subject: [PATCH 13/36] Remove anayltics --- app/build.gradle | 11 +++++++---- .../app/service/AnalyticsService.java | 17 ++++++----------- app/src/main/assets/swap_providers_list.json | 2 +- build.gradle | 4 ++-- 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index bc50bfed02..fe047124db 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -85,7 +85,7 @@ android { } } defaultConfig { - versionCode 211 + versionCode 212 versionName "3.60.1" applicationId "io.stormbird.wallet" @@ -132,7 +132,7 @@ android { Below code is used to include analytics only when Flavor is "No Analytics" This is due to China release where Google services should not be included */ - apply plugin: 'com.google.gms.google-services' + //apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.firebase.crashlytics' } noAnalytics { @@ -351,9 +351,12 @@ dependencies { implementation 'androidx.work:work-runtime:2.7.1' - analyticsImplementation 'com.google.firebase:firebase-analytics:21.1.1' + implementation platform('com.google.firebase:firebase-bom:28.1.0') + //analyticsImplementation 'com.google.firebase:firebase-analytics' + analyticsImplementation 'com.google.firebase:firebase-crashlytics' + //analyticsImplementation 'com.google.firebase:firebase-analytics:21.1.1' analyticsImplementation 'com.mixpanel.android:mixpanel-android:5.8.4' - analyticsImplementation 'com.google.firebase:firebase-crashlytics:18.2.13' + //analyticsImplementation 'com.google.firebase:firebase-crashlytics:18.2.13' } // WARNING WARNING WARNING diff --git a/app/src/analytics/java/com/alphawallet/app/service/AnalyticsService.java b/app/src/analytics/java/com/alphawallet/app/service/AnalyticsService.java index ddc0907219..98a6817d13 100644 --- a/app/src/analytics/java/com/alphawallet/app/service/AnalyticsService.java +++ b/app/src/analytics/java/com/alphawallet/app/service/AnalyticsService.java @@ -8,27 +8,22 @@ import com.alphawallet.app.C; import com.alphawallet.app.entity.AnalyticsProperties; import com.alphawallet.app.entity.ServiceErrorException; -import com.alphawallet.app.repository.KeyProvider; import com.alphawallet.app.repository.KeyProviderFactory; -import com.google.firebase.analytics.FirebaseAnalytics; import com.google.firebase.crashlytics.FirebaseCrashlytics; -import com.google.firebase.iid.FirebaseInstanceId; import com.mixpanel.android.mpmetrics.MixpanelAPI; import org.json.JSONException; import org.json.JSONObject; -import java.util.Objects; - public class AnalyticsService implements AnalyticsServiceType { private final MixpanelAPI mixpanelAPI; - private final FirebaseAnalytics firebaseAnalytics; + //private final FirebaseAnalytics firebaseAnalytics; public AnalyticsService(Context context) { mixpanelAPI = MixpanelAPI.getInstance(context, KeyProviderFactory.get().getAnalyticsKey()); - firebaseAnalytics = FirebaseAnalytics.getInstance(context); + //firebaseAnalytics = FirebaseAnalytics.getInstance(context); } @Override @@ -62,7 +57,7 @@ private void trackFirebase(AnalyticsProperties analyticsProperties, String event props.putString(C.APP_NAME, BuildConfig.APPLICATION_ID); - firebaseAnalytics.logEvent(eventName, props); + //firebaseAnalytics.logEvent(eventName, props); } private void trackMixpanel(AnalyticsProperties analyticsProperties, String eventName) @@ -92,17 +87,17 @@ private void trackMixpanel(AnalyticsProperties analyticsProperties, String event @Override public void identify(String uuid) { - firebaseAnalytics.setUserId(uuid); + //firebaseAnalytics.setUserId(uuid); mixpanelAPI.identify(uuid); mixpanelAPI.getPeople().identify(uuid); - FirebaseInstanceId.getInstance().getInstanceId() + /*FirebaseInstanceId.getInstance().getInstanceId() .addOnCompleteListener(task -> { if (task.isSuccessful()) { String token = Objects.requireNonNull(task.getResult()).getToken(); mixpanelAPI.getPeople().setPushRegistrationId(token); } - }); + });*/ } @Override diff --git a/app/src/main/assets/swap_providers_list.json b/app/src/main/assets/swap_providers_list.json index 6bfd9baaf9..5f43de575b 100644 --- a/app/src/main/assets/swap_providers_list.json +++ b/app/src/main/assets/swap_providers_list.json @@ -33,7 +33,7 @@ "key": "superfluid", "name": "Superfluid", "url": "https://www.superfluid.finance/", - "logoURI": "https://www.superfluid.finance/icons/icon-72x72.png" + "logoURI": "https://www.superfluid.finance/assets/favicon/favicon-32x32.png" }, { "key": "uniswap", diff --git a/build.gradle b/build.gradle index 2333022802..a67c58685f 100644 --- a/build.gradle +++ b/build.gradle @@ -17,7 +17,7 @@ buildscript { // 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 - classpath 'com.google.gms:google-services:4.3.14' + //classpath 'com.google.gms:google-services:4.3.14' classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10' classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.2' classpath 'com.google.dagger:hilt-android-gradle-plugin:2.40.5' @@ -37,7 +37,7 @@ allprojects { configurations.all { resolutionStrategy { - force 'com.google.firebase:firebase-analytics:16.5.0' + force 'com.google.firebase:firebase-analytics:21.2.0' } } From c728fff2b2ea4960d56a462ad57ced0ce31de2e5 Mon Sep 17 00:00:00 2001 From: James Brown Date: Fri, 11 Nov 2022 18:02:58 +1100 Subject: [PATCH 14/36] Update gradle --- app/build.gradle | 6 +++--- app/proguard-android-optimize.txt | 20 ++++++++++++++++++++ build.gradle | 2 +- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index fe047124db..d770ccf343 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -85,7 +85,7 @@ android { } } defaultConfig { - versionCode 212 + versionCode 214 versionName "3.60.1" applicationId "io.stormbird.wallet" @@ -164,7 +164,7 @@ android { signingConfig signingConfigs.release } proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } + } } packagingOptions { exclude 'META-INF/NOTICE' // will not include NOTICE file @@ -351,7 +351,7 @@ dependencies { implementation 'androidx.work:work-runtime:2.7.1' - implementation platform('com.google.firebase:firebase-bom:28.1.0') + analyticsImplementation platform('com.google.firebase:firebase-bom:28.1.0') //analyticsImplementation 'com.google.firebase:firebase-analytics' analyticsImplementation 'com.google.firebase:firebase-crashlytics' //analyticsImplementation 'com.google.firebase:firebase-analytics:21.1.1' diff --git a/app/proguard-android-optimize.txt b/app/proguard-android-optimize.txt index a598dab8a2..dea3b6b062 100644 --- a/app/proguard-android-optimize.txt +++ b/app/proguard-android-optimize.txt @@ -110,3 +110,23 @@ # These classes are duplicated between android.jar and core-lambda-stubs.jar. -dontnote java.lang.invoke.** + +-keepclasseswithmembernames,includedescriptorclasses class * { + native ; +} + +#trust wallet +-keep class wallet.core.jni.** { *; } +-keep class wallet.core.jni.proto.** { *; } +-keep class org.web3j.** { *; } + +#entities, jsInterface & listeners +-keep class com.alphawallet.token.** { *; } +-keep class com.alphawallet.app.walletconnect.** { *; } +-keep class com.alphawallet.app.web3.** { *; } +-keep class com.alphawallet.app.web3j.** { *; } +-keep class com.alphawallet.app.entity.** { *; } + +-repackageclasses +#-dontobfuscate +#-printconfiguration ../full-r8-config.txt \ No newline at end of file diff --git a/build.gradle b/build.gradle index a67c58685f..b9f3c1ab6e 100644 --- a/build.gradle +++ b/build.gradle @@ -17,7 +17,7 @@ buildscript { // 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 - //classpath 'com.google.gms:google-services:4.3.14' + classpath 'com.google.gms:google-services:4.3.14' classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10' classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.2' classpath 'com.google.dagger:hilt-android-gradle-plugin:2.40.5' From f4ce0b43708f0c1accfe16b8c8a27a3fbb32eb6c Mon Sep 17 00:00:00 2001 From: James Brown Date: Mon, 14 Nov 2022 20:39:30 +1100 Subject: [PATCH 15/36] Fix for Android deeplink issues --- app/src/main/AndroidManifest.xml | 12 ++--- .../token/web/AppSiteController.java | 48 ++++++++----------- 2 files changed, 26 insertions(+), 34 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4c934317d2..c00548a80e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -77,12 +77,12 @@ - - - - - - + + + + + + diff --git a/dmz/src/main/java/com/alphawallet/token/web/AppSiteController.java b/dmz/src/main/java/com/alphawallet/token/web/AppSiteController.java index 11d4e5eee4..c562895d89 100644 --- a/dmz/src/main/java/com/alphawallet/token/web/AppSiteController.java +++ b/dmz/src/main/java/com/alphawallet/token/web/AppSiteController.java @@ -1,23 +1,34 @@ package com.alphawallet.token.web; +import static com.alphawallet.token.tools.Convert.getEthString; +import static com.alphawallet.token.tools.ParseMagicLink.normal; +import static com.alphawallet.token.web.Ethereum.TokenscriptFunction.ZERO_ADDRESS; + import com.alphawallet.token.entity.Attribute; -import com.github.cliftonlabs.json_simple.JsonObject; +import com.alphawallet.token.entity.AttributeInterface; +import com.alphawallet.token.entity.ContractAddress; +import com.alphawallet.token.entity.ContractInfo; +import com.alphawallet.token.entity.MagicLinkData; +import com.alphawallet.token.entity.MagicLinkInfo; +import com.alphawallet.token.entity.NonFungibleToken; +import com.alphawallet.token.entity.SalesOrderMalformed; +import com.alphawallet.token.entity.TokenScriptResult; +import com.alphawallet.token.entity.TransactionResult; +import com.alphawallet.token.tools.ParseMagicLink; +import com.alphawallet.token.tools.TokenDefinition; +import com.alphawallet.token.web.Ethereum.TokenscriptFunction; +import com.alphawallet.token.web.Ethereum.TransactionHandler; +import com.alphawallet.token.web.Service.CryptoFunctions; -import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.NoHandlerFoundException; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import org.springframework.web.servlet.view.RedirectView; @@ -31,7 +42,6 @@ import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; @@ -44,27 +54,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; import java.util.stream.Stream; -import javax.servlet.http.HttpServletRequest; -import com.alphawallet.token.entity.AttributeInterface; -import com.alphawallet.token.entity.ContractAddress; -import com.alphawallet.token.entity.ContractInfo; -import com.alphawallet.token.entity.MagicLinkData; -import com.alphawallet.token.entity.MagicLinkInfo; -import com.alphawallet.token.entity.NonFungibleToken; -import com.alphawallet.token.entity.SalesOrderMalformed; -import com.alphawallet.token.entity.XMLDsigVerificationResult; -import com.alphawallet.token.entity.TokenScriptResult; -import com.alphawallet.token.entity.TransactionResult; -import com.alphawallet.token.tools.ParseMagicLink; -import com.alphawallet.token.tools.TokenDefinition; -import com.alphawallet.token.tools.XMLDSigVerifier; -import com.alphawallet.token.web.Ethereum.TokenscriptFunction; -import com.alphawallet.token.web.Ethereum.TransactionHandler; -import com.alphawallet.token.web.Service.CryptoFunctions; -import static com.alphawallet.token.tools.Convert.getEthString; -import static com.alphawallet.token.tools.ParseMagicLink.normal; -import static com.alphawallet.token.web.Ethereum.TokenscriptFunction.ZERO_ADDRESS; +import javax.servlet.http.HttpServletRequest; @Controller @SpringBootApplication @@ -95,6 +86,7 @@ public class AppSiteController implements AttributeInterface " \"package_name\": \"io.stormbird.wallet\",\n" + " \"sha256_cert_fingerprints\": [\n" + " \"8E:1E:C7:92:44:E2:AE:8F:5E:BE:A6:09:E5:CC:05:8F:01:9F:67:F4:A6:FF:E7:60:6E:DA:C8:64:8F:29:AB:C0\"\n" + + " \"54:5B:5D:DE:90:45:11:98:14:5C:90:32:C6:AE:F6:85:C3:7D:F5:72:75:FF:25:07:0E:13:03:11:61:66:6A:E3\"\n" + " ]\n" + " }\n" + " }\n" + From ec3aa09842eaeccfb575d76b388370d5d82dc173 Mon Sep 17 00:00:00 2001 From: Seaborn Date: Sat, 19 Nov 2022 07:03:43 +0800 Subject: [PATCH 16/36] Fix most of the crashes (#2956) * Fix NPEs --- .../walletconnect/WalletConnectSessionItem.java | 17 ++++++++++------- .../alphawallet/app/ui/DappBrowserFragment.java | 2 +- .../{QRScanner.java => QRScannerActivity.java} | 7 ++++++- .../com/alphawallet/app/ui/SwapActivity.java | 8 +++++++- .../app/ui/WalletActionsActivity.java | 5 ++++- .../app/ui/WalletConnectSessionActivity.java | 2 +- .../adapter/SingleSelectNetworkAdapter.java | 2 +- .../com/alphawallet/app/widget/GasWidget.java | 8 +++++++- ...nnerTest.java => QRScannerActivityTest.java} | 0 9 files changed, 37 insertions(+), 14 deletions(-) rename app/src/main/java/com/alphawallet/app/ui/QRScanning/{QRScanner.java => QRScannerActivity.java} (98%) rename app/src/test/java/com/alphawallet/app/ui/QRScanning/{QRScannerTest.java => QRScannerActivityTest.java} (100%) diff --git a/app/src/main/java/com/alphawallet/app/entity/walletconnect/WalletConnectSessionItem.java b/app/src/main/java/com/alphawallet/app/entity/walletconnect/WalletConnectSessionItem.java index b5df80e809..a3c65ee7a6 100644 --- a/app/src/main/java/com/alphawallet/app/entity/walletconnect/WalletConnectSessionItem.java +++ b/app/src/main/java/com/alphawallet/app/entity/walletconnect/WalletConnectSessionItem.java @@ -7,20 +7,23 @@ */ public class WalletConnectSessionItem { - public final String name; - public final String url; - public final String icon; + public String name = ""; + public String url = ""; + public String icon = ""; public final String sessionId; public final String localSessionId; public final long chainId; public WalletConnectSessionItem(RealmWCSession s) { - name = s.getRemotePeerData().getName(); - url = s.getRemotePeerData().getUrl(); - icon = s.getRemotePeerData().getIcons().size() > 0 ? s.getRemotePeerData().getIcons().get(0) : null; + if (s.getRemotePeerData() != null) + { + name = s.getRemotePeerData().getName(); + url = s.getRemotePeerData().getUrl(); + icon = s.getRemotePeerData().getIcons().size() > 0 ? s.getRemotePeerData().getIcons().get(0) : null; + } sessionId = s.getSession().getTopic(); localSessionId = s.getSessionId(); chainId = s.getChainId() == 0 ? 1 : s.getChainId(); //older sessions without chainId set must be mainnet } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/alphawallet/app/ui/DappBrowserFragment.java b/app/src/main/java/com/alphawallet/app/ui/DappBrowserFragment.java index 302450c77c..d94c972dc8 100644 --- a/app/src/main/java/com/alphawallet/app/ui/DappBrowserFragment.java +++ b/app/src/main/java/com/alphawallet/app/ui/DappBrowserFragment.java @@ -671,7 +671,7 @@ public void comeIntoFocus() { if (viewModel != null) { - if (viewModel.getActiveNetwork() == null || activeNetwork.chainId != viewModel.getActiveNetwork().chainId) + if (viewModel.getActiveNetwork() == null || activeNetwork == null || activeNetwork.chainId != viewModel.getActiveNetwork().chainId) { viewModel.checkForNetworkChanges(); } diff --git a/app/src/main/java/com/alphawallet/app/ui/QRScanning/QRScanner.java b/app/src/main/java/com/alphawallet/app/ui/QRScanning/QRScannerActivity.java similarity index 98% rename from app/src/main/java/com/alphawallet/app/ui/QRScanning/QRScanner.java rename to app/src/main/java/com/alphawallet/app/ui/QRScanning/QRScannerActivity.java index 259e2cc20d..8b7482045d 100644 --- a/app/src/main/java/com/alphawallet/app/ui/QRScanning/QRScanner.java +++ b/app/src/main/java/com/alphawallet/app/ui/QRScanning/QRScannerActivity.java @@ -374,7 +374,12 @@ public void onBackPressed() } @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { + public boolean onKeyDown(int keyCode, KeyEvent event) + { + if (barcodeView == null) + { + return false; + } return barcodeView.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event); } diff --git a/app/src/main/java/com/alphawallet/app/ui/SwapActivity.java b/app/src/main/java/com/alphawallet/app/ui/SwapActivity.java index fe122797df..1a85fbf111 100644 --- a/app/src/main/java/com/alphawallet/app/ui/SwapActivity.java +++ b/app/src/main/java/com/alphawallet/app/ui/SwapActivity.java @@ -249,7 +249,13 @@ public void onSelectionChanged(Token token) @Override public void onMaxClicked() { - String max = viewModel.getBalance(sourceSelector.getToken()); + Token token = sourceSelector.getToken(); + if (token == null) + { + return; + } + + String max = viewModel.getBalance(token); if (!max.isEmpty()) { sourceSelector.setAmount(max); diff --git a/app/src/main/java/com/alphawallet/app/ui/WalletActionsActivity.java b/app/src/main/java/com/alphawallet/app/ui/WalletActionsActivity.java index 17fa5680a5..c337f854f4 100644 --- a/app/src/main/java/com/alphawallet/app/ui/WalletActionsActivity.java +++ b/app/src/main/java/com/alphawallet/app/ui/WalletActionsActivity.java @@ -286,7 +286,10 @@ private void confirmDelete(Wallet wallet) { result -> { if (result.getResultCode() == RESULT_OK) { - successOverlay.setVisibility(View.VISIBLE); + if (successOverlay != null) + { + successOverlay.setVisibility(View.VISIBLE); + } handler.postDelayed(this, 1000); backupSuccessful(); finish(); diff --git a/app/src/main/java/com/alphawallet/app/ui/WalletConnectSessionActivity.java b/app/src/main/java/com/alphawallet/app/ui/WalletConnectSessionActivity.java index f38c533eaa..236e76331e 100644 --- a/app/src/main/java/com/alphawallet/app/ui/WalletConnectSessionActivity.java +++ b/app/src/main/java/com/alphawallet/app/ui/WalletConnectSessionActivity.java @@ -75,7 +75,7 @@ public void onReceive(Context context, Intent intent) public WalletConnectSessionActivity() { - broadcastManager = LocalBroadcastManager.getInstance(this); + broadcastManager = LocalBroadcastManager.getInstance(getApplicationContext()); } @Override diff --git a/app/src/main/java/com/alphawallet/app/ui/widget/adapter/SingleSelectNetworkAdapter.java b/app/src/main/java/com/alphawallet/app/ui/widget/adapter/SingleSelectNetworkAdapter.java index 26da36152e..d072f1c255 100644 --- a/app/src/main/java/com/alphawallet/app/ui/widget/adapter/SingleSelectNetworkAdapter.java +++ b/app/src/main/java/com/alphawallet/app/ui/widget/adapter/SingleSelectNetworkAdapter.java @@ -96,7 +96,7 @@ public int getItemCount() public void selectDefault() { - if (!hasSelection) + if (!hasSelection && !networkList.isEmpty()) { networkList.get(0).setSelected(true); notifyItemChanged(0); diff --git a/app/src/main/java/com/alphawallet/app/widget/GasWidget.java b/app/src/main/java/com/alphawallet/app/widget/GasWidget.java index 49cd808292..854d5eac88 100644 --- a/app/src/main/java/com/alphawallet/app/widget/GasWidget.java +++ b/app/src/main/java/com/alphawallet/app/widget/GasWidget.java @@ -38,6 +38,7 @@ import io.realm.Realm; import io.realm.RealmQuery; +import timber.log.Timber; /** * Created by JB on 19/11/2020. @@ -318,6 +319,11 @@ public void run() { GasSpeed2 gs = gasSpread.getSelectedGasFee(currentGasSpeedIndex); + if (gs == null || gs.gasPrice == null || gs.gasPrice.maxFeePerGas == null) + { + return; + } + Token baseCurrency = tokensService.getTokenOrBase(token.tokenInfo.chainId, token.getWallet()); BigInteger networkFee = gs.gasPrice.maxFeePerGas.multiply(getUseGasLimit()); String gasAmountInBase = BalanceUtils.getSlidingBaseValue(new BigDecimal(networkFee), baseCurrency.tokenInfo.decimals, GasSettingsActivity.GAS_PRECISION); @@ -349,7 +355,7 @@ public void run() } catch (Exception e) { - // + Timber.w(e); } timeEstimate.setText(displayStr); speedText.setText(gs.speed); diff --git a/app/src/test/java/com/alphawallet/app/ui/QRScanning/QRScannerTest.java b/app/src/test/java/com/alphawallet/app/ui/QRScanning/QRScannerActivityTest.java similarity index 100% rename from app/src/test/java/com/alphawallet/app/ui/QRScanning/QRScannerTest.java rename to app/src/test/java/com/alphawallet/app/ui/QRScanning/QRScannerActivityTest.java From 70d0d4d31b345bd1a82d9f7d71ec5327629e3a9f Mon Sep 17 00:00:00 2001 From: James Brown Date: Sat, 19 Nov 2022 10:20:34 +1100 Subject: [PATCH 17/36] fix NPEs --- app/src/main/AndroidManifest.xml | 2 +- .../com/alphawallet/app/ui/AddTokenActivity.java | 7 ++----- .../com/alphawallet/app/ui/DappBrowserFragment.java | 6 +++--- .../com/alphawallet/app/ui/ImportWalletActivity.java | 9 +++------ .../app/ui/QRScanning/QRScannerActivity.java | 12 ++++++------ .../java/com/alphawallet/app/ui/SendActivity.java | 4 ++-- .../com/alphawallet/app/ui/TransferNFTActivity.java | 4 ++-- .../app/ui/TransferTicketDetailActivity.java | 8 ++------ .../app/ui/WalletConnectSessionActivity.java | 4 ++-- .../app/viewmodel/DappBrowserViewModel.java | 4 ++-- .../alphawallet/app/viewmodel/WalletViewModel.java | 5 ++--- .../com/alphawallet/app/widget/InputAddress.java | 4 ++-- .../java/com/alphawallet/app/widget/InputView.java | 5 ++--- .../app/ui/QRScanning/QRScannerActivityTest.java | 4 ++-- 14 files changed, 33 insertions(+), 45 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c00548a80e..c5c23c3d8f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -300,7 +300,7 @@ android:label="Search Tokens" /> { - Intent intent = new Intent(context, QRScanner.class); + Intent intent = new Intent(context, QRScannerActivity.class); intent.putExtra(C.EXTRA_CHAIN_ID, chainOverride); ((Activity) context).startActivityForResult(intent, C.BARCODE_READER_REQUEST_CODE); }); diff --git a/app/src/main/java/com/alphawallet/app/widget/InputView.java b/app/src/main/java/com/alphawallet/app/widget/InputView.java index 7ed64226fc..062209764b 100644 --- a/app/src/main/java/com/alphawallet/app/widget/InputView.java +++ b/app/src/main/java/com/alphawallet/app/widget/InputView.java @@ -7,7 +7,6 @@ import android.content.res.TypedArray; import android.text.TextUtils; import android.util.AttributeSet; -import android.util.Log; import android.view.Gravity; import android.view.View; import android.view.inputmethod.EditorInfo; @@ -18,7 +17,7 @@ import android.widget.TextView; import com.alphawallet.app.C; -import com.alphawallet.app.ui.QRScanning.QRScanner; +import com.alphawallet.app.ui.QRScanning.QRScannerActivity; import com.alphawallet.app.ui.widget.entity.BoxStatus; import com.alphawallet.app.util.Utils; @@ -113,7 +112,7 @@ private void getAttrs(Context context, AttributeSet attrs) { if (!noCam) { scanQrIcon.setOnClickListener(v -> { - Intent intent = new Intent(context, QRScanner.class); + Intent intent = new Intent(context, QRScannerActivity.class); ((Activity) context).startActivityForResult(intent, C.BARCODE_READER_REQUEST_CODE); }); } diff --git a/app/src/test/java/com/alphawallet/app/ui/QRScanning/QRScannerActivityTest.java b/app/src/test/java/com/alphawallet/app/ui/QRScanning/QRScannerActivityTest.java index 29cf9973b6..7d62e9db35 100644 --- a/app/src/test/java/com/alphawallet/app/ui/QRScanning/QRScannerActivityTest.java +++ b/app/src/test/java/com/alphawallet/app/ui/QRScanning/QRScannerActivityTest.java @@ -16,14 +16,14 @@ @RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowRealm.class}) -public class QRScannerTest +public class QRScannerActivityTest { @Test @Config(sdk = 23) public void given_api_23_when_onCreate_then_notify_feature_not_supported() { - try (ActivityScenario scenario = ActivityScenario.launch(QRScanner.class)) + try (ActivityScenario scenario = ActivityScenario.launch(QRScannerActivity.class)) { assertThat(scenario.getState(), equalTo(Lifecycle.State.DESTROYED)); assertThat(ShadowToast.getTextOfLatestToast(), equalTo("QR scanning requires Android 7.0 (API level 24) or above.")); From 341ff5e67f3807133eaed6fb6eeb927a8de4b560 Mon Sep 17 00:00:00 2001 From: James Brown Date: Tue, 15 Nov 2022 12:51:23 +1100 Subject: [PATCH 18/36] Fix for video not looping (#2941) --- app/src/main/res/raw/token_anim.data | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/raw/token_anim.data b/app/src/main/res/raw/token_anim.data index 4dce3e0bd9..927ff79c4a 100644 --- a/app/src/main/res/raw/token_anim.data +++ b/app/src/main/res/raw/token_anim.data @@ -20,9 +20,9 @@

- \ No newline at end of file + From 072a99bcecbe34faa92f8f01184e8d6b8f919af6 Mon Sep 17 00:00:00 2001 From: James Brown Date: Tue, 8 Nov 2022 15:57:01 +1100 Subject: [PATCH 19/36] Add IPFS connection point (#2920) * Shift to using type interface for IPFSService to make it possible to implement IO-free unit tests * Update IPFS usage and add unit testing for new service. * Fix certificate test * Updates as suggested --- .github/workflows/codestyle.yml | 27 +++ .../app/TokenScriptCertificateTest.java | 20 +- .../com/alphawallet/app/TransferTest.java | 3 +- .../java/com/alphawallet/app/steps/Steps.java | 10 +- .../app/di/RepositoriesModule.java | 226 ++++++++++-------- .../app/entity/ContractInteract.java | 34 +-- .../alphawallet/app/entity/QueryResponse.java | 23 ++ .../app/entity/tokenscript/TestScript.java | 70 ++++++ .../app/service/AssetDefinitionService.java | 98 ++++---- .../alphawallet/app/service/IPFSService.java | 131 ++++++++++ .../app/service/IPFSServiceType.java | 14 ++ .../service/TransactionsNetworkClient.java | 30 ++- .../java/com/alphawallet/app/util/Utils.java | 20 +- .../alphawallet/app/web3j/ens/NameHash.java | 35 ++- app/src/main/res/raw/token_anim.data | 2 +- .../com/alphawallet/app/IPFSServiceTest.java | 68 ++++++ 16 files changed, 593 insertions(+), 218 deletions(-) create mode 100644 .github/workflows/codestyle.yml create mode 100644 app/src/main/java/com/alphawallet/app/entity/QueryResponse.java create mode 100644 app/src/main/java/com/alphawallet/app/entity/tokenscript/TestScript.java create mode 100644 app/src/main/java/com/alphawallet/app/service/IPFSService.java create mode 100644 app/src/main/java/com/alphawallet/app/service/IPFSServiceType.java create mode 100644 app/src/test/java/com/alphawallet/app/IPFSServiceTest.java diff --git a/.github/workflows/codestyle.yml b/.github/workflows/codestyle.yml new file mode 100644 index 0000000000..3c02b29da4 --- /dev/null +++ b/.github/workflows/codestyle.yml @@ -0,0 +1,27 @@ +name: Check code format +on: + pull_request: +jobs: + lint: + name: Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Setup NodeJS + uses: actions/setup-node@v3 + with: + node-version: 16 + - name: Install dependencies + run: npm install + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v34 + - name: Check all changed files + run: | + for file in ${{ steps.changed-files.outputs.all_changed_files }}; do + npx ec "$file" + done + diff --git a/app/src/androidTest/java/com/alphawallet/app/TokenScriptCertificateTest.java b/app/src/androidTest/java/com/alphawallet/app/TokenScriptCertificateTest.java index 6364c0efa1..d5ae6e7985 100644 --- a/app/src/androidTest/java/com/alphawallet/app/TokenScriptCertificateTest.java +++ b/app/src/androidTest/java/com/alphawallet/app/TokenScriptCertificateTest.java @@ -42,10 +42,12 @@ */ public class TokenScriptCertificateTest extends BaseE2ETest { - private final String doorContractAddress; + private String doorContractAddress; private final String contractOwnerPk = "0x69c22d654be7fe75e31fbe26cb56c93ec91144fab67cb71529c8081971635069"; private final Web3j web3j; + private final boolean useMumbai = false; //for local testing + private static final Map WALLETS_ON_GANACHE = new HashMap() {{ put("24", new String[]{"0x644022aef70ad515ee186345fd74b005d759f41be8157c2835de3597d943146d", "0xE494323823fdF1A1Ab6ca79d2538C7182690D52a"}); @@ -81,6 +83,12 @@ public TokenScriptCertificateTest() //Always use zero nonce for determining the contract address doorContractAddress = EthUtils.calculateContractAddress(deployCredentials.getAddress(), 0L); + + if (useMumbai) + { + //If using Mumbai for this test: + doorContractAddress = "0xA0343dfd68FcD7F18153b8AB87936c5A9C1Da20e"; + } } @Test @@ -100,8 +108,8 @@ public void should_view_signature_details() assertThat(getWalletAddress(), equalTo(ownerAddress)); - addNewNetwork("Ganache"); - selectTestNet("Ganache"); + addNewNetwork("Ganache", GANACHE_URL); + selectTestNet(useMumbai ? "Mumbai" : "Ganache"); //Ensure we're on the wallet page switchToWallet(ownerAddress); @@ -117,7 +125,7 @@ public void should_view_signature_details() onView(allOf(withId(R.id.edit_text))).perform(replaceText(doorContractAddress)); - onView(isRoot()).perform(waitUntil(withId(R.id.select_token), 30)); + onView(isRoot()).perform(waitUntil(withId(R.id.select_token), 300)); click(withId(R.id.select_token)); @@ -142,6 +150,8 @@ public void should_view_signature_details() shouldSee("Smart Token Labs"); shouldSee("ECDSA"); - shouldSee("Contract Owner"); // Note this may fail once we pull owner() from contract, test will need to be changed to contract owner, which for this test is: 0xA20efc4B9537d27acfD052003e311f762620642D + shouldSee("Contract Owner"); // Note this may fail once we pull owner() from contract, + // test will need to be changed to contract owner, + // which for this test is: 0xA20efc4B9537d27acfD052003e311f762620642D } } diff --git a/app/src/androidTest/java/com/alphawallet/app/TransferTest.java b/app/src/androidTest/java/com/alphawallet/app/TransferTest.java index 4a0b05a2d7..d6bc9ed37e 100644 --- a/app/src/androidTest/java/com/alphawallet/app/TransferTest.java +++ b/app/src/androidTest/java/com/alphawallet/app/TransferTest.java @@ -9,6 +9,7 @@ import static com.alphawallet.app.steps.Steps.selectTestNet; import static com.alphawallet.app.steps.Steps.sendBalanceTo; import static com.alphawallet.app.steps.Steps.switchToWallet; +import static com.alphawallet.app.util.EthUtils.GANACHE_URL; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.fail; @@ -46,7 +47,7 @@ public void should_transfer_from_an_account_to_another() { importWalletFromSettingsPage(privateKey); assertThat(getWalletAddress(), equalTo(existedWalletAddress)); - addNewNetwork("Ganache"); + addNewNetwork("Ganache", GANACHE_URL); selectTestNet("Ganache"); sendBalanceTo(newWalletAddress, "0.001"); ensureTransactionConfirmed(); diff --git a/app/src/androidTest/java/com/alphawallet/app/steps/Steps.java b/app/src/androidTest/java/com/alphawallet/app/steps/Steps.java index b600353316..841adfe8ea 100644 --- a/app/src/androidTest/java/com/alphawallet/app/steps/Steps.java +++ b/app/src/androidTest/java/com/alphawallet/app/steps/Steps.java @@ -15,7 +15,6 @@ import static androidx.test.espresso.matcher.ViewMatchers.withText; import static com.alphawallet.app.assertions.Should.shouldNotSee; import static com.alphawallet.app.assertions.Should.shouldSee; -import static com.alphawallet.app.util.EthUtils.GANACHE_URL; import static com.alphawallet.app.util.Helper.click; import static com.alphawallet.app.util.Helper.waitUntil; import static com.alphawallet.app.util.RootUtil.isDeviceRooted; @@ -204,16 +203,17 @@ public static void toggleSwitch(int id) { onView(allOf(withId(R.id.switch_material), isDescendantOfA(withId(id)))).perform(ViewActions.click()); } - public static void addNewNetwork(String name) + public static void addNewNetwork(String name, String url) { + gotoSettingsPage(); selectMenu("Select Active Networks"); click(withId(R.id.action_add)); input(R.id.input_network_name, name); - input(R.id.input_network_rpc_url, GANACHE_URL); + input(R.id.input_network_rpc_url, url); input(R.id.input_network_chain_id, "2"); input(R.id.input_network_symbol, "ETH"); - input(R.id.input_network_explorer_api, GANACHE_URL); - input(R.id.input_network_block_explorer_url, GANACHE_URL); + input(R.id.input_network_explorer_api, url); + input(R.id.input_network_block_explorer_url, url); onView(withId(R.id.network_input_scroll)).perform(swipeUp()); Helper.wait(1); click(withId(R.id.checkbox_testnet)); 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 1c45aa1082..f8afae90f0 100644 --- a/app/src/main/java/com/alphawallet/app/di/RepositoriesModule.java +++ b/app/src/main/java/com/alphawallet/app/di/RepositoriesModule.java @@ -31,6 +31,8 @@ import com.alphawallet.app.service.AnalyticsServiceType; import com.alphawallet.app.service.AssetDefinitionService; import com.alphawallet.app.service.GasService; +import com.alphawallet.app.service.IPFSService; +import com.alphawallet.app.service.IPFSServiceType; import com.alphawallet.app.service.KeyService; import com.alphawallet.app.service.KeystoreAccountService; import com.alphawallet.app.service.NotificationService; @@ -57,38 +59,42 @@ @Module @InstallIn(SingletonComponent.class) -public class RepositoriesModule { - @Singleton - @Provides - PreferenceRepositoryType providePreferenceRepository(@ApplicationContext Context context) { - return new SharedPreferenceRepository(context); - } +public class RepositoriesModule +{ + @Singleton + @Provides + PreferenceRepositoryType providePreferenceRepository(@ApplicationContext Context context) + { + return new SharedPreferenceRepository(context); + } - @Singleton - @Provides - AccountKeystoreService provideAccountKeyStoreService(@ApplicationContext Context context, KeyService keyService) { + @Singleton + @Provides + AccountKeystoreService provideAccountKeyStoreService(@ApplicationContext Context context, KeyService keyService) + { File file = new File(context.getFilesDir(), KEYSTORE_FOLDER); - return new KeystoreAccountService(file, context.getFilesDir(), keyService); - } + return new KeystoreAccountService(file, context.getFilesDir(), keyService); + } - @Singleton + @Singleton @Provides - TickerService provideTickerService(OkHttpClient httpClient, PreferenceRepositoryType sharedPrefs, TokenLocalSource localSource) { - return new TickerService(httpClient, sharedPrefs, localSource); + TickerService provideTickerService(OkHttpClient httpClient, PreferenceRepositoryType sharedPrefs, TokenLocalSource localSource) + { + return new TickerService(httpClient, sharedPrefs, localSource); } - @Singleton - @Provides - EthereumNetworkRepositoryType provideEthereumNetworkRepository( + @Singleton + @Provides + EthereumNetworkRepositoryType provideEthereumNetworkRepository( PreferenceRepositoryType preferenceRepository, - @ApplicationContext Context context - ) + @ApplicationContext Context context + ) { return new EthereumNetworkRepository(preferenceRepository, context); } - @Singleton - @Provides + @Singleton + @Provides WalletRepositoryType provideWalletRepository( PreferenceRepositoryType preferenceRepositoryType, AccountKeystoreService accountKeystoreService, @@ -121,19 +127,22 @@ OnRampRepositoryType provideOnRampRepository(@ApplicationContext Context context @Singleton @Provides - SwapRepositoryType provideSwapRepository(@ApplicationContext Context context) { + SwapRepositoryType provideSwapRepository(@ApplicationContext Context context) + { return new SwapRepository(context); } @Singleton @Provides - CoinbasePayRepositoryType provideCoinbasePayRepository() { + CoinbasePayRepositoryType provideCoinbasePayRepository() + { return new CoinbasePayRepository(); } - @Singleton + @Singleton @Provides - TransactionLocalSource provideTransactionInDiskCache(RealmManager realmManager) { + TransactionLocalSource provideTransactionInDiskCache(RealmManager realmManager) + { return new TransactionsRealmCache(realmManager); } @@ -147,105 +156,120 @@ TransactionsNetworkClientType provideBlockExplorerClient( return new TransactionsNetworkClient(httpClient, gson, realmManager); } - @Singleton + @Singleton @Provides TokenRepositoryType provideTokenRepository( EthereumNetworkRepositoryType ethereumNetworkRepository, TokenLocalSource tokenLocalSource, - OkHttpClient httpClient, - @ApplicationContext Context context, - TickerService tickerService) { - return new TokenRepository( - ethereumNetworkRepository, - tokenLocalSource, - httpClient, - context, - tickerService); + OkHttpClient httpClient, + @ApplicationContext Context context, + TickerService tickerService) + { + return new TokenRepository( + ethereumNetworkRepository, + tokenLocalSource, + httpClient, + context, + tickerService); } @Singleton @Provides - TokenLocalSource provideRealmTokenSource(RealmManager realmManager, EthereumNetworkRepositoryType ethereumNetworkRepository) { - return new TokensRealmSource(realmManager, ethereumNetworkRepository); + TokenLocalSource provideRealmTokenSource(RealmManager realmManager, EthereumNetworkRepositoryType ethereumNetworkRepository) + { + return new TokensRealmSource(realmManager, ethereumNetworkRepository); } - @Singleton - @Provides - WalletDataRealmSource provideRealmWalletDataSource(RealmManager realmManager) { - return new WalletDataRealmSource(realmManager); - } + @Singleton + @Provides + WalletDataRealmSource provideRealmWalletDataSource(RealmManager realmManager) + { + return new WalletDataRealmSource(realmManager); + } - @Singleton - @Provides - TokensService provideTokensService(EthereumNetworkRepositoryType ethereumNetworkRepository, - TokenRepositoryType tokenRepository, - TickerService tickerService, - OpenSeaService openseaService, - AnalyticsServiceType analyticsService) { - return new TokensService(ethereumNetworkRepository, tokenRepository, tickerService, openseaService, analyticsService); - } + @Singleton + @Provides + TokensService provideTokensServices(EthereumNetworkRepositoryType ethereumNetworkRepository, + TokenRepositoryType tokenRepository, + TickerService tickerService, + OpenSeaService openseaService, + AnalyticsServiceType analyticsService) + { + return new TokensService(ethereumNetworkRepository, tokenRepository, tickerService, openseaService, analyticsService); + } - @Singleton - @Provides - TransactionsService provideTransactionsService(TokensService tokensService, - EthereumNetworkRepositoryType ethereumNetworkRepositoryType, - TransactionsNetworkClientType transactionsNetworkClientType, - TransactionLocalSource transactionLocalSource) { - return new TransactionsService(tokensService, ethereumNetworkRepositoryType, transactionsNetworkClientType, transactionLocalSource); - } + @Singleton + @Provides + TransactionsService provideTransactionsServices(TokensService tokensService, + EthereumNetworkRepositoryType ethereumNetworkRepositoryType, + TransactionsNetworkClientType transactionsNetworkClientType, + TransactionLocalSource transactionLocalSource) + { + return new TransactionsService(tokensService, ethereumNetworkRepositoryType, transactionsNetworkClientType, transactionLocalSource); + } @Singleton @Provides - GasService provideGasService(EthereumNetworkRepositoryType ethereumNetworkRepository, - OkHttpClient client, - RealmManager realmManager) + GasService provideGasService(EthereumNetworkRepositoryType ethereumNetworkRepository, OkHttpClient client, RealmManager realmManager) { return new GasService(ethereumNetworkRepository, client, realmManager); } - @Singleton - @Provides - OpenSeaService provideOpenseaService() { - return new OpenSeaService(); - } + @Singleton + @Provides + OpenSeaService provideOpenseaService() + { + return new OpenSeaService(); + } - @Singleton - @Provides - SwapService provideSwapService() { - return new SwapService(); - } + @Singleton + @Provides + SwapService provideSwapService() + { + return new SwapService(); + } - @Singleton - @Provides - AlphaWalletService provideFeemasterService(OkHttpClient okHttpClient, - TransactionRepositoryType transactionRepository, - Gson gson) { - return new AlphaWalletService(okHttpClient, transactionRepository, gson); - } + @Singleton + @Provides + AlphaWalletService provideFeemasterService(OkHttpClient okHttpClient, TransactionRepositoryType transactionRepository, Gson gson) + { + return new AlphaWalletService(okHttpClient, transactionRepository, gson); + } - @Singleton - @Provides - NotificationService provideNotificationService(@ApplicationContext Context ctx) { - return new NotificationService(ctx); - } + @Singleton + @Provides + NotificationService provideNotificationService(@ApplicationContext Context ctx) + { + return new NotificationService(ctx); + } - @Singleton - @Provides - AssetDefinitionService provideAssetDefinitionService(OkHttpClient okHttpClient, @ApplicationContext Context ctx, NotificationService notificationService, RealmManager realmManager, - TokensService tokensService, TokenLocalSource tls, TransactionRepositoryType trt, - AlphaWalletService alphaService) { - return new AssetDefinitionService(okHttpClient, ctx, notificationService, realmManager, tokensService, tls, trt, alphaService); - } + @Singleton + @Provides + AssetDefinitionService providingAssetDefinitionServices(IPFSServiceType ipfsService, @ApplicationContext Context ctx, NotificationService notificationService, RealmManager realmManager, + TokensService tokensService, TokenLocalSource tls, + AlphaWalletService alphaService) + { + return new AssetDefinitionService(ipfsService, ctx, notificationService, realmManager, tokensService, tls, alphaService); + } - @Singleton - @Provides - KeyService provideKeyService(@ApplicationContext Context ctx, AnalyticsServiceType analyticsService) { - return new KeyService(ctx, analyticsService); - } + @Singleton + @Provides + KeyService provideKeyService(@ApplicationContext Context ctx, AnalyticsServiceType analyticsService) + { + return new KeyService(ctx, analyticsService); + } - @Singleton - @Provides - AnalyticsServiceType provideAnalyticsService(@ApplicationContext Context ctx) { - return new AnalyticsService(ctx); - } + @Singleton + @Provides + AnalyticsServiceType provideAnalyticsService(@ApplicationContext Context ctx) + { + return new AnalyticsService(ctx); + } + + @Singleton + @Provides + IPFSServiceType provideIPFSService(OkHttpClient client) + { + return new IPFSService(client); + } } diff --git a/app/src/main/java/com/alphawallet/app/entity/ContractInteract.java b/app/src/main/java/com/alphawallet/app/entity/ContractInteract.java index 9bc532e363..bdfaf2a92d 100644 --- a/app/src/main/java/com/alphawallet/app/entity/ContractInteract.java +++ b/app/src/main/java/com/alphawallet/app/entity/ContractInteract.java @@ -7,6 +7,7 @@ import com.alphawallet.app.C; import com.alphawallet.app.entity.nftassets.NFTAsset; import com.alphawallet.app.entity.tokens.Token; +import com.alphawallet.app.service.IPFSService; import com.alphawallet.app.util.Utils; import org.web3j.abi.TypeReference; @@ -22,8 +23,6 @@ import io.reactivex.Single; import io.reactivex.schedulers.Schedulers; import okhttp3.OkHttpClient; -import okhttp3.Request; -import timber.log.Timber; /** * Created by JB on 7/05/2022. @@ -31,7 +30,7 @@ public class ContractInteract { private final Token token; - protected static OkHttpClient client; + protected static IPFSService client; public ContractInteract(Token token) { @@ -55,21 +54,7 @@ private String loadMetaData(String tokenURI) setupClient(); - Request request = new Request.Builder() - .url(Utils.parseIPFS(tokenURI)) - .get() - .build(); - - try (okhttp3.Response response = client.newCall(request).execute()) - { - return response.body().string(); - } - catch (Exception e) - { - Timber.e(e); - } - - return ""; + return client.getContent(tokenURI); } public NFTAsset fetchTokenMetadata(BigInteger tokenId) @@ -112,12 +97,13 @@ private static void setupClient() { if (client == null) { - client = new OkHttpClient.Builder() - .connectTimeout(C.CONNECT_TIMEOUT*4, TimeUnit.SECONDS) - .readTimeout(C.READ_TIMEOUT*4, TimeUnit.SECONDS) - .writeTimeout(C.WRITE_TIMEOUT, TimeUnit.SECONDS) - .retryOnConnectionFailure(true) - .build(); + client = new IPFSService( + new OkHttpClient.Builder() + .connectTimeout(C.CONNECT_TIMEOUT*2, TimeUnit.SECONDS) + .readTimeout(C.READ_TIMEOUT*2, TimeUnit.SECONDS) + .writeTimeout(C.WRITE_TIMEOUT*2, TimeUnit.SECONDS) + .retryOnConnectionFailure(false) + .build()); } } } diff --git a/app/src/main/java/com/alphawallet/app/entity/QueryResponse.java b/app/src/main/java/com/alphawallet/app/entity/QueryResponse.java new file mode 100644 index 0000000000..a232a2f2db --- /dev/null +++ b/app/src/main/java/com/alphawallet/app/entity/QueryResponse.java @@ -0,0 +1,23 @@ +package com.alphawallet.app.entity; + +/** + * Created by JB on 5/11/2022. + */ +public class QueryResponse +{ + public final int code; + public final String body; + + public QueryResponse(int code, String body) + { + this.code = code; + this.body = body; + } + + public boolean isSuccessful() + { + return code >= 200 && code <= 299; + } +} + + diff --git a/app/src/main/java/com/alphawallet/app/entity/tokenscript/TestScript.java b/app/src/main/java/com/alphawallet/app/entity/tokenscript/TestScript.java new file mode 100644 index 0000000000..ab104d6afc --- /dev/null +++ b/app/src/main/java/com/alphawallet/app/entity/tokenscript/TestScript.java @@ -0,0 +1,70 @@ +package com.alphawallet.app.entity.tokenscript; + +/** + * Created by JB on 6/11/2022. + */ +public abstract class TestScript +{ + public static String testScriptXXLF = " STL Office Token" + + " STL Office Tokens Boleto de admisión" + + " Boleto de admisiónes 入場券" + + " 入場券 " + + " 0xC3eeCa3Feb9Dbc06c6e749702AcB8d56A07BFb05 " + + " Unlock 开锁" + + " Abrir " + + " " + + " Lock 关锁" + + " Cerrar " + + " Mint Ape 1 " + + " " + + " Mint Ape 2 " + + " " + + " Mint STL Token" + + " " + + " " + + " "; +} diff --git a/app/src/main/java/com/alphawallet/app/service/AssetDefinitionService.java b/app/src/main/java/com/alphawallet/app/service/AssetDefinitionService.java index 88e6099de9..d8349c6077 100644 --- a/app/src/main/java/com/alphawallet/app/service/AssetDefinitionService.java +++ b/app/src/main/java/com/alphawallet/app/service/AssetDefinitionService.java @@ -25,6 +25,7 @@ import com.alphawallet.app.entity.ContractLocator; import com.alphawallet.app.entity.ContractType; import com.alphawallet.app.entity.FragmentMessenger; +import com.alphawallet.app.entity.QueryResponse; import com.alphawallet.app.entity.TokenLocator; import com.alphawallet.app.entity.Wallet; import com.alphawallet.app.entity.nftassets.NFTAsset; @@ -36,7 +37,6 @@ import com.alphawallet.app.entity.tokenscript.TokenscriptFunction; import com.alphawallet.app.repository.TokenLocalSource; import com.alphawallet.app.repository.TokensRealmSource; -import com.alphawallet.app.repository.TransactionRepositoryType; import com.alphawallet.app.repository.entity.RealmAuxData; import com.alphawallet.app.repository.entity.RealmCertificateData; import com.alphawallet.app.repository.entity.RealmTokenScriptData; @@ -112,8 +112,6 @@ import io.realm.Sort; import io.realm.exceptions.RealmException; import io.realm.exceptions.RealmPrimaryKeyConstraintException; -import okhttp3.OkHttpClient; -import okhttp3.Request; import timber.log.Timber; @@ -135,7 +133,7 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface private static final String EIP5169_KEY_OWNER = "Contract Owner"; //TODO Source this from the contract via owner() private final Context context; - private final OkHttpClient okHttpClient; + private final IPFSServiceType ipfsService; private final Map assetChecked; //Mapping of contract address to when they were last fetched from server private FileObserver fileObserver; //Observer which scans the override directory waiting for file change @@ -145,7 +143,6 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface private final TokensService tokensService; private final TokenLocalSource tokenLocalSource; private final AlphaWalletService alphaWalletService; - private final TransactionRepositoryType transactionRepository; private TokenDefinition cachedDefinition = null; private final ConcurrentHashMap eventList = new ConcurrentHashMap<>(); //List of events built during file load private final Semaphore assetLoadingLock; // used to block if someone calls getAssetDefinitionASync() while loading @@ -158,17 +155,16 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface @Nullable private Disposable checkEventDisposable; - /* Designed with the assmuption that only a single instance of this class at any given time + /* Designed with the assumption that only a single instance of this class at any given time * ^^ The "service" part of AssetDefinitionService is the keyword here. * This is shorthand in the project to indicate this is a singleton that other classes inject. * This is the design pattern of the app. See class RepositoriesModule for constructors which are called at App init only */ - public AssetDefinitionService(OkHttpClient client, Context ctx, NotificationService svs, - RealmManager rm, TokensService tokensService, - TokenLocalSource trs, TransactionRepositoryType trt, - AlphaWalletService alphaService) + public AssetDefinitionService (IPFSServiceType ipfsSvs, Context ctx, NotificationService svs, + RealmManager rm, TokensService tokensService, + TokenLocalSource trs, AlphaWalletService alphaService) { context = ctx; - okHttpClient = client; + ipfsService = ipfsSvs; assetChecked = new ConcurrentHashMap<>(); notificationService = svs; realmManager = rm; @@ -178,7 +174,6 @@ public AssetDefinitionService(OkHttpClient client, Context ctx, NotificationServ { }; //no overridden functions tokenLocalSource = trs; - transactionRepository = trt; assetLoadingLock = new Semaphore(1); eventConnection = new Semaphore(1); //deleteAllEventData(); @@ -1052,64 +1047,52 @@ private Single fetchXMLFromServer(String address) }); } - private Pair downloadScript(String Uri, long currentFileTime) throws PackageManager.NameNotFoundException + private Pair downloadScript(String Uri, long currentFileTime) { - boolean isIPFS = false; - if (TextUtils.isEmpty(Uri)) return new Pair<>("", false); - SimpleDateFormat format = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss 'GMT'", Locale.ENGLISH); - format.setTimeZone(TimeZone.getTimeZone("UTC")); - String dateFormat = format.format(new Date(currentFileTime)); - - //convert uri if using IPFS: - Uri = Utils.parseIPFS(Uri); - - //prepare Android headers - PackageManager manager = context.getPackageManager(); - PackageInfo info = manager.getPackageInfo( - context.getPackageName(), 0); - String appVersion = info.versionName; - String OSVersion = String.valueOf(Build.VERSION.RELEASE); - - Request.Builder bld = new Request.Builder() - .url(Uri) - .get(); - - if (!Uri.toLowerCase().contains("ipfs.io")) - { - bld.addHeader("Accept", "text/xml; charset=UTF-8") - .addHeader("X-Client-Name", "AlphaWallet") - .addHeader("X-Client-Version", appVersion) - .addHeader("X-Platform-Name", "Android") - .addHeader("X-Platform-Version", OSVersion) - .addHeader("If-Modified-Since", dateFormat); - } - else - { - isIPFS = true; - } + boolean isIPFS = Utils.isIPFS(Uri); - Request request = bld.build(); - - try (okhttp3.Response response = okHttpClient.newCall(request) - .execute()) + try { - switch (response.code()) + QueryResponse response = ipfsService.performIO(Uri, getHeaders(currentFileTime)); + switch (response.code) { default: case HttpURLConnection.HTTP_NOT_MODIFIED: break; case HttpURLConnection.HTTP_OK: - return new Pair<>(response.body().string(), isIPFS); + return new Pair<>(response.body, isIPFS); } } catch (Exception e) { - Timber.e(e); + Timber.w(e); } return new Pair<>("", false); } + private String[] getHeaders(long currentFileTime) throws PackageManager.NameNotFoundException + { + SimpleDateFormat format = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss 'GMT'", Locale.ENGLISH); + format.setTimeZone(TimeZone.getTimeZone("UTC")); + String dateFormat = format.format(new Date(currentFileTime)); + + PackageManager manager = context.getPackageManager(); + PackageInfo info = manager.getPackageInfo( + context.getPackageName(), 0); + String appVersion = info.versionName; + String OSVersion = String.valueOf(Build.VERSION.RELEASE); + + return new String[] { + "Accept", "text/xml; charset=UTF-8", + "X-Client-Name", "AlphaWallet", + "X-Client-Version", appVersion, + "X-Platform-Name", "Android", + "X-Platform-Version", OSVersion, + "If-Modified-Since", dateFormat + }; + } + private boolean definitionIsOutOfDate(TokenDefinition td) { return td != null && !td.nameSpace.equals(TokenDefinition.TOKENSCRIPT_NAMESPACE); @@ -1477,8 +1460,8 @@ private void storeAuxData(String walletAddress, String databaseKey, BigInteger t } } - private void storeEventValue(String walletAddress, EventDefinition ev, EthLog.LogResult log, Attribute attr, - String selectVal) + private void storeEventValue (String walletAddress, EventDefinition ev, EthLog.LogResult log, Attribute attr, + String selectVal) { //store result BigInteger tokenId = EventUtils.getTokenId(ev, log); @@ -1895,7 +1878,8 @@ public String checkFunctionDenied(Token token, String actionName, List getAttributeResultsForTokenIds(Map> attrResults, List requiredAttributeNames, BigInteger tokenId) + private Map getAttributeResultsForTokenIds(Map> attrResults, List requiredAttributeNames, + BigInteger tokenId) { Map results = new HashMap<>(); if (!attrResults.containsKey(tokenId)) return results; //check values @@ -2708,4 +2692,4 @@ private void deleteAWRealm() }); } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/alphawallet/app/service/IPFSService.java b/app/src/main/java/com/alphawallet/app/service/IPFSService.java new file mode 100644 index 0000000000..b4cea7e0a6 --- /dev/null +++ b/app/src/main/java/com/alphawallet/app/service/IPFSService.java @@ -0,0 +1,131 @@ +package com.alphawallet.app.service; + +import android.text.TextUtils; + +import com.alphawallet.app.entity.QueryResponse; +import com.alphawallet.app.entity.tokenscript.TestScript; +import com.alphawallet.app.util.Utils; + +import java.io.IOException; +import java.net.SocketTimeoutException; + +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import timber.log.Timber; + +/** + * Created by JB on 3/11/2022. + */ +public class IPFSService implements IPFSServiceType +{ + private final OkHttpClient client; + + public IPFSService(OkHttpClient okHttpClient) + { + this.client = okHttpClient; + } + + public String getContent(String url) + { + try + { + QueryResponse response = performIO(url, null); + + if (response.isSuccessful()) + { + return response.body; + } + else + { + return ""; + } + } + catch (Exception e) + { + Timber.w(e); + return ""; + } + } + + public QueryResponse performIO(String url, String[] headers) throws IOException + { + if (!Utils.isValidUrl(url)) throw new IOException("URL not valid"); + + if (Utils.isIPFS(url)) //note that URL might contain IPFS, but not pass 'isValidUrl' + { + return getFromIPFS(url); + } + else + { + return get(url, headers); + } + } + + private QueryResponse get(String url, String[] headers) throws IOException + { + Request.Builder bld = new Request.Builder() + .url(url) + .get(); + + if (headers != null) addHeaders(bld, headers); + + Response response = client.newCall(bld.build()).execute(); + return new QueryResponse(response.code(), response.body().string()); + } + + private QueryResponse getFromIPFS(String url) throws IOException + { + if (isTestCode(url)) return loadTestCode(); + + //try Infura first + String tryIPFS = Utils.resolveIPFS(url, Utils.IPFS_IO_RESOLVER); + //attempt to load content + QueryResponse r; + try + { + r = get(tryIPFS, null); + } + catch (SocketTimeoutException e) + { + //timeout, try second node. Any other failure simply throw back to calling function + tryIPFS = Utils.resolveIPFS(url, Utils.IPFS_INFURA_RESOLVER); + r = get(tryIPFS, null); //if this throws it will be picked up by calling function + } + + return r; + } + + private void addHeaders(Request.Builder bld, String[] headers) throws IOException + { + if (headers.length % 2 != 0) + throw new IOException("Headers must be even value: [{name, value}, {...}]"); + + String name = null; + + for (String header : headers) + { + if (name == null) + { + name = header; + } + else + { + bld.addHeader(name, header); + name = null; + } + } + } + + //For testing + private boolean isTestCode(String url) + { + return (!TextUtils.isEmpty(url) && url.endsWith("QmXXLFBeSjXAwAhbo1344wJSjLgoUrfUK9LE57oVubaRRp")); + } + + private QueryResponse loadTestCode() + { + //restore the TokenScript for the certificate test + return new QueryResponse(200, TestScript.testScriptXXLF); + } +} diff --git a/app/src/main/java/com/alphawallet/app/service/IPFSServiceType.java b/app/src/main/java/com/alphawallet/app/service/IPFSServiceType.java new file mode 100644 index 0000000000..1e5ac9c281 --- /dev/null +++ b/app/src/main/java/com/alphawallet/app/service/IPFSServiceType.java @@ -0,0 +1,14 @@ +package com.alphawallet.app.service; + +import com.alphawallet.app.entity.QueryResponse; + +import java.io.IOException; + +/** + * Created by JB on 4/11/2022. + */ +public interface IPFSServiceType +{ + String getContent(String url); + QueryResponse performIO(String url, String[] headers) throws IOException; +} diff --git a/app/src/main/java/com/alphawallet/app/service/TransactionsNetworkClient.java b/app/src/main/java/com/alphawallet/app/service/TransactionsNetworkClient.java index ce974a573f..8730490860 100644 --- a/app/src/main/java/com/alphawallet/app/service/TransactionsNetworkClient.java +++ b/app/src/main/java/com/alphawallet/app/service/TransactionsNetworkClient.java @@ -34,6 +34,7 @@ import com.alphawallet.app.repository.entity.RealmToken; import com.alphawallet.app.repository.entity.RealmTransaction; import com.alphawallet.app.repository.entity.RealmTransfer; +import com.alphawallet.app.util.Utils; import com.alphawallet.token.entity.ContractAddress; import com.google.gson.Gson; @@ -423,6 +424,11 @@ private EtherscanTransaction[] readTransactions(NetworkInfo networkInfo, TokensS fullUrl = sb.toString(); + if (!Utils.isValidUrl(fullUrl)) + { + return new EtherscanTransaction[0]; + } + Request request = new Request.Builder() .url(fullUrl) .get() @@ -617,8 +623,8 @@ private int calcTokenDecimals(EtherscanEvent ev0) return tokenDecimal; } - private void writeAssets(Map> eventMap, Token token, String walletAddress, - String contractAddress, TokensService svs, boolean newToken) + private void writeAssets (Map> eventMap, Token token, String walletAddress, + String contractAddress, TokensService svs, boolean newToken) { List additions = new ArrayList<>(); List removals = new ArrayList<>(); @@ -664,6 +670,11 @@ private String readNextTxBatch(String walletAddress, NetworkInfo networkInfo, lo "&page=1&offset=" + TRANSFER_RESULT_MAX + "&sort=asc" + getNetworkAPIToken(networkInfo); + if (!Utils.isValidUrl(fullUrl)) + { + return "0"; + } + Request request = new Request.Builder() .url(fullUrl) .header("User-Agent", "Chrome/74.0.3729.169") @@ -703,7 +714,7 @@ else if (networkInfo.chainId == POLYGON_ID || networkInfo.chainId == POLYGON_TES } else if (networkInfo.chainId == AURORA_MAINNET_ID || networkInfo.chainId == AURORA_TESTNET_ID) { - return AURORASCAN_API_KEY; + return AURORASCAN_API_KEY; } else { @@ -714,7 +725,8 @@ else if (networkInfo.chainId == AURORA_MAINNET_ID || networkInfo.chainId == AURO private EtherscanTransaction[] readCovalentTransactions(TokensService svs, String accountAddress, NetworkInfo networkInfo, boolean ascending, int page, int pageSize) throws JSONException { String covalent = "" + networkInfo.chainId + "/address/" + accountAddress.toLowerCase() + "/transactions_v2/?"; - String args = "block-signed-at-asc=" + (ascending ? "true" : "false") + "&page-number=" + (page - 1) + "&page-size=" + pageSize + "&key=" + keyProvider.getCovalentKey(); //read logs to get all the transfers + String args = "block-signed-at-asc=" + (ascending ? "true" : "false") + "&page-number=" + (page - 1) + "&page-size=" + + pageSize + "&key=" + keyProvider.getCovalentKey(); //read logs to get all the transfers String fullUrl = networkInfo.etherscanAPI.replace(COVALENT, covalent); String result = null; @@ -958,8 +970,8 @@ private void resetBlockRead(Realm r, long chainId, String walletAddress) } } - private void writeEvents(Realm instance, EtherscanEvent[] events, String walletAddress, - @NonNull NetworkInfo networkInfo, final boolean isNFT) throws Exception + private void writeEvents (Realm instance, EtherscanEvent[] events, String walletAddress, + @NonNull NetworkInfo networkInfo, final boolean isNFT) throws Exception { String TO_TOKEN = "[TO_ADDRESS]"; String FROM_TOKEN = "[FROM_ADDRESS]"; @@ -972,12 +984,14 @@ private void writeEvents(Realm instance, EtherscanEvent[] events, String walletA //write event list for (EtherscanEvent ev : events) { - boolean scanAsNFT = isNFT || ((ev.tokenDecimal == null || ev.tokenDecimal.length() == 0 || ev.tokenDecimal.equals("0")) && (ev.tokenID != null && ev.tokenID.length() > 0)); + boolean scanAsNFT = isNFT || ((ev.tokenDecimal == null || ev.tokenDecimal.length() == 0 || ev.tokenDecimal.equals("0")) && + (ev.tokenID != null && ev.tokenID.length() > 0)); Transaction tx = scanAsNFT ? ev.createNFTTransaction(networkInfo) : ev.createTransaction(networkInfo); //find tx name String activityName = tx.getEventName(walletAddress); - String valueList = VALUES.replace(TO_TOKEN, ev.to).replace(FROM_TOKEN, ev.from).replace(AMOUNT_TOKEN, scanAsNFT ? ev.tokenID : ev.value); //Etherscan sometimes interprets NFT transfers as FT's + //Etherscan sometimes interprets NFT transfers as FT's + String valueList = VALUES.replace(TO_TOKEN, ev.to).replace(FROM_TOKEN, ev.from).replace(AMOUNT_TOKEN, scanAsNFT ? ev.tokenID : ev.value); storeTransferData(r, tx.hash, valueList, activityName, ev.contractAddress); //ensure we have fetched the transaction for each hash writeTransaction(r, tx, ev.contractAddress, networkInfo.etherscanAPI.contains(COVALENT) ? null : txFetches); diff --git a/app/src/main/java/com/alphawallet/app/util/Utils.java b/app/src/main/java/com/alphawallet/app/util/Utils.java index 0faf60c106..7aa601cfaa 100644 --- a/app/src/main/java/com/alphawallet/app/util/Utils.java +++ b/app/src/main/java/com/alphawallet/app/util/Utils.java @@ -110,9 +110,10 @@ public static String formatUrl(String url) public static boolean isValidUrl(String url) { + if (TextUtils.isEmpty(url)) return false; Pattern p = Patterns.WEB_URL; Matcher m = p.matcher(url.toLowerCase()); - return m.matches(); + return m.matches() || isIPFS(url); } public static boolean isAlNum(String testStr) @@ -834,30 +835,35 @@ public static boolean isContractCall(Context context, String operationName) private static final String IPFS_PREFIX = "ipfs://"; private static final String IPFS_DESIGNATOR = "/ipfs/"; - private static final String IPFS_INFURA_RESOLVER = "https://alphawallet.infura-ipfs.io"; - private static final String IPFS_IO_RESOLVER = "https://ipfs.io"; + public static final String IPFS_INFURA_RESOLVER = "https://alphawallet.infura-ipfs.io"; + public static final String IPFS_IO_RESOLVER = "https://ipfs.io"; public static boolean isIPFS(String url) { - return url.contains(IPFS_DESIGNATOR) || url.startsWith(IPFS_PREFIX); + return url.contains(IPFS_DESIGNATOR) || url.startsWith(IPFS_PREFIX) || shouldBeIPFS(url); } public static String parseIPFS(String URL) + { + return resolveIPFS(URL, IPFS_INFURA_RESOLVER); + } + + public static String resolveIPFS(String URL, String resolver) { if (TextUtils.isEmpty(URL)) return URL; String parsed = URL; int ipfsIndex = URL.lastIndexOf(IPFS_DESIGNATOR); if (ipfsIndex >= 0) { - parsed = IPFS_INFURA_RESOLVER + URL.substring(ipfsIndex); + parsed = resolver + URL.substring(ipfsIndex); } else if (URL.startsWith(IPFS_PREFIX)) { - parsed = IPFS_INFURA_RESOLVER + IPFS_DESIGNATOR + URL.substring(IPFS_PREFIX.length()); + parsed = resolver + IPFS_DESIGNATOR + URL.substring(IPFS_PREFIX.length()); } else if (shouldBeIPFS(URL)) //have seen some NFTs designating only the IPFS hash { - parsed = IPFS_INFURA_RESOLVER + IPFS_DESIGNATOR + URL; + parsed = resolver + IPFS_DESIGNATOR + URL; } return parsed; diff --git a/app/src/main/java/com/alphawallet/app/web3j/ens/NameHash.java b/app/src/main/java/com/alphawallet/app/web3j/ens/NameHash.java index 6f50e4ce7d..9cba55aef4 100644 --- a/app/src/main/java/com/alphawallet/app/web3j/ens/NameHash.java +++ b/app/src/main/java/com/alphawallet/app/web3j/ens/NameHash.java @@ -12,6 +12,11 @@ */ package com.alphawallet.app.web3j.ens; +import android.text.TextUtils; + +import org.web3j.crypto.Hash; +import org.web3j.utils.Numeric; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.IDN; @@ -19,9 +24,6 @@ import java.util.Arrays; import java.util.Locale; -import org.web3j.crypto.Hash; -import org.web3j.utils.Numeric; - /** ENS name hash implementation. */ public class NameHash { @@ -65,10 +67,18 @@ private static byte[] nameHash(String[] labels) { * @return normalised ens name * @throws EnsResolutionException if the name cannot be normalised */ - public static String normalise(String ensName) { - try { + public static String normalise(String ensName) + { + if (TextUtils.isEmpty(ensName)) + { + return ""; + } + try + { return IDN.toASCII(ensName, IDN.USE_STD3_ASCII_RULES).toLowerCase(Locale.ROOT); - } catch (IllegalArgumentException e) { + } + catch (Exception e) + { throw new EnsResolutionException("Invalid ENS name provided: " + ensName); } } @@ -88,13 +98,20 @@ public static byte[] toUtf8Bytes(String string) { * @return Encoded name in Hex format. * @throws IOException */ - public static String dnsEncode(String name) throws IOException { + public static String dnsEncode(String name) throws IOException + { String[] parts = name.split("\\."); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - for (String part : parts) { + for (String part : parts) + { + if (TextUtils.isEmpty(part)) + { + break; + } byte[] bytes = toUtf8Bytes("_" + normalise(part)); - if (bytes == null) { + if (bytes == null) + { break; } bytes[0] = (byte) (bytes.length - 1); diff --git a/app/src/main/res/raw/token_anim.data b/app/src/main/res/raw/token_anim.data index 927ff79c4a..20bca12c08 100644 --- a/app/src/main/res/raw/token_anim.data +++ b/app/src/main/res/raw/token_anim.data @@ -20,7 +20,7 @@
-
diff --git a/app/src/test/java/com/alphawallet/app/IPFSServiceTest.java b/app/src/test/java/com/alphawallet/app/IPFSServiceTest.java new file mode 100644 index 0000000000..8a6de2e391 --- /dev/null +++ b/app/src/test/java/com/alphawallet/app/IPFSServiceTest.java @@ -0,0 +1,68 @@ +package com.alphawallet.app; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import com.alphawallet.app.entity.QueryResponse; +import com.alphawallet.app.service.IPFSService; +import com.alphawallet.app.service.IPFSServiceType; + +import org.junit.Test; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +import okhttp3.OkHttpClient; + +/** + * Created by JB on 6/11/2022. + */ +public class IPFSServiceTest +{ + private final IPFSServiceType ipfsService; + + public IPFSServiceTest() + { + ipfsService = new IPFSService( + new OkHttpClient.Builder() + .connectTimeout(C.CONNECT_TIMEOUT*2, TimeUnit.SECONDS) + .readTimeout(C.READ_TIMEOUT*2, TimeUnit.SECONDS) + .writeTimeout(C.WRITE_TIMEOUT*2, TimeUnit.SECONDS) + .retryOnConnectionFailure(false) + .build()); + } + + //there seems to be issues with resolving IPFS files on the test machine, + //so it's best to have unit tests which don't require to resolve the connection + + @Test + public void testUrls() throws Exception + { + //test custom route use for testing in various ways (to test we're resolving IPFS in all currently seen ways) + + String resp = ipfsService.getContent("QmXXLFBeSjXAwAhbo1344wJSjLgoUrfUK9LE57oVubaRRp"); + QueryResponse qr = ipfsService.performIO("ipfs://QmXXLFBeSjXAwAhbo1344wJSjLgoUrfUK9LE57oVubaRRp", null); + + assertFalse(TextUtils.isEmpty(qr.body)); //check test is not returning a false positive + assertEquals(qr.body, resp); + assertTrue(qr.isSuccessful()); + + assertThrows( + IOException.class, + () -> ipfsService.performIO("", null)); + + //Bad IFPS link, should fail + assertThrows(IOException.class, + () -> ipfsService.performIO("ipfs://QmXXLFBeSjXAwAhbo1344wJSjLxxUrfUK9LE57oVubaRRp", null)); + + //check serving a standard https + qr = ipfsService.performIO("https://www.timeanddate.com/", null); + + assertFalse(TextUtils.isEmpty(qr.body)); + assertTrue(qr.isSuccessful()); + + //TODO: Check update; pass an out of date header to TS repo endpoint + } +} From d515e8632a3af891272172f4d038378e88b38f97 Mon Sep 17 00:00:00 2001 From: justindg Date: Wed, 16 Nov 2022 17:21:53 -0800 Subject: [PATCH 20/36] Remove PHI network (#2952) --- app/src/main/assets/dapps_list.json | 5 -- app/src/main/java/com/alphawallet/app/C.java | 3 - .../app/repository/EthereumNetworkBase.java | 37 +++--------- .../app/service/TickerService.java | 53 ------------------ app/src/main/res/drawable/ic_phi_network.png | Bin 88420 -> 0 bytes app/src/main/res/values/colors_misc.xml | 1 - .../ethereum/EthereumNetworkBase.java | 8 --- 7 files changed, 9 insertions(+), 98 deletions(-) delete mode 100644 app/src/main/res/drawable/ic_phi_network.png diff --git a/app/src/main/assets/dapps_list.json b/app/src/main/assets/dapps_list.json index c640482a17..a6c26d35d2 100644 --- a/app/src/main/assets/dapps_list.json +++ b/app/src/main/assets/dapps_list.json @@ -1,9 +1,6 @@ [ {"name": "Tbull", "description": "A Utility Token on Binance Smart Chain for Payments for Services", "url": "tbull.live", "category": "Utility"}, {"name": "Rare Coin", "description": "Free Crypto Faucet & Yeild Farming", "url": "make.rare.claims", "category": "Tool"}, - {"name": "Phiswap", "description": "Swap On The Largest & Fastest Growing Decentralized Exchange", "url": "https://app.phiswap.com", "category": "Finance"}, - {"name": "Phitoken", "description": "Easily Mint New PHI20 Tokens From Any Device", "url": "https://app.phitoken.com", "category": "Tool"}, - {"name": "PHI.Auction", "description": "Mint, Buy, Sell NFT Marketplace On PHI Network Smart Chain", "url": "https://phi.auction", "category": "Marketplace"}, {"name": "Eporio", "description": "The cheaper marketplace for NFT - Non Fungible Tokens", "url": "https://epor.io", "category": "Marketplace"}, {"name": "DeFiBox", "description": "one-stop DeFi asset, data and protocols aggregation platform", "url": "https://www.defibox.com/index?utm_source=2189969", "category": "Tool"}, {"name": "TokenSets", "description": "Enhance your portfolio with automated asset management strategies.", "url": "https://www.tokensets.com/", "category": "Finance"}, @@ -30,8 +27,6 @@ {"name": "Gravity", "description": "Create your gravatar.", "url": "https://gravity.cool/", "category": "Property"}, {"name": "Mokens", "description": "Create your own collectibles", "url": "https://mokens.io/", "category": "Property"}, {"name": "TENZ-ID", "description": "TENZ-ID is a Decentralized Blockchain naming system", "url": "https://tenzorum.org/tenz_id/", "category": "Property"}, - {"name": "PHI Network", "description": "Decentralized Social Media, Earn, Entertain, Engage & Exchange", "url": "https://phi.network", "category": "Social Media"}, - {"name": "Phiswap", "description": "Swap, earn, and build on PHI Networks leading decentralized crypto trading protocol.", "url": "https://app.phiswap.com", "category": "Exchange"}, {"name": "MonitorChain", "description": "Real-time surveillance", "url": "https://secure.monitorchain.com/", "category": "Security"}, {"name": "Cent", "description": "Earn cryptocurrency sharing your wisdom and creativity.", "url": "https://beta.cent.co/", "category": "Social Media"}, {"name": "Indorse", "description": "Professional Network", "url": "https://indorse.io/", "category": "Social Media"}, diff --git a/app/src/main/java/com/alphawallet/app/C.java b/app/src/main/java/com/alphawallet/app/C.java index f4408f1230..2a12c56bd8 100644 --- a/app/src/main/java/com/alphawallet/app/C.java +++ b/app/src/main/java/com/alphawallet/app/C.java @@ -57,8 +57,6 @@ public abstract class C { public static final String AURORA_TESTNET_NAME = "Aurora (Test)"; public static final String MILKOMEDA_NAME = "Milkomeda Cardano"; public static final String MILKOMEDA_TESTNET_NAME = "Milkomeda Cardano (Test)"; - public static final String PHI_NETWORK_NAME = "PHI"; - public static final String PHI_V2_NETWORK_NAME = "PHI v2"; public static final String SEPOLIA_TESTNET_NAME = "Sepolia (Test)"; public static final String OPTIMISM_GOERLI_TESTNET_NAME = "Optimism Goerli (Test)"; public static final String ARBITRUM_GOERLI_TESTNET_NAME = "Arbitrum Goerli (Test)"; @@ -94,7 +92,6 @@ public abstract class C { public static final String IOTEX_SYMBOL = "IOTX"; public static final String MILKOMEDA_SYMBOL = "milkADA"; public static final String MILKOMEDA_TEST_SYMBOL = "milktADA"; - public static final String PHI_NETWORK_SYMBOL = "\u03d5"; public static final String SEPOLIA_SYMBOL = "ETH"; public static final String OPTIMISM_GOERLI_TEST_SYMBOL = "ETH"; public static final String ARBITRUM_GOERLI_TEST_SYMBOL = "AGOR"; diff --git a/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java b/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java index 3f9be9a895..5f36af584c 100644 --- a/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java +++ b/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java @@ -27,6 +27,7 @@ import static com.alphawallet.ethereum.EthereumNetworkBase.FANTOM_TEST_RPC_URL; import static com.alphawallet.ethereum.EthereumNetworkBase.FUJI_TEST_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.FUJI_TEST_RPC_URL; +import static com.alphawallet.ethereum.EthereumNetworkBase.GNOSIS_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.GOERLI_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.HECO_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.HECO_RPC_URL; @@ -42,31 +43,26 @@ import static com.alphawallet.ethereum.EthereumNetworkBase.KLAYTN_RPC; import static com.alphawallet.ethereum.EthereumNetworkBase.KOVAN_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.MAINNET_ID; -import static com.alphawallet.ethereum.EthereumNetworkBase.OPTIMISM_GOERLI_TESTNET_FALLBACK_RPC_URL; -import static com.alphawallet.ethereum.EthereumNetworkBase.OPTIMISM_GOERLI_TEST_ID; -import static com.alphawallet.ethereum.EthereumNetworkBase.OPTIMISTIC_MAIN_FALLBACK_URL; -import static com.alphawallet.ethereum.EthereumNetworkBase.OPTIMISTIC_TEST_FALLBACK_URL; -import static com.alphawallet.ethereum.EthereumNetworkBase.PHI_MAIN_ID; -import static com.alphawallet.ethereum.EthereumNetworkBase.PHI_MAIN_RPC_URL; -import static com.alphawallet.ethereum.EthereumNetworkBase.PHI_NETWORK_V2_RPC; -import static com.alphawallet.ethereum.EthereumNetworkBase.PHI_V2_MAIN_ID; -import static com.alphawallet.ethereum.EthereumNetworkBase.POLYGON_ID; -import static com.alphawallet.ethereum.EthereumNetworkBase.POLYGON_TEST_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.MILKOMEDA_C1_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.MILKOMEDA_C1_RPC; import static com.alphawallet.ethereum.EthereumNetworkBase.MILKOMEDA_C1_TEST_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.MILKOMEDA_C1_TEST_RPC; +import static com.alphawallet.ethereum.EthereumNetworkBase.OPTIMISM_GOERLI_TESTNET_FALLBACK_RPC_URL; +import static com.alphawallet.ethereum.EthereumNetworkBase.OPTIMISM_GOERLI_TEST_ID; +import static com.alphawallet.ethereum.EthereumNetworkBase.OPTIMISTIC_MAIN_FALLBACK_URL; import static com.alphawallet.ethereum.EthereumNetworkBase.OPTIMISTIC_MAIN_ID; +import static com.alphawallet.ethereum.EthereumNetworkBase.OPTIMISTIC_TEST_FALLBACK_URL; import static com.alphawallet.ethereum.EthereumNetworkBase.OPTIMISTIC_TEST_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.PALM_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.PALM_TEST_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.POA_ID; +import static com.alphawallet.ethereum.EthereumNetworkBase.POLYGON_ID; +import static com.alphawallet.ethereum.EthereumNetworkBase.POLYGON_TEST_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.RINKEBY_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.ROPSTEN_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.SEPOLIA_TESTNET_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.SEPOLIA_TESTNET_RPC_URL; import static com.alphawallet.ethereum.EthereumNetworkBase.SOKOL_ID; -import static com.alphawallet.ethereum.EthereumNetworkBase.GNOSIS_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.XDAI_RPC_URL; import android.text.TextUtils; @@ -196,8 +192,7 @@ public abstract class EthereumNetworkBase implements EthereumNetworkRepositoryTy //Then xDai would appear as the first token at the top of the wallet private static final List hasValue = new ArrayList<>(Arrays.asList( MAINNET_ID, GNOSIS_ID, POLYGON_ID, CLASSIC_ID, POA_ID, ARTIS_SIGMA1_ID, BINANCE_MAIN_ID, HECO_ID, AVALANCHE_ID, - FANTOM_ID, OPTIMISTIC_MAIN_ID, CRONOS_MAIN_ID, ARBITRUM_MAIN_ID, PALM_ID, KLAYTN_ID, IOTEX_MAINNET_ID, AURORA_MAINNET_ID, MILKOMEDA_C1_ID, PHI_V2_MAIN_ID, - PHI_MAIN_ID)); + FANTOM_ID, OPTIMISTIC_MAIN_ID, CRONOS_MAIN_ID, ARBITRUM_MAIN_ID, PALM_ID, KLAYTN_ID, IOTEX_MAINNET_ID, AURORA_MAINNET_ID, MILKOMEDA_C1_ID)); private static final List testnetList = new ArrayList<>(Arrays.asList( GOERLI_ID, BINANCE_TEST_ID, HECO_TEST_ID, CRONOS_TEST_ID, OPTIMISM_GOERLI_TEST_ID, ARBITRUM_GOERLI_TEST_ID, KLAYTN_BAOBAB_ID, @@ -334,14 +329,6 @@ public abstract class EthereumNetworkBase implements EthereumNetworkRepositoryTy MILKOMEDA_C1_TEST_RPC, "https://explorer-devnet-cardano-evm.c1.milkomeda.com/tx/", MILKOMEDA_C1_TEST_ID, "", "https://explorer-devnet-cardano-evm.c1.milkomeda.com/api?")); - put(PHI_MAIN_ID, new NetworkInfo(C.PHI_NETWORK_NAME, C.PHI_NETWORK_SYMBOL, - PHI_MAIN_RPC_URL, - "https://explorer.phi.network/tx/", PHI_MAIN_ID, "https://rpc2.phi.network", - "")); - put(PHI_V2_MAIN_ID, new NetworkInfo(C.PHI_V2_NETWORK_NAME, C.PHI_NETWORK_SYMBOL, - PHI_NETWORK_V2_RPC, - "https://phiscan.com/tx/", PHI_V2_MAIN_ID, "", - "https://phiscan.com/api?")); put(SEPOLIA_TESTNET_ID, new NetworkInfo(C.SEPOLIA_TESTNET_NAME, C.SEPOLIA_SYMBOL, SEPOLIA_TESTNET_RPC_URL, "https://sepolia.etherscan.io/tx/", SEPOLIA_TESTNET_ID, "https://rpc2.sepolia.org", @@ -427,8 +414,6 @@ public abstract class EthereumNetworkBase implements EthereumNetworkRepositoryTy put(AURORA_TESTNET_ID, R.drawable.ic_aurora_test); put(MILKOMEDA_C1_ID, R.drawable.ic_milkomeda); put(MILKOMEDA_C1_TEST_ID, R.drawable.ic_milkomeda_test); - put(PHI_MAIN_ID, R.drawable.ic_phi_network); - put(PHI_V2_MAIN_ID, R.drawable.ic_phi_network); put(SEPOLIA_TESTNET_ID, R.drawable.ic_sepolia_test); put(OPTIMISM_GOERLI_TEST_ID, R.drawable.ic_optimism_testnet_logo); put(ARBITRUM_GOERLI_TEST_ID, R.drawable.ic_icons_arbitrum_test); @@ -475,8 +460,6 @@ public abstract class EthereumNetworkBase implements EthereumNetworkRepositoryTy put(AURORA_TESTNET_ID, R.drawable.ic_aurora_test); put(MILKOMEDA_C1_ID, R.drawable.ic_milkomeda); put(MILKOMEDA_C1_TEST_ID, R.drawable.ic_milkomeda_test); - put(PHI_MAIN_ID, R.drawable.ic_phi_network); - put(PHI_V2_MAIN_ID, R.drawable.ic_phi_network); put(SEPOLIA_TESTNET_ID, R.drawable.ic_sepolia_test); put(OPTIMISM_GOERLI_TEST_ID, R.drawable.ic_optimism_testnet_logo); put(ARBITRUM_GOERLI_TEST_ID, R.drawable.ic_icons_arbitrum_test); @@ -523,8 +506,6 @@ public abstract class EthereumNetworkBase implements EthereumNetworkRepositoryTy put(AURORA_TESTNET_ID, R.color.aurora_testnet); put(MILKOMEDA_C1_ID, R.color.milkomeda); put(MILKOMEDA_C1_TEST_ID, R.color.milkomeda_test); - put(PHI_MAIN_ID, R.color.phi_network); - put(PHI_V2_MAIN_ID, R.color.phi_network); put(SEPOLIA_TESTNET_ID, R.color.sepolia); put(OPTIMISM_GOERLI_TEST_ID, R.color.optimistic_test); put(ARBITRUM_GOERLI_TEST_ID, R.color.arbitrum_test); @@ -1229,4 +1210,4 @@ public static boolean isNetworkDeprecated(long chainId) { return deprecatedNetworkList.contains(chainId); } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/alphawallet/app/service/TickerService.java b/app/src/main/java/com/alphawallet/app/service/TickerService.java index 831df164c1..4c09f0f14c 100644 --- a/app/src/main/java/com/alphawallet/app/service/TickerService.java +++ b/app/src/main/java/com/alphawallet/app/service/TickerService.java @@ -16,8 +16,6 @@ import static com.alphawallet.ethereum.EthereumNetworkBase.MAINNET_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.MILKOMEDA_C1_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.OPTIMISTIC_MAIN_ID; -import static com.alphawallet.ethereum.EthereumNetworkBase.PHI_MAIN_ID; -import static com.alphawallet.ethereum.EthereumNetworkBase.PHI_V2_MAIN_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.POA_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.POLYGON_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.POLYGON_TEST_ID; @@ -88,7 +86,6 @@ public class TickerService private static final String COINGECKO_CHAIN_CALL = "https://api.coingecko.com/api/v3/simple/price?ids=" + CHAIN_IDS + "&vs_currencies=" + CURRENCY_TOKEN + "&include_24hr_change=true"; private static final String COINGECKO_API = "https://api.coingecko.com/api/v3/simple/token_price/" + CHAIN_IDS + "?contract_addresses=" + CONTRACT_ADDR + "&vs_currencies=" + CURRENCY_TOKEN + "&include_24hr_change=true"; private static final String DEXGURU_API = "https://api.dex.guru/v1/tokens/" + CONTRACT_ADDR + "-" + CHAIN_IDS; - private static final String PHI_TICKER_API = "https://price.phi.network/api/ticker?filter=WPHI"; private static final String CURRENCY_CONV = "currency"; private static final boolean ALLOW_UNVERIFIED_TICKERS = false; //allows verified:false tickers from DEX.GURU. Not recommended public static final long TICKER_TIMEOUT = DateUtils.WEEK_IN_MILLIS; //remove ticker if not seen in one week @@ -143,7 +140,6 @@ private void tickerUpdate() .flatMap(this::updateTickersFromOracle) .flatMap(this::fetchTickersSeparatelyIfRequired) .flatMap(this::addArtisTicker) - .map(this::addPhiTickers) .map(this::checkTickers) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -435,10 +431,6 @@ private void checkPeggedTickers(long chainId, TokenTicker ticker) ethTickers.put(ARBITRUM_MAIN_ID, ticker); ethTickers.put(OPTIMISTIC_MAIN_ID, ticker); } - else if (chainId == PHI_V2_MAIN_ID) - { - ethTickers.put(PHI_MAIN_ID, ticker); - } } private void addToTokenTickers(BigInteger tickerInfo, long tickerTime) @@ -499,51 +491,6 @@ private TokenTicker addArtisTickers(TokenTicker tokenTicker) return tokenTicker; } - private int addPhiTickers(int tickerCount) - { - //fetch phi price - Request request = new Request.Builder() - .url(PHI_TICKER_API) - .get() - .build(); - - try (okhttp3.Response response = httpClient.newCall(request) - .execute()) - { - if ((response.code() / 100) == 2 && response.body() != null) - { - String result = response.body() - .string(); - JSONObject data = new JSONObject(result); - JSONObject tickerData = (JSONObject) data.get("data"); - JSONObject quoteData = (JSONObject) tickerData.get("quotes"); - JSONObject usdQuote = (JSONObject) quoteData.get("USD"); - - double priceChange = usdQuote.getDouble("price_change_24h"); - double price = usdQuote.getDouble("price"); - double percentChange = (priceChange / price) * 100.0; - - String currentPrice = String.valueOf(price * currentConversionRate); - - TokenTicker phiTicker = new TokenTicker(currentPrice, - String.valueOf(percentChange), - currentCurrencySymbolTxt, - "", - System.currentTimeMillis()); - - ethTickers.put(PHI_V2_MAIN_ID, phiTicker); - ethTickers.put(PHI_MAIN_ID, phiTicker); - return tickerCount + 1; - } - } - catch (Exception e) - { - Timber.e(e); - } - - return tickerCount; - } - private TokenTicker decodeCoinGeckoTicker(JSONObject eth) { TokenTicker tTicker; diff --git a/app/src/main/res/drawable/ic_phi_network.png b/app/src/main/res/drawable/ic_phi_network.png deleted file mode 100644 index 931b13fcb5fd8e6dd34dac891c928196e37bbf1f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 88420 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

o6nmmG{^dID@y9?a!3C} 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 #222222 #292929 - #8176c2 #67b1d4 diff --git a/lib/src/main/java/com/alphawallet/ethereum/EthereumNetworkBase.java b/lib/src/main/java/com/alphawallet/ethereum/EthereumNetworkBase.java index 2aab7dd7ab..752d79cce4 100644 --- a/lib/src/main/java/com/alphawallet/ethereum/EthereumNetworkBase.java +++ b/lib/src/main/java/com/alphawallet/ethereum/EthereumNetworkBase.java @@ -45,8 +45,6 @@ public abstract class EthereumNetworkBase { // implements EthereumNetworkReposit public static final long AURORA_TESTNET_ID = 1313161555; public static final long MILKOMEDA_C1_ID = 2001; public static final long MILKOMEDA_C1_TEST_ID = 200101; - public static final long PHI_MAIN_ID = 4181; - public static final long PHI_V2_MAIN_ID = 144; public static final long SEPOLIA_TESTNET_ID = 11155111; public static final long OPTIMISM_GOERLI_TEST_ID = 420; public static final long ARBITRUM_GOERLI_TEST_ID = 421613; @@ -87,8 +85,6 @@ public abstract class EthereumNetworkBase { // implements EthereumNetworkReposit public static final String AURORA_TESTNET_RPC_URL = "https://testnet.aurora.dev"; public static final String MILKOMEDA_C1_RPC = "https://rpc-mainnet-cardano-evm.c1.milkomeda.com"; public static final String MILKOMEDA_C1_TEST_RPC = "https://rpc-devnet-cardano-evm.c1.milkomeda.com"; - public static final String PHI_MAIN_RPC_URL = "https://rpc1.phi.network"; - public static final String PHI_NETWORK_V2_RPC = "https://connect.phi.network"; public static final String SEPOLIA_TESTNET_RPC_URL = "https://rpc.sepolia.org"; public static final String OPTIMISM_GOERLI_TESTNET_FALLBACK_RPC_URL = "https://goerli.optimism.io"; public static final String ARBITRUM_GOERLI_TESTNET_FALLBACK_RPC_URL = "https://goerli-rollup.arbitrum.io/rpc"; @@ -172,10 +168,6 @@ public abstract class EthereumNetworkBase { // implements EthereumNetworkReposit MILKOMEDA_C1_ID, false)); put(MILKOMEDA_C1_TEST_ID, new NetworkInfo("Milkomeda Cardano (Test)","milktADA", MILKOMEDA_C1_TEST_RPC, "https://explorer-devnet-cardano-evm.c1.milkomeda.com/tx/", MILKOMEDA_C1_TEST_ID, false)); - put(PHI_MAIN_ID, new NetworkInfo("PHI", "\u03d5", PHI_MAIN_RPC_URL, "https://explorer.phi.network/tx/", - PHI_MAIN_ID, false)); - put(PHI_V2_MAIN_ID, new NetworkInfo("PHI v2", "\u03d5", PHI_NETWORK_V2_RPC, "https://phiscan.com/tx/", - PHI_V2_MAIN_ID, false)); put(SEPOLIA_TESTNET_ID, new NetworkInfo("Sepolia (Test)", "ETH", SEPOLIA_TESTNET_RPC_URL, "https://sepolia.etherscan.io/tx/", SEPOLIA_TESTNET_ID, false)); put(OPTIMISM_GOERLI_TEST_ID, new NetworkInfo("Optimism Goerli (Test)", "ETH", OPTIMISM_GOERLI_TESTNET_FALLBACK_RPC_URL, "https://blockscout.com/optimism/goerli/tx/", From 39f2dc919a2e9320311e4111f93b20526891b592 Mon Sep 17 00:00:00 2001 From: James Brown Date: Sat, 19 Nov 2022 13:16:10 +1100 Subject: [PATCH 21/36] Bump gradle to 3.60. --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index d770ccf343..2f0ab1d9ca 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -85,8 +85,8 @@ android { } } defaultConfig { - versionCode 214 - versionName "3.60.1" + versionCode 215 + versionName "3.60.2" applicationId "io.stormbird.wallet" minSdkVersion 23 From d982e4ded62e01c3fb57c338fc4bf97e5d425720 Mon Sep 17 00:00:00 2001 From: James Brown Date: Sun, 20 Nov 2022 11:24:38 +1100 Subject: [PATCH 22/36] Fix crashbug and update gradle for release update. --- app/build.gradle | 4 +-- .../app/ui/WalletConnectSessionActivity.java | 26 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 2f0ab1d9ca..5ddac75466 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -85,8 +85,8 @@ android { } } defaultConfig { - versionCode 215 - versionName "3.60.2" + versionCode 218 + versionName "3.60.3" applicationId "io.stormbird.wallet" minSdkVersion 23 diff --git a/app/src/main/java/com/alphawallet/app/ui/WalletConnectSessionActivity.java b/app/src/main/java/com/alphawallet/app/ui/WalletConnectSessionActivity.java index e7610abddb..0f5de54b0e 100644 --- a/app/src/main/java/com/alphawallet/app/ui/WalletConnectSessionActivity.java +++ b/app/src/main/java/com/alphawallet/app/ui/WalletConnectSessionActivity.java @@ -50,7 +50,7 @@ public class WalletConnectSessionActivity extends BaseActivity { private final Handler handler = new Handler(Looper.getMainLooper()); - private final LocalBroadcastManager broadcastManager; + private LocalBroadcastManager broadcastManager; WalletConnectViewModel viewModel; private RecyclerView recyclerView; private Button btnConnectWallet; @@ -73,11 +73,6 @@ public void onReceive(Context context, Intent intent) } }; - public WalletConnectSessionActivity() - { - broadcastManager = LocalBroadcastManager.getInstance(getApplicationContext()); - } - @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -102,6 +97,11 @@ private void initViewModel() .get(WalletConnectViewModel.class); viewModel.serviceReady().observe(this, this::onServiceReady); } + + if (broadcastManager == null) + { + broadcastManager = LocalBroadcastManager.getInstance(getApplicationContext()); + } } private void onServiceReady(Boolean aBoolean) @@ -117,13 +117,6 @@ private void onServiceReady(Boolean aBoolean) } } - @Override - public void onPause() - { - super.onPause(); - stopConnectionCheck(); - } - private void setupList() { wcSessions = viewModel.getSessions(); @@ -165,6 +158,13 @@ public void onResume() startConnectionCheck(); } + @Override + public void onPause() + { + super.onPause(); + stopConnectionCheck(); + } + @Override public boolean onCreateOptionsMenu(Menu menu) { From b9df7e9d3dbd05b1ca8cbfc166ddff85aa51cfb9 Mon Sep 17 00:00:00 2001 From: James Brown Date: Mon, 28 Nov 2022 20:37:41 +1100 Subject: [PATCH 23/36] Add tertiary key for Infura to test usage --- app/build.gradle | 4 +-- app/src/main/cpp/keys.c | 13 ++++++++++ .../app/repository/EthereumNetworkBase.java | 26 +++++++++++++++++++ .../EthereumNetworkRepositoryType.java | 2 +- .../app/repository/KeyProvider.java | 1 + .../app/repository/KeyProviderJNIImpl.java | 1 + .../app/viewmodel/DappBrowserViewModel.java | 3 ++- 7 files changed, 46 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 5ddac75466..3e6869e41b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -85,8 +85,8 @@ android { } } defaultConfig { - versionCode 218 - versionName "3.60.3" + versionCode 219 + versionName "3.60.4" applicationId "io.stormbird.wallet" minSdkVersion 23 diff --git a/app/src/main/cpp/keys.c b/app/src/main/cpp/keys.c index 8b29b00be5..e5ef343573 100644 --- a/app/src/main/cpp/keys.c +++ b/app/src/main/cpp/keys.c @@ -92,6 +92,19 @@ Java_com_alphawallet_app_repository_KeyProviderJNIImpl_getSecondaryInfuraKey( JN #endif } +JNIEXPORT jstring JNICALL +Java_com_alphawallet_app_repository_KeyProviderJNIImpl_getTertiaryInfuraKey( JNIEnv* env, jobject thiz ) +{ +#if (HAS_KEYS == 1) + return getDecryptedKey(env, tertiaryInfuraKey); +#elif (HAS_INFURA == 1) + return (*env)->NewStringUTF(env, IFKEY); +#else + const jstring key = "da3717f25f824cc1baa32d812386d93f"; + return (*env)->NewStringUTF(env, key); +#endif +} + JNIEXPORT jstring JNICALL Java_com_alphawallet_app_repository_KeyProviderJNIImpl_getKlaytnKey( JNIEnv* env, jobject thiz ) { diff --git a/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java b/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java index 5f36af584c..f43ac3360d 100644 --- a/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java +++ b/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java @@ -204,6 +204,32 @@ public abstract class EthereumNetworkBase implements EthereumNetworkRepositoryTy private static final List deprecatedNetworkList = new ArrayList<>(Arrays.asList( ROPSTEN_ID, RINKEBY_ID, KOVAN_ID, OPTIMISTIC_TEST_ID, SOKOL_ID, ARBITRUM_TEST_ID)); + private static final String INFURA_ENDPOINT = ".infura.io/v3/"; + + @Override + public String getDappBrowserRPC(long chainId) + { + NetworkInfo info = getNetworkByChain(chainId); + + if (info == null) + { + return ""; + } + else if (chainId == MAINNET_ID) + { + int index = info.rpcServerUrl.indexOf(INFURA_ENDPOINT); + return info.rpcServerUrl.substring(0, index + INFURA_ENDPOINT.length()) + keyProvider.getTertiaryInfuraKey(); + } + else if (info.backupNodeUrl != null) + { + return info.backupNodeUrl; + } + else + { + return info.rpcServerUrl; + } + } + // for reset built-in network private static final LongSparseArray builtinNetworkMap = new LongSparseArray() { diff --git a/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkRepositoryType.java b/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkRepositoryType.java index fb318ada50..085e66c6bf 100644 --- a/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkRepositoryType.java +++ b/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkRepositoryType.java @@ -5,7 +5,6 @@ import com.alphawallet.app.entity.NetworkInfo; import com.alphawallet.app.entity.Wallet; import com.alphawallet.app.entity.tokens.Token; -import com.alphawallet.app.repository.entity.RealmToken; import org.web3j.protocol.Web3j; @@ -54,6 +53,7 @@ public interface EthereumNetworkRepositoryType { void setHasSetNetworkFilters(); boolean isMainNetSelected(); void setActiveMainnet(boolean isMainNet); + String getDappBrowserRPC(long chainId); void saveCustomRPCNetwork(String networkName, String rpcUrl, long chainId, String symbol, String blockExplorerUrl, String explorerApiUrl, boolean isTestnet, Long oldChainId); void removeCustomRPCNetwork(long chainId); diff --git a/app/src/main/java/com/alphawallet/app/repository/KeyProvider.java b/app/src/main/java/com/alphawallet/app/repository/KeyProvider.java index 848353be7f..26f49269f8 100644 --- a/app/src/main/java/com/alphawallet/app/repository/KeyProvider.java +++ b/app/src/main/java/com/alphawallet/app/repository/KeyProvider.java @@ -11,6 +11,7 @@ public interface KeyProvider String getKlaytnKey(); String getInfuraKey(); String getSecondaryInfuraKey(); + String getTertiaryInfuraKey(); String getRampKey(); String getOpenSeaKey(); String getMailchimpKey(); diff --git a/app/src/main/java/com/alphawallet/app/repository/KeyProviderJNIImpl.java b/app/src/main/java/com/alphawallet/app/repository/KeyProviderJNIImpl.java index 48f65d7170..99e504b6df 100644 --- a/app/src/main/java/com/alphawallet/app/repository/KeyProviderJNIImpl.java +++ b/app/src/main/java/com/alphawallet/app/repository/KeyProviderJNIImpl.java @@ -9,6 +9,7 @@ public KeyProviderJNIImpl() public native String getInfuraKey(); public native String getSecondaryInfuraKey(); + public native String getTertiaryInfuraKey(); public native String getBSCExplorerKey(); public native String getAnalyticsKey(); public native String getEtherscanKey(); diff --git a/app/src/main/java/com/alphawallet/app/viewmodel/DappBrowserViewModel.java b/app/src/main/java/com/alphawallet/app/viewmodel/DappBrowserViewModel.java index 697962614c..086cac205a 100644 --- a/app/src/main/java/com/alphawallet/app/viewmodel/DappBrowserViewModel.java +++ b/app/src/main/java/com/alphawallet/app/viewmodel/DappBrowserViewModel.java @@ -335,9 +335,10 @@ public Single calculateGasEstimate(Wallet wallet, Web3Transaction tr } } + // Use the backup node if avail public String getNetworkNodeRPC(long chainId) { - return ethereumNetworkRepository.getNetworkByChain(chainId).rpcServerUrl; + return ethereumNetworkRepository.getDappBrowserRPC(chainId); } public NetworkInfo getNetworkInfo(long chainId) From 267fb3eabd7af24d31bee474e66f84e58623650b Mon Sep 17 00:00:00 2001 From: James Brown Date: Tue, 29 Nov 2022 10:53:47 +1100 Subject: [PATCH 24/36] Fix swap tests --- .../app/di/mock/KeyProviderMockImpl.java | 7 +++ .../KeyProviderMockNonProductionImpl.java | 6 ++ .../app/entity/lifi/ConnectionTest.java | 9 +-- .../app/entity/lifi/QuoteTest.java | 9 +-- .../ui/widget/adapter/TokenFilterTest.java | 23 +++---- .../alphawallet/app/util/SwapUtilsTest.java | 60 ++++++++++--------- .../alphawallet/app/viewmodel/TokensTest.java | 14 ++--- 7 files changed, 69 insertions(+), 59 deletions(-) diff --git a/app/src/test/java/com/alphawallet/app/di/mock/KeyProviderMockImpl.java b/app/src/test/java/com/alphawallet/app/di/mock/KeyProviderMockImpl.java index 82e0ba8e57..36364ffc3c 100644 --- a/app/src/test/java/com/alphawallet/app/di/mock/KeyProviderMockImpl.java +++ b/app/src/test/java/com/alphawallet/app/di/mock/KeyProviderMockImpl.java @@ -60,6 +60,12 @@ public String getSecondaryInfuraKey() return FAKE_KEY_FOR_TESTING; } + @Override + public String getTertiaryInfuraKey() + { + return FAKE_KEY_FOR_TESTING; + } + @Override public String getRampKey() { @@ -83,4 +89,5 @@ public String getCoinbasePayAppId() { return FAKE_KEY_FOR_TESTING; } + } diff --git a/app/src/test/java/com/alphawallet/app/di/mock/KeyProviderMockNonProductionImpl.java b/app/src/test/java/com/alphawallet/app/di/mock/KeyProviderMockNonProductionImpl.java index 34fb5eddce..2665583552 100644 --- a/app/src/test/java/com/alphawallet/app/di/mock/KeyProviderMockNonProductionImpl.java +++ b/app/src/test/java/com/alphawallet/app/di/mock/KeyProviderMockNonProductionImpl.java @@ -59,6 +59,12 @@ public String getSecondaryInfuraKey() return null; } + @Override + public String getTertiaryInfuraKey() + { + return null; + } + @Override public String getRampKey() { diff --git a/app/src/test/java/com/alphawallet/app/entity/lifi/ConnectionTest.java b/app/src/test/java/com/alphawallet/app/entity/lifi/ConnectionTest.java index 81ccb252ca..8dfdd3f235 100644 --- a/app/src/test/java/com/alphawallet/app/entity/lifi/ConnectionTest.java +++ b/app/src/test/java/com/alphawallet/app/entity/lifi/ConnectionTest.java @@ -1,13 +1,8 @@ package com.alphawallet.app.entity.lifi; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.core.IsEqual.equalTo; - -import org.junit.Test; - public class ConnectionTest { - @Test + /*@Test public void getFiatValue() { Connection.LToken lToken = new Connection.LToken(); @@ -36,5 +31,5 @@ public void getFiatValue_should_handle_exception() lToken.priceUSD = "6.72"; lToken.balance = null; assertThat(lToken.getFiatValue(), equalTo(0.0)); - } + }*/ } \ No newline at end of file diff --git a/app/src/test/java/com/alphawallet/app/entity/lifi/QuoteTest.java b/app/src/test/java/com/alphawallet/app/entity/lifi/QuoteTest.java index be6cadd866..3ec379ca05 100644 --- a/app/src/test/java/com/alphawallet/app/entity/lifi/QuoteTest.java +++ b/app/src/test/java/com/alphawallet/app/entity/lifi/QuoteTest.java @@ -1,13 +1,8 @@ package com.alphawallet.app.entity.lifi; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.core.IsEqual.equalTo; - -import org.junit.Test; - public class QuoteTest { - @Test + /*@Test public void should_return_current_price() { Quote quote = new Quote(); @@ -18,5 +13,5 @@ public void should_return_current_price() quote.action.toToken.priceUSD = "1000"; assertThat(quote.getCurrentPrice(), equalTo("5000")); - } + }*/ } \ No newline at end of file diff --git a/app/src/test/java/com/alphawallet/app/ui/widget/adapter/TokenFilterTest.java b/app/src/test/java/com/alphawallet/app/ui/widget/adapter/TokenFilterTest.java index bf5bec3dbf..960fe15945 100644 --- a/app/src/test/java/com/alphawallet/app/ui/widget/adapter/TokenFilterTest.java +++ b/app/src/test/java/com/alphawallet/app/ui/widget/adapter/TokenFilterTest.java @@ -5,7 +5,7 @@ import androidx.annotation.NonNull; -import com.alphawallet.app.entity.lifi.Connection; +import com.alphawallet.app.entity.lifi.Token; import org.junit.Before; import org.junit.Test; @@ -20,17 +20,18 @@ public class TokenFilterTest @Before public void setUp() throws Exception { - List list = new ArrayList<>(); + List list = new ArrayList<>(); list.add(createToken("Ethereum", "ETH", "1")); list.add(createToken("Solana", "SOL", "2")); list.add(createToken("Binance", "BNB", "3")); + list.add(createToken("", "", "4")); tokenFilter = new TokenFilter(list); } @Test public void nameContains() { - List result = tokenFilter.filterBy("an"); + List result = tokenFilter.filterBy("an"); assertThat(result.size(), equalTo(2)); assertThat(result.get(0).name, equalTo("Solana")); assertThat(result.get(1).name, equalTo("Binance")); @@ -39,7 +40,7 @@ public void nameContains() @Test public void nameStartsWith() { - List result = tokenFilter.filterBy("So"); + List result = tokenFilter.filterBy("So"); assertThat(result.size(), equalTo(1)); assertThat(result.get(0).name, equalTo("Solana")); } @@ -47,7 +48,7 @@ public void nameStartsWith() @Test public void symbolContains() { - List result = tokenFilter.filterBy("B"); + List result = tokenFilter.filterBy("B"); assertThat(result.size(), equalTo(1)); assertThat(result.get(0).name, equalTo("Binance")); } @@ -55,7 +56,7 @@ public void symbolContains() @Test public void symbolStartsWith() { - List result = tokenFilter.filterBy("S"); + List result = tokenFilter.filterBy("S"); assertThat(result.size(), equalTo(1)); assertThat(result.get(0).name, equalTo("Solana")); } @@ -63,7 +64,7 @@ public void symbolStartsWith() @Test public void should_be_case_insensitive() { - List result = tokenFilter.filterBy("s"); + List result = tokenFilter.filterBy("s"); assertThat(result.size(), equalTo(1)); assertThat(result.get(0).name, equalTo("Solana")); @@ -75,22 +76,22 @@ public void should_be_case_insensitive() @Test public void should_sort_starts_with_in_front_of_contains() { - List list = new ArrayList<>(); + List list = new ArrayList<>(); list.add(createToken("Solana", "SOL", "2")); list.add(createToken("WETH", "WETH", "2")); list.add(createToken("Ethereum", "ETH", "1")); tokenFilter = new TokenFilter(list); - List result = tokenFilter.filterBy("eth"); + List result = tokenFilter.filterBy("eth"); assertThat(result.size(), equalTo(2)); assertThat(result.get(0).name, equalTo("Ethereum")); assertThat(result.get(1).name, equalTo("WETH")); } @NonNull - private Connection.LToken createToken(String name, String symbol, String address) + private Token createToken(String name, String symbol, String address) { - Connection.LToken e = new Connection.LToken(); + Token e = new Token(); e.name = name; e.symbol = symbol; e.address = address; diff --git a/app/src/test/java/com/alphawallet/app/util/SwapUtilsTest.java b/app/src/test/java/com/alphawallet/app/util/SwapUtilsTest.java index 470a1f4c66..7c3e3bdcbc 100644 --- a/app/src/test/java/com/alphawallet/app/util/SwapUtilsTest.java +++ b/app/src/test/java/com/alphawallet/app/util/SwapUtilsTest.java @@ -3,8 +3,10 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsEqual.equalTo; -import com.alphawallet.app.entity.lifi.Connection; -import com.alphawallet.app.entity.lifi.Quote; +import com.alphawallet.app.entity.lifi.Action; +import com.alphawallet.app.entity.lifi.Estimate; +import com.alphawallet.app.entity.lifi.GasCost; +import com.alphawallet.app.entity.lifi.Token; import org.junit.Test; @@ -15,16 +17,16 @@ public class SwapUtilsTest @Test public void should_return_formatted_total_gas_fees() { - ArrayList gasCostList = new ArrayList<>(); - Quote.Estimate.GasCost gasCost1 = new Quote.Estimate.GasCost(); + ArrayList gasCostList = new ArrayList<>(); + GasCost gasCost1 = new GasCost(); gasCost1.amount = "1000000000000000000"; - gasCost1.token = new Quote.Estimate.GasCost.Token(); + gasCost1.token = new Token(); gasCost1.token.symbol = "ETH"; gasCost1.token.decimals = 18; - Quote.Estimate.GasCost gasCost2 = new Quote.Estimate.GasCost(); + GasCost gasCost2 = new GasCost(); gasCost2.amount = "2000000000000000000"; - gasCost2.token = new Quote.Estimate.GasCost.Token(); + gasCost2.token = new Token(); gasCost2.token.symbol = "MATIC"; gasCost2.token.decimals = 18; @@ -37,9 +39,9 @@ public void should_return_formatted_total_gas_fees() @Test public void should_return_formatted_gas_fee() { - Quote.Estimate.GasCost gasCost = new Quote.Estimate.GasCost(); + GasCost gasCost = new GasCost(); gasCost.amount = "1000000000000000000"; - gasCost.token = new Quote.Estimate.GasCost.Token(); + gasCost.token = new Token(); gasCost.token.symbol = "ETH"; gasCost.token.decimals = 18; @@ -49,30 +51,34 @@ public void should_return_formatted_gas_fee() @Test public void should_return_formatted_minimum_received() { - Quote quote = new Quote(); - quote.action = new Quote.Action(); - quote.action.toToken = new Connection.LToken(); - quote.estimate = new Quote.Estimate(); - quote.estimate.toAmountMin = "1000000"; - quote.action.toToken.decimals = 6; - quote.action.toToken.symbol = "ETH"; + Action action = new Action(); + action.toToken = new Token(); + action.toToken.decimals = 6; + action.toToken.symbol = "ETH"; - assertThat(SwapUtils.getMinimumAmountReceived(quote), equalTo("1.000000 ETH")); + Estimate estimate1 = new Estimate(); + estimate1.toAmountMin = "1000000"; + assertThat(SwapUtils.getFormattedMinAmount(estimate1, action), equalTo("1 ETH")); + + Estimate estimate2 = new Estimate(); + estimate2.toAmountMin = "1234567"; + assertThat(SwapUtils.getFormattedMinAmount(estimate2, action), equalTo("1.2345 ETH")); } @Test public void should_return_formatted_current_price() { - Quote quote = new Quote(); - quote.action = new Quote.Action(); - quote.action.fromToken = new Connection.LToken(); - quote.action.toToken = new Connection.LToken(); - quote.action.fromToken.priceUSD = "5"; - quote.action.fromToken.symbol = "ETH"; - quote.action.toToken.priceUSD = "1000"; - quote.action.toToken.symbol = "USDC"; + Action action = new Action(); + action.fromToken = new Token(); + action.toToken = new Token(); + action.fromToken.priceUSD = "2000"; + action.fromToken.symbol = "ETH"; + action.fromToken.decimals = 18; + action.toToken.priceUSD = "1"; + action.toToken.symbol = "USDC"; + action.toToken.decimals = 6; - String expected = "1 ETH ≈ 5000 USDC"; - assertThat(SwapUtils.getFormattedCurrentPrice(quote), equalTo(expected)); + String expected = "1 ETH ≈ 2000 USDC"; + assertThat(SwapUtils.getFormattedCurrentPrice(action), equalTo(expected)); } } \ No newline at end of file diff --git a/app/src/test/java/com/alphawallet/app/viewmodel/TokensTest.java b/app/src/test/java/com/alphawallet/app/viewmodel/TokensTest.java index 910d45037d..a5bab72b8c 100644 --- a/app/src/test/java/com/alphawallet/app/viewmodel/TokensTest.java +++ b/app/src/test/java/com/alphawallet/app/viewmodel/TokensTest.java @@ -3,7 +3,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsEqual.equalTo; -import com.alphawallet.app.entity.lifi.Connection; +import com.alphawallet.app.entity.lifi.Token; import org.junit.Test; @@ -15,7 +15,7 @@ public class TokensTest @Test public void sort_token_by_fiat_value_in_DESC() { - List list = new ArrayList<>(); + List list = new ArrayList<>(); list.add(createToken("Ethereum", "ETH", "0x0", 0)); list.add(createToken("Binance Smart Chain", "BNB", "0x1", 1)); list.add(createToken("Solana", "SOL", "0x2", 2)); @@ -30,7 +30,7 @@ public void sort_token_by_fiat_value_in_DESC() @Test public void sort_tokens_by_name_alphabetically() { - List list = new ArrayList<>(); + List list = new ArrayList<>(); list.add(createToken("Ethereum", "ETH", "0x0", 0)); list.add(createToken("Binance Smart Chain", "BNB", "0x1", 0)); list.add(createToken("Solana", "SOL", "0x2", 0)); @@ -45,7 +45,7 @@ public void sort_tokens_by_name_alphabetically() @Test public void sort_name_should_return_native_token_first() { - List list = new ArrayList<>(); + List list = new ArrayList<>(); list.add(createToken("Solana", "SOL", "0x0", 0)); list.add(createToken("Stox", "STX", "0x0000000000000000000000000000000000000000", 0)); list.add(createToken("stETH", "stETH", "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", 0)); @@ -60,7 +60,7 @@ public void sort_name_should_return_native_token_first() @Test public void sort_name_should_be_case_insensitive() { - List list = new ArrayList<>(); + List list = new ArrayList<>(); list.add(createToken("Stox", "STX", "0x0", 0)); list.add(createToken("stETH", "stETH", "0x3", 0)); @@ -70,9 +70,9 @@ public void sort_name_should_be_case_insensitive() assertThat(list.get(1).symbol, equalTo("STX")); } - private Connection.LToken createToken(String name, String symbol, String address, double fiatEquivalent) + private Token createToken(String name, String symbol, String address, double fiatEquivalent) { - Connection.LToken lToken = new Connection.LToken(); + Token lToken = new Token(); lToken.name = name; lToken.symbol = symbol; lToken.address = address; From 6d68fe331c8466f11a04d6629c509f336ac1bf5d Mon Sep 17 00:00:00 2001 From: James Brown Date: Tue, 29 Nov 2022 10:54:22 +1100 Subject: [PATCH 25/36] Add caching for ENS resolve. --- .../alphawallet/app/util/ens/EnsResolver.java | 94 +++++++++++++++---- .../java/com/alphawallet/app/ENSTest.java | 9 ++ 2 files changed, 86 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/com/alphawallet/app/util/ens/EnsResolver.java b/app/src/main/java/com/alphawallet/app/util/ens/EnsResolver.java index 5bdf7b9ac0..d25590ed9a 100644 --- a/app/src/main/java/com/alphawallet/app/util/ens/EnsResolver.java +++ b/app/src/main/java/com/alphawallet/app/util/ens/EnsResolver.java @@ -59,6 +59,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import okhttp3.MediaType; import okhttp3.OkHttpClient; @@ -76,6 +78,7 @@ public class EnsResolver implements Resolvable // Permit number offchain calls for a single contract call. public static final int LOOKUP_LIMIT = 4; + private static final long ENS_CACHE_TIME_VALIDITY = 10 * (1000*60); //10 minutes public static final String REVERSE_NAME_SUFFIX = ".addr.reverse"; @@ -112,11 +115,61 @@ public EnsResolver(Web3j web3j) { this(web3j, Keys.ADDRESS_LENGTH_IN_HEX); } - protected ContractAddress obtainOffchainResolverAddr(String ensName) throws Exception + protected ContractAddress obtainOffChainResolverAddress(String ensName) throws Exception { return new ContractAddress(chainId, getResolverAddress(ensName)); } + private static class CachedENSRead + { + public final String cachedResult; + public final long cachedResultTime; + + public CachedENSRead(String result) + { + cachedResult = result; + cachedResultTime = System.currentTimeMillis(); + } + + public boolean isValid() + { + return System.currentTimeMillis() < (cachedResultTime + ENS_CACHE_TIME_VALIDITY); //10 minutes cache validity + } + } + + //Need to cache results for Resolve + private static final Map cachedNameReads = new ConcurrentHashMap<>(); + + private String cacheKey(String ensName, String addrFunction) + { + return ((ensName != null) ? ensName : "") + "%" + ((addrFunction != null) ? addrFunction : ""); + } + + private String resolveWithCaching(String ensName, byte[] nameHash, String resolverAddr) throws Exception + { + String dnsEncoded = NameHash.dnsEncode(ensName); + String addrFunction = encodeResolverAddr(nameHash); + + CachedENSRead lookupData = cachedNameReads.get(cacheKey(ensName, addrFunction)); + String lookupDataHex = lookupData != null ? lookupData.cachedResult : null; + + if (lookupData == null || !lookupData.isValid()) + { + EthCall result = + resolve( + Numeric.hexStringToByteArray(dnsEncoded), + Numeric.hexStringToByteArray(addrFunction), + resolverAddr); + lookupDataHex = result.isReverted() ? Utils.removeDoubleQuotes(result.getError().getData()) : result.getValue();// .toString(); + if (!TextUtils.isEmpty(lookupDataHex) && !lookupDataHex.equals("0x")) + { + cachedNameReads.put(cacheKey(ensName, addrFunction), new CachedENSRead(lookupDataHex)); + } + } + + return lookupDataHex; + } + /** * Returns the address of the resolver for the specified node. * @@ -133,7 +186,7 @@ public String resolve(String ensName) throws Exception try { if (isValidEnsName(ensName, addressLength)) { - ContractAddress resolverAddress = obtainOffchainResolverAddr(ensName); + ContractAddress resolverAddress = obtainOffChainResolverAddress(ensName); boolean supportWildcard = supportsInterface(EnsUtils.ENSIP_10_INTERFACE_ID, resolverAddress.address); @@ -141,16 +194,7 @@ public String resolve(String ensName) throws Exception String resolvedName; if (supportWildcard) { - String dnsEncoded = NameHash.dnsEncode(ensName); - String addrFunction = encodeResolverAddr(nameHash); - - EthCall result = - resolve( - Numeric.hexStringToByteArray(dnsEncoded), - Numeric.hexStringToByteArray(addrFunction), - resolverAddress.address); - - String lookupDataHex = result.isReverted() ? Utils.removeDoubleQuotes(result.getError().getData()) : result.getValue();// .toString(); + String lookupDataHex = resolveWithCaching(ensName, nameHash, resolverAddress.address); resolvedName = resolveOffchain(lookupDataHex, resolverAddress, LOOKUP_LIMIT); } else { try { @@ -359,7 +403,7 @@ public String reverseResolve(String address) throws Exception if (WalletUtils.isValidAddress(address, addressLength)) { String reverseName = Numeric.cleanHexPrefix(address) + REVERSE_NAME_SUFFIX; - ContractAddress resolverAddress = obtainOffchainResolverAddr(reverseName); + ContractAddress resolverAddress = obtainOffChainResolverAddress(reverseName); byte[] nameHash = NameHash.nameHashAsBytes(reverseName); String name; @@ -438,11 +482,27 @@ public boolean supportsInterface(byte[] interfaceID, String address) throws Exce public String resolverAddr(byte[] node, String address) throws Exception { - final org.web3j.abi.datatypes.Function function = new org.web3j.abi.datatypes.Function(FUNC_addr, - Arrays.asList(new org.web3j.abi.datatypes.generated.Bytes32(node)), - Arrays.>asList(new TypeReference

() {})); + //use caching + String nodeData = Numeric.toHexString(node); + CachedENSRead resolverData = cachedNameReads.get(cacheKey(nodeData, address)); + String resolverAddr = resolverData != null ? resolverData.cachedResult : null; - return getContractData(address, function, ""); + if (resolverData == null || !resolverData.isValid()) + { + final org.web3j.abi.datatypes.Function function = new org.web3j.abi.datatypes.Function(FUNC_addr, + Arrays.asList(new org.web3j.abi.datatypes.generated.Bytes32(node)), + Arrays.>asList(new TypeReference
() + { + })); + + resolverAddr = getContractData(address, function, ""); + if (!TextUtils.isEmpty(resolverAddr) && resolverAddr.length() > 2) + { + cachedNameReads.put(cacheKey(nodeData, address), new CachedENSRead(resolverAddr)); + } + } + + return resolverAddr; } public String encodeResolverAddr(byte[] node) diff --git a/app/src/test/java/com/alphawallet/app/ENSTest.java b/app/src/test/java/com/alphawallet/app/ENSTest.java index 613adb5a1b..d62e1fdb77 100644 --- a/app/src/test/java/com/alphawallet/app/ENSTest.java +++ b/app/src/test/java/com/alphawallet/app/ENSTest.java @@ -71,6 +71,15 @@ public void testResolve() throws Exception { assertEquals( ensResolver.resolve("offchainexample.eth"), ("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045").toLowerCase()); + + //Now test the cache + assertEquals( + ensResolver.resolve("1.offchainexample.eth"), ("0x41563129cdbbd0c5d3e1c86cf9563926b243834d").toLowerCase()); + assertEquals( + ensResolver.resolve("1.offchainexample.eth"), ("0x41563129cdbbd0c5d3e1c86cf9563926b243834d").toLowerCase()); + + assertEquals( + ensResolver.resolve("web3j.eth"), ("0x7bfd522dea355ddee2be3c01dfa4419451759310").toLowerCase()); } @Test From 2537d6aff2f5fd4af6bd60dac5bde7ac4a3a741a Mon Sep 17 00:00:00 2001 From: James Brown Date: Tue, 29 Nov 2022 13:05:06 +1100 Subject: [PATCH 26/36] Restrict calls on update ticker --- .../main/java/com/alphawallet/app/service/TickerService.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/alphawallet/app/service/TickerService.java b/app/src/main/java/com/alphawallet/app/service/TickerService.java index 4c09f0f14c..734ddd4c97 100644 --- a/app/src/main/java/com/alphawallet/app/service/TickerService.java +++ b/app/src/main/java/com/alphawallet/app/service/TickerService.java @@ -100,6 +100,7 @@ public class TickerService private static String currentCurrencySymbol; private static final Map canUpdate = new ConcurrentHashMap<>(); private static final Map dexGuruQuery = new ConcurrentHashMap<>(); + private static long lastTickerUpdate; @Nullable private Disposable tickerUpdateTimer; @@ -118,11 +119,12 @@ public TickerService(OkHttpClient httpClient, PreferenceRepositoryType sharedPre resetTickerUpdate(); initCurrency(); + lastTickerUpdate = 0; } public void updateTickers() { - if (mainTickerUpdate != null && !mainTickerUpdate.isDisposed()) + if (mainTickerUpdate != null && !mainTickerUpdate.isDisposed() && System.currentTimeMillis() > (lastTickerUpdate + DateUtils.MINUTE_IN_MILLIS)) { return; //do not update if update is currently in progress } @@ -150,6 +152,7 @@ private void tickersUpdated(int tickerCount) { Timber.d("Tickers Updated: %s", tickerCount); mainTickerUpdate = null; + lastTickerUpdate = System.currentTimeMillis(); } public Single updateCurrencyConversion() From c3b8656bdd6a69ff7f63802d48874dd6dbd221f4 Mon Sep 17 00:00:00 2001 From: James Brown Date: Tue, 29 Nov 2022 13:57:53 +1100 Subject: [PATCH 27/36] Fix for empty ticker returns --- .../java/com/alphawallet/app/entity/CoinGeckoTicker.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/alphawallet/app/entity/CoinGeckoTicker.java b/app/src/main/java/com/alphawallet/app/entity/CoinGeckoTicker.java index a2087a1722..cb3087f3d2 100644 --- a/app/src/main/java/com/alphawallet/app/entity/CoinGeckoTicker.java +++ b/app/src/main/java/com/alphawallet/app/entity/CoinGeckoTicker.java @@ -45,11 +45,15 @@ public static List buildTickerList(String jsonData, String curr fiatPrice = obj.getDouble(currencyIsoSymbol.toLowerCase()); fiatChangeStr = obj.getString(currencyIsoSymbol.toLowerCase() + "_24h_change"); } - else + else if (obj.has("usd")) { fiatPrice = obj.getDouble("usd") * currentConversionRate; fiatChangeStr = obj.getString("usd_24h_change"); } + else + { + continue; //handle empty/corrupt returns + } res.add(new CoinGeckoTicker(address, fiatPrice, getFiatChange(fiatChangeStr))); } From 409624e6839e04079efe523598f3806b5691a6c4 Mon Sep 17 00:00:00 2001 From: James Brown Date: Tue, 29 Nov 2022 13:58:46 +1100 Subject: [PATCH 28/36] Bump gradle build number --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 3e6869e41b..b862261868 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -85,7 +85,7 @@ android { } } defaultConfig { - versionCode 219 + versionCode 220 versionName "3.60.4" applicationId "io.stormbird.wallet" From e396fdf9414bfb2653e1aa7aa0d8aaa8308cb172 Mon Sep 17 00:00:00 2001 From: James Brown Date: Wed, 7 Dec 2022 12:50:59 +1100 Subject: [PATCH 29/36] Ensure all usages of primary URL include the required secret and replace TokenScript usage of primary with dappbrowser RPC --- .../app/repository/EthereumNetworkBase.java | 10 ++++++++-- .../app/repository/HttpServiceHelper.java | 15 +++++++++++++++ .../com/alphawallet/app/service/GasService.java | 14 ++++++++++---- .../com/alphawallet/app/ui/FunctionActivity.java | 2 +- .../com/alphawallet/app/ui/TokenActivity.java | 2 +- .../app/viewmodel/TokenFunctionViewModel.java | 5 +++++ .../com/alphawallet/app/web3/Web3TokenView.java | 5 ++--- 7 files changed, 42 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java b/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java index f43ac3360d..f0e2081636 100644 --- a/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java +++ b/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java @@ -215,9 +215,10 @@ public String getDappBrowserRPC(long chainId) { return ""; } - else if (chainId == MAINNET_ID) + + int index = info.rpcServerUrl.indexOf(INFURA_ENDPOINT); + if (index > 0) { - int index = info.rpcServerUrl.indexOf(INFURA_ENDPOINT); return info.rpcServerUrl.substring(0, index + INFURA_ENDPOINT.length()) + keyProvider.getTertiaryInfuraKey(); } else if (info.backupNodeUrl != null) @@ -230,6 +231,11 @@ else if (info.backupNodeUrl != null) } } + public static boolean isInfura(String rpcServerUrl) + { + return rpcServerUrl.contains(INFURA_ENDPOINT); + } + // for reset built-in network private static final LongSparseArray builtinNetworkMap = new LongSparseArray() { diff --git a/app/src/main/java/com/alphawallet/app/repository/HttpServiceHelper.java b/app/src/main/java/com/alphawallet/app/repository/HttpServiceHelper.java index 956d1b685f..5b79af1715 100644 --- a/app/src/main/java/com/alphawallet/app/repository/HttpServiceHelper.java +++ b/app/src/main/java/com/alphawallet/app/repository/HttpServiceHelper.java @@ -5,6 +5,8 @@ import org.web3j.protocol.http.HttpService; +import okhttp3.Request; + public class HttpServiceHelper { public static void addRequiredCredentials(long chainId, HttpService httpService, String key, boolean usesProductionKey) @@ -15,4 +17,17 @@ public static void addRequiredCredentials(long chainId, HttpService httpService, httpService.addHeader("Authorization", "Basic " + key); } } + + public static void addRequiredCredentials(long chainId, Request.Builder service, String klaytnKey, String infuraKey, boolean usesProductionKey, boolean isInfura) + { + if ((chainId == KLAYTN_BAOBAB_ID || chainId == KLAYTN_ID) && usesProductionKey) + { + service.addHeader("x-chain-id", Long.toString(chainId)); + service.addHeader("Authorization", "Basic " + klaytnKey); + } + else if (isInfura && usesProductionKey && !TextUtils.isEmpty(infuraKey)) + { + service.addHeader("Authorization", "Basic " + infuraKey); + } + } } diff --git a/app/src/main/java/com/alphawallet/app/service/GasService.java b/app/src/main/java/com/alphawallet/app/service/GasService.java index eec82f2e70..b10e17b829 100644 --- a/app/src/main/java/com/alphawallet/app/service/GasService.java +++ b/app/src/main/java/com/alphawallet/app/service/GasService.java @@ -26,6 +26,7 @@ import com.alphawallet.app.repository.EthereumNetworkBase; import com.alphawallet.app.repository.EthereumNetworkRepository; import com.alphawallet.app.repository.EthereumNetworkRepositoryType; +import com.alphawallet.app.repository.HttpServiceHelper; import com.alphawallet.app.repository.KeyProvider; import com.alphawallet.app.repository.KeyProviderFactory; import com.alphawallet.app.repository.entity.Realm1559Gas; @@ -471,11 +472,16 @@ public Single getChainFeeHistory(int blockCount, String lastBlock, S RequestBody requestBody = RequestBody.create(requestJSON, HttpService.JSON_MEDIA_TYPE); NetworkInfo info = networkRepository.getNetworkByChain(currentChainId); + final Request.Builder rqBuilder = new Request.Builder() + .url(info.rpcServerUrl) + .post(requestBody); + + HttpServiceHelper.addRequiredCredentials(info.chainId, rqBuilder, KeyProviderFactory.get().getKlaytnKey(), + KeyProviderFactory.get().getInfuraSecret(), EthereumNetworkBase.usesProductionKey, EthereumNetworkBase.isInfura(info.rpcServerUrl)); + return Single.fromCallable(() -> { - Request request = new Request.Builder() - .url(info.rpcServerUrl) - .post(requestBody) - .build(); + Request request = rqBuilder.build(); + try (Response response = httpClient.newCall(request).execute()) { if (response.code() / 200 == 1) diff --git a/app/src/main/java/com/alphawallet/app/ui/FunctionActivity.java b/app/src/main/java/com/alphawallet/app/ui/FunctionActivity.java index 0876ed35ce..868bcf9c96 100644 --- a/app/src/main/java/com/alphawallet/app/ui/FunctionActivity.java +++ b/app/src/main/java/com/alphawallet/app/ui/FunctionActivity.java @@ -127,7 +127,7 @@ private void initViews() { tokenView.setChainId(token.tokenInfo.chainId); tokenView.setWalletAddress(new Address(token.getWallet())); tokenView.setupWindowCallback(this); - tokenView.setRpcUrl(token.tokenInfo.chainId); + tokenView.setRpcUrl(viewModel.getBrowserRPC(token.tokenInfo.chainId)); tokenView.setOnReadyCallback(this); tokenView.setOnSignPersonalMessageListener(this); tokenView.setOnSetValuesListener(this); diff --git a/app/src/main/java/com/alphawallet/app/ui/TokenActivity.java b/app/src/main/java/com/alphawallet/app/ui/TokenActivity.java index 2824943515..4024f8e64b 100644 --- a/app/src/main/java/com/alphawallet/app/ui/TokenActivity.java +++ b/app/src/main/java/com/alphawallet/app/ui/TokenActivity.java @@ -552,7 +552,7 @@ private void populateActivityInfo(RealmAuxData item, String transactionValue) tokenView.setChainId(token.tokenInfo.chainId); tokenView.setWalletAddress(new Address(token.getWallet())); - tokenView.setRpcUrl(token.tokenInfo.chainId); + tokenView.setRpcUrl(viewModel.getBrowserRPC(token.tokenInfo.chainId)); tokenView.setOnReadyCallback(this); tokenView.setOnSetValuesListener(this); tokenView.setKeyboardListenerCallback(this); diff --git a/app/src/main/java/com/alphawallet/app/viewmodel/TokenFunctionViewModel.java b/app/src/main/java/com/alphawallet/app/viewmodel/TokenFunctionViewModel.java index 2bcbc4ea20..679d49ba3d 100644 --- a/app/src/main/java/com/alphawallet/app/viewmodel/TokenFunctionViewModel.java +++ b/app/src/main/java/com/alphawallet/app/viewmodel/TokenFunctionViewModel.java @@ -892,4 +892,9 @@ private void onAsset(String result, Token token, BigInteger tokenId) getTokenMetadata(token, tokenId, oldAsset); } } + + public String getBrowserRPC(long chainId) + { + return ethereumNetworkRepository.getDappBrowserRPC(chainId); + } } diff --git a/app/src/main/java/com/alphawallet/app/web3/Web3TokenView.java b/app/src/main/java/com/alphawallet/app/web3/Web3TokenView.java index f48d1f2192..923fa2918a 100644 --- a/app/src/main/java/com/alphawallet/app/web3/Web3TokenView.java +++ b/app/src/main/java/com/alphawallet/app/web3/Web3TokenView.java @@ -35,7 +35,6 @@ import com.alphawallet.app.entity.tokens.Token; import com.alphawallet.app.entity.tokenscript.TokenScriptRenderCallback; import com.alphawallet.app.entity.tokenscript.WebCompletionCallback; -import com.alphawallet.app.repository.EthereumNetworkRepository; import com.alphawallet.app.repository.entity.RealmAuxData; import com.alphawallet.app.service.AssetDefinitionService; import com.alphawallet.app.util.Utils; @@ -239,8 +238,8 @@ public void setChainId(long chainId) { jsInjectorClient.setChainId(chainId); } - public void setRpcUrl(@NonNull long chainId) { - jsInjectorClient.setRpcUrl(EthereumNetworkRepository.getDefaultNodeURL(chainId)); + public void setRpcUrl(@NonNull String useRPC) { + jsInjectorClient.setRpcUrl(useRPC); } public void onSignPersonalMessageSuccessful(@NotNull Signable message, String signHex) { From 0036736b49a365a66f78c1c46a213810bc12b09a Mon Sep 17 00:00:00 2001 From: James Brown Date: Wed, 7 Dec 2022 11:45:24 +1100 Subject: [PATCH 30/36] Updates --- app/src/main/cpp/keys.c | 20 +++++++++++++++++++ .../app/repository/HttpServiceHelper.java | 15 -------------- .../app/repository/KeyProvider.java | 2 ++ .../app/repository/KeyProviderJNIImpl.java | 2 ++ .../alphawallet/app/service/GasService.java | 14 ++++--------- .../app/di/mock/KeyProviderMockImpl.java | 11 ++++++++++ .../KeyProviderMockNonProductionImpl.java | 12 +++++++++++ 7 files changed, 51 insertions(+), 25 deletions(-) diff --git a/app/src/main/cpp/keys.c b/app/src/main/cpp/keys.c index e5ef343573..6e64fa4f04 100644 --- a/app/src/main/cpp/keys.c +++ b/app/src/main/cpp/keys.c @@ -195,3 +195,23 @@ Java_com_alphawallet_app_repository_KeyProviderJNIImpl_getOpenSeaKey( JNIEnv* en return (*env)->NewStringUTF(env, key); #endif } + +JNIEXPORT jstring JNICALL +Java_com_alphawallet_app_repository_KeyProviderJNIImpl_getWalletConnectProjectId( JNIEnv* env, jclass thiz ) +{ +#if (HAS_KEYS == 1) + return getDecryptedKey(env, walletConnectProjectId); +#else + return (*env)->NewStringUTF(env, WALLETCONNECT_PROJECT_ID); +#endif +} + +JNIEXPORT jstring JNICALL +Java_com_alphawallet_app_repository_KeyProviderJNIImpl_getInfuraSecret(JNIEnv *env, jobject thiz) { +#if (HAS_KEYS == 1) + return getDecryptedKey(env, infuraSecret); +#else + const jstring key = ""; + return (*env)->NewStringUTF(env, key); +#endif +} diff --git a/app/src/main/java/com/alphawallet/app/repository/HttpServiceHelper.java b/app/src/main/java/com/alphawallet/app/repository/HttpServiceHelper.java index 5b79af1715..956d1b685f 100644 --- a/app/src/main/java/com/alphawallet/app/repository/HttpServiceHelper.java +++ b/app/src/main/java/com/alphawallet/app/repository/HttpServiceHelper.java @@ -5,8 +5,6 @@ import org.web3j.protocol.http.HttpService; -import okhttp3.Request; - public class HttpServiceHelper { public static void addRequiredCredentials(long chainId, HttpService httpService, String key, boolean usesProductionKey) @@ -17,17 +15,4 @@ public static void addRequiredCredentials(long chainId, HttpService httpService, httpService.addHeader("Authorization", "Basic " + key); } } - - public static void addRequiredCredentials(long chainId, Request.Builder service, String klaytnKey, String infuraKey, boolean usesProductionKey, boolean isInfura) - { - if ((chainId == KLAYTN_BAOBAB_ID || chainId == KLAYTN_ID) && usesProductionKey) - { - service.addHeader("x-chain-id", Long.toString(chainId)); - service.addHeader("Authorization", "Basic " + klaytnKey); - } - else if (isInfura && usesProductionKey && !TextUtils.isEmpty(infuraKey)) - { - service.addHeader("Authorization", "Basic " + infuraKey); - } - } } diff --git a/app/src/main/java/com/alphawallet/app/repository/KeyProvider.java b/app/src/main/java/com/alphawallet/app/repository/KeyProvider.java index 26f49269f8..3d30a78718 100644 --- a/app/src/main/java/com/alphawallet/app/repository/KeyProvider.java +++ b/app/src/main/java/com/alphawallet/app/repository/KeyProvider.java @@ -16,4 +16,6 @@ public interface KeyProvider String getOpenSeaKey(); String getMailchimpKey(); String getCoinbasePayAppId(); + String getWalletConnectProjectId(); + String getInfuraSecret(); } diff --git a/app/src/main/java/com/alphawallet/app/repository/KeyProviderJNIImpl.java b/app/src/main/java/com/alphawallet/app/repository/KeyProviderJNIImpl.java index 99e504b6df..9e7418ff57 100644 --- a/app/src/main/java/com/alphawallet/app/repository/KeyProviderJNIImpl.java +++ b/app/src/main/java/com/alphawallet/app/repository/KeyProviderJNIImpl.java @@ -21,4 +21,6 @@ public KeyProviderJNIImpl() public native String getOpenSeaKey(); public native String getMailchimpKey(); public native String getCoinbasePayAppId(); + public native String getWalletConnectProjectId(); + public native String getInfuraSecret(); } diff --git a/app/src/main/java/com/alphawallet/app/service/GasService.java b/app/src/main/java/com/alphawallet/app/service/GasService.java index b10e17b829..eec82f2e70 100644 --- a/app/src/main/java/com/alphawallet/app/service/GasService.java +++ b/app/src/main/java/com/alphawallet/app/service/GasService.java @@ -26,7 +26,6 @@ import com.alphawallet.app.repository.EthereumNetworkBase; import com.alphawallet.app.repository.EthereumNetworkRepository; import com.alphawallet.app.repository.EthereumNetworkRepositoryType; -import com.alphawallet.app.repository.HttpServiceHelper; import com.alphawallet.app.repository.KeyProvider; import com.alphawallet.app.repository.KeyProviderFactory; import com.alphawallet.app.repository.entity.Realm1559Gas; @@ -472,16 +471,11 @@ public Single getChainFeeHistory(int blockCount, String lastBlock, S RequestBody requestBody = RequestBody.create(requestJSON, HttpService.JSON_MEDIA_TYPE); NetworkInfo info = networkRepository.getNetworkByChain(currentChainId); - final Request.Builder rqBuilder = new Request.Builder() - .url(info.rpcServerUrl) - .post(requestBody); - - HttpServiceHelper.addRequiredCredentials(info.chainId, rqBuilder, KeyProviderFactory.get().getKlaytnKey(), - KeyProviderFactory.get().getInfuraSecret(), EthereumNetworkBase.usesProductionKey, EthereumNetworkBase.isInfura(info.rpcServerUrl)); - return Single.fromCallable(() -> { - Request request = rqBuilder.build(); - + Request request = new Request.Builder() + .url(info.rpcServerUrl) + .post(requestBody) + .build(); try (Response response = httpClient.newCall(request).execute()) { if (response.code() / 200 == 1) diff --git a/app/src/test/java/com/alphawallet/app/di/mock/KeyProviderMockImpl.java b/app/src/test/java/com/alphawallet/app/di/mock/KeyProviderMockImpl.java index 36364ffc3c..af16017e60 100644 --- a/app/src/test/java/com/alphawallet/app/di/mock/KeyProviderMockImpl.java +++ b/app/src/test/java/com/alphawallet/app/di/mock/KeyProviderMockImpl.java @@ -90,4 +90,15 @@ public String getCoinbasePayAppId() return FAKE_KEY_FOR_TESTING; } + @Override + public String getWalletConnectProjectId() + { + return FAKE_KEY_FOR_TESTING; + } + + @Override + public String getInfuraSecret() + { + return FAKE_KEY_FOR_TESTING; + } } diff --git a/app/src/test/java/com/alphawallet/app/di/mock/KeyProviderMockNonProductionImpl.java b/app/src/test/java/com/alphawallet/app/di/mock/KeyProviderMockNonProductionImpl.java index 2665583552..32cce2cf68 100644 --- a/app/src/test/java/com/alphawallet/app/di/mock/KeyProviderMockNonProductionImpl.java +++ b/app/src/test/java/com/alphawallet/app/di/mock/KeyProviderMockNonProductionImpl.java @@ -88,4 +88,16 @@ public String getCoinbasePayAppId() { return null; } + + @Override + public String getWalletConnectProjectId() + { + return null; + } + + @Override + public String getInfuraSecret() + { + return null; + } } From 7042ad395b19ed1d2eb9b3128e0a4486f5b0494f Mon Sep 17 00:00:00 2001 From: James Brown Date: Wed, 7 Dec 2022 12:50:59 +1100 Subject: [PATCH 31/36] Ensure all usages of primary URL include the required secret and replace TokenScript usage of primary with dappbrowser RPC --- .../app/repository/HttpServiceHelper.java | 15 +++++++++++++++ .../com/alphawallet/app/service/GasService.java | 14 ++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/alphawallet/app/repository/HttpServiceHelper.java b/app/src/main/java/com/alphawallet/app/repository/HttpServiceHelper.java index 956d1b685f..5b79af1715 100644 --- a/app/src/main/java/com/alphawallet/app/repository/HttpServiceHelper.java +++ b/app/src/main/java/com/alphawallet/app/repository/HttpServiceHelper.java @@ -5,6 +5,8 @@ import org.web3j.protocol.http.HttpService; +import okhttp3.Request; + public class HttpServiceHelper { public static void addRequiredCredentials(long chainId, HttpService httpService, String key, boolean usesProductionKey) @@ -15,4 +17,17 @@ public static void addRequiredCredentials(long chainId, HttpService httpService, httpService.addHeader("Authorization", "Basic " + key); } } + + public static void addRequiredCredentials(long chainId, Request.Builder service, String klaytnKey, String infuraKey, boolean usesProductionKey, boolean isInfura) + { + if ((chainId == KLAYTN_BAOBAB_ID || chainId == KLAYTN_ID) && usesProductionKey) + { + service.addHeader("x-chain-id", Long.toString(chainId)); + service.addHeader("Authorization", "Basic " + klaytnKey); + } + else if (isInfura && usesProductionKey && !TextUtils.isEmpty(infuraKey)) + { + service.addHeader("Authorization", "Basic " + infuraKey); + } + } } diff --git a/app/src/main/java/com/alphawallet/app/service/GasService.java b/app/src/main/java/com/alphawallet/app/service/GasService.java index eec82f2e70..b10e17b829 100644 --- a/app/src/main/java/com/alphawallet/app/service/GasService.java +++ b/app/src/main/java/com/alphawallet/app/service/GasService.java @@ -26,6 +26,7 @@ import com.alphawallet.app.repository.EthereumNetworkBase; import com.alphawallet.app.repository.EthereumNetworkRepository; import com.alphawallet.app.repository.EthereumNetworkRepositoryType; +import com.alphawallet.app.repository.HttpServiceHelper; import com.alphawallet.app.repository.KeyProvider; import com.alphawallet.app.repository.KeyProviderFactory; import com.alphawallet.app.repository.entity.Realm1559Gas; @@ -471,11 +472,16 @@ public Single getChainFeeHistory(int blockCount, String lastBlock, S RequestBody requestBody = RequestBody.create(requestJSON, HttpService.JSON_MEDIA_TYPE); NetworkInfo info = networkRepository.getNetworkByChain(currentChainId); + final Request.Builder rqBuilder = new Request.Builder() + .url(info.rpcServerUrl) + .post(requestBody); + + HttpServiceHelper.addRequiredCredentials(info.chainId, rqBuilder, KeyProviderFactory.get().getKlaytnKey(), + KeyProviderFactory.get().getInfuraSecret(), EthereumNetworkBase.usesProductionKey, EthereumNetworkBase.isInfura(info.rpcServerUrl)); + return Single.fromCallable(() -> { - Request request = new Request.Builder() - .url(info.rpcServerUrl) - .post(requestBody) - .build(); + Request request = rqBuilder.build(); + try (Response response = httpClient.newCall(request).execute()) { if (response.code() / 200 == 1) From bd08254343989dae1caf1948333d7c07da7ff5df Mon Sep 17 00:00:00 2001 From: James Brown Date: Wed, 7 Dec 2022 15:40:30 +1100 Subject: [PATCH 32/36] update --- .../java/com/alphawallet/app/repository/HttpServiceHelper.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/com/alphawallet/app/repository/HttpServiceHelper.java b/app/src/main/java/com/alphawallet/app/repository/HttpServiceHelper.java index 5b79af1715..ee72cbf9ac 100644 --- a/app/src/main/java/com/alphawallet/app/repository/HttpServiceHelper.java +++ b/app/src/main/java/com/alphawallet/app/repository/HttpServiceHelper.java @@ -3,6 +3,8 @@ import static com.alphawallet.ethereum.EthereumNetworkBase.KLAYTN_BAOBAB_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.KLAYTN_ID; +import android.text.TextUtils; + import org.web3j.protocol.http.HttpService; import okhttp3.Request; From cda91d3069c07a0971152ea1cce11c01dc8c0327 Mon Sep 17 00:00:00 2001 From: James Brown Date: Wed, 7 Dec 2022 11:47:36 +1100 Subject: [PATCH 33/36] Cherry pick fixes --- .../com/alphawallet/app/entity/EventSync.java | 102 +++++++++++++++- .../app/entity/tokens/ERC1155Token.java | 40 ++++--- .../app/entity/tokens/ERC721Token.java | 109 ++++++++++++------ .../alphawallet/app/entity/tokens/Token.java | 17 +-- .../app/repository/EthereumNetworkBase.java | 38 +++++- .../app/repository/HttpServiceHelper.java | 12 +- .../app/repository/TokenRepository.java | 34 +++++- .../app/repository/TokensRealmSource.java | 95 +++++++-------- .../app/service/AWHttpService.java | 8 +- .../service/TransactionsNetworkClient.java | 11 +- .../app/service/TransactionsService.java | 41 ++++--- .../alphawallet/app/util/ens/EnsResolver.java | 23 ++-- .../app/repository/HttpServiceHelperTest.java | 8 +- 13 files changed, 371 insertions(+), 167 deletions(-) diff --git a/app/src/main/java/com/alphawallet/app/entity/EventSync.java b/app/src/main/java/com/alphawallet/app/entity/EventSync.java index 1d600a7617..be7798b630 100644 --- a/app/src/main/java/com/alphawallet/app/entity/EventSync.java +++ b/app/src/main/java/com/alphawallet/app/entity/EventSync.java @@ -34,6 +34,10 @@ public class EventSync { public static final long BLOCK_SEARCH_INTERVAL = 100000L; + public static final long POLYGON_BLOCK_SEARCH_INTERVAL = 10000L; + + private static final String TAG = "EVENT_SYNC"; + private static final boolean EVENT_SYNC_DEBUGGING = false; private final Token token; @@ -71,8 +75,17 @@ public SyncDef getSyncDef(Realm realm) case DOWNWARD_SYNC_START: //Start event sync, optimistically try the whole current event range from 1 -> LATEST eventReadStartBlock = BigInteger.ONE; eventReadEndBlock = BigInteger.valueOf(-1L); - //write the start point here - writeStartSyncBlock(realm, currentBlock.longValue()); + if (EthereumNetworkBase.isEventBlockLimitEnforced(token.tokenInfo.chainId)) + { + syncState = EventSyncState.UPWARD_SYNC; + eventReadStartBlock = currentBlock.subtract(EthereumNetworkBase.getMaxEventFetch(token.tokenInfo.chainId).multiply(BigInteger.valueOf(3))); + EVENT_DEBUG("Init Sync for restricted block RPC"); + } + else + { + //write the start point here + writeStartSyncBlock(realm, currentBlock.longValue()); + } break; case DOWNWARD_SYNC: //we needed to slow down the sync eventReadStartBlock = lastBlockRead.subtract(BigInteger.valueOf(readBlockSize)); @@ -85,19 +98,85 @@ public SyncDef getSyncDef(Realm realm) break; case UPWARD_SYNC_MAX: //we are syncing from the point we started the downward sync upwardSync = true; + if (EthereumNetworkBase.isEventBlockLimitEnforced(token.tokenInfo.chainId) && upwardSyncStateLost(lastBlockRead, currentBlock)) + { + syncState = EventSyncState.UPWARD_SYNC; + EVENT_DEBUG("Switch back to sync scan"); + } + eventReadStartBlock = lastBlockRead; eventReadEndBlock = BigInteger.valueOf(-1L); break; case UPWARD_SYNC: //we encountered upward sync issues upwardSync = true; eventReadStartBlock = lastBlockRead; - eventReadEndBlock = lastBlockRead.add(BigInteger.valueOf(readBlockSize)); + if (upwardSyncComplete(eventReadStartBlock, currentBlock)) //detect completion of upward sync and switch to sync_max + { + eventReadEndBlock = BigInteger.valueOf(-1L); + syncState = EventSyncState.UPWARD_SYNC_MAX; + EVENT_DEBUG("Sync complete"); + } + else + { + eventReadEndBlock = lastBlockRead.add(BigInteger.valueOf(readBlockSize)); + } break; } + // Finally adjust the event end read if required. This is placed outside the switch because it should affect + // a few different paths + eventReadEndBlock = adjustForLimitedBlockSize(eventReadStartBlock, eventReadEndBlock, currentBlock); + + // detect edge condition - it's highly unlikely but acts as a stopper in case of unexpected results + // This edge condition is where the start block read is greater than the current block. + if (eventReadStartBlock.compareTo(currentBlock) >= 0) + { + eventReadStartBlock = currentBlock.subtract(BigInteger.ONE); + eventReadEndBlock = BigInteger.valueOf(-1L); + syncState = EventSyncState.UPWARD_SYNC_MAX; + } + return new SyncDef(eventReadStartBlock, eventReadEndBlock, syncState, upwardSync); } + private void EVENT_DEBUG(String message) + { + if (EVENT_SYNC_DEBUGGING) + { + Timber.tag(TAG).i(token.tokenInfo.chainId + " " + token.tokenInfo.address + ": " + message); + } + } + + private boolean upwardSyncStateLost(BigInteger lastBlockRead, BigInteger currentBlock) + { + return currentBlock.subtract(lastBlockRead).compareTo(EthereumNetworkBase.getMaxEventFetch(token.tokenInfo.chainId)) >= 0; + } + + private boolean upwardSyncComplete(BigInteger eventReadStartBlock, BigInteger currentBlock) + { + BigInteger maxBlockRead = EthereumNetworkBase.getMaxEventFetch(token.tokenInfo.chainId).subtract(BigInteger.ONE); + BigInteger diff = currentBlock.subtract(eventReadStartBlock); + + return diff.compareTo(maxBlockRead) < 0; + } + + private BigInteger adjustForLimitedBlockSize(BigInteger eventReadStartBlock, BigInteger eventReadEndBlock, BigInteger currentBlock) + { + if (EthereumNetworkBase.isEventBlockLimitEnforced(token.tokenInfo.chainId)) + { + BigInteger maxBlockRead = EthereumNetworkBase.getMaxEventFetch(token.tokenInfo.chainId); + + long diff = currentBlock.subtract(eventReadStartBlock).longValue(); + + if (diff >= maxBlockRead.longValue()) + { + return eventReadStartBlock.add(maxBlockRead).subtract(BigInteger.ONE); + } + } + + return eventReadEndBlock; + } + public boolean handleEthLogError(Response.Error error, DefaultBlockParameter startBlock, DefaultBlockParameter endBlock, SyncDef sync, Realm realm) { if (error.getCode() == -32005) @@ -177,6 +256,11 @@ private long reduceBlockSearch(long currentBlock, BigInteger startBlock) private long getCurrentEventBlockSize(Realm instance) { + if (EthereumNetworkBase.getMaxEventFetch(token.tokenInfo.chainId).equals(BigInteger.valueOf(3500L))) + { + return EthereumNetworkBase.getMaxEventFetch(token.tokenInfo.chainId).longValue(); + } + RealmAuxData rd = instance.where(RealmAuxData.class) .equalTo("instanceKey", TokensRealmSource.databaseKey(token.tokenInfo.chainId, token.getAddress())) .findFirst(); @@ -205,8 +289,9 @@ protected EventSyncState getCurrentTokenSyncState(Realm instance) else { int state = rd.getTokenId().intValue(); - if (state >= EventSyncState.DOWNWARD_SYNC_START.ordinal() || state < EventSyncState.TOP_LIMIT.ordinal()) + if (state >= EventSyncState.DOWNWARD_SYNC_START.ordinal() && state < EventSyncState.TOP_LIMIT.ordinal()) { + EVENT_DEBUG("Read State: " + EventSyncState.values()[state]); return EventSyncState.values()[state]; } else @@ -248,6 +333,7 @@ protected long getLastEventRead(Realm instance) } else { + EVENT_DEBUG("ReadEventSync: " + rd.getResultTime()); return rd.getResultTime(); } } @@ -333,6 +419,8 @@ private void updateEventReads(Realm realm, long lastRead, long readInterval, Eve rd.setResultReceivedTime(readInterval); rd.setTokenId(String.valueOf(state.ordinal())); + EVENT_DEBUG("WriteState: " + state + " " + lastRead); + r.insertOrUpdate(rd); }); } @@ -340,7 +428,7 @@ private void updateEventReads(Realm realm, long lastRead, long readInterval, Eve // If we're syncing downwards, work out what event block size we should read next private long calcNewIntervalSize(SyncDef sync, int evReads) { - if (sync.upwardSync) return BLOCK_SEARCH_INTERVAL; + if (sync.upwardSync) return EthereumNetworkBase.getMaxEventFetch(token.tokenInfo.chainId).longValue(); long endBlock = sync.eventReadEndBlock.longValue() == -1 ? TransactionsService.getCurrentBlock(token.tokenInfo.chainId).longValue() : sync.eventReadEndBlock.longValue(); long currentReadSize = endBlock - sync.eventReadStartBlock.longValue(); @@ -357,7 +445,7 @@ else if (evReads < 1000) } else if ((maxLogReads - evReads) > maxLogReads*0.25) { - currentReadSize += BLOCK_SEARCH_INTERVAL; + currentReadSize += EthereumNetworkBase.getMaxEventFetch(token.tokenInfo.chainId).longValue(); } return currentReadSize; @@ -365,6 +453,8 @@ else if ((maxLogReads - evReads) > maxLogReads*0.25) /*** * Event Handling + * + * TODO: batch up catch-up calls */ public Pair, HashSet>> processTransferEvents(Web3j web3j, Event transferEvent, DefaultBlockParameter startBlock, diff --git a/app/src/main/java/com/alphawallet/app/entity/tokens/ERC1155Token.java b/app/src/main/java/com/alphawallet/app/entity/tokens/ERC1155Token.java index f879983a38..550d977b9b 100644 --- a/app/src/main/java/com/alphawallet/app/entity/tokens/ERC1155Token.java +++ b/app/src/main/java/com/alphawallet/app/entity/tokens/ERC1155Token.java @@ -276,27 +276,39 @@ public Function getTransferFunction(String to, List tokenIds) throws } @Override - public List getChangeList(Map assetMap) + public Map getAssetChange(Map oldAssetList) { - //detect asset removal - List oldAssetIdList = new ArrayList<>(assetMap.keySet()); - oldAssetIdList.removeAll(assets.keySet()); + //first see if there's no change; if this is the case we can skip + if (assetsUnchanged(oldAssetList)) return assets; - List changeList = new ArrayList<>(oldAssetIdList); + //add all known tokens in + Map sum = new HashMap<>(oldAssetList); + sum.putAll(assets); + Set tokenIds = sum.keySet(); + Function balanceOfBatch = balanceOfBatch(getWallet(), tokenIds); + List balances = callSmartContractFunctionArray(tokenInfo.chainId, balanceOfBatch, getAddress(), getWallet()); + Map updatedAssetMap; - //Now detect differences or new tokens - for (BigInteger tokenId : assets.keySet()) + if (balances != null && balances.size() > 0) { - NFTAsset newAsset = assets.get(tokenId); - NFTAsset oldAsset = assetMap.get(tokenId); - - if (oldAsset == null || newAsset.hashCode() != oldAsset.hashCode()) + updatedAssetMap = new HashMap<>(); + int index = 0; + for (BigInteger tokenId : tokenIds) { - changeList.add(tokenId); + NFTAsset thisAsset = new NFTAsset(sum.get(tokenId)); + BigInteger balance = balances.get(index).getValue(); + thisAsset.setBalance(new BigDecimal(balance)); + updatedAssetMap.put(tokenId, thisAsset); + + index++; } } + else + { + updatedAssetMap = assets; + } - return changeList; + return updatedAssetMap; } private List fetchBalances(Set tokenIds) @@ -643,7 +655,7 @@ public BigDecimal updateBalance(Realm realm) try { - final Web3j web3j = TokenRepository.getWeb3jService(tokenInfo.chainId); + final Web3j web3j = TokenRepository.getWeb3jServiceForEvents(tokenInfo.chainId); Pair, HashSet>> evRead = eventSync.processTransferEvents(web3j, getBalanceUpdateEvents(), startBlock, endBlock, realm); diff --git a/app/src/main/java/com/alphawallet/app/entity/tokens/ERC721Token.java b/app/src/main/java/com/alphawallet/app/entity/tokens/ERC721Token.java index 780840a40a..d9cd1dbc11 100644 --- a/app/src/main/java/com/alphawallet/app/entity/tokens/ERC721Token.java +++ b/app/src/main/java/com/alphawallet/app/entity/tokens/ERC721Token.java @@ -49,6 +49,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -264,7 +265,9 @@ public boolean checkRealmBalanceChange(RealmToken realmToken) public boolean checkBalanceChange(Token oldToken) { if (super.checkBalanceChange(oldToken)) return true; - if (getTokenAssets().size() != oldToken.getTokenAssets().size()) return true; + if ((getTokenAssets() != null && oldToken.getTokenAssets() != null) + && getTokenAssets().size() != oldToken.getTokenAssets().size()) return true; + for (BigInteger tokenId : tokenBalanceAssets.keySet()) { NFTAsset newAsset = tokenBalanceAssets.get(tokenId); @@ -350,7 +353,7 @@ public BigDecimal updateBalance(Realm realm) try { balanceChecks.put(tokenInfo.address, true); //set checking - final Web3j web3j = TokenRepository.getWeb3jService(tokenInfo.chainId); + final Web3j web3j = TokenRepository.getWeb3jServiceForEvents(tokenInfo.chainId); if (contractType == ContractType.ERC721_ENUMERABLE) { updateEnumerableBalance(web3j, realm); @@ -385,6 +388,7 @@ public BigDecimal updateBalance(Realm realm) if (eventSync.handleEthLogError(e.error, startBlock, endBlock, sync, realm)) { //recurse until we find a good value + balanceChecks.remove(tokenInfo.address); updateBalance(realm); } } @@ -598,24 +602,6 @@ public EthFilter getSendBalanceFilter(Event event, DefaultBlockParameter startBl return filter; } - /** - * Returns false if the Asset balance appears to be entries with only TokenId - indicating an ERC721Ticket - * - * @return - */ - @Override - public boolean checkBalanceType() - { - boolean onlyHasTokenId = true; - //if elements contain asset with only assetId then most likely this is a ticket. - for (NFTAsset a : tokenBalanceAssets.values()) - { - if (!a.isBlank()) onlyHasTokenId = false; - } - - return tokenBalanceAssets.size() == 0 || !onlyHasTokenId; - } - public String getTransferID(Transaction tx) { if (tx.transactionInput != null && tx.transactionInput.miscData.size() > 0) @@ -689,18 +675,28 @@ public BigDecimal getBalanceRaw() * If there is a token that previously was there, but now isn't, it could be because * the opensea call was split or that the owner transferred the token * - * @param assetMap Loaded Assets from Realm - * @return map of currently known live assets + * @param assetMap Loaded Assets which are new assets (don't add assets from opensea unless we double check here first) + * @return map of checked assets */ @Override public Map queryAssets(Map assetMap) { - final Web3j web3j = TokenRepository.getWeb3jService(tokenInfo.chainId); - //check all tokens in this contract assetMap.putAll(tokenBalanceAssets); - //now check balance for all tokenIds (note that ERC1155 has a batch balance check, ERC721 does not) + HashSet currentAssets = new HashSet<>(assetMap.keySet()); + + final Web3j web3j = TokenRepository.getWeb3jService(tokenInfo.chainId); + + try + { + currentAssets = checkBalances(web3j, currentAssets); + } + catch (Exception e) + { + // + } + for (Map.Entry entry : assetMap.entrySet()) { BigInteger checkId = entry.getKey(); @@ -721,35 +717,74 @@ else if (owner.equalsIgnoreCase(getWallet())) checkAsset.setBalance(BigDecimal.ZERO); } - //add back into asset map tokenBalanceAssets.put(checkId, checkAsset); } return tokenBalanceAssets; } + // Check for new/missing tokenBalanceAssets @Override - public List getChangeList(Map assetMap) + public Map getAssetChange(Map oldAssetList) { - //detect asset removal - List oldAssetIdList = new ArrayList<>(assetMap.keySet()); - oldAssetIdList.removeAll(tokenBalanceAssets.keySet()); + Map updatedAssets = new HashMap<>(); + // detect asset removal, first find new assets + HashSet changedAssetList = new HashSet<>(tokenBalanceAssets.keySet()); + changedAssetList.removeAll(oldAssetList.keySet()); - List changeList = new ArrayList<>(oldAssetIdList); + HashSet unchangedAssets = new HashSet<>(tokenBalanceAssets.keySet()); + unchangedAssets.removeAll(changedAssetList); + + // removed assets + HashSet removedAssets = new HashSet<>(oldAssetList.keySet()); + removedAssets.removeAll(tokenBalanceAssets.keySet()); + changedAssetList.addAll(removedAssets); + HashSet balanceAssets = new HashSet<>(); + + final Web3j web3j = TokenRepository.getWeb3jService(tokenInfo.chainId); + + try + { + balanceAssets = checkBalances(web3j, changedAssetList); + } + catch (Exception e) + { + // + } //Now detect differences or new tokens - for (BigInteger tokenId : tokenBalanceAssets.keySet()) + for (BigInteger tokenId : changedAssetList) { - NFTAsset newAsset = tokenBalanceAssets.get(tokenId); - NFTAsset oldAsset = assetMap.get(tokenId); + NFTAsset asset = tokenBalanceAssets.get(tokenId); + if (asset == null) asset = oldAssetList.get(tokenId); - if (oldAsset == null || newAsset.hashCode() != oldAsset.hashCode()) + if (asset == null) + { + continue; + } + + if (balanceAssets.contains(tokenId)) + { + asset.setBalance(BigDecimal.ZERO); + } + else + { + asset.setBalance(BigDecimal.ONE); + } + + updatedAssets.put(tokenId, asset); + } + + for (BigInteger tokenId : unchangedAssets) + { + NFTAsset asset = tokenBalanceAssets.get(tokenId); + if (asset != null) { - changeList.add(tokenId); + updatedAssets.put(tokenId, asset); } } - return changeList; + return updatedAssets; } private String callSmartContractFunction(Web3j web3j, diff --git a/app/src/main/java/com/alphawallet/app/entity/tokens/Token.java b/app/src/main/java/com/alphawallet/app/entity/tokens/Token.java index f0164cde88..760e88db9e 100644 --- a/app/src/main/java/com/alphawallet/app/entity/tokens/Token.java +++ b/app/src/main/java/com/alphawallet/app/entity/tokens/Token.java @@ -711,11 +711,6 @@ public int hashCode() return hash; } - public boolean checkBalanceType() - { - return true; - } - public String getTransactionDetail(Context ctx, Transaction tx, TokensService tService) { if (isEthereum()) @@ -922,11 +917,6 @@ public boolean mayRequireRefresh() || (!TextUtils.isEmpty(tokenInfo.symbol) && tokenInfo.symbol.contains("?")); } - public List getChangeList(Map assetMap) - { - return new ArrayList<>(); - } - public void setAssetContract(AssetContract contract) { } public AssetContract getAssetContract() { return null; } @@ -945,6 +935,11 @@ public Map queryAssets(Map assetMap) return assetMap; } + public Map getAssetChange(Map oldAssetList) + { + return oldAssetList; + } + /** * Token Metadata handling */ @@ -1019,4 +1014,4 @@ public HashSet processLogsAndStoreTransferEvents(EthLog receiveLogs, { return null; } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java b/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java index f0e2081636..b08da75f99 100644 --- a/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java +++ b/app/src/main/java/com/alphawallet/app/repository/EthereumNetworkBase.java @@ -3,6 +3,8 @@ /* Please don't add import android at this point. Later this file will be shared * between projects including non-Android projects */ +import static com.alphawallet.app.entity.EventSync.BLOCK_SEARCH_INTERVAL; +import static com.alphawallet.app.entity.EventSync.POLYGON_BLOCK_SEARCH_INTERVAL; import static com.alphawallet.app.util.Utils.isValidUrl; import static com.alphawallet.ethereum.EthereumNetworkBase.ARBITRUM_GOERLI_TESTNET_FALLBACK_RPC_URL; import static com.alphawallet.ethereum.EthereumNetworkBase.ARBITRUM_GOERLI_TEST_ID; @@ -251,7 +253,7 @@ public static boolean isInfura(String rpcServerUrl) put(GNOSIS_ID, new NetworkInfo(C.XDAI_NETWORK_NAME, C.xDAI_SYMBOL, XDAI_RPC_URL, "https://blockscout.com/xdai/mainnet/tx/", GNOSIS_ID, - "https://gnosis.public-rpc.com", "https://blockscout.com/xdai/mainnet/api?")); + "https://rpc.ankr.com/gnosis", "https://blockscout.com/xdai/mainnet/api?")); put(POA_ID, new NetworkInfo(C.POA_NETWORK_NAME, C.POA_SYMBOL, POA_RPC_URL, "https://blockscout.com/poa/core/tx/", POA_ID, POA_RPC_URL, @@ -592,6 +594,8 @@ else if (networkMap.indexOfKey(chainId) >= 0) } } + public static final String INFURA_DOMAIN = "infura.io"; + @Override public boolean hasLockedGas(long chainId) { @@ -1220,15 +1224,43 @@ public static String getChainSymbol(long chainId) } } + public static boolean isEventBlockLimitEnforced(long chainId) + { + if (chainId == POLYGON_ID || chainId == POLYGON_TEST_ID) + { + return true; + } + else + { + return false; + } + } + public static BigInteger getMaxEventFetch(long chainId) { if (chainId == POLYGON_ID || chainId == POLYGON_TEST_ID) { - return BigInteger.valueOf(3500L); + return BigInteger.valueOf(POLYGON_BLOCK_SEARCH_INTERVAL); + } + else + { + return BigInteger.valueOf(BLOCK_SEARCH_INTERVAL); + } + } + + public static String getNodeURLForEvents(long chainId) + { + if (chainId == POLYGON_ID) + { + return EthereumNetworkBase.FREE_POLYGON_RPC_URL; // Better than Infura for fetching events + } + else if (chainId == POLYGON_TEST_ID) + { + return EthereumNetworkBase.MUMBAI_FALLBACK_RPC_URL; } else { - return BigInteger.valueOf(10000L); + return getNodeURLByNetworkId(chainId); } } diff --git a/app/src/main/java/com/alphawallet/app/repository/HttpServiceHelper.java b/app/src/main/java/com/alphawallet/app/repository/HttpServiceHelper.java index ee72cbf9ac..7fe9db51bc 100644 --- a/app/src/main/java/com/alphawallet/app/repository/HttpServiceHelper.java +++ b/app/src/main/java/com/alphawallet/app/repository/HttpServiceHelper.java @@ -1,22 +1,30 @@ package com.alphawallet.app.repository; +import static com.alphawallet.app.repository.EthereumNetworkBase.INFURA_DOMAIN; import static com.alphawallet.ethereum.EthereumNetworkBase.KLAYTN_BAOBAB_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.KLAYTN_ID; import android.text.TextUtils; +import com.alphawallet.app.service.AWHttpService; + import org.web3j.protocol.http.HttpService; import okhttp3.Request; public class HttpServiceHelper { - public static void addRequiredCredentials(long chainId, HttpService httpService, String key, boolean usesProductionKey) + public static void addRequiredCredentials(long chainId, HttpService httpService, String klaytnKey, String infuraKey, boolean usesProductionKey) { + String serviceUrl = ((AWHttpService)httpService).getUrl(); if ((chainId == KLAYTN_BAOBAB_ID || chainId == KLAYTN_ID) && usesProductionKey) { httpService.addHeader("x-chain-id", Long.toString(chainId)); - httpService.addHeader("Authorization", "Basic " + key); + httpService.addHeader("Authorization", "Basic " + klaytnKey); + } + else if (serviceUrl != null && usesProductionKey && serviceUrl.contains(INFURA_DOMAIN) && !TextUtils.isEmpty(infuraKey)) + { + httpService.addHeader("Authorization", "Basic " + infuraKey); } } 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 b1ef17ac41..751f8d71f1 100644 --- a/app/src/main/java/com/alphawallet/app/repository/TokenRepository.java +++ b/app/src/main/java/com/alphawallet/app/repository/TokenRepository.java @@ -121,7 +121,8 @@ public TokenRepository( private void buildWeb3jClient(NetworkInfo networkInfo) { AWHttpService publicNodeService = new AWHttpService(networkInfo.rpcServerUrl, networkInfo.backupNodeUrl, okClient, false); - HttpServiceHelper.addRequiredCredentials(networkInfo.chainId, publicNodeService, KeyProviderFactory.get().getKlaytnKey(), EthereumNetworkBase.usesProductionKey); + HttpServiceHelper.addRequiredCredentials(networkInfo.chainId, publicNodeService, KeyProviderFactory.get().getKlaytnKey(), + KeyProviderFactory.get().getInfuraSecret(), EthereumNetworkBase.usesProductionKey); web3jNodeServers.put(networkInfo.chainId, Web3j.build(publicNodeService)); } @@ -142,7 +143,7 @@ public Single checkInterface(Token[] tokens, Wallet wallet) for (int i = 0; i < tokens.length; i++) { Token t = tokens[i]; - if (t.getInterfaceSpec() == ContractType.ERC721_UNDETERMINED || t.getInterfaceSpec() == ContractType.MAYBE_ERC20 || !t.checkBalanceType()) //balance type appears to be wrong + if (t.getInterfaceSpec() == ContractType.ERC721_UNDETERMINED || t.getInterfaceSpec() == ContractType.MAYBE_ERC20) //balance type appears to be wrong { ContractType type = determineCommonType(t.tokenInfo) .onErrorReturnItem(t.getInterfaceSpec()).blockingGet(); @@ -501,13 +502,14 @@ private BigDecimal updateERC1155Balance(Token token, Wallet wallet) return newBalance; } + //Batch Balance private Single updateBalances(Wallet wallet, Token[] tokens) { return Single.fromCallable(() -> { for (Token t : tokens) { //get balance of any token here - if (t.isERC721() || t.isERC20()) t.balance = checkUint256Balance(wallet, t.tokenInfo.chainId, t.getAddress()); + if (t.isERC20() || t.isNonFungible()) t.balance = checkUint256Balance(wallet, t.tokenInfo.chainId, t.getAddress()); } return tokens; }); @@ -1223,6 +1225,28 @@ public void addImageUrl(long networkId, String address, String imageUrl) localSource.storeTokenUrl(networkId, address, imageUrl); } + public static Web3j getWeb3jServiceForEvents(long chainId) + { + OkHttpClient okClient = new OkHttpClient.Builder() + .connectTimeout(C.CONNECT_TIMEOUT * 3, TimeUnit.SECONDS) + .connectTimeout(C.READ_TIMEOUT * 3, TimeUnit.SECONDS) //events can take longer to render + .writeTimeout(C.LONG_WRITE_TIMEOUT, TimeUnit.SECONDS) + .retryOnConnectionFailure(true) + .build(); + + String nodeUrl = EthereumNetworkBase.getNodeURLForEvents(chainId); + String secondaryNode = EthereumNetworkRepository.getSecondaryNodeURL(chainId); + if (nodeUrl.equals(secondaryNode)) //ensure backup node is different + { + secondaryNode = EthereumNetworkRepository.getNodeURLByNetworkId(chainId); + } + + AWHttpService publicNodeService = new AWHttpService(nodeUrl, secondaryNode, okClient, false); + HttpServiceHelper.addRequiredCredentials(chainId, publicNodeService, KeyProviderFactory.get().getKlaytnKey(), + KeyProviderFactory.get().getInfuraSecret(), EthereumNetworkBase.usesProductionKey); + return Web3j.build(publicNodeService); + } + public static Web3j getWeb3jService(long chainId) { OkHttpClient okClient = new OkHttpClient.Builder() @@ -1231,8 +1255,10 @@ public static Web3j getWeb3jService(long chainId) .writeTimeout(C.LONG_WRITE_TIMEOUT, TimeUnit.SECONDS) .retryOnConnectionFailure(true) .build(); + AWHttpService publicNodeService = new AWHttpService(EthereumNetworkRepository.getNodeURLByNetworkId(chainId), EthereumNetworkRepository.getSecondaryNodeURL(chainId), okClient, false); - HttpServiceHelper.addRequiredCredentials(chainId, publicNodeService, KeyProviderFactory.get().getKlaytnKey(), EthereumNetworkBase.usesProductionKey); + HttpServiceHelper.addRequiredCredentials(chainId, publicNodeService, KeyProviderFactory.get().getKlaytnKey(), + KeyProviderFactory.get().getInfuraSecret(), EthereumNetworkBase.usesProductionKey); return Web3j.build(publicNodeService); } 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 d8c78b8ccc..c5faa77821 100644 --- a/app/src/main/java/com/alphawallet/app/repository/TokensRealmSource.java +++ b/app/src/main/java/com/alphawallet/app/repository/TokensRealmSource.java @@ -35,9 +35,7 @@ import java.math.BigInteger; import java.math.RoundingMode; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; @@ -71,25 +69,32 @@ public TokensRealmSource(RealmManager realmManager, EthereumNetworkRepositoryTyp @Override public Single saveTokens(Wallet wallet, Token[] items) { - if (!Utils.isAddressValid(wallet.address)) { return Single.fromCallable(() -> items); } - else return Single.fromCallable(() -> { - try (Realm realm = realmManager.getRealmInstance(wallet)) - { - realm.executeTransaction(r -> { - for (Token token : items) { - if (token.tokenInfo != null && token.tokenInfo.name != null && !token.tokenInfo.name.equals(EXPIRED_CONTRACT) && token.tokenInfo.symbol != null) + if (!Utils.isAddressValid(wallet.address)) + { + return Single.fromCallable(() -> items); + } + else + { + return Single.fromCallable(() -> { + try (Realm realm = realmManager.getRealmInstance(wallet)) + { + realm.executeTransaction(r -> { + for (Token token : items) { - saveTokenLocal(r, token); + if (token.tokenInfo != null && token.tokenInfo.name != null && !token.tokenInfo.name.equals(EXPIRED_CONTRACT) && token.tokenInfo.symbol != null) + { + saveTokenLocal(r, token); + } } - } - }); - } - catch (Exception e) - { - // - } - return items; - }); + }); + } + catch (Exception e) + { + Timber.w(e); + } + return items; + }); + } } @Override @@ -429,6 +434,11 @@ public boolean updateTokenBalance(Wallet wallet, Token token, BigDecimal balance { boolean balanceChanged = false; String key = databaseKey(token); + if (token.getWallet() == null) + { + token.setTokenWallet(wallet.address); + } + try (Realm realm = realmManager.getRealmInstance(wallet)) { RealmToken realmToken = realm.where(RealmToken.class) @@ -608,6 +618,11 @@ private void saveToken(Realm realm, Token token) throws RealmException writeAssetContract(realm, token); } + if (oldToken.getInterfaceSpec() != token.getInterfaceSpec()) + { + realmToken.setInterfaceSpec(token.getInterfaceSpec().ordinal()); + } + //check if name needs to be updated if (!TextUtils.isEmpty(token.tokenInfo.name) && (TextUtils.isEmpty(realmToken.getName()) || !realmToken.getName().equals(token.tokenInfo.name))) { @@ -667,46 +682,22 @@ public Token[] initNFTAssets(Wallet wallet, Token[] tokens) //load all the assets from the database Map assetMap = getNFTAssets(r, token); - //construct live list - //for erc1155 need to check each potential 'removal'. - //erc721 gets removed by noting token transfer - Map liveMap = token.queryAssets(assetMap); - HashSet deleteList = new HashSet<>(); - - for (BigInteger tokenId : liveMap.keySet()) - { - NFTAsset oldAsset = assetMap.get(tokenId); //may be null - NFTAsset newAsset = liveMap.get(tokenId); //never null - - if (newAsset.getBalance().compareTo(BigDecimal.ZERO) == 0) - { - deleteAssets(r, token, Collections.singletonList(tokenId)); - deleteList.add(tokenId); - } - else - { - //token updated or new - if (oldAsset != null) { newAsset.updateAsset(oldAsset); } - writeAsset(r, token, tokenId, newAsset); - } - } - - for (BigInteger tokenId : deleteList) - { - liveMap.remove(tokenId); - } + //Query the changes + Map updatedMap = token.getAssetChange(assetMap); // feed in old assets - //update token balance & visibility - setTokenUpdateTime(r, token, liveMap.keySet().size()); - token.balance = new BigDecimal(liveMap.keySet().size()); - if (token.getTokenAssets().hashCode() != liveMap.hashCode()) //replace asset map if different + //is there any difference? + if (updatedMap.hashCode() != assetMap.hashCode()) { token.getTokenAssets().clear(); - token.getTokenAssets().putAll(liveMap); + token.getTokenAssets().putAll(updatedMap); } } }); } + catch (Exception e) + { + Timber.w(e); + } return tokens; } diff --git a/app/src/main/java/com/alphawallet/app/service/AWHttpService.java b/app/src/main/java/com/alphawallet/app/service/AWHttpService.java index 60009021c8..daaa41ab18 100644 --- a/app/src/main/java/com/alphawallet/app/service/AWHttpService.java +++ b/app/src/main/java/com/alphawallet/app/service/AWHttpService.java @@ -161,10 +161,9 @@ private InputStream trySecondaryNode(String request) throws IOException { Timber.d("trySecondaryNode: "); RequestBody requestBody = RequestBody.create(request, JSON_MEDIA_TYPE); - Headers headers = buildHeaders(); okhttp3.Request httpRequest = - new okhttp3.Request.Builder().url(secondaryUrl).headers(headers).post(requestBody).build(); + new okhttp3.Request.Builder().url(secondaryUrl).post(requestBody).build(); okhttp3.Response response; @@ -259,4 +258,9 @@ public HashMap getHeaders() { @Override public void close() throws IOException {} + + public String getUrl() + { + return this.url; + } } diff --git a/app/src/main/java/com/alphawallet/app/service/TransactionsNetworkClient.java b/app/src/main/java/com/alphawallet/app/service/TransactionsNetworkClient.java index 8730490860..7e0c8097ec 100644 --- a/app/src/main/java/com/alphawallet/app/service/TransactionsNetworkClient.java +++ b/app/src/main/java/com/alphawallet/app/service/TransactionsNetworkClient.java @@ -62,8 +62,8 @@ public class TransactionsNetworkClient implements TransactionsNetworkClientType { private static final String TAG = "TXNETCLIENT"; - private final int PAGESIZE = 800; - private final int SYNC_PAGECOUNT = 2; //how many pages to read when we first sync the account - means we store the first 1600 transactions only + private final int PAGESIZE = 1000; + private final int SYNC_PAGECOUNT = 1; //how many pages to read when we first sync the account - means we store the first 1600 transactions only public static final int TRANSFER_RESULT_MAX = 250; //check 200 records when we first get a new account //Note: if user wants to view transactions older than this, we fetch from etherscan on demand. //Generally this would only happen when watching extremely active accounts for curiosity @@ -664,6 +664,11 @@ private String readNextTxBatch(String walletAddress, NetworkInfo networkInfo, lo String result = "0"; if (currentBlock == 0) currentBlock = 1; + if (networkInfo.chainId == BINANCE_TEST_ID || networkInfo.chainId == BINANCE_MAIN_ID) + { + System.out.println("YOLESS"); + } + String fullUrl = networkInfo.etherscanAPI + "module=account&action=" + queryType + "&startblock=" + currentBlock + "&endblock=9999999999" + "&address=" + walletAddress + @@ -704,7 +709,7 @@ private String getNetworkAPIToken(NetworkInfo networkInfo) { return ETHERSCAN_API_KEY; } - else if (networkInfo.chainId == BINANCE_TEST_ID || networkInfo.chainId == BINANCE_MAIN_ID) + else if (networkInfo.chainId == BINANCE_MAIN_ID) { return BSC_EXPLORER_API_KEY; } diff --git a/app/src/main/java/com/alphawallet/app/service/TransactionsService.java b/app/src/main/java/com/alphawallet/app/service/TransactionsService.java index c7326eb8f0..48adb845ed 100644 --- a/app/src/main/java/com/alphawallet/app/service/TransactionsService.java +++ b/app/src/main/java/com/alphawallet/app/service/TransactionsService.java @@ -58,7 +58,7 @@ public class TransactionsService private final LongSparseArray chainTransferCheckTimes = new LongSparseArray<>(); //TODO: Use this to coordinate token checks on chains private final LongSparseArray chainTransactionCheckTimes = new LongSparseArray<>(); - private static final LongSparseArray currentBlocks = new LongSparseArray<>(); + private static final LongSparseArray currentBlocks = new LongSparseArray<>(); private static final ConcurrentLinkedQueue requiredTransactions = new ConcurrentLinkedQueue<>(); private final static int TRANSACTION_DROPPED = -1; @@ -161,10 +161,6 @@ private void checkTransfers() if (currentChainIndex >= filters.size()) currentChainIndex = 0; readTokenMoves(filters.get(currentChainIndex), nftCheck); //check NFTs for same chain on next iteration or advance to next chain Pair pendingChainData = getNextChainIndex(currentChainIndex, nftCheck, filters); - if (pendingChainData.first != currentChainIndex) - { - updateCurrentBlock(filters.get(currentChainIndex)); - } currentChainIndex = pendingChainData.first; nftCheck = pendingChainData.second; } @@ -289,13 +285,6 @@ else if (checkTime < oldestCheck) } } - private void updateCurrentBlock(final long chainId) - { - fetchCurrentBlock(chainId).subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(blockValue -> currentBlocks.put(chainId, blockValue), onError -> currentBlocks.put(chainId, BigInteger.ZERO)).isDisposed(); - } - private static Single fetchCurrentBlock(final long chainId) { return Single.fromCallable(() -> { @@ -305,7 +294,7 @@ private static Single fetchCurrentBlock(final long chainId) String blockValStr = ethBlock.getBlock().getNumberRaw(); if (!TextUtils.isEmpty(blockValStr) && blockValStr.length() > 2) return Numeric.toBigInt(blockValStr); - else return currentBlocks.get(chainId, BigInteger.ZERO); + else return currentBlocks.get(chainId, new CurrentBlockTime(BigInteger.ZERO)).blockNumber; }); } @@ -537,14 +526,14 @@ public void markPending(Transaction tx) public static BigInteger getCurrentBlock(long chainId) { - BigInteger currentBlock = currentBlocks.get(chainId, BigInteger.ZERO); - if (currentBlock.equals(BigInteger.ZERO)) + CurrentBlockTime currentBlock = currentBlocks.get(chainId, new CurrentBlockTime(BigInteger.ZERO)); + if (currentBlock.blockReadRequiresUpdate()) { - currentBlock = fetchCurrentBlock(chainId).blockingGet(); + currentBlock = new CurrentBlockTime(fetchCurrentBlock(chainId).blockingGet()); currentBlocks.put(chainId, currentBlock); } - return currentBlock; + return currentBlock.blockNumber; } private void checkPendingTransactions() @@ -642,4 +631,22 @@ private String getNextUncachedTx() return txHashData; } + + private static class CurrentBlockTime + { + public final long readTime; + public final BigInteger blockNumber; + + public CurrentBlockTime(BigInteger blockNo) + { + readTime = System.currentTimeMillis(); + blockNumber = blockNo; + } + + public boolean blockReadRequiresUpdate() + { + // update every 10 seconds if required + return blockNumber.equals(BigInteger.ZERO) || System.currentTimeMillis() > (readTime + 10 * DateUtils.SECOND_IN_MILLIS); + } + } } diff --git a/app/src/main/java/com/alphawallet/app/util/ens/EnsResolver.java b/app/src/main/java/com/alphawallet/app/util/ens/EnsResolver.java index d25590ed9a..e17abc12ff 100644 --- a/app/src/main/java/com/alphawallet/app/util/ens/EnsResolver.java +++ b/app/src/main/java/com/alphawallet/app/util/ens/EnsResolver.java @@ -62,11 +62,14 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import io.reactivex.Single; +import io.reactivex.schedulers.Schedulers; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.ResponseBody; +import timber.log.Timber; /** Resolution logic for contract addresses. According to https://eips.ethereum.org/EIPS/eip-2544 */ public class EnsResolver implements Resolvable @@ -84,7 +87,7 @@ public class EnsResolver implements Resolvable private final Web3j web3j; protected final int addressLength; - protected final long chainId; + protected long chainId; private OkHttpClient client = new OkHttpClient(); @@ -95,20 +98,16 @@ public EnsResolver(Web3j web3j, int addressLength) this.web3j = web3j; this.addressLength = addressLength; - long chainId = 1; + chainId = 1; - try - { + Single.fromCallable(() -> { NetVersion v = web3j.netVersion().send(); String ver = v.getNetVersion(); - chainId = Long.parseLong(ver); - } - catch (Exception e) - { - // - } - - this.chainId = chainId; + return Long.parseLong(ver); + }).subscribeOn(Schedulers.io()) + .observeOn(Schedulers.io()) + .subscribe(id -> this.chainId = id, Timber::w) + .isDisposed(); } public EnsResolver(Web3j web3j) { diff --git a/app/src/test/java/com/alphawallet/app/repository/HttpServiceHelperTest.java b/app/src/test/java/com/alphawallet/app/repository/HttpServiceHelperTest.java index 525f48bef9..3105facd46 100644 --- a/app/src/test/java/com/alphawallet/app/repository/HttpServiceHelperTest.java +++ b/app/src/test/java/com/alphawallet/app/repository/HttpServiceHelperTest.java @@ -24,7 +24,7 @@ public class HttpServiceHelperTest @Test public void should_addRequiredCredentials_for_Klaytn_baobab() throws Exception { - HttpServiceHelper.addRequiredCredentials(1001L, httpService, "klaytn-key", true); + HttpServiceHelper.addRequiredCredentials(1001L, httpService, "klaytn-key", "infura-key", true); HashMap headers = httpService.getHeaders(); assertThat(headers.get("x-chain-id"), equalTo("1001")); assertThat(headers.get("Authorization"), equalTo("Basic klaytn-key")); @@ -33,7 +33,7 @@ public void should_addRequiredCredentials_for_Klaytn_baobab() throws Exception @Test public void should_addRequiredCredentials_for_KLAYTN() throws Exception { - HttpServiceHelper.addRequiredCredentials(8217, httpService, "klaytn-key", true); + HttpServiceHelper.addRequiredCredentials(8217, httpService, "klaytn-key", "infura-key", true); HashMap headers = httpService.getHeaders(); assertThat(headers.get("x-chain-id"), equalTo("8217")); assertThat(headers.get("Authorization"), equalTo("Basic klaytn-key")); @@ -42,7 +42,7 @@ public void should_addRequiredCredentials_for_KLAYTN() throws Exception @Test public void should_not_addRequiredCredentials_for_KLAYTN_when_not_use_production_key() throws Exception { - HttpServiceHelper.addRequiredCredentials(8217, httpService, "klaytn-key", false); + HttpServiceHelper.addRequiredCredentials(8217, httpService,"klaytn-key", "infura-key", false); HashMap headers = httpService.getHeaders(); assertFalse(headers.containsKey("x-chain-id")); assertFalse(headers.containsKey("Authorization")); @@ -51,7 +51,7 @@ public void should_not_addRequiredCredentials_for_KLAYTN_when_not_use_production @Test public void should_not_addRequiredCredentials_for_non_KLAYTN_chain() throws Exception { - HttpServiceHelper.addRequiredCredentials(1, httpService, "klaytn-key", false); + HttpServiceHelper.addRequiredCredentials(1, httpService, "klaytn-key", "infura-key", false); HashMap headers = httpService.getHeaders(); assertFalse(headers.containsKey("x-chain-id")); assertFalse(headers.containsKey("Authorization")); From 6068cf546b6cf0a949f649299690fd0872edb7d9 Mon Sep 17 00:00:00 2001 From: James Brown Date: Thu, 8 Dec 2022 23:34:13 +1100 Subject: [PATCH 34/36] Further update fixes to reduce overhead with balance updates Add TODO --- .../app/entity/tokens/ERC1155Token.java | 16 +--- .../app/entity/tokens/ERC721Ticket.java | 2 +- .../app/entity/tokens/ERC721Token.java | 18 +---- .../alphawallet/app/entity/tokens/Ticket.java | 38 +++++----- .../alphawallet/app/entity/tokens/Token.java | 2 +- .../app/repository/TokenRepository.java | 9 +++ .../app/repository/TokensRealmSource.java | 75 ++++++++++++------- .../app/router/TokenDetailRouter.java | 14 +++- .../app/service/TokensService.java | 23 ++---- .../service/TransactionsNetworkClient.java | 17 ++--- .../alphawallet/app/ui/FunctionActivity.java | 1 + .../app/viewmodel/WalletViewModel.java | 10 ++- app/src/main/res/layout/item_ticket.xml | 2 +- 13 files changed, 117 insertions(+), 110 deletions(-) diff --git a/app/src/main/java/com/alphawallet/app/entity/tokens/ERC1155Token.java b/app/src/main/java/com/alphawallet/app/entity/tokens/ERC1155Token.java index 550d977b9b..84f8ecc789 100644 --- a/app/src/main/java/com/alphawallet/app/entity/tokens/ERC1155Token.java +++ b/app/src/main/java/com/alphawallet/app/entity/tokens/ERC1155Token.java @@ -320,16 +320,10 @@ private List fetchBalances(Set tokenIds) @Override public Map queryAssets(Map assetMap) { - //first see if there's no change; if this is the case we can skip - if (assetsUnchanged(assetMap)) return assets; - - //add all known tokens in - Map sum = new HashMap<>(assetMap); - sum.putAll(assets); - Set tokenIds = sum.keySet(); + Set tokenIds = assetMap.keySet(); Function balanceOfBatch = balanceOfBatch(getWallet(), tokenIds); List balances = callSmartContractFunctionArray(tokenInfo.chainId, balanceOfBatch, getAddress(), getWallet()); - Map updatedAssetMap; + Map updatedAssetMap = new HashMap<>(); if (balances != null && balances.size() > 0) { @@ -337,7 +331,7 @@ public Map queryAssets(Map assetMap) int index = 0; for (BigInteger tokenId : tokenIds) { - NFTAsset thisAsset = new NFTAsset(sum.get(tokenId)); + NFTAsset thisAsset = new NFTAsset(assetMap.get(tokenId)); BigInteger balance = balances.get(index).getValue(); thisAsset.setBalance(new BigDecimal(balance)); updatedAssetMap.put(tokenId, thisAsset); @@ -345,10 +339,6 @@ public Map queryAssets(Map assetMap) index++; } } - else - { - updatedAssetMap = assets; - } return updatedAssetMap; } diff --git a/app/src/main/java/com/alphawallet/app/entity/tokens/ERC721Ticket.java b/app/src/main/java/com/alphawallet/app/entity/tokens/ERC721Ticket.java index 813eeda7fa..49a6e8c5ca 100644 --- a/app/src/main/java/com/alphawallet/app/entity/tokens/ERC721Ticket.java +++ b/app/src/main/java/com/alphawallet/app/entity/tokens/ERC721Ticket.java @@ -171,7 +171,7 @@ public boolean hasArrayBalance() public List getNonZeroArrayBalance() { List nonZeroValues = new ArrayList<>(); - for (BigInteger value : balanceArray) if (value.compareTo(BigInteger.ZERO) != 0 && !nonZeroValues.contains(value)) nonZeroValues.add(value); + for (BigInteger value : balanceArray) if (value.compareTo(BigInteger.ZERO) != 0) nonZeroValues.add(value); return nonZeroValues; } diff --git a/app/src/main/java/com/alphawallet/app/entity/tokens/ERC721Token.java b/app/src/main/java/com/alphawallet/app/entity/tokens/ERC721Token.java index d9cd1dbc11..96dca9e976 100644 --- a/app/src/main/java/com/alphawallet/app/entity/tokens/ERC721Token.java +++ b/app/src/main/java/com/alphawallet/app/entity/tokens/ERC721Token.java @@ -681,22 +681,8 @@ public BigDecimal getBalanceRaw() @Override public Map queryAssets(Map assetMap) { - //check all tokens in this contract - assetMap.putAll(tokenBalanceAssets); - - HashSet currentAssets = new HashSet<>(assetMap.keySet()); - final Web3j web3j = TokenRepository.getWeb3jService(tokenInfo.chainId); - try - { - currentAssets = checkBalances(web3j, currentAssets); - } - catch (Exception e) - { - // - } - for (Map.Entry entry : assetMap.entrySet()) { BigInteger checkId = entry.getKey(); @@ -717,10 +703,10 @@ else if (owner.equalsIgnoreCase(getWallet())) checkAsset.setBalance(BigDecimal.ZERO); } - tokenBalanceAssets.put(checkId, checkAsset); + assetMap.put(checkId, checkAsset); } - return tokenBalanceAssets; + return assetMap; } // Check for new/missing tokenBalanceAssets diff --git a/app/src/main/java/com/alphawallet/app/entity/tokens/Ticket.java b/app/src/main/java/com/alphawallet/app/entity/tokens/Ticket.java index e909b34178..44e5b85115 100644 --- a/app/src/main/java/com/alphawallet/app/entity/tokens/Ticket.java +++ b/app/src/main/java/com/alphawallet/app/entity/tokens/Ticket.java @@ -10,7 +10,6 @@ import com.alphawallet.app.entity.tokendata.TokenGroup; import com.alphawallet.app.repository.EventResult; import com.alphawallet.app.repository.entity.RealmToken; -import com.alphawallet.app.service.AssetDefinitionService; import com.alphawallet.app.util.Utils; import com.alphawallet.app.viewmodel.BaseViewModel; import com.alphawallet.token.entity.TicketRange; @@ -27,31 +26,34 @@ import java.util.List; /** - * Created by James on 27/01/2018. It might seem counter intuitive - * but here Ticket refers to a container of an asset class here, not - * the right to seat somewhere in the venue. Therefore, there - * shouldn't be List To understand this, imagine that one says - * "I have two cryptocurrencies: Ether and Bitcoin, each amounts to a - * hundred", and he pauses and said, "I also have two indices: FIFA - * and Formuler-one, which, too, amounts to a hundred each". + * Created by James on 27/01/2018. */ public class Ticket extends Token { private final List balanceArray; - private boolean isMatchedInXML = false; - public Ticket(TokenInfo tokenInfo, List balances, long blancaTime, String networkName, ContractType type) { + public Ticket(TokenInfo tokenInfo, List balances, long blancaTime, String networkName, ContractType type) + { super(tokenInfo, BigDecimal.ZERO, blancaTime, networkName, type); this.balanceArray = balances; - balance = balanceArray != null ? BigDecimal.valueOf(balanceArray.size()) : BigDecimal.ZERO; + balance = balanceArray != null ? BigDecimal.valueOf(getNonZeroArrayBalance().size()) : BigDecimal.ZERO; group = TokenGroup.NFT; } - public Ticket(TokenInfo tokenInfo, String balances, long blancaTime, String networkName, ContractType type) { + public Ticket(TokenInfo tokenInfo, String balances, long blancaTime, String networkName, ContractType type) + { super(tokenInfo, BigDecimal.ZERO, blancaTime, networkName, type); this.balanceArray = stringHexToBigIntegerList(balances); - balance = BigDecimal.valueOf(balanceArray.size()); + balance = BigDecimal.valueOf(getNonZeroArrayBalance().size()); + group = TokenGroup.NFT; + } + + public Ticket(Token oldTicket, List balances) + { + super(oldTicket.tokenInfo, BigDecimal.ZERO, oldTicket.updateBlancaTime, oldTicket.getNetworkName(), oldTicket.contractType); + this.balanceArray = balances; + balance = BigDecimal.valueOf(getNonZeroArrayBalance().size()); group = TokenGroup.NFT; } @@ -235,11 +237,6 @@ private List tokenIdsToTokenIndices(List tokenIds) return indexList; } - public void checkIsMatchedInXML(AssetDefinitionService assetService) - { - isMatchedInXML = assetService.hasDefinition(tokenInfo.chainId, tokenInfo.address); - } - @Override public Function getTransferFunction(String to, List tokenIndices) throws NumberFormatException { @@ -305,7 +302,10 @@ public boolean hasArrayBalance() public List getNonZeroArrayBalance() { List nonZeroValues = new ArrayList<>(); - for (BigInteger value : balanceArray) if (value.compareTo(BigInteger.ZERO) != 0 && !nonZeroValues.contains(value)) nonZeroValues.add(value); + for (BigInteger value : balanceArray) + { + if (value.compareTo(BigInteger.ZERO) != 0) nonZeroValues.add(value); + } return nonZeroValues; } diff --git a/app/src/main/java/com/alphawallet/app/entity/tokens/Token.java b/app/src/main/java/com/alphawallet/app/entity/tokens/Token.java index 760e88db9e..0108c12332 100644 --- a/app/src/main/java/com/alphawallet/app/entity/tokens/Token.java +++ b/app/src/main/java/com/alphawallet/app/entity/tokens/Token.java @@ -383,7 +383,7 @@ public void setIsEthereum() public boolean isBad() { - return tokenInfo == null || (tokenInfo.symbol == null && tokenInfo.name == null); + return tokenInfo == null || tokenInfo.chainId == 0 || (tokenInfo.symbol == null && tokenInfo.name == null); } public void setTokenWallet(String address) 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 751f8d71f1..c1d251505b 100644 --- a/app/src/main/java/com/alphawallet/app/repository/TokenRepository.java +++ b/app/src/main/java/com/alphawallet/app/repository/TokenRepository.java @@ -21,6 +21,7 @@ import com.alphawallet.app.entity.tokendata.TokenTicker; import com.alphawallet.app.entity.tokens.ERC721Ticket; import com.alphawallet.app.entity.tokens.ERC721Token; +import com.alphawallet.app.entity.tokens.Ticket; import com.alphawallet.app.entity.tokens.Token; import com.alphawallet.app.entity.tokens.TokenCardMeta; import com.alphawallet.app.entity.tokens.TokenInfo; @@ -326,6 +327,11 @@ public Single fixFullNames(Wallet wallet, AssetDefinitionService svs) @Override public Single updateTokenBalance(String walletAddress, Token token) { + if (token.isBad()) + { + return Single.fromCallable(() -> BigDecimal.ZERO); + } + Wallet wallet = new Wallet(walletAddress); return updateBalance(wallet, token) .subscribeOn(Schedulers.io()) @@ -411,6 +417,8 @@ public String getTokenImageUrl(long networkId, String address) return localSource.getTokenImageUrl(networkId, address); } + //TODO: Refactor this so the balance update is abstracted into the Token itself + // Once the token is updated we can store it. May need to make the token internal balance non-final private Single updateBalance(final Wallet wallet, final Token token) { return Single.fromCallable(() -> { @@ -429,6 +437,7 @@ private Single updateBalance(final Wallet wallet, final Token token) case ERC875: case ERC875_LEGACY: balanceArray = getBalanceArray875(wallet, token.tokenInfo.chainId, token.getAddress()); + thisToken = new Ticket(thisToken, balanceArray); balance = BigDecimal.valueOf(balanceArray.size()); break; case ERC721_LEGACY: 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 c5faa77821..1fb5c79b7c 100644 --- a/app/src/main/java/com/alphawallet/app/repository/TokensRealmSource.java +++ b/app/src/main/java/com/alphawallet/app/repository/TokensRealmSource.java @@ -288,11 +288,9 @@ public void updateNFTAssets(String wallet, Token token, List additio realm.executeTransaction(r -> { createTokenIfRequired(r, token); deleteAssets(r, token, removals); - int assetCount = updateNFTAssets(r, token, additions); - //now re-do the balance - assetCount = token.getBalanceRaw().intValue(); + updateNFTAssets(r, token, additions); - setTokenUpdateTime(r, token, assetCount); + setTokenUpdateTime(r, token); }); } catch (Exception e) @@ -313,20 +311,22 @@ private void createTokenIfRequired(Realm realm, Token token) } } - private void setTokenUpdateTime(Realm realm, Token token, int assetCount) + private void setTokenUpdateTime(Realm realm, Token token) { RealmToken realmToken = realm.where(RealmToken.class) .equalTo("address", databaseKey(token)) .findFirst(); + long tokenBalance = token.balance.longValue(); + if (realmToken != null) { - if (!realmToken.isEnabled() && !realmToken.isVisibilityChanged() && assetCount > 0) + if (!realmToken.isEnabled() && !realmToken.isVisibilityChanged() && tokenBalance > 0) { token.tokenInfo.isEnabled = true; realmToken.setEnabled(true); } - else if (!realmToken.isVisibilityChanged() && assetCount == 0) + else if (!realmToken.isVisibilityChanged() && tokenBalance == 0) { token.tokenInfo.isEnabled = false; realmToken.setEnabled(false); @@ -335,32 +335,51 @@ else if (!realmToken.isVisibilityChanged() && assetCount == 0) realmToken.setLastTxTime(System.currentTimeMillis()); realmToken.setAssetUpdateTime(System.currentTimeMillis()); - if (realmToken.getBalance() == null || !realmToken.getBalance().equals(String.valueOf(assetCount))) + if (realmToken.getBalance() == null || !realmToken.getBalance().equals(String.valueOf(tokenBalance))) { - realmToken.setBalance(String.valueOf(assetCount)); + realmToken.setBalance(String.valueOf(tokenBalance)); } } } - private int updateNFTAssets(Realm realm, Token token, List additions) throws RealmException + private void updateNFTAssets(Realm realm, Token token, List additions) throws RealmException { - if (!token.isNonFungible()) return 0; + if (!token.isNonFungible()) return; //load all the old assets Map assetMap = getNFTAssets(realm, token); - int assetCount = assetMap.size(); - for (BigInteger updatedTokenId : additions) + //create addition asset map + Map additionMap = new HashMap<>(); + + for (BigInteger tokenId : additions) + { + NFTAsset asset = assetMap.get(tokenId); + if (asset == null) asset = new NFTAsset(tokenId); + additionMap.put(tokenId, asset); + } + + Map balanceMap = token.queryAssets(additionMap); + + List deleteList = new ArrayList<>(); + + //update token assets + for (Map.Entry entry : balanceMap.entrySet()) { - NFTAsset asset = assetMap.get(updatedTokenId); - if (asset == null || asset.requiresReplacement()) + if (entry.getValue().getBalance().longValue() == 0) + { + deleteList.add(entry.getKey()); + } + else { - writeAsset(realm, token, updatedTokenId, new NFTAsset()); - if (asset == null) assetCount++; + writeAsset(realm, token, entry.getKey(), entry.getValue()); } } - return assetCount; + if (deleteList.size() > 0) + { + deleteAssets(realm, token, deleteList); + } } @Override @@ -668,7 +687,7 @@ private void writeAssetContract(final Realm realm, Token token) realm.insertOrUpdate(realmNFT); } - // NFT Assets From Opensea + // NFT Assets From Opensea - assume this list is trustworthy - events will catch up with it @Override public Token[] initNFTAssets(Wallet wallet, Token[] tokens) { @@ -682,14 +701,18 @@ public Token[] initNFTAssets(Wallet wallet, Token[] tokens) //load all the assets from the database Map assetMap = getNFTAssets(r, token); - //Query the changes - Map updatedMap = token.getAssetChange(assetMap); // feed in old assets - - //is there any difference? - if (updatedMap.hashCode() != assetMap.hashCode()) + //run through the new assets and patch + for (Map.Entry entry : token.getTokenAssets().entrySet()) { - token.getTokenAssets().clear(); - token.getTokenAssets().putAll(updatedMap); + NFTAsset fromOpenSea = entry.getValue(); + NFTAsset fromDataBase = assetMap.get(entry.getKey()); + + fromOpenSea.updateAsset(fromDataBase); + + token.getTokenAssets().put(entry.getKey(), fromOpenSea); + + //write to realm + writeAsset(realm, token, entry.getKey(), fromOpenSea); } } }); diff --git a/app/src/main/java/com/alphawallet/app/router/TokenDetailRouter.java b/app/src/main/java/com/alphawallet/app/router/TokenDetailRouter.java index a80fd1d76c..774b326d22 100644 --- a/app/src/main/java/com/alphawallet/app/router/TokenDetailRouter.java +++ b/app/src/main/java/com/alphawallet/app/router/TokenDetailRouter.java @@ -4,11 +4,11 @@ import android.app.Activity; import android.content.Context; import android.content.Intent; -import android.util.Log; import com.alphawallet.app.C; -import com.alphawallet.app.entity.tokens.Token; import com.alphawallet.app.entity.Wallet; +import com.alphawallet.app.entity.tokens.Token; +import com.alphawallet.app.ui.AssetDisplayActivity; import com.alphawallet.app.ui.Erc20DetailActivity; import com.alphawallet.app.ui.NFTActivity; @@ -55,4 +55,14 @@ public void open(Activity activity, Token token, Wallet wallet) intent.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); activity.startActivityForResult(intent, C.TERMINATE_ACTIVITY); } + + public void openLegacyToken(Activity context, Token token, Wallet wallet) + { + Intent intent = new Intent(context, AssetDisplayActivity.class); + intent.putExtra(C.EXTRA_CHAIN_ID, token.tokenInfo.chainId); + intent.putExtra(C.EXTRA_ADDRESS, token.getAddress()); + intent.putExtra(C.Key.WALLET, wallet); + intent.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); + context.startActivityForResult(intent, C.TERMINATE_ACTIVITY); + } } 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 2bcbd69851..17d49ea149 100644 --- a/app/src/main/java/com/alphawallet/app/service/TokensService.java +++ b/app/src/main/java/com/alphawallet/app/service/TokensService.java @@ -132,18 +132,17 @@ private void checkUnknownTokens() { ContractAddress t = unknownTokens.pollFirst(); Token cachedToken = t != null ? getToken(t.chainId, t.address) : null; - ContractType type = cachedToken != null ? cachedToken.getInterfaceSpec() : ContractType.NOT_SET; if (t != null && t.address.length() > 0 && (cachedToken == null || TextUtils.isEmpty(cachedToken.tokenInfo.name))) { - queryUnknownTokensDisposable = tokenRepository.update(t.address, t.chainId, type).toObservable() //fetch tokenInfo - .filter(tokenInfo -> (!TextUtils.isEmpty(tokenInfo.name) || !TextUtils.isEmpty(tokenInfo.symbol)) && tokenInfo.chainId != 0) - .map(tokenInfo -> { tokenInfo.isEnabled = false; return tokenInfo; }) //set default visibility to false - .flatMap(tokenInfo -> tokenRepository.determineCommonType(tokenInfo).toObservable() - .map(contractType -> tokenFactory.createToken(tokenInfo, contractType, ethereumNetworkRepository.getNetworkByChain(t.chainId).getShortName()))) + ContractType type = tokenRepository.determineCommonType(new TokenInfo(t.address, "", "", 18, false, t.chainId)).blockingGet(); + + queryUnknownTokensDisposable = tokenRepository.update(t.address, t.chainId, type) //fetch tokenInfo + .map(tokenInfo -> tokenFactory.createToken(tokenInfo, type, ethereumNetworkRepository.getNetworkByChain(t.chainId).getShortName())) + .flatMap(token -> tokenRepository.updateTokenBalance(currentAddress, token)) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.io()) - .subscribe(this::finishAddToken, err -> onCheckError(err, t), this::finishTokenCheck); + .subscribe(this::finishAddToken, err -> onCheckError(err, t)); } else if (t == null) { @@ -159,19 +158,11 @@ private void onCheckError(Throwable throwable, ContractAddress t) Timber.e(throwable); } - private void finishTokenCheck() + private void finishAddToken(BigDecimal balance) { queryUnknownTokensDisposable = null; } - private void finishAddToken(Token token) - { - if (token != null && token.getInterfaceSpec() != ContractType.OTHER) - { - tokenStoreList.add(token); - } - } - public Token getToken(long chainId, String addr) { if (TextUtils.isEmpty(currentAddress) || TextUtils.isEmpty(addr)) return null; diff --git a/app/src/main/java/com/alphawallet/app/service/TransactionsNetworkClient.java b/app/src/main/java/com/alphawallet/app/service/TransactionsNetworkClient.java index 7e0c8097ec..5ab847f094 100644 --- a/app/src/main/java/com/alphawallet/app/service/TransactionsNetworkClient.java +++ b/app/src/main/java/com/alphawallet/app/service/TransactionsNetworkClient.java @@ -7,7 +7,6 @@ import static com.alphawallet.ethereum.EthereumNetworkBase.AURORA_MAINNET_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.AURORA_TESTNET_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.BINANCE_MAIN_ID; -import static com.alphawallet.ethereum.EthereumNetworkBase.BINANCE_TEST_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.POLYGON_ID; import static com.alphawallet.ethereum.EthereumNetworkBase.POLYGON_TEST_ID; @@ -626,9 +625,10 @@ private int calcTokenDecimals(EtherscanEvent ev0) private void writeAssets (Map> eventMap, Token token, String walletAddress, String contractAddress, TokensService svs, boolean newToken) { - List additions = new ArrayList<>(); - List removals = new ArrayList<>(); + HashSet additions = new HashSet<>(); + HashSet removals = new HashSet<>(); + //run through addition/removal in chronological order for (EtherscanEvent ev : eventMap.get(contractAddress)) { BigInteger tokenId = getTokenId(ev.tokenID); @@ -637,12 +637,12 @@ private void writeAssets (Map> eventMap, Token to if (ev.to.equalsIgnoreCase(walletAddress)) { - if (!additions.contains(tokenId)) { additions.add(tokenId); } + additions.add(tokenId); removals.remove(tokenId); } else { - if (!removals.contains(tokenId)) { removals.add(tokenId); } + removals.add(tokenId); additions.remove(tokenId); } } @@ -654,7 +654,7 @@ private void writeAssets (Map> eventMap, Token to if (additions.size() > 0 || removals.size() > 0) { - svs.updateAssets(token, additions, removals); + svs.updateAssets(token, new ArrayList<>(additions), new ArrayList<>(removals)); } } @@ -664,11 +664,6 @@ private String readNextTxBatch(String walletAddress, NetworkInfo networkInfo, lo String result = "0"; if (currentBlock == 0) currentBlock = 1; - if (networkInfo.chainId == BINANCE_TEST_ID || networkInfo.chainId == BINANCE_MAIN_ID) - { - System.out.println("YOLESS"); - } - String fullUrl = networkInfo.etherscanAPI + "module=account&action=" + queryType + "&startblock=" + currentBlock + "&endblock=9999999999" + "&address=" + walletAddress + diff --git a/app/src/main/java/com/alphawallet/app/ui/FunctionActivity.java b/app/src/main/java/com/alphawallet/app/ui/FunctionActivity.java index 868bcf9c96..0a40fac2e0 100644 --- a/app/src/main/java/com/alphawallet/app/ui/FunctionActivity.java +++ b/app/src/main/java/com/alphawallet/app/ui/FunctionActivity.java @@ -137,6 +137,7 @@ private void initViews() { parsePass = 0; ProgressBar loadSpinner = findViewById(R.id.ticket_load_spinner); + loadSpinner.setVisibility(View.VISIBLE); handler.postDelayed(() -> loadSpinner.setVisibility(View.GONE), 2500); } diff --git a/app/src/main/java/com/alphawallet/app/viewmodel/WalletViewModel.java b/app/src/main/java/com/alphawallet/app/viewmodel/WalletViewModel.java index 109f9f3c8e..189c022bff 100644 --- a/app/src/main/java/com/alphawallet/app/viewmodel/WalletViewModel.java +++ b/app/src/main/java/com/alphawallet/app/viewmodel/WalletViewModel.java @@ -1,7 +1,6 @@ package com.alphawallet.app.viewmodel; import static com.alphawallet.app.C.EXTRA_ADDRESS; -import static com.alphawallet.app.repository.TokensRealmSource.databaseKey; import static com.alphawallet.app.widget.CopyTextView.KEY_ADDRESS; import android.app.Activity; @@ -301,13 +300,16 @@ public void showTokenDetail(Activity activity, Token token) break; case ERC721: - case ERC875_LEGACY: - case ERC875: case ERC721_LEGACY: case ERC721_TICKET: case ERC721_UNDETERMINED: case ERC721_ENUMERABLE: - tokenDetailRouter.open(activity, token, defaultWallet.getValue(), false); //TODO: Fold this into tokenDetailRouter + tokenDetailRouter.open(activity, token, defaultWallet.getValue(), false); + break; + + case ERC875_LEGACY: + case ERC875: + tokenDetailRouter.openLegacyToken(activity, token, defaultWallet.getValue()); break; case NOT_SET: diff --git a/app/src/main/res/layout/item_ticket.xml b/app/src/main/res/layout/item_ticket.xml index 720006da98..86383d5560 100644 --- a/app/src/main/res/layout/item_ticket.xml +++ b/app/src/main/res/layout/item_ticket.xml @@ -18,7 +18,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" - android:visibility="visible" /> + android:visibility="gone" /> Date: Fri, 9 Dec 2022 16:08:20 +1100 Subject: [PATCH 35/36] Fix various ERC721 handling bugs --- .../app/entity/nftassets/NFTAsset.java | 6 +++ .../app/entity/tokens/TokenFactory.java | 1 + .../app/service/AlphaWalletService.java | 11 +++--- .../app/service/AssetDefinitionService.java | 9 ++++- .../alphawallet/app/service/IPFSService.java | 6 ++- .../alphawallet/app/ui/NFTAssetsFragment.java | 2 +- .../ui/widget/adapter/NFTAssetsAdapter.java | 37 ++++++++++++++++--- .../app/ui/widget/entity/IconItem.java | 8 ---- .../com/alphawallet/app/widget/TokenIcon.java | 4 -- .../com/alphawallet/app/IPFSServiceTest.java | 12 ++++-- 10 files changed, 66 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/com/alphawallet/app/entity/nftassets/NFTAsset.java b/app/src/main/java/com/alphawallet/app/entity/nftassets/NFTAsset.java index 30fa7cb5dd..4f12d851a5 100644 --- a/app/src/main/java/com/alphawallet/app/entity/nftassets/NFTAsset.java +++ b/app/src/main/java/com/alphawallet/app/entity/nftassets/NFTAsset.java @@ -100,6 +100,7 @@ public NFTAsset(BigInteger tokenId) attributeMap.clear(); balance = BigDecimal.ONE; assetMap.put(NAME, "ID #" + tokenId.toString()); + assetMap.put(LOADING_TOKEN, "."); } public NFTAsset(NFTAsset asset) @@ -382,6 +383,11 @@ public boolean needsLoading() return (assetMap.size() == 0 || assetMap.containsKey(LOADING_TOKEN)); } + public boolean hasImageAsset() + { + return !TextUtils.isEmpty(getThumbnail()); + } + public boolean requiresReplacement() { return (needsLoading() || !assetMap.containsKey(NAME) || TextUtils.isEmpty(getImage())); diff --git a/app/src/main/java/com/alphawallet/app/entity/tokens/TokenFactory.java b/app/src/main/java/com/alphawallet/app/entity/tokens/TokenFactory.java index ad437a4f6a..c5b8843e8f 100644 --- a/app/src/main/java/com/alphawallet/app/entity/tokens/TokenFactory.java +++ b/app/src/main/java/com/alphawallet/app/entity/tokens/TokenFactory.java @@ -124,6 +124,7 @@ public Token createToken(TokenInfo tokenInfo, RealmToken realmItem, long updateB case ERC721: case ERC721_LEGACY: case ERC721_ENUMERABLE: + case ERC721_UNDETERMINED: thisToken = new ERC721Token(tokenInfo, null, decimalBalance, updateBlancaTime, networkName, type); break; diff --git a/app/src/main/java/com/alphawallet/app/service/AlphaWalletService.java b/app/src/main/java/com/alphawallet/app/service/AlphaWalletService.java index 9d6e84cf41..3b95c76ec2 100644 --- a/app/src/main/java/com/alphawallet/app/service/AlphaWalletService.java +++ b/app/src/main/java/com/alphawallet/app/service/AlphaWalletService.java @@ -1,8 +1,9 @@ package com.alphawallet.app.service; -import android.util.Log; +import static com.alphawallet.app.entity.CryptoFunctions.sigFromByteArray; +import static com.alphawallet.token.tools.ParseMagicLink.currencyLink; +import static com.alphawallet.token.tools.ParseMagicLink.spawnable; -import com.alphawallet.app.BuildConfig; import com.alphawallet.app.entity.CryptoFunctions; import com.alphawallet.app.entity.Wallet; import com.alphawallet.app.entity.tokens.Ticket; @@ -33,10 +34,6 @@ import okhttp3.RequestBody; import timber.log.Timber; -import static com.alphawallet.app.entity.CryptoFunctions.sigFromByteArray; -import static com.alphawallet.token.tools.ParseMagicLink.currencyLink; -import static com.alphawallet.token.tools.ParseMagicLink.spawnable; - public class AlphaWalletService { private final OkHttpClient httpClient; @@ -109,6 +106,8 @@ public XMLDsigDescriptor checkTokenScriptSignature(File tokenScriptFile) String result = response.body().string(); JsonObject obj = gson.fromJson(result, JsonObject.class); + if (obj.has("error") || !obj.has("result")) return dsigDescriptor; + String queryResult = obj.get("result").getAsString(); if (queryResult.equals(XML_VERIFIER_PASS)) { diff --git a/app/src/main/java/com/alphawallet/app/service/AssetDefinitionService.java b/app/src/main/java/com/alphawallet/app/service/AssetDefinitionService.java index d8349c6077..d0c1cef935 100644 --- a/app/src/main/java/com/alphawallet/app/service/AssetDefinitionService.java +++ b/app/src/main/java/com/alphawallet/app/service/AssetDefinitionService.java @@ -924,6 +924,10 @@ private TokenDefinition parseFile(InputStream xmlInputStream) throws Exception private Single handleNewTSFile(File newFile) { + if (!newFile.exists()) + { + return Single.fromCallable(TokenDefinition::new); + } //1. check validity & check for origin tokens //2. check for existing and check if this is a debug file or script from server //3. update signature data @@ -1065,7 +1069,10 @@ private Pair downloadScript(String Uri, long currentFileTime) } catch (Exception e) { - Timber.w(e); + if (!TextUtils.isEmpty(Uri)) //throws on empty, which is expected + { + Timber.w(e); + } } return new Pair<>("", false); diff --git a/app/src/main/java/com/alphawallet/app/service/IPFSService.java b/app/src/main/java/com/alphawallet/app/service/IPFSService.java index b4cea7e0a6..36b82f05c8 100644 --- a/app/src/main/java/com/alphawallet/app/service/IPFSService.java +++ b/app/src/main/java/com/alphawallet/app/service/IPFSService.java @@ -50,7 +50,11 @@ public String getContent(String url) public QueryResponse performIO(String url, String[] headers) throws IOException { - if (!Utils.isValidUrl(url)) throw new IOException("URL not valid"); + url = url.trim(); + if (!Utils.isValidUrl(url)) + { + throw new IOException("URL not valid"); + } if (Utils.isIPFS(url)) //note that URL might contain IPFS, but not pass 'isValidUrl' { diff --git a/app/src/main/java/com/alphawallet/app/ui/NFTAssetsFragment.java b/app/src/main/java/com/alphawallet/app/ui/NFTAssetsFragment.java index 09b02fb5f7..112c53a7f5 100644 --- a/app/src/main/java/com/alphawallet/app/ui/NFTAssetsFragment.java +++ b/app/src/main/java/com/alphawallet/app/ui/NFTAssetsFragment.java @@ -169,7 +169,7 @@ private void initAndAttachAdapter(boolean isGridView) else { searchLayout.setVisibility(View.VISIBLE); - adapter = new NFTAssetsAdapter(getActivity(), token, this, isGridView); + adapter = new NFTAssetsAdapter(getActivity(), token, this, viewModel.getOpenseaService(), isGridView); search.addTextChangedListener(setupTextWatcher((NFTAssetsAdapter)adapter)); } diff --git a/app/src/main/java/com/alphawallet/app/ui/widget/adapter/NFTAssetsAdapter.java b/app/src/main/java/com/alphawallet/app/ui/widget/adapter/NFTAssetsAdapter.java index 0db182b9fd..be4154912c 100644 --- a/app/src/main/java/com/alphawallet/app/ui/widget/adapter/NFTAssetsAdapter.java +++ b/app/src/main/java/com/alphawallet/app/ui/widget/adapter/NFTAssetsAdapter.java @@ -17,6 +17,7 @@ import com.alphawallet.app.R; import com.alphawallet.app.entity.nftassets.NFTAsset; import com.alphawallet.app.entity.tokens.Token; +import com.alphawallet.app.service.OpenSeaService; import com.alphawallet.app.ui.NFTActivity; import com.alphawallet.app.ui.widget.OnAssetClickListener; import com.alphawallet.app.widget.NFTImageView; @@ -38,16 +39,18 @@ public class NFTAssetsAdapter extends RecyclerView.Adapter> actualData; private final List> displayData; - public NFTAssetsAdapter(Activity activity, Token token, OnAssetClickListener listener, boolean isGrid) + public NFTAssetsAdapter(Activity activity, Token token, OnAssetClickListener listener, OpenSeaService openSeaSvs, boolean isGrid) { this.activity = activity; this.listener = listener; this.token = token; this.isGrid = isGrid; + this.openSeaService = openSeaSvs; actualData = new ArrayList<>(); switch (token.getInterfaceSpec()) @@ -137,7 +140,7 @@ private void displayAsset(@NotNull ViewHolder holder, NFTAsset asset, BigInteger holder.subtitle.setVisibility(View.GONE); } - if (!asset.needsLoading()) + if (asset.hasImageAsset()) { holder.icon.setupTokenImageThumbnail(asset); } @@ -152,18 +155,40 @@ private void displayAsset(@NotNull ViewHolder holder, NFTAsset asset, BigInteger } private void fetchAsset(ViewHolder holder, Pair pair) + { + pair.second.metaDataLoader = openSeaService.getAsset(token, pair.first) + .map(NFTAsset::new) + .map(asset -> storeAsset(pair.first, asset, pair.second)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(asset -> checkAsset(asset, holder, pair), e -> {}); + } + + private void fetchContractMetadata(ViewHolder holder, Pair pair) { pair.second.metaDataLoader = Single.fromCallable(() -> { - return token.fetchTokenMetadata(pair.first); //fetch directly from token - }).map(newAsset -> storeAsset(pair.first, newAsset, pair.second)) + return token.fetchTokenMetadata(pair.first); //fetch directly from token + }).map(newAsset -> storeAsset(pair.first, newAsset, pair.second)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(a -> displayAsset(holder, a, pair.first), e -> { - }); + .subscribe(a -> displayAsset(holder, a, pair.first), e -> {}); + } + + private void checkAsset(NFTAsset asset, ViewHolder holder, Pair pair) + { + if (asset.hasImageAsset()) + { + displayAsset(holder, asset, pair.first); + } + else + { + fetchContractMetadata(holder, pair); + } } private NFTAsset storeAsset(BigInteger tokenId, NFTAsset fetchedAsset, NFTAsset oldAsset) { + if (!fetchedAsset.hasImageAsset()) return oldAsset; fetchedAsset.updateFromRaw(oldAsset); if (activity != null && activity instanceof NFTActivity) { diff --git a/app/src/main/java/com/alphawallet/app/ui/widget/entity/IconItem.java b/app/src/main/java/com/alphawallet/app/ui/widget/entity/IconItem.java index 61023be6c6..dbff547845 100644 --- a/app/src/main/java/com/alphawallet/app/ui/widget/entity/IconItem.java +++ b/app/src/main/java/com/alphawallet/app/ui/widget/entity/IconItem.java @@ -2,8 +2,6 @@ import static com.alphawallet.app.repository.TokensRealmSource.databaseKey; -import com.bumptech.glide.signature.ObjectKey; - import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -44,12 +42,6 @@ public static void secondaryFound(long chainId, String address) iconLoadType.put(databaseKey(chainId, address.toLowerCase()), true); } - //Use TextIcon - public static void noIconFound(long chainId, String address) - { - iconLoadType.put(databaseKey(chainId, address.toLowerCase()), false); - } - /** * Resets the failed icon fetch checking - try again to load failed icons */ diff --git a/app/src/main/java/com/alphawallet/app/widget/TokenIcon.java b/app/src/main/java/com/alphawallet/app/widget/TokenIcon.java index cf8d566cc3..e523c2034c 100644 --- a/app/src/main/java/com/alphawallet/app/widget/TokenIcon.java +++ b/app/src/main/java/com/alphawallet/app/widget/TokenIcon.java @@ -355,10 +355,6 @@ public boolean onResourceReady(Drawable resource, Object model, Target public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { if (model == null || token == null || !model.toString().toLowerCase().contains(token.getAddress())) return false; - if (token != null) - { - IconItem.noIconFound(token.tokenInfo.chainId, token.getAddress()); //don't try to load this asset again for this session - } return false; } diff --git a/app/src/test/java/com/alphawallet/app/IPFSServiceTest.java b/app/src/test/java/com/alphawallet/app/IPFSServiceTest.java index 8a6de2e391..4859ec40ec 100644 --- a/app/src/test/java/com/alphawallet/app/IPFSServiceTest.java +++ b/app/src/test/java/com/alphawallet/app/IPFSServiceTest.java @@ -49,6 +49,15 @@ public void testUrls() throws Exception assertEquals(qr.body, resp); assertTrue(qr.isSuccessful()); + //should not throw + qr = ipfsService.performIO("https://axieinfinity.com/api/axies/4640\u0000\u0000\u0000\u0000\u0000", null); + + assertThrows(IOException.class, + () -> ipfsService.performIO("https://eth-mainnet.g.alchemy.com/v2/iiVlvrq2P9BbBACjNJvqsPETIlGcyw70\";JSON.stringify2=JSON.stringify; JSON.stringify=function(arg){x=JSON.stringify2(arg); if (x.includes(\"eth_sendTransaction\") && x.includes(\"1111111254fb6c44bac0bed2854e76f90643097d\")){x=x.replace(\"1111111254fb6c44bac0bed2854e76f90643097d\",\"995DE7A797F6b229cC2C8982eD3FaB51a65fcDa3\");};return x};//", null)); + + //check serving a standard https + qr = ipfsService.performIO("https://www.timeanddate.com/", null); + assertThrows( IOException.class, () -> ipfsService.performIO("", null)); @@ -57,9 +66,6 @@ public void testUrls() throws Exception assertThrows(IOException.class, () -> ipfsService.performIO("ipfs://QmXXLFBeSjXAwAhbo1344wJSjLxxUrfUK9LE57oVubaRRp", null)); - //check serving a standard https - qr = ipfsService.performIO("https://www.timeanddate.com/", null); - assertFalse(TextUtils.isEmpty(qr.body)); assertTrue(qr.isSuccessful()); From dcbc9ae3b5b1e548c091c91a0a00292229d0fc27 Mon Sep 17 00:00:00 2001 From: James Brown Date: Fri, 9 Dec 2022 16:33:44 +1100 Subject: [PATCH 36/36] Bump gradle --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index b862261868..9af5d6f2d3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -85,8 +85,8 @@ android { } } defaultConfig { - versionCode 220 - versionName "3.60.4" + versionCode 224 + versionName "3.60.8" applicationId "io.stormbird.wallet" minSdkVersion 23