Skip to content

Commit

Permalink
replacing suspendCoroutine with callbackFlow for fixing double resume…
Browse files Browse the repository at this point in the history
… problem
  • Loading branch information
Babak-gh committed Nov 12, 2023
1 parent 91e2af3 commit 8ecc29e
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,20 @@ package org.xmtp.android.example.account

import android.net.Uri
import com.walletconnect.wcmodal.client.Modal
import kotlinx.coroutines.flow.first
import org.web3j.crypto.Keys
import org.xmtp.android.example.connect.DappDelegate
import org.xmtp.android.example.connect.getPersonalSignBody
import org.xmtp.android.example.extension.requestMethod
import org.xmtp.android.library.SigningKey
import org.xmtp.android.library.messages.SignatureBuilder
import org.xmtp.proto.message.contents.SignatureOuterClass


data class WalletConnectV2Account(val session: Modal.Model.ApprovedSession, val chain: String, private val sendSessionRequestDeepLink: (Uri) -> Unit) :
data class WalletConnectV2Account(
val session: Modal.Model.ApprovedSession,
val chain: String,
private val sendSessionRequestDeepLink: (Uri) -> Unit
) :
SigningKey {
override val address: String
get() = Keys.toChecksumAddress(
Expand All @@ -35,10 +40,10 @@ data class WalletConnectV2Account(val session: Modal.Model.ApprovedSession, val
chainId = "$parentChain:$chainId"
)
}

runCatching { DappDelegate.request(requestParams!!, sendSessionRequestDeepLink) }
runCatching {
requestMethod(requestParams!!, sendSessionRequestDeepLink).first().getOrThrow()
}
.onSuccess {

return SignatureBuilder.buildFromSignatureData(it)
}
.onFailure {}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package org.xmtp.android.example.connect

import android.net.Uri
import androidx.core.net.toUri
import com.walletconnect.wcmodal.client.Modal
import com.walletconnect.wcmodal.client.WalletConnectModal
import kotlinx.coroutines.CoroutineScope
Expand All @@ -10,15 +8,8 @@ import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.web3j.utils.Numeric
import timber.log.Timber
import kotlin.coroutines.Continuation
import kotlin.coroutines.suspendCoroutine

object DappDelegate : WalletConnectModal.ModalDelegate {
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
Expand Down Expand Up @@ -95,63 +86,4 @@ object DappDelegate : WalletConnectModal.ModalDelegate {
_wcEventModels.emit(error)
}
}

suspend fun request(
requestParams: Modal.Params.Request,
sendSessionRequestDeepLink: (Uri) -> Unit
): ByteArray {
return withContext(Dispatchers.IO) {
suspendCoroutine { continuation ->
WalletConnectModal.request(
request = requestParams,
onSuccess = { sentRequest ->
WalletConnectModal.getActiveSessionByTopic(requestParams.sessionTopic)?.redirect?.toUri()
?.let { deepLinkUri ->
sendSessionRequestDeepLink(deepLinkUri)
}
onResponse(continuation, sentRequest)
},
onError = { Timber.e(it.throwable) }
)
}
}
}

private fun onResponse(
continuation: Continuation<ByteArray>,
sentRequest: Modal.Model.SentRequest
) {
wcEventModels
.filterNotNull()
.onEach { event ->
when (event) {
is Modal.Model.SessionRequestResponse -> {
if (event.topic == sentRequest.sessionTopic && event.result.id == sentRequest.requestId) {
when (val res = event.result) {
is Modal.Model.JsonRpcResponse.JsonRpcResult -> {
var result = res.result
if (result.startsWith("0x") && result.length == 132) {
result = result.drop(2)
}

val resultData = Numeric.hexStringToByteArray(result)

// Ensure we have a valid recovery byte
resultData[resultData.size - 1] =
(1 - resultData[resultData.size - 1] % 2).toByte()

continuation.resumeWith(Result.success(resultData))
}

is Modal.Model.JsonRpcResponse.JsonRpcError -> {
continuation.resumeWith(Result.failure(Throwable(res.message)))
}
}
} else continuation.resumeWith(Result.failure(Throwable("The result id is different from the request id!")))
}

else -> {}
}
}.launchIn(scope)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package org.xmtp.android.example.extension

import android.net.Uri
import androidx.core.net.toUri
import com.walletconnect.wcmodal.client.Modal
import com.walletconnect.wcmodal.client.WalletConnectModal
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.channels.ProducerScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.channels.trySendBlocking
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.withContext
import org.web3j.utils.Numeric
import org.xmtp.android.example.connect.DappDelegate
import timber.log.Timber

suspend fun requestMethod(
requestParams: Modal.Params.Request,
sendSessionRequestDeepLink: (Uri) -> Unit
): Flow<Result<ByteArray>> {
val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
return withContext(Dispatchers.IO) {
callbackFlow {
WalletConnectModal.request(
request = requestParams,
onSuccess = { sentRequest ->
WalletConnectModal.getActiveSessionByTopic(requestParams.sessionTopic)?.redirect?.toUri()
?.let { deepLinkUri ->
sendSessionRequestDeepLink(deepLinkUri)
}
onResponse(scope, this, sentRequest)

},
onError = { Timber.e(it.throwable) }
)
awaitClose { }
}

}

}

private fun onResponse(
scope: CoroutineScope,
continuation: ProducerScope<Result<ByteArray>>,
sentRequest: Modal.Model.SentRequest
) {
DappDelegate.wcEventModels
.filterNotNull()
.onEach { event ->
when (event) {
is Modal.Model.SessionRequestResponse -> {
if (event.topic == sentRequest.sessionTopic && event.result.id == sentRequest.requestId) {
when (val res = event.result) {
is Modal.Model.JsonRpcResponse.JsonRpcResult -> {
var result = res.result
if (result.startsWith("0x") && result.length == 132) {
result = result.drop(2)
}

val resultData = Numeric.hexStringToByteArray(result)

// Ensure we have a valid recovery byte
resultData[resultData.size - 1] =
(1 - resultData[resultData.size - 1] % 2).toByte()

continuation.trySendBlocking(Result.success(resultData))
}
is Modal.Model.JsonRpcResponse.JsonRpcError -> {
continuation.trySendBlocking(Result.failure(Throwable(res.message)))
}
}
} else continuation.trySendBlocking(Result.failure(Throwable("The result id is different from the request id!")))
}

else -> {}
}
}.launchIn(scope)

}

0 comments on commit 8ecc29e

Please sign in to comment.