Updated on 2026-08-14

This commit is contained in:
Tangem 2023-07-17 10:56:23 +03:00
commit 57b3776292
7 changed files with 94 additions and 35 deletions

View file

@ -100,7 +100,7 @@ internal class BiometricUserWalletsListManager(
} else {
val isWalletSaved = state.value.userWallets
.any {
it.walletId == userWallet.walletId || it.cardsInWallet.contains(userWallet.cardId)
it.walletId == userWallet.walletId
}
if (isWalletSaved) {

View file

@ -6,6 +6,7 @@ import com.tangem.core.analytics.Analytics
import com.tangem.tap.common.analytics.events.WalletConnect
import com.tangem.tap.domain.walletconnect2.domain.WalletConnectRepository
import com.tangem.tap.domain.walletconnect2.domain.WcJrpcRequestsDeserializer
import com.tangem.tap.domain.walletconnect2.domain.WcRequest
import com.tangem.tap.domain.walletconnect2.domain.models.*
import com.walletconnect.android.Core
import com.walletconnect.android.CoreClient
@ -87,7 +88,10 @@ class WalletConnectRepositoryImpl @Inject constructor(
private fun defineWalletDelegate(): Web3Wallet.WalletDelegate {
return object : Web3Wallet.WalletDelegate {
override fun onSessionProposal(sessionProposal: Wallet.Model.SessionProposal) {
override fun onSessionProposal(
sessionProposal: Wallet.Model.SessionProposal,
verifyContext: Wallet.Model.VerifyContext,
) {
// Triggered when wallet receives the session proposal sent by a Dapp
Timber.d("sessionProposal: $sessionProposal")
this@WalletConnectRepositoryImpl.sessionProposal = sessionProposal
@ -106,7 +110,10 @@ class WalletConnectRepositoryImpl @Inject constructor(
}
}
override fun onSessionRequest(sessionRequest: Wallet.Model.SessionRequest) {
override fun onSessionRequest(
sessionRequest: Wallet.Model.SessionRequest,
verifyContext: Wallet.Model.VerifyContext,
) {
// Triggered when a Dapp sends SessionRequest to sign a transaction or a message
Timber.d("sessionRequest: $sessionRequest")
val request = wcRequestDeserializer.deserialize(
@ -115,22 +122,38 @@ class WalletConnectRepositoryImpl @Inject constructor(
)
Timber.d("sessionRequestParsed: $request")
scope.launch {
_events.emit(
WalletConnectEvents.SessionRequest(
request = request,
chainId = sessionRequest.chainId,
when (request) {
is WcRequest.AddChain -> {
// we can send approval automatically, because in WC 2.0 the list of chains is approved when
// initial connection is established
sendRequest(
topic = sessionRequest.topic,
id = sessionRequest.request.id,
metaUrl = sessionRequest.peerMetaData?.url ?: "",
metaName = sessionRequest.peerMetaData?.name ?: "",
),
)
result = "",
)
}
else ->
scope.launch {
_events.emit(
WalletConnectEvents.SessionRequest(
request = request,
chainId = sessionRequest.chainId,
topic = sessionRequest.topic,
id = sessionRequest.request.id,
metaUrl = sessionRequest.peerMetaData?.url ?: "",
metaName = sessionRequest.peerMetaData?.name ?: "",
),
)
}
}
}
override fun onAuthRequest(authRequest: Wallet.Model.AuthRequest) {
override fun onAuthRequest(
authRequest: Wallet.Model.AuthRequest,
verifyContext: Wallet.Model.VerifyContext,
) {
// Triggered when Dapp / Requester makes an authorization request
Timber.d("onAuthRequest: $authRequest")
}
override fun onSessionDelete(sessionDelete: Wallet.Model.SessionDelete) {
@ -174,6 +197,7 @@ class WalletConnectRepositoryImpl @Inject constructor(
override fun onError(error: Wallet.Model.Error) {
// Triggered whenever there is an issue inside the SDK
Timber.d("onError: $error")
}
}
}

View file

@ -1,9 +1,6 @@
package com.tangem.tap.domain.walletconnect2.domain
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.JsonClass
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
import com.squareup.moshi.*
import com.tangem.datasource.di.SdkMoshi
import com.tangem.tap.domain.walletconnect2.domain.models.binance.WCBinanceTxConfirmParam
import com.tangem.tap.domain.walletconnect2.domain.models.binance.WcBinanceCancelOrder
@ -24,6 +21,7 @@ enum class WcJrpcMethods(val code: String) {
BNB_SIGN("bnb_sign"),
BNB_TRANSACTION_CONFIRM("bnb_tx_confirmation"),
SIGN_TRANSACTION("trust_signTransaction"),
WALLET_ADD_ETHEREUM_CHAIN("wallet_addEthereumChain"),
;
companion object {
@ -33,13 +31,25 @@ enum class WcJrpcMethods(val code: String) {
@JsonClass(generateAdapter = true)
data class WCSignTransaction(
@Json(name = "network")
val network: Int,
@Json(name = "transaction")
val transaction: String,
) : WcRequestData
@JsonClass(generateAdapter = true)
data class WcAddChain(
@Json(name = "chainId")
val chainId: String,
) : WcRequestData
@JsonClass(generateAdapter = true)
data class WcEthereumSignMessage(
@Json(name = "raw")
val raw: List<String>,
@Json(name = "type")
val type: WCSignType,
) : WcRequestData {
enum class WCSignType {
@ -71,15 +81,34 @@ data class WcEthereumSignMessage(
@JsonClass(generateAdapter = true)
data class WcEthereumTransaction(
@Json(name = "from")
val from: String,
@Json(name = "to")
val to: String?,
@Json(name = "nonce")
val nonce: String?,
@Json(name = "gasPrice")
val gasPrice: String?,
@Json(name = "maxFeePerGas")
val maxFeePerGas: String?,
@Json(name = "maxPriorityFeePerGas")
val maxPriorityFeePerGas: String?,
@Json(name = "gas")
val gas: String?,
@Json(name = "gasLimit")
val gasLimit: String?,
@Json(name = "value")
val value: String?,
@Json(name = "data")
val data: String,
) : WcRequestData
@ -96,6 +125,7 @@ sealed class WcRequest(open val data: WcRequestData) {
data class BnbTransfer(override val data: WcBinanceTransferOrder) : WcRequest(data)
data class BnbTxConfirm(override val data: WCBinanceTxConfirmParam) : WcRequest(data)
data class SignTransaction(override val data: WCSignTransaction) : WcRequest(data)
data class AddChain(override val data: WcAddChain) : WcRequest(data)
data class CustomRequest(override val data: WcCustomRequestData) : WcRequest(data)
}
@ -167,6 +197,12 @@ class WcJrpcRequestsDeserializer @Inject constructor(@SdkMoshi private val moshi
).fromJsonFirstOrNull(params) ?: return customRequest
WcRequest.SignTransaction(data = deserializedParams)
}
WcJrpcMethods.WALLET_ADD_ETHEREUM_CHAIN -> {
val deserializedParams: WcAddChain = moshi.adapter<List<WcAddChain>>(
Types.newParameterizedType(List::class.java, WcAddChain::class.java),
).fromJsonFirstOrNull(params) ?: return customRequest
WcRequest.AddChain(data = deserializedParams)
}
}
}

View file

@ -7,7 +7,6 @@ import com.tangem.common.services.Result
import com.tangem.common.services.performRequest
import com.tangem.datasource.api.common.createRetrofitInstance
import com.tangem.domain.common.extensions.withIOContext
import com.tangem.tap.common.extensions.urlEncode
import com.tangem.tap.common.redux.global.CryptoCurrencyName
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.network.exchangeServices.CurrencyExchangeManager
@ -103,39 +102,37 @@ class MoonPayService(
cryptoCurrencyName: CryptoCurrencyName,
fatCurrency: String,
walletAddress: String,
): String? {
): String {
if (action == CurrencyExchangeManager.Action.Buy) throw UnsupportedOperationException()
val uri = Uri.Builder()
.scheme(SCHEME)
.authority(URL_SELL)
.appendQueryParameter("apiKey", apiKey.urlEncode())
.appendQueryParameter("baseCurrencyCode", cryptoCurrencyName.urlEncode())
.appendQueryParameter("refundWalletAddress", walletAddress.urlEncode())
.appendQueryParameter("redirectURL", "tangem://sell-request.tangem.com".urlEncode())
.appendQueryParameter("apiKey", apiKey)
.appendQueryParameter("baseCurrencyCode", cryptoCurrencyName)
.appendQueryParameter("refundWalletAddress", walletAddress)
.appendQueryParameter("redirectURL", "tangem://sell-request.tangem.com")
val originalQuery = uri.build().toString()
val originalQuery = uri.build().encodedQuery ?: uri.build().toString()
val signature = createSignature(originalQuery)
uri.appendQueryParameter("signature", signature.urlEncode())
uri.appendQueryParameter("signature", signature)
val url = uri.build().toString()
return url
return uri.build().toString()
}
override fun getSellCryptoReceiptUrl(action: CurrencyExchangeManager.Action, transactionId: String): String? {
val url = Uri.Builder()
override fun getSellCryptoReceiptUrl(action: CurrencyExchangeManager.Action, transactionId: String): String {
return Uri.Builder()
.scheme(SCHEME)
.authority(URL_SELL)
.appendPath("transaction_receipt")
.appendQueryParameter("transactionId", transactionId).build().toString()
return url
}
private fun createSignature(data: String): String {
val sha256Hmac = Mac.getInstance("HmacSHA256")
val secretKey = SecretKeySpec(secretKey.toByteArray(), "HmacSHA256")
sha256Hmac.init(secretKey)
val sha256encoded = sha256Hmac.doFinal(data.toByteArray())
val sha256encoded = sha256Hmac.doFinal("?$data".toByteArray())
return Base64.encodeToString(sha256encoded, Base64.NO_WRAP)
}