Updated on 2026-08-14
This commit is contained in:
parent
bc587895f0
commit
90bdddb5e8
12 changed files with 278 additions and 71 deletions
|
|
@ -36,6 +36,9 @@ private val coroutineContext: CoroutineContext
|
|||
get() = Job() + Dispatchers.IO + initCoroutineExceptionHandler()
|
||||
val scope = CoroutineScope(coroutineContext)
|
||||
|
||||
private val mainCoroutineContext: CoroutineContext
|
||||
get() = Job() + Dispatchers.Main
|
||||
val mainScope = CoroutineScope(mainCoroutineContext)
|
||||
|
||||
private fun initCoroutineExceptionHandler(): CoroutineExceptionHandler {
|
||||
return CoroutineExceptionHandler { _, throwable ->
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ package com.tangem.tap.domain
|
|||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.commands.common.network.Result
|
||||
import com.tangem.tap.network.payid.PayIdService
|
||||
import com.tangem.tap.network.payid.PayIdVerifyService
|
||||
import com.tangem.tap.network.payid.SetPayIdResponse
|
||||
import com.tangem.tap.network.payid.VerifyPayIdResponse
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import retrofit2.HttpException
|
||||
|
|
@ -41,13 +43,19 @@ class PayIdManager {
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun verifyPayId(payId: String, blockchain: Blockchain): Result<VerifyPayIdResponse> = withContext(Dispatchers.IO) {
|
||||
val splitPayId = payId.split("\$")
|
||||
val user = splitPayId[0]
|
||||
val baseUrl = "https://${splitPayId[1]}/"
|
||||
return@withContext PayIdVerifyService(baseUrl).verifyAddress(user, blockchain.getPayIdNetwork())
|
||||
}
|
||||
|
||||
private fun Blockchain.getPayIdNetwork(): String {
|
||||
return when (this) {
|
||||
Blockchain.XRP -> "XRPL"
|
||||
Blockchain.RSK -> "RSK"
|
||||
else -> this.currency
|
||||
}
|
||||
}.toLowerCase()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,19 @@
|
|||
package com.tangem.tap.features.send.redux
|
||||
|
||||
import com.tangem.blockchain.common.Wallet
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.commands.common.network.Result
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.domain.PayIdManager
|
||||
import com.tangem.tap.domain.PayIdManager.Companion.isPayId
|
||||
import com.tangem.tap.domain.isPayIdSupported
|
||||
import com.tangem.tap.features.send.redux.AddressPayIdActionUI.SetAddressOrPayId
|
||||
import com.tangem.tap.features.send.redux.AddressPayIdVerifyAction.*
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.rekotlin.Action
|
||||
import org.rekotlin.Middleware
|
||||
|
||||
|
|
@ -29,59 +35,84 @@ private fun handleSendAction(action: Action) {
|
|||
when (sendAction) {
|
||||
is AddressPayIdActionUI -> {
|
||||
when (sendAction) {
|
||||
is SetAddressOrPayId -> AddressPayIdHandler().handle(sendAction.data?.toString())
|
||||
is SetAddressOrPayId -> AddressPayIdHandler().handle(sendAction.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class AddressPayIdHandler {
|
||||
fun handle(data: String?) {
|
||||
fun handle(data: String) {
|
||||
val walletManager = store.state.globalState.walletManager ?: return
|
||||
val clipboardData = data ?: return
|
||||
|
||||
if (PayIdManager.isPayId(clipboardData)) {
|
||||
if (walletManager.wallet.blockchain.isPayIdSupported()) {
|
||||
store.dispatch(AddressPayIdAction.Verification.PayIdNotSupportedByBlockchain)
|
||||
} else {
|
||||
scope.launch {
|
||||
val response = verifyPayID(walletManager, clipboardData)
|
||||
if (response == null) {
|
||||
store.dispatch(AddressPayIdAction.Verification.Failed)
|
||||
} else {
|
||||
val address = "some address D:" // extract from response
|
||||
store.dispatch(AddressPayIdAction.Verification.Success(address))
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isPayId(data)) {
|
||||
verifyPayId(data, walletManager)
|
||||
store.dispatch(ProcessedButNotVerifiedAddressPayId(data))
|
||||
} else {
|
||||
|
||||
val supposedAddress = extractAddressFromShareUri(data)
|
||||
store.dispatch(PayIdVerification.Failed(supposedAddress, FailReason.IS_NOT_PAY_ID))
|
||||
store.dispatch(ProcessedButNotVerifiedAddressPayId(supposedAddress))
|
||||
verifyAddress(walletManager, supposedAddress)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun verifyPayID(walletManager: WalletManager, payID: String?): String? {
|
||||
val cardId = walletManager.cardId
|
||||
val publicKey = store.state.globalState.card?.cardPublicKey
|
||||
private fun verifyPayId(payId: String, walletManager: WalletManager) {
|
||||
val blockchain = walletManager.wallet.blockchain
|
||||
if (!blockchain.isPayIdSupported()) {
|
||||
store.dispatch(PayIdVerification.Failed(payId, FailReason.PAY_ID_UNSUPPORTED_BY_BLOCKCHAIN))
|
||||
return
|
||||
}
|
||||
|
||||
// val result = PayIdManager().getPayId(cardId, publicKey.toHexString())
|
||||
// withContext(Dispatchers.Main) {
|
||||
// when (result) {
|
||||
// is Result.Success -> {
|
||||
// val payId = result.data
|
||||
// if (payId == null) {
|
||||
// store.dispatch(WalletAction.LoadPayId.NotCreated)
|
||||
// } else {
|
||||
// store.dispatch(WalletAction.LoadPayId.Success(payId))
|
||||
// }
|
||||
// }
|
||||
// is Result.Failure -> store.dispatch(WalletAction.LoadPayId.Failure)
|
||||
// }
|
||||
// }
|
||||
return null
|
||||
scope.launch {
|
||||
val result = PayIdManager().verifyPayId(payId, blockchain)
|
||||
withContext(Dispatchers.Main) {
|
||||
when (result) {
|
||||
is Result.Success -> {
|
||||
val address = result.data.getAddress()
|
||||
if (address == null) {
|
||||
store.dispatch(PayIdVerification.Failed(payId, FailReason.PAY_ID_NOT_REGISTERED))
|
||||
return@withContext
|
||||
}
|
||||
val failReason = isValidBlockchainAddressAndNotTheSameAsWallet(walletManager.wallet, address)
|
||||
|
||||
val actionToSend = if (failReason == FailReason.NONE) PayIdVerification.Success(payId, address)
|
||||
else AddressVerification.Failed(payId, failReason)
|
||||
store.dispatch(actionToSend)
|
||||
}
|
||||
is Result.Failure -> {
|
||||
store.dispatch(PayIdVerification.Failed(payId, FailReason.PAY_ID_REQUEST_FAILED))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun verifyWalletAddress(payID: String?): Boolean {
|
||||
val isRealAddress = true
|
||||
return isRealAddress
|
||||
private fun verifyAddress(walletManager: WalletManager, supposedAddress: String) {
|
||||
val failReason = isValidBlockchainAddressAndNotTheSameAsWallet(walletManager.wallet, supposedAddress)
|
||||
val actionToSend = if (failReason == FailReason.NONE) AddressVerification.Success(supposedAddress)
|
||||
else AddressVerification.Failed(supposedAddress, failReason)
|
||||
|
||||
store.dispatch(actionToSend)
|
||||
}
|
||||
|
||||
private fun isValidBlockchainAddressAndNotTheSameAsWallet(wallet: Wallet, address: String): FailReason {
|
||||
return if (wallet.blockchain.validateAddress(address)) {
|
||||
if (wallet.address != address) {
|
||||
FailReason.NONE
|
||||
} else {
|
||||
FailReason.ADDRESS_SAME_AS_WALLET
|
||||
}
|
||||
} else {
|
||||
FailReason.ADDRESS_INVALID_OR_UNSUPPORTED_BY_BLOCKCHAIN
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: move to the blockchainSDK
|
||||
private fun extractAddressFromShareUri(shareUri: String): String {
|
||||
val sharePrefix = listOf("bitcoin:", "ethereum:", "ripple:")
|
||||
val prefixes = sharePrefix.filter { shareUri.contains(it) }
|
||||
return if (prefixes.isEmpty()) shareUri
|
||||
else shareUri.replace(prefixes[0], "")
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.tap.features.send.redux
|
||||
|
||||
import android.view.View
|
||||
import com.tangem.tap.features.send.redux.AddressPayIdActionUI.SetAddressOrPayId
|
||||
import com.tangem.tap.features.send.redux.FeeActionUI.*
|
||||
import org.rekotlin.Action
|
||||
import org.rekotlin.StateType
|
||||
|
|
@ -16,32 +15,47 @@ class SendReducer {
|
|||
}
|
||||
}
|
||||
|
||||
private fun internalReduce(action: Action, sendState: SendState): SendState {
|
||||
if (action is ReleaseSendState) return SendState()
|
||||
val sendAction = action as? SendScreenAction ?: return sendState
|
||||
private fun internalReduce(incomingAction: Action, sendState: SendState): SendState {
|
||||
if (incomingAction is ReleaseSendState) return SendState()
|
||||
val action = incomingAction as? SendScreenAction ?: return sendState
|
||||
|
||||
return when (sendAction) {
|
||||
is AddressPayIdActionUI -> handleAddressPayIdAction(sendAction, sendState, sendState.addressPayIDState)
|
||||
is FeeActionUI -> handleFeeLayoutAction(sendAction, sendState, sendState.feeLayoutState)
|
||||
return when (action) {
|
||||
is FeeActionUI -> handleFeeLayoutAction(action, sendState, sendState.feeLayoutState)
|
||||
// is SetAddressOrPayId -> handleAddressPayIdUIAction(action, sendState, sendState.addressPayIDState)
|
||||
is AddressPayIdVerifyAction -> handleAddressPayIdAction(action, sendState, sendState.addressPayIDState)
|
||||
else -> sendState
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleAddressPayIdAction(
|
||||
action: AddressPayIdActionUI,
|
||||
action: AddressPayIdVerifyAction,
|
||||
sendState: SendState,
|
||||
state: AddressPayIDState
|
||||
): SendState {
|
||||
var state = state
|
||||
|
||||
when (action) {
|
||||
is SetAddressOrPayId -> {
|
||||
state = state.copy(value = action.data?.toString())
|
||||
return updateLastState(sendState.copy(addressPayIDState = state), state)
|
||||
val result: AddressPayIDState? = when (action) {
|
||||
is AddressPayIdVerifyAction.PayIdVerification.Success -> {
|
||||
state.copyPayIdWalletAddress(action.payId, action.payIdWalletAddress)
|
||||
}
|
||||
is AddressPayIdVerifyAction.PayIdVerification.Failed -> {
|
||||
state.copyPaiIdError(action.payId, action.reason)
|
||||
}
|
||||
is AddressPayIdVerifyAction.AddressVerification.Success -> {
|
||||
state.copyWalletAddress(action.address)
|
||||
}
|
||||
is AddressPayIdVerifyAction.AddressVerification.Failed -> {
|
||||
state.copyError(action.address, action.reason)
|
||||
}
|
||||
is AddressPayIdVerifyAction.ProcessedButNotVerifiedAddressPayId -> {
|
||||
state.copy(etFieldValue = action.data)
|
||||
}
|
||||
}
|
||||
return if (result == null) {
|
||||
Timber.e("AddressPayIDState didn't modified.")
|
||||
sendState
|
||||
} else {
|
||||
updateLastState(sendState.copy(addressPayIDState = result), result)
|
||||
}
|
||||
|
||||
return sendState
|
||||
}
|
||||
|
||||
private fun handleFeeLayoutAction(action: FeeActionUI, sendState: SendState, state: FeeLayoutState): SendState {
|
||||
|
|
@ -64,8 +78,8 @@ private fun handleFeeLayoutAction(action: FeeActionUI, sendState: SendState, sta
|
|||
}
|
||||
}
|
||||
|
||||
private fun updateLastState(sendState: SendState, state: StateType): SendState {
|
||||
val sendState = sendState.copy(lastChangedStateType = state)
|
||||
private fun updateLastState(sendState: SendState, lastChangedState: StateType): SendState {
|
||||
val sendState = sendState.copy(lastChangedStateType = lastChangedState)
|
||||
Timber.d("$sendState")
|
||||
return sendState
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,14 +16,31 @@ sealed class FeeActionUI : SendScreenActionUI {
|
|||
class ChangeIncludeFee(val isChecked: Boolean) : FeeActionUI()
|
||||
}
|
||||
|
||||
// shortness AddressOrPayId = APid
|
||||
sealed class AddressPayIdActionUI : SendScreenActionUI {
|
||||
data class SetAddressOrPayId(val data: CharSequence?) : AddressPayIdActionUI()
|
||||
data class SetAddressOrPayId(val data: String) : AddressPayIdActionUI()
|
||||
}
|
||||
|
||||
sealed class AddressPayIdAction : SendScreenAction {
|
||||
object Verification : AddressPayIdAction() {
|
||||
object PayIdNotSupportedByBlockchain : AddressPayIdAction()
|
||||
object Failed : AddressPayIdAction()
|
||||
data class Success(val payIdWalletAddress: String) : AddressPayIdAction()
|
||||
sealed class AddressPayIdVerifyAction : SendScreenAction {
|
||||
enum class FailReason {
|
||||
NONE,
|
||||
IS_NOT_PAY_ID,
|
||||
PAY_ID_UNSUPPORTED_BY_BLOCKCHAIN,
|
||||
PAY_ID_NOT_REGISTERED,
|
||||
PAY_ID_REQUEST_FAILED,
|
||||
ADDRESS_INVALID_OR_UNSUPPORTED_BY_BLOCKCHAIN,
|
||||
ADDRESS_SAME_AS_WALLET
|
||||
}
|
||||
|
||||
data class ProcessedButNotVerifiedAddressPayId(val data: String) : AddressPayIdVerifyAction()
|
||||
|
||||
sealed class PayIdVerification : AddressPayIdVerifyAction() {
|
||||
data class Failed(val payId: String, val reason: FailReason) : PayIdVerification()
|
||||
data class Success(val payId: String, val payIdWalletAddress: String) : PayIdVerification()
|
||||
}
|
||||
|
||||
sealed class AddressVerification : AddressPayIdVerifyAction() {
|
||||
data class Failed(val address: String, val reason: FailReason) : AddressVerification()
|
||||
data class Success(val address: String) : AddressVerification()
|
||||
}
|
||||
}
|
||||
|
|
@ -18,10 +18,28 @@ data class SendState(
|
|||
class NoneState : StateType
|
||||
|
||||
data class AddressPayIDState(
|
||||
val value: String? = null,
|
||||
val payIDWalletAddress: String? = null,
|
||||
val error: String? = null,
|
||||
) : StateType
|
||||
val etFieldValue: String? = null,
|
||||
val walletAddress: String? = null,
|
||||
val error: AddressPayIdVerifyAction.FailReason? = null,
|
||||
) : StateType {
|
||||
|
||||
fun isPayIdState():Boolean = walletAddress != null && walletAddress != etFieldValue
|
||||
|
||||
fun copyWalletAddress(address: String): AddressPayIDState {
|
||||
return this.copy(etFieldValue = address, walletAddress = address, error = null)
|
||||
}
|
||||
fun copyError(address: String, error: AddressPayIdVerifyAction.FailReason): AddressPayIDState {
|
||||
return this.copy(etFieldValue = address, error = error, walletAddress = null)
|
||||
}
|
||||
|
||||
fun copyPayIdWalletAddress(payId: String, address: String): AddressPayIDState {
|
||||
return this.copy(etFieldValue = payId, walletAddress = address, error = null)
|
||||
}
|
||||
|
||||
fun copyPaiIdError(payId: String, error: AddressPayIdVerifyAction.FailReason): AddressPayIDState {
|
||||
return this.copy(etFieldValue = payId, error = error, walletAddress = null)
|
||||
}
|
||||
}
|
||||
|
||||
data class FeeLayoutState(
|
||||
val visibility: Int = View.GONE,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ package com.tangem.tap.features.send.ui
|
|||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.EditText
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
import com.tangem.tap.common.extensions.getFromClipboard
|
||||
import com.tangem.tap.common.qrCodeScan.ScanQrCodeActivity
|
||||
import com.tangem.tap.features.send.BaseStoreFragment
|
||||
|
|
@ -11,11 +13,17 @@ import com.tangem.tap.features.send.redux.FeeActionUI.*
|
|||
import com.tangem.tap.features.send.redux.ReleaseSendState
|
||||
import com.tangem.tap.features.send.ui.stateSubscribers.SendStateSubscriber
|
||||
import com.tangem.tap.features.send.ui.stateSubscribers.WalletStateSubscriber
|
||||
import com.tangem.tap.mainScope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.btn_paste.*
|
||||
import kotlinx.android.synthetic.main.btn_qr_code.*
|
||||
import kotlinx.android.synthetic.main.layout_send_address_payid.*
|
||||
import kotlinx.android.synthetic.main.layout_send_network_fee.*
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
@ -27,7 +35,6 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
flExpandCollapse.setOnClickListener {
|
||||
store.dispatch(ToggleFeeLayoutVisibility)
|
||||
}
|
||||
|
|
@ -38,8 +45,14 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
|||
store.dispatch(ChangeIncludeFee(isChecked))
|
||||
}
|
||||
|
||||
etAddressOrPayId.inputedTextAsFlow()
|
||||
.debounce(400)
|
||||
.filter { store.state.sendState.addressPayIDState.etFieldValue != it }
|
||||
.onEach { store.dispatch(SetAddressOrPayId(it)) }
|
||||
.launchIn(mainScope)
|
||||
|
||||
imvPaste.setOnClickListener {
|
||||
store.dispatch(SetAddressOrPayId(requireContext().getFromClipboard()))
|
||||
store.dispatch(SetAddressOrPayId(requireContext().getFromClipboard()?.toString() ?: ""))
|
||||
}
|
||||
imvQrCode.setOnClickListener {
|
||||
requireActivity().startActivity(Intent(requireContext(), ScanQrCodeActivity::class.java))
|
||||
|
|
@ -64,5 +77,11 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
|||
}
|
||||
}
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
fun EditText.inputedTextAsFlow(): Flow<String> = callbackFlow {
|
||||
val watcher = addTextChangedListener { editable -> offer(editable?.toString() ?: "") }
|
||||
awaitClose { removeTextChangedListener(watcher) }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
package com.tangem.tap.features.send.ui.stateSubscribers
|
||||
|
||||
import android.content.Context
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.transition.TransitionManager
|
||||
import com.tangem.tap.features.send.redux.AddressPayIDState
|
||||
import com.tangem.tap.features.send.redux.AddressPayIdVerifyAction.FailReason
|
||||
import com.tangem.tap.features.send.redux.FeeLayoutState
|
||||
import com.tangem.tap.features.send.redux.SendState
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.btn_expand_collapse.*
|
||||
import kotlinx.android.synthetic.main.layout_send_address_payid.*
|
||||
import kotlinx.android.synthetic.main.layout_send_network_fee.*
|
||||
|
|
@ -23,7 +26,29 @@ class SendStateSubscriber(fragment: Fragment) : FragmentStateSubscriber<SendStat
|
|||
}
|
||||
|
||||
private fun handleAddressPayIdState(fg: Fragment, state: AddressPayIDState) {
|
||||
fg.etAddressOrPayId.setText(state.value)
|
||||
fun parseError(context: Context, error: FailReason?): String? {
|
||||
val resId = when (error) {
|
||||
FailReason.IS_NOT_PAY_ID -> R.string.error_payid_verification_failed
|
||||
FailReason.PAY_ID_UNSUPPORTED_BY_BLOCKCHAIN -> R.string.error_payid_unsupported_by_blockchain
|
||||
FailReason.PAY_ID_NOT_REGISTERED -> R.string.error_payid_not_registere
|
||||
FailReason.PAY_ID_REQUEST_FAILED -> R.string.error_payid_request_failed
|
||||
FailReason.ADDRESS_INVALID_OR_UNSUPPORTED_BY_BLOCKCHAIN -> R.string.error_address_invalid_or_unsupported
|
||||
FailReason.ADDRESS_SAME_AS_WALLET -> R.string.error_address_same_as_wallet
|
||||
else -> null
|
||||
}
|
||||
return if (resId == null) null
|
||||
else context.getString(resId)
|
||||
}
|
||||
|
||||
val parsedError = parseError(fg.tilAddressOrPayId.context, state.error)
|
||||
fg.tilAddressOrPayId.error = parsedError
|
||||
fg.tilAddressOrPayId.isErrorEnabled = parsedError != null
|
||||
fg.tilAddressOrPayId.helperText = state.walletAddress
|
||||
fg.tilAddressOrPayId.isHelperTextEnabled = state.isPayIdState() && parsedError == null
|
||||
if (fg.etAddressOrPayId.text?.toString() != state.etFieldValue) {
|
||||
fg.etAddressOrPayId.setText(state.etFieldValue)
|
||||
if (fg.etAddressOrPayId.isFocused) fg.etAddressOrPayId.setSelection(state.etFieldValue?.length ?: 0)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleFeeLayoutState(fg: Fragment, layoutState: FeeLayoutState) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
package com.tangem.tap.network.payid
|
||||
|
||||
import com.squareup.moshi.JsonClass
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Header
|
||||
import retrofit2.http.Path
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface PayIdVerifyApi {
|
||||
@GET("{user}")
|
||||
suspend fun verifyAddress(
|
||||
@Path("user") user: String,
|
||||
@Header("Accept") acceptNetworkHeader: String,
|
||||
@Header("PayID-Version") payIdVersion: String = "1.0"
|
||||
): VerifyPayIdResponse
|
||||
}
|
||||
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class VerifyPayIdResponse(
|
||||
val addresses: List<PayIdAddress> = mutableListOf(),
|
||||
val payId: String? = null,
|
||||
) {
|
||||
fun getAddress(): String? {
|
||||
return if (addresses.isEmpty()) null
|
||||
else addresses[0].addressDetails.address
|
||||
}
|
||||
}
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class PayIdAddress(
|
||||
var paymentNetwork: String,
|
||||
var environment: String,
|
||||
var addressDetailsType: String,
|
||||
var addressDetails: PayIdAddressDetails
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class PayIdAddressDetails(
|
||||
var address: String,
|
||||
var tag: String? = null
|
||||
)
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.tangem.tap.network.payid
|
||||
|
||||
import com.tangem.commands.common.network.Result
|
||||
import com.tangem.commands.common.network.performRequest
|
||||
import com.tangem.tap.network.createRetrofitInstance
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class PayIdVerifyService(
|
||||
private val baseUrl: String
|
||||
) {
|
||||
|
||||
private val api = createRetrofitInstance(baseUrl).create(PayIdVerifyApi::class.java)
|
||||
|
||||
suspend fun verifyAddress(user: String, network: String): Result<VerifyPayIdResponse> {
|
||||
return performRequest { api.verifyAddress(user, createNetworkHeader(network)) }
|
||||
}
|
||||
|
||||
private fun createNetworkHeader(network: String): String = "application/$network-mainnet+json"
|
||||
}
|
||||
|
|
@ -45,7 +45,7 @@
|
|||
layout="@layout/btn_qr_code"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/tilAddressOrPayId"
|
||||
android:layout_marginTop="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/tilAddressOrPayId" />
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,13 @@
|
|||
<string name="error_payid_already_created">This PayID already exists. Try a different one.</string>
|
||||
<string name="error_creating_payid">Error response while creating PayID.</string>
|
||||
|
||||
<string name="error_payid_verification_failed">PayID verification failed</string>
|
||||
<string name="error_payid_unsupported_by_blockchain">PayID unsupported by blockchain</string>
|
||||
<string name="error_payid_not_registere">PayID not registered</string>
|
||||
<string name="error_payid_request_failed">PayID request failed</string>
|
||||
<string name="error_address_invalid_or_unsupported">Address is invalid or unsupported by blockchain</string>
|
||||
<string name="error_address_same_as_wallet">Address is invalid or unsupported by blockchain</string>
|
||||
|
||||
|
||||
<string name="send_title">Send</string>
|
||||
<string name="send_address_or_payid">Address or PayID</string>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue