diff --git a/android/app/build.gradle b/android/app/build.gradle index cd57cc08..535d0730 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -260,12 +260,12 @@ dependencies { // - // https://github.com/WalletConnect/WalletConnectKotlinV2 + // https://github.com/reown-com/reown-kotlin // - implementation platform("com.walletconnect:android-bom:$walletConnectVersion") - implementation('com.walletconnect:android-core') - implementation("com.walletconnect:walletconnect-modal") + implementation(platform("com.reown:android-bom:$walletConnectVersion")) + implementation("com.reown:android-core") + implementation("com.reown:appkit") // // https://docs.cloud.coinbase.com/wallet-sdk/docs/android-install diff --git a/android/build.gradle b/android/build.gradle index 2acb38c7..34a956bc 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -2,10 +2,10 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile buildscript { ext.ktlintVersion = '0.48.0' - ext.kotlinVersion = '2.0.21' + ext.kotlinVersion = '2.2.0' ext.androidApplicationVersion = '8.13.0' - ext.navigationVersion = '2.9.1' + ext.navigationVersion = '2.8.4' ext.hiltVersion = '2.57.1' ext.googleServicesVersion = '4.3.12' @@ -17,7 +17,7 @@ buildscript { dependencies { classpath "com.android.tools.build:gradle:$androidApplicationVersion" classpath "com.squareup:javapoet:1.13.0" - classpath 'com.google.gms:google-services:4.4.3' + classpath 'com.google.gms:google-services:4.4.4' classpath 'com.facebook.react:react-native-gradle-plugin' @@ -181,7 +181,7 @@ ext { flowExtVersion = '0.7.1' material3Version = '1.2.0-rc01' web3jVersion = '4.8.8-android' - walletConnectVersion = '1.35.2' + walletConnectVersion = '1.4.11' amplitudeVersion = '1.21.4' } diff --git a/android/v4/core/build.gradle b/android/v4/core/build.gradle index 445c1e74..e3494ec7 100644 --- a/android/v4/core/build.gradle +++ b/android/v4/core/build.gradle @@ -139,9 +139,9 @@ dependencies { implementation "androidx.biometric:biometric-ktx:$biometricVersion" - implementation platform("com.walletconnect:android-bom:$walletConnectVersion") - implementation('com.walletconnect:android-core') - implementation("com.walletconnect:walletconnect-modal") + implementation(platform("com.reown:android-bom:$walletConnectVersion")) + implementation("com.reown:android-core") + implementation("com.reown:appkit") implementation 'com.google.accompanist:accompanist-navigation-material:0.36.0' // need for modal implementation("tz.co.asoft:kollections-interoperable:$kollectionsVersion") diff --git a/android/v4/core/src/main/java/exchange/dydx/trading/core/DydxNavGraph.kt b/android/v4/core/src/main/java/exchange/dydx/trading/core/DydxNavGraph.kt index ecd986a6..468431e7 100644 --- a/android/v4/core/src/main/java/exchange/dydx/trading/core/DydxNavGraph.kt +++ b/android/v4/core/src/main/java/exchange/dydx/trading/core/DydxNavGraph.kt @@ -12,7 +12,7 @@ import androidx.navigation.compose.rememberNavController import com.google.accompanist.navigation.material.BottomSheetNavigator import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi import com.google.accompanist.navigation.material.ModalBottomSheetLayout -import com.walletconnect.wcmodal.ui.walletConnectModalGraph +import com.reown.appkit.ui.appKitGraph import exchange.dydx.feature.onboarding.loginGraph import exchange.dydx.newsalerts.newsAlertsGraph import exchange.dydx.trading.common.navigation.DydxRouter @@ -60,7 +60,9 @@ fun DydxNavGraph( InitializeManagers() - ModalBottomSheetLayout(bottomSheetNavigator = bottomSheetNavigator) { + ModalBottomSheetLayout( + bottomSheetNavigator = bottomSheetNavigator, + ) { NavHost( navController = navController, startDestination = DEFAULT_START_DESTINATION, @@ -106,7 +108,7 @@ fun DydxNavGraph( logger = logger, ) - walletConnectModalGraph(navController) + appKitGraph(navController) } } } diff --git a/android/v4/feature/portfolio/src/main/java/exchange/dydx/trading/feature/portfolio/components/pendingpositions/DydxPortfolioPendingPositionItemView.kt b/android/v4/feature/portfolio/src/main/java/exchange/dydx/trading/feature/portfolio/components/pendingpositions/DydxPortfolioPendingPositionItemView.kt index 39b64d3e..cbd6dff5 100644 --- a/android/v4/feature/portfolio/src/main/java/exchange/dydx/trading/feature/portfolio/components/pendingpositions/DydxPortfolioPendingPositionItemView.kt +++ b/android/v4/feature/portfolio/src/main/java/exchange/dydx/trading/feature/portfolio/components/pendingpositions/DydxPortfolioPendingPositionItemView.kt @@ -11,7 +11,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Text -import androidx.compose.material.ripple.rememberRipple +import androidx.compose.material.ripple import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Alignment @@ -142,7 +142,7 @@ object DydxPortfolioPendingPositionItemView { vertical = 12.dp, ) .clickable( - indication = rememberRipple(color = ThemeColor.SemanticColor.layer_3.color), + indication = ripple(color = ThemeColor.SemanticColor.layer_3.color), interactionSource = remember { MutableInteractionSource() }, onClick = { state.viewOrderAction() }, ), @@ -161,7 +161,7 @@ object DydxPortfolioPendingPositionItemView { vertical = 12.dp, ) .clickable( - indication = rememberRipple(color = ThemeColor.SemanticColor.layer_3.color), + indication = ripple(color = ThemeColor.SemanticColor.layer_3.color), interactionSource = remember { MutableInteractionSource() }, onClick = { state.cancelOrderAction() }, ), diff --git a/android/v4/integration/dydxCartera/build.gradle b/android/v4/integration/dydxCartera/build.gradle index 74058253..cbec1027 100644 --- a/android/v4/integration/dydxCartera/build.gradle +++ b/android/v4/integration/dydxCartera/build.gradle @@ -51,14 +51,12 @@ dependencies { implementation 'com.solanamobile:rpc-core:0.2.8' // - // https://github.com/WalletConnect/WalletConnectKotlinV2 + // https://github.com/reown-com/reown-kotlin // - implementation platform('com.walletconnect:android-bom:1.35.2') - implementation("com.walletconnect:android-core") - implementation("com.walletconnect:walletconnect-modal") - implementation 'com.walletconnect:sign' - //implementation 'com.walletconnect:push' + implementation(platform("com.reown:android-bom:$walletConnectVersion")) + implementation("com.reown:android-core") + implementation("com.reown:appkit") // // https://docs.cloud.coinbase.com/wallet-sdk/docs/android-install diff --git a/android/v4/integration/dydxCartera/src/main/java/exchange/dydx/cartera/CarteraConfig.kt b/android/v4/integration/dydxCartera/src/main/java/exchange/dydx/cartera/CarteraConfig.kt index f9868ed1..8d9c32fe 100644 --- a/android/v4/integration/dydxCartera/src/main/java/exchange/dydx/cartera/CarteraConfig.kt +++ b/android/v4/integration/dydxCartera/src/main/java/exchange/dydx/cartera/CarteraConfig.kt @@ -71,14 +71,7 @@ class CarteraConfig( registration[WalletConnectionType.WalletConnect] = RegistrationConfig( provider = WalletConnectV1Provider(), ) - if (walletProvidersConfig.walletConnectV2 != null) { - registration[WalletConnectionType.WalletConnectV2] = RegistrationConfig( - provider = WalletConnectV2Provider( - walletConnectV2Config = walletProvidersConfig.walletConnectV2, - application = application, - ), - ) - } + if (walletProvidersConfig.walletSegue != null) { registration[WalletConnectionType.WalletSegue] = RegistrationConfig( provider = WalletSegueProvider( @@ -102,10 +95,18 @@ class CarteraConfig( } fun updateModalConfig(walletConnectModal: WalletConnectModalConfig) { + if (walletProvidersConfig.walletConnectV2 != null) { + registration[WalletConnectionType.WalletConnectV2] = RegistrationConfig( + provider = WalletConnectV2Provider( + walletConnectV2Config = walletProvidersConfig.walletConnectV2, + modalConfig = walletConnectModal, + application = application, + ), + ) + } registration[WalletConnectionType.WalletConnectModal] = RegistrationConfig( provider = WalletConnectModalProvider( application = application, - config = walletConnectModal, ), ) } diff --git a/android/v4/integration/dydxCartera/src/main/java/exchange/dydx/cartera/entities/ModelExtensions.kt b/android/v4/integration/dydxCartera/src/main/java/exchange/dydx/cartera/entities/ModelExtensions.kt index 1b250da5..8126f64a 100644 --- a/android/v4/integration/dydxCartera/src/main/java/exchange/dydx/cartera/entities/ModelExtensions.kt +++ b/android/v4/integration/dydxCartera/src/main/java/exchange/dydx/cartera/entities/ModelExtensions.kt @@ -9,7 +9,6 @@ import exchange.dydx.dydxCartera.Utils import exchange.dydx.dydxCartera.WalletConnectionType import exchange.dydx.dydxCartera.toHexString import exchange.dydx.dydxCartera.walletprovider.EthereumTransactionRequest -import okhttp3.internal.toHexString import org.json.JSONException import org.json.JSONObject diff --git a/android/v4/integration/dydxCartera/src/main/java/exchange/dydx/cartera/walletprovider/providers/WalletConnectModalProvider.kt b/android/v4/integration/dydxCartera/src/main/java/exchange/dydx/cartera/walletprovider/providers/WalletConnectModalProvider.kt index fc67296a..8fdead2a 100644 --- a/android/v4/integration/dydxCartera/src/main/java/exchange/dydx/cartera/walletprovider/providers/WalletConnectModalProvider.kt +++ b/android/v4/integration/dydxCartera/src/main/java/exchange/dydx/cartera/walletprovider/providers/WalletConnectModalProvider.kt @@ -5,14 +5,14 @@ import android.content.ActivityNotFoundException import android.content.Intent import android.net.Uri import androidx.navigation.NavHostController -import com.google.gson.Gson -import com.google.gson.reflect.TypeToken -import com.walletconnect.android.CoreClient -import com.walletconnect.wcmodal.client.Modal -import com.walletconnect.wcmodal.client.WalletConnectModal -import com.walletconnect.wcmodal.ui.openWalletConnectModal +import com.reown.appkit.client.AppKit +import com.reown.appkit.client.Modal +import com.reown.appkit.client.models.request.SentRequestResult +import com.reown.appkit.presets.AppKitChainsPresets +import com.reown.appkit.presets.AppKitChainsPresets.ethToken +import com.reown.appkit.ui.openAppKit +import com.reown.appkit.utils.EthUtils import exchange.dydx.dydxCartera.CarteraErrorCode -import exchange.dydx.dydxCartera.WalletConnectModalConfig import exchange.dydx.dydxCartera.entities.Wallet import exchange.dydx.dydxCartera.entities.toJsonRequest import exchange.dydx.dydxCartera.tag @@ -33,17 +33,14 @@ import exchange.dydx.dydxCartera.walletprovider.WalletStatusImp import exchange.dydx.dydxCartera.walletprovider.WalletStatusProtocol import exchange.dydx.dydxCartera.walletprovider.WalletTransactionRequest import exchange.dydx.dydxCartera.walletprovider.WalletUserConsentProtocol -import exchange.dydx.dydxcartera.R import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import timber.log.Timber -import java.lang.reflect.Type class WalletConnectModalProvider( private val application: Application, - private val config: WalletConnectModalConfig?, -) : WalletOperationProviderProtocol, WalletConnectModal.ModalDelegate { +) : WalletOperationProviderProtocol, AppKit.ModalDelegate { private var _walletStatus = WalletStatusImp() set(value) { @@ -57,7 +54,7 @@ class WalletConnectModalProvider( override var userConsentDelegate: WalletUserConsentProtocol? = null private var requestingWallet: WalletRequest? = null - private var currentSession: Modal.Model.ApprovedSession? = null + private var currentSession: Modal.Model.ApprovedSession.WalletConnectSession? = null private val connectCompletions: MutableList = mutableListOf() private val operationCompletions: MutableMap = mutableMapOf() @@ -70,36 +67,6 @@ class WalletConnectModalProvider( var nav: NavHostController? = null - init { - val jsonData = application.getResources().openRawResource(R.raw.wc_modal_ids) - .bufferedReader().use { it.readText() } - val gson = Gson() - val idListType: Type = object : TypeToken?>() {}.type - val wc_modal_ids: List? = gson.fromJson(jsonData, idListType) - val excludedIds = wc_modal_ids?.toMutableList() ?: mutableListOf() - for (id in config?.walletIds ?: emptyList()) { - if (excludedIds.contains(id)) { - excludedIds.remove(id) - } - } - WalletConnectModal.initialize( - init = Modal.Params.Init( - core = CoreClient, - // recommendedWalletsIds = config?.walletIds ?: emptyList(), - // excludedWalletIds = excludedIds, - ), - onSuccess = { - // Callback will be called if initialization is successful - Timber.tag(tag(this)).d("WalletConnectModal initialized.") - }, - onError = { error -> - // Error will be thrown if there's an issue during initialization - Timber.tag(tag(this)) - .e(error.throwable.stackTraceToString()) - }, - ) - } - override fun handleResponse(uri: Uri): Boolean { return false } @@ -110,54 +77,36 @@ class WalletConnectModalProvider( } else { requestingWallet = request - val chain: String = if (request.chainId != null) { - "$ethNamespace:${request.chainId}" + if (request.chainId != null) { + val testnetChain = Modal.Model.Chain( + chainName = "Ethereum", + chainNamespace = "eip155", + chainReference = request.chainId, + requiredMethods = EthUtils.ethRequiredMethods, + optionalMethods = EthUtils.ethOptionalMethods, + events = EthUtils.ethEvents, + token = ethToken, + ) + AppKit.setChains(listOf(testnetChain)) } else { - "$ethNamespace:1" + AppKit.setChains(AppKitChainsPresets.ethChains.values.toList()) } - val chains: List = listOf(chain) - val methods: List = listOf( - "personal_sign", - "eth_sendTransaction", - "eth_signTypedData", - // "wallet_addEthereumChain", - // "eth_sign" - ) - val events: List = listOf( - "accountsChanged", - "chainChanged", - ) - val namespaces = mapOf( - ethNamespace to Modal.Model.Namespace.Proposal( - chains = chains, - methods = methods, - events = events, - ), - ) - - val sessionParams = Modal.Params.SessionParams( - requiredNamespaces = namespaces, - optionalNamespaces = null, - properties = null, - ) - - WalletConnectModal.setSessionParams(sessionParams) - - WalletConnectModal.setDelegate(this) + + AppKit.setDelegate(this) connectCompletions.add(completion) - nav?.openWalletConnectModal() + nav?.openAppKit() } } override fun disconnect() { val currentSession = this.currentSession if (currentSession != null) { - WalletConnectModal.disconnect(Modal.Params.Disconnect(currentSession.topic), onSuccess = { - Timber.tag(tag(this)).d("Disconnected from session: ${currentSession!!.topic}") + AppKit.disconnect(onSuccess = { + Timber.tag(tag(this)).d("Disconnected from session ") }, onError = { - Timber.tag(tag(this)).e(it.throwable.stackTraceToString()) + Timber.tag(tag(this)).e(it.message) }) this.currentSession = null } @@ -178,20 +127,12 @@ class WalletConnectModalProvider( status: WalletOperationStatus?, completion: WalletOperationCompletion ) { - fun requestParams(): Modal.Params.Request? { - val sessionTopic = currentSession?.topic + fun requestParams(): com.reown.appkit.client.models.request.Request? { val account = _walletStatus.connectedWallet?.address - val chainId = if (request.chainId != null) { - "$ethNamespace:${request.chainId}" - } else { - currentSession?.namespaces?.get(ethNamespace)?.chains?.firstOrNull() - } - return if (sessionTopic != null && account != null && chainId != null) { - Modal.Params.Request( - sessionTopic = sessionTopic, + return if (account != null) { + com.reown.appkit.client.models.request.Request( method = "personal_sign", params = "[\"${message}\", \"${account}\"]", - chainId = chainId, expiry = requestExpiry, ) } else { @@ -209,22 +150,14 @@ class WalletConnectModalProvider( status: WalletOperationStatus?, completion: WalletOperationCompletion ) { - fun requestParams(): Modal.Params.Request? { - val sessionTopic = currentSession?.topic + fun requestParams(): com.reown.appkit.client.models.request.Request? { val account = _walletStatus.connectedWallet?.address - val chainId = if (request.chainId != null) { - "$ethNamespace:${request.chainId}" - } else { - currentSession?.namespaces?.get(ethNamespace)?.chains?.firstOrNull() - } val message = typedDataProvider?.typedDataAsString?.replace("\"", "\\\"") - return if (sessionTopic != null && account != null && chainId != null && message != null) { - Modal.Params.Request( - sessionTopic = sessionTopic, + return if (account != null && message != null) { + com.reown.appkit.client.models.request.Request( method = "eth_signTypedData", params = "[\"${account}\", \"${message}\"]", - chainId = chainId, expiry = requestExpiry, ) } else { @@ -241,22 +174,14 @@ class WalletConnectModalProvider( status: WalletOperationStatus?, completion: WalletOperationCompletion ) { - fun requestParams(): Modal.Params.Request? { - val sessionTopic = currentSession?.topic + fun requestParams(): com.reown.appkit.client.models.request.Request? { val account = _walletStatus.connectedWallet?.address - val chainId = if (request.walletRequest.chainId != null) { - "$ethNamespace:${request.walletRequest.chainId}" - } else { - currentSession?.namespaces?.get(ethNamespace)?.chains?.firstOrNull() - } val message = request.ethereum?.toJsonRequest() - return if (sessionTopic != null && account != null && chainId != null && message != null) { - Modal.Params.Request( - sessionTopic = sessionTopic, + return if (account != null && message != null) { + com.reown.appkit.client.models.request.Request( method = "eth_sendTransaction", params = "[$message]", - chainId = chainId, expiry = requestExpiry, ) } else { @@ -279,7 +204,7 @@ class WalletConnectModalProvider( private fun connectAndMakeRequest( request: WalletRequest, - requestParams: (() -> Modal.Params.Request?), + requestParams: (() -> com.reown.appkit.client.models.request.Request?), connected: WalletConnectedCompletion?, status: WalletOperationStatus?, completion: WalletOperationCompletion @@ -314,26 +239,27 @@ class WalletConnectModalProvider( } private fun reallyMakeRequest( - requestParams: Modal.Params.Request, + requestParams: com.reown.appkit.client.models.request.Request, status: WalletOperationStatus?, completion: WalletOperationCompletion ) { - WalletConnectModal.request( + AppKit.request( request = requestParams, onSuccess = { sendRequest -> /* callback that letting you know that you have successful request */ Timber.d("Wallet request made.") - operationCompletions[sendRequest.sessionTopic] = completion + val walletConnect = sendRequest as SentRequestResult.WalletConnect + operationCompletions[walletConnect.sessionTopic] = completion }, onError = { error -> /* callback that letting you know that you have error */ - Timber.e(error.throwable.stackTraceToString()) + Timber.e(error.stackTrace.toString()) completion( null, WalletError( code = CarteraErrorCode.CONNECTION_FAILED, title = "WalletConnectModal.request error", - message = error.throwable.stackTraceToString(), + message = error.stackTrace.toString(), ), ) }, @@ -361,6 +287,7 @@ class WalletConnectModalProvider( } override fun onSessionApproved(approvedSession: Modal.Model.ApprovedSession) { + val approvedSession = approvedSession as Modal.Model.ApprovedSession.WalletConnectSession Timber.d("Session approved: $approvedSession") CoroutineScope(Dispatchers.Main).launch { @@ -496,6 +423,7 @@ class WalletConnectModalProvider( } private fun fromApprovedSession(session: Modal.Model.ApprovedSession, wallet: Wallet?): WalletInfo { + val session = session as Modal.Model.ApprovedSession.WalletConnectSession val account = session.accounts.firstOrNull() var address: String? = null var chainId: String? = null diff --git a/android/v4/integration/dydxCartera/src/main/java/exchange/dydx/cartera/walletprovider/providers/WalletConnectV2Provider.kt b/android/v4/integration/dydxCartera/src/main/java/exchange/dydx/cartera/walletprovider/providers/WalletConnectV2Provider.kt index d416dcaa..daa52871 100644 --- a/android/v4/integration/dydxCartera/src/main/java/exchange/dydx/cartera/walletprovider/providers/WalletConnectV2Provider.kt +++ b/android/v4/integration/dydxCartera/src/main/java/exchange/dydx/cartera/walletprovider/providers/WalletConnectV2Provider.kt @@ -5,12 +5,17 @@ import android.content.ActivityNotFoundException import android.content.Intent import android.net.Uri import android.util.Log -import com.walletconnect.android.Core -import com.walletconnect.android.CoreClient -import com.walletconnect.android.relay.ConnectionType -import com.walletconnect.sign.client.Sign -import com.walletconnect.sign.client.SignClient +import com.reown.android.Core +import com.reown.android.CoreClient +import com.reown.android.relay.ConnectionType +import com.reown.appkit.client.AppKit +import com.reown.appkit.client.Modal +import com.reown.appkit.client.models.request.SentRequestResult +import com.reown.appkit.presets.AppKitChainsPresets +import com.reown.appkit.presets.AppKitChainsPresets.ethToken +import com.reown.appkit.utils.EthUtils import exchange.dydx.dydxCartera.CarteraErrorCode +import exchange.dydx.dydxCartera.WalletConnectModalConfig import exchange.dydx.dydxCartera.WalletConnectV2Config import exchange.dydx.dydxCartera.WalletConnectionType import exchange.dydx.dydxCartera.entities.Wallet @@ -37,10 +42,12 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.launch +import timber.log.Timber import java.util.concurrent.TimeUnit class WalletConnectV2Provider( private val walletConnectV2Config: WalletConnectV2Config?, + private val modalConfig: WalletConnectModalConfig?, private val application: Application ) : WalletOperationProviderProtocol { private var _walletStatus = WalletStatusImp() @@ -58,7 +65,7 @@ class WalletConnectV2Provider( private val operationCompletions: MutableMap = mutableMapOf() private var requestingWallet: WalletRequest? = null - private var currentSession: Sign.Model.ApprovedSession? = null + private var currentSession: Modal.Model.ApprovedSession? = null private var currentPairing: Core.Model.Pairing? = null @@ -66,43 +73,43 @@ class WalletConnectV2Provider( private val requestExpiry: Long get() = (System.currentTimeMillis() / 1000) + 400 - private val nilDelegate = object : SignClient.DappDelegate { - override fun onConnectionStateChange(state: Sign.Model.ConnectionState) { + private val nilDelegate = object : AppKit.ModalDelegate { + override fun onSessionApproved(approvedSession: Modal.Model.ApprovedSession) { } - override fun onError(error: Sign.Model.Error) { + override fun onSessionRejected(rejectedSession: Modal.Model.RejectedSession) { } - override fun onProposalExpired(proposal: Sign.Model.ExpiredProposal) { + override fun onSessionUpdate(updatedSession: Modal.Model.UpdatedSession) { } - override fun onRequestExpired(request: Sign.Model.ExpiredRequest) { + override fun onSessionExtend(session: Modal.Model.Session) { } - override fun onSessionApproved(approvedSession: Sign.Model.ApprovedSession) { + override fun onSessionEvent(sessionEvent: Modal.Model.SessionEvent) { } - override fun onSessionDelete(deletedSession: Sign.Model.DeletedSession) { + override fun onSessionDelete(deletedSession: Modal.Model.DeletedSession) { } - override fun onSessionEvent(sessionEvent: Sign.Model.SessionEvent) { + override fun onSessionRequestResponse(response: Modal.Model.SessionRequestResponse) { } - override fun onSessionExtend(session: Sign.Model.Session) { + override fun onProposalExpired(proposal: Modal.Model.ExpiredProposal) { } - override fun onSessionRejected(rejectedSession: Sign.Model.RejectedSession) { + override fun onRequestExpired(request: Modal.Model.ExpiredRequest) { } - override fun onSessionRequestResponse(response: Sign.Model.SessionRequestResponse) { + override fun onConnectionStateChange(state: Modal.Model.ConnectionState) { } - override fun onSessionUpdate(updatedSession: Sign.Model.UpdatedSession) { + override fun onError(error: Modal.Model.Error) { } } - private val dappDelegate = object : SignClient.DappDelegate { - override fun onSessionApproved(approvedSession: Sign.Model.ApprovedSession) { + private val dappDelegate = object : AppKit.ModalDelegate { + override fun onSessionApproved(approvedSession: Modal.Model.ApprovedSession) { // Triggered when Dapp receives the session approval from wallet Log.d(tag(this@WalletConnectV2Provider), "onSessionApproved") @@ -140,7 +147,7 @@ class WalletConnectV2Provider( } } - override fun onSessionRejected(rejectedSession: Sign.Model.RejectedSession) { + override fun onSessionRejected(rejectedSession: Modal.Model.RejectedSession) { // Triggered when Dapp receives the session rejection from wallet Log.d(tag(this@WalletConnectV2Provider), "onSessionRejected: $rejectedSession") @@ -165,22 +172,22 @@ class WalletConnectV2Provider( } } - override fun onSessionUpdate(updatedSession: Sign.Model.UpdatedSession) { + override fun onSessionUpdate(updatedSession: Modal.Model.UpdatedSession) { // Triggered when Dapp receives the session update from wallet Log.d(tag(this@WalletConnectV2Provider), "onSessionUpdate") } - override fun onSessionExtend(session: Sign.Model.Session) { + override fun onSessionExtend(session: Modal.Model.Session) { // Triggered when Dapp receives the session extend from wallet Log.d(tag(this@WalletConnectV2Provider), "onSessionExtend") } - override fun onSessionEvent(sessionEvent: Sign.Model.SessionEvent) { + override fun onSessionEvent(sessionEvent: Modal.Model.SessionEvent) { // Triggered when the peer emits events that match the list of events agreed upon session settlement Log.d(tag(this@WalletConnectV2Provider), "onSessionEvent") } - override fun onSessionDelete(deletedSession: Sign.Model.DeletedSession) { + override fun onSessionDelete(deletedSession: Modal.Model.DeletedSession) { // Triggered when Dapp receives the session delete from wallet Log.d(tag(this@WalletConnectV2Provider), "onSessionDelete: $deletedSession") @@ -189,7 +196,7 @@ class WalletConnectV2Provider( } } - override fun onSessionRequestResponse(response: Sign.Model.SessionRequestResponse) { + override fun onSessionRequestResponse(response: Modal.Model.SessionRequestResponse) { // Triggered when Dapp receives the session request response from wallet Log.d(tag(this@WalletConnectV2Provider), "onSessionRequestResponse: $response") @@ -197,18 +204,18 @@ class WalletConnectV2Provider( val completion = operationCompletions[response.topic] if (completion != null) { when (response.result) { - is Sign.Model.JsonRpcResponse.JsonRpcResult -> { + is Modal.Model.JsonRpcResponse.JsonRpcResult -> { val result = - response.result as Sign.Model.JsonRpcResponse.JsonRpcResult + response.result as Modal.Model.JsonRpcResponse.JsonRpcResult completion.invoke( result.result, null, ) } - is Sign.Model.JsonRpcResponse.JsonRpcError -> { + is Modal.Model.JsonRpcResponse.JsonRpcError -> { val error = - response.result as Sign.Model.JsonRpcResponse.JsonRpcError + response.result as Modal.Model.JsonRpcResponse.JsonRpcError completion.invoke( null, WalletError( @@ -224,22 +231,22 @@ class WalletConnectV2Provider( } } - override fun onConnectionStateChange(state: Sign.Model.ConnectionState) { + override fun onConnectionStateChange(state: Modal.Model.ConnectionState) { // Triggered whenever the connection state is changed Log.d(tag(this@WalletConnectV2Provider), "onConnectionStateChange: $state") } - override fun onError(error: Sign.Model.Error) { + override fun onError(error: Modal.Model.Error) { // Triggered whenever there is an issue inside the SDK Log.d(tag(this@WalletConnectV2Provider), "onError: $error") } - override fun onProposalExpired(proposal: Sign.Model.ExpiredProposal) { + override fun onProposalExpired(proposal: Modal.Model.ExpiredProposal) { Log.d(tag(this@WalletConnectV2Provider), "onProposalExpired: $proposal") } - override fun onRequestExpired(request: Sign.Model.ExpiredRequest) { + override fun onRequestExpired(request: Modal.Model.ExpiredRequest) { Log.d(tag(this@WalletConnectV2Provider), "onRequestExpired: $request") } } @@ -270,11 +277,23 @@ class WalletConnectV2Provider( }, ) - val init = Sign.Params.Init(core = CoreClient) - - SignClient.initialize(init) { error -> - Log.e(tag(this@WalletConnectV2Provider), error.throwable.stackTraceToString()) - } + AppKit.initialize( + init = Modal.Params.Init( + core = CoreClient, + recommendedWalletsIds = modalConfig?.walletIds ?: emptyList(), + includeWalletIds = modalConfig?.walletIds ?: emptyList(), + coinbaseEnabled = false, + ), + onSuccess = { + // Callback will be called if initialization is successful + Timber.tag(tag(this)).d("WalletConnectModal initialized.") + }, + onError = { error -> + // Error will be thrown if there's an issue during initialization + Timber.tag(tag(this)) + .e(error.throwable.stackTraceToString()) + }, + ) } } @@ -288,7 +307,22 @@ class WalletConnectV2Provider( } else { requestingWallet = request - SignClient.setDappDelegate(dappDelegate) + AppKit.setDelegate(dappDelegate) + + if (request.chainId != null) { + val testnetChain = Modal.Model.Chain( + chainName = "Ethereum", + chainNamespace = "eip155", + chainReference = request.chainId, + requiredMethods = EthUtils.ethRequiredMethods, + optionalMethods = EthUtils.ethOptionalMethods, + events = EthUtils.ethEvents, + token = ethToken, + ) + AppKit.setChains(listOf(testnetChain)) + } else { + AppKit.setChains(AppKitChainsPresets.ethChains.values.toList()) + } CoroutineScope(IO).launch { doConnect(request = request) { pairing, error -> @@ -343,7 +377,7 @@ class WalletConnectV2Provider( connectCompletions.clear() operationCompletions.clear() - SignClient.setDappDelegate(nilDelegate) + AppKit.setDelegate(nilDelegate) } override fun signMessage( @@ -353,17 +387,14 @@ class WalletConnectV2Provider( status: WalletOperationStatus?, completion: WalletOperationCompletion ) { - fun requestParams(): Sign.Params.Request? { - val sessionTopic = currentSession?.topic + fun requestParams(): com.reown.appkit.client.models.request.Request? { val account = currentSession?.account() val namespace = currentSession?.namespace() val chainId = request.chainId ?: currentSession?.chainId() - return if (sessionTopic != null && account != null && namespace != null && chainId != null) { - Sign.Params.Request( - sessionTopic = sessionTopic, + return if (account != null && namespace != null && chainId != null) { + com.reown.appkit.client.models.request.Request( method = "personal_sign", params = "[\"${message}\", \"${account}\"]", - chainId = "$namespace:$chainId", expiry = requestExpiry, ) } else { @@ -381,19 +412,16 @@ class WalletConnectV2Provider( status: WalletOperationStatus?, completion: WalletOperationCompletion ) { - fun requestParams(): Sign.Params.Request? { - val sessionTopic = currentSession?.topic + fun requestParams(): com.reown.appkit.client.models.request.Request? { val account = currentSession?.account() val namespace = currentSession?.namespace() val chainId = request.chainId ?: currentSession?.chainId() val message = typedDataProvider?.typedDataAsString?.replace("\"", "\\\"") - return if (sessionTopic != null && account != null && namespace != null && chainId != null && message != null) { - Sign.Params.Request( - sessionTopic = sessionTopic, + return if (account != null && namespace != null && chainId != null && message != null) { + com.reown.appkit.client.models.request.Request( method = "eth_signTypedData", params = "[\"${account}\", \"${message}\"]", - chainId = "$namespace:$chainId", expiry = requestExpiry, ) } else { @@ -410,18 +438,15 @@ class WalletConnectV2Provider( status: WalletOperationStatus?, completion: WalletOperationCompletion ) { - fun requestParams(): Sign.Params.Request? { - val sessionTopic = currentSession?.topic + fun requestParams(): com.reown.appkit.client.models.request.Request? { val account = currentSession?.account() val namespace = currentSession?.namespace() val chainId = request.walletRequest.chainId ?: currentSession?.chainId() val message = request.ethereum?.toJsonRequest() - return if (sessionTopic != null && account != null && namespace != null && chainId != null && message != null) { - Sign.Params.Request( - sessionTopic = sessionTopic, + return if (account != null && namespace != null && chainId != null && message != null) { + com.reown.appkit.client.models.request.Request( method = "eth_sendTransaction", params = "[$message]", - chainId = "$namespace:$chainId", expiry = requestExpiry, ) } else { @@ -460,9 +485,8 @@ class WalletConnectV2Provider( "accountsChanged", "chainChanged", ) - val proposal = Sign.Model.Namespace.Proposal(chains, methods, events) - val requiredNamespaces: Map = mapOf(namespace to proposal) /*Required namespaces to setup a session*/ - val optionalNamespaces: Map = emptyMap() /*Optional namespaces to setup a session*/ + val proposal = Modal.Model.Namespace.Proposal(chains, methods, events) + val requiredNamespaces: Map = mapOf(namespace to proposal) /*Required namespaces to setup a session*/ val pairings = CoreClient.Pairing.getPairings() for (pairing in pairings) { @@ -477,21 +501,20 @@ class WalletConnectV2Provider( if (pairing != null) { val connectParams = - Sign.Params.Connect( - namespaces = requiredNamespaces, - optionalNamespaces = optionalNamespaces, + Modal.Params.ConnectParams( + sessionNamespaces = requiredNamespaces, properties = properties, pairing = pairing, ) - SignClient.connect( - connect = connectParams, + AppKit.connect( + connectParams = connectParams, onSuccess = { value -> - Log.d(tag(this@WalletConnectV2Provider), "Connected to wallet: $value") + Log.d(tag(this), "Connected to wallet: $value") completion(pairing, null) }, - onError = { error: Sign.Model.Error -> - Log.e(tag(this@WalletConnectV2Provider), error.throwable.stackTraceToString()) + onError = { error: Modal.Model.Error -> + Log.e(tag(this), error.throwable.stackTraceToString()) completion( null, WalletError( @@ -502,13 +525,14 @@ class WalletConnectV2Provider( ) }, ) + openPeerDeeplink(request, pairing) } } private fun connectAndMakeRequest( request: WalletRequest, - requestParams: (() -> Sign.Params.Request?), + requestParams: (() -> com.reown.appkit.client.models.request.Request?), connected: WalletConnectedCompletion?, completion: WalletOperationCompletion ) { @@ -542,25 +566,29 @@ class WalletConnectV2Provider( private fun reallyMakeRequest( request: WalletRequest, - requestParams: Sign.Params.Request, + requestParams: com.reown.appkit.client.models.request.Request, completion: WalletOperationCompletion ) { - SignClient.request( + AppKit.request( request = requestParams, - onSuccess = { sendRequest: Sign.Model.SentRequest -> + onSuccess = { sendRequest: SentRequestResult -> + val sendRequest = sendRequest as SentRequestResult.WalletConnect Log.d(tag(this@WalletConnectV2Provider), "Wallet request made.") operationCompletions[sendRequest.sessionTopic] = completion }, - onError = { error -> - Log.e(tag(this@WalletConnectV2Provider), error.throwable.stackTraceToString()) - completion( - null, - WalletError( - CarteraErrorCode.CONNECTION_FAILED, - "SignClient.request error", - error.throwable.stackTraceToString(), - ), - ) + onError = { + Log.e(tag(this@WalletConnectV2Provider), it.stackTraceToString()) + val isSuccessCalled = operationCompletions.values.contains(completion) + if (!isSuccessCalled) { + completion( + null, + WalletError( + CarteraErrorCode.CONNECTION_FAILED, + "SignClient.request error", + it.stackTraceToString(), + ), + ) + } }, ) @@ -577,7 +605,8 @@ class WalletConnectV2Provider( ) } - private fun fromApprovedSession(session: Sign.Model.ApprovedSession, wallet: Wallet?): WalletInfo { + private fun fromApprovedSession(session: Modal.Model.ApprovedSession, wallet: Wallet?): WalletInfo { + val session = session as Modal.Model.ApprovedSession.WalletConnectSession return WalletInfo( address = session.account(), chainId = session.chainId(), @@ -617,8 +646,9 @@ class WalletConnectV2Provider( } } -private fun Sign.Model.ApprovedSession.chainId(): String? { - val split = accounts.first().split(":") +private fun Modal.Model.ApprovedSession.chainId(): String? { + val session = this as Modal.Model.ApprovedSession.WalletConnectSession + val split = session.accounts.first().split(":") return if (split.count() > 1) { split[1] } else { @@ -626,8 +656,9 @@ private fun Sign.Model.ApprovedSession.chainId(): String? { } } -private fun Sign.Model.ApprovedSession.chainIds(): List? { - return accounts.mapNotNull { +private fun Modal.Model.ApprovedSession.chainIds(): List? { + val session = this as Modal.Model.ApprovedSession.WalletConnectSession + return session.accounts.mapNotNull { val split = it.split(":") if (split.count() > 1) { split[1] @@ -637,8 +668,9 @@ private fun Sign.Model.ApprovedSession.chainIds(): List? { } } -private fun Sign.Model.ApprovedSession.namespace(): String? { - val split = accounts.first().split(":") +private fun Modal.Model.ApprovedSession.namespace(): String? { + val session = this as Modal.Model.ApprovedSession.WalletConnectSession + val split = session.accounts.first().split(":") return if (split.count() > 0) { split[0] } else { @@ -646,8 +678,9 @@ private fun Sign.Model.ApprovedSession.namespace(): String? { } } -private fun Sign.Model.ApprovedSession.account(): String? { - val split = accounts.first().split(":") +private fun Modal.Model.ApprovedSession.account(): String? { + val session = this as Modal.Model.ApprovedSession.WalletConnectSession + val split = session.accounts.first().split(":") return if (split.count() > 2) { split[2] } else {