Updated on 2026-08-14
This commit is contained in:
parent
6d56af68f5
commit
3d9e937ee9
30 changed files with 258 additions and 344 deletions
|
|
@ -20,27 +20,38 @@ internal class DefaultVisaContractInfoProvider(
|
|||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : VisaContractInfoProvider {
|
||||
|
||||
override suspend fun getContractInfo(walletAddress: String): VisaContractInfo {
|
||||
override suspend fun getContractInfo(walletAddress: String, paymentAccountAddress: String?): VisaContractInfo {
|
||||
return parZip(
|
||||
dispatchers.io,
|
||||
{ loadPaymentAccount(walletAddress) },
|
||||
{ loadPaymentAccount(walletAddress = walletAddress, paymentAccountAddress = paymentAccountAddress) },
|
||||
{ loadPaymentTokenInfo() },
|
||||
{ paymentAccount, paymentToken ->
|
||||
fetchBalancesAndLimits(paymentAccount, paymentToken)
|
||||
fetchBalancesAndLimits(
|
||||
paymentAccount = paymentAccount,
|
||||
paymentToken = paymentToken,
|
||||
walletAddress = walletAddress,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun loadPaymentAccount(walletAddress: String): TangemPaymentAccount {
|
||||
private fun loadPaymentAccount(walletAddress: String, paymentAccountAddress: String?): TangemPaymentAccount {
|
||||
return TangemPaymentAccount.load(
|
||||
/* contractAddress = */ paymentAccountAddress ?: getPaymentAccountAddressFromRegistry(walletAddress),
|
||||
/* web3j = */ web3j,
|
||||
/* transactionManager = */ transactionManager,
|
||||
/* contractGasProvider = */ gasProvider,
|
||||
)
|
||||
}
|
||||
|
||||
private fun getPaymentAccountAddressFromRegistry(walletAddress: String): String {
|
||||
val paymentAccountRegistry = TangemPaymentAccountRegistry.load(
|
||||
/* contractAddress = */ paymentAccountRegistryAddress,
|
||||
/* web3j = */ web3j,
|
||||
/* transactionManager = */ transactionManager,
|
||||
/* contractGasProvider = */ gasProvider,
|
||||
)
|
||||
val paymentAccountAddress = paymentAccountRegistry.paymentAccountByCard(walletAddress).send()
|
||||
|
||||
return TangemPaymentAccount.load(paymentAccountAddress, web3j, transactionManager, gasProvider)
|
||||
return paymentAccountRegistry.paymentAccountByCard(walletAddress).send()
|
||||
}
|
||||
|
||||
private fun loadPaymentTokenInfo(): PaymentTokenInfo {
|
||||
|
|
@ -63,11 +74,12 @@ internal class DefaultVisaContractInfoProvider(
|
|||
private suspend fun fetchBalancesAndLimits(
|
||||
paymentAccount: TangemPaymentAccount,
|
||||
paymentToken: PaymentTokenInfo,
|
||||
walletAddress: String,
|
||||
): VisaContractInfo = parZip(
|
||||
dispatchers.io,
|
||||
{ fetchToken(paymentAccount) },
|
||||
{ fetchBalances(paymentAccount, paymentToken) },
|
||||
{ fetchLimits(paymentAccount, paymentToken) },
|
||||
{ fetchLimits(paymentAccount, paymentToken, walletAddress) },
|
||||
{ token, balances, (oldLimit, newLimit, changeDate) ->
|
||||
VisaContractInfo(token, balances, oldLimit, newLimit, changeDate)
|
||||
},
|
||||
|
|
@ -123,19 +135,15 @@ internal class DefaultVisaContractInfoProvider(
|
|||
private fun fetchLimits(
|
||||
paymentAccount: TangemPaymentAccount,
|
||||
paymentToken: PaymentTokenInfo,
|
||||
walletAddress: String,
|
||||
): Triple<Limits, Limits, Instant> {
|
||||
TODO() // TODO: [REDACTED_TASK_KEY]
|
||||
// val (
|
||||
// oldLimit,
|
||||
// newLimit,
|
||||
// changeDateSeconds,
|
||||
// ) = paymentAccount.cards("").send().component5()
|
||||
//
|
||||
// return Triple(
|
||||
// first = getLimits(oldLimit, paymentToken),
|
||||
// second = getLimits(newLimit, paymentToken),
|
||||
// third = changeDateSeconds.toInstant(),
|
||||
// )
|
||||
val limits = paymentAccount.cards(walletAddress).send().component5()
|
||||
|
||||
return Triple(
|
||||
first = getLimits(limits.oldValue, paymentToken),
|
||||
second = getLimits(limits.newValue, paymentToken),
|
||||
third = limits.changeTimestamp.toInstant(),
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
|
|
|
|||
|
|
@ -21,7 +21,14 @@ import java.util.concurrent.TimeUnit
|
|||
|
||||
interface VisaContractInfoProvider {
|
||||
|
||||
suspend fun getContractInfo(walletAddress: String): VisaContractInfo
|
||||
/**
|
||||
* Fetches Visa contract info for the given wallet address.
|
||||
*
|
||||
* @param walletAddress Wallet address to fetch contract info for.
|
||||
* @param paymentAccountAddress Payment account address to fetch data from. If null,
|
||||
* it will be fetched from the registry.
|
||||
*/
|
||||
suspend fun getContractInfo(walletAddress: String, paymentAccountAddress: String?): VisaContractInfo
|
||||
|
||||
class Builder(
|
||||
private val useTestnetRpc: Boolean,
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
package com.tangem.lib.visa.api
|
||||
|
||||
import com.tangem.datasource.api.common.response.ApiResponse
|
||||
import com.tangem.lib.visa.model.VisaTxHistoryResponse
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Header
|
||||
import retrofit2.http.Query
|
||||
|
||||
interface VisaApi {
|
||||
|
||||
@GET("transaction")
|
||||
suspend fun getTxHistory(
|
||||
@Header("Authorization") authorizationHeader: String,
|
||||
@Query("card_public_key") cardPublicKey: String,
|
||||
@Query("limit") limit: Int,
|
||||
@Query("offset") offset: Int,
|
||||
): ApiResponse<VisaTxHistoryResponse>
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
package com.tangem.lib.visa.api
|
||||
|
||||
import android.util.Log
|
||||
import com.ihsanbal.logging.Level
|
||||
import com.ihsanbal.logging.LoggingInterceptor
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.datasource.api.common.response.ApiResponseCallAdapterFactory
|
||||
import com.tangem.lib.visa.utils.Constants
|
||||
import com.tangem.lib.visa.utils.Constants.NETWORK_LOGS_TAG
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.OkHttpClient
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.moshi.MoshiConverterFactory
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class VisaApiBuilder(
|
||||
private val useDevApi: Boolean,
|
||||
private val isNetworkLoggingEnabled: Boolean,
|
||||
private val moshi: Moshi,
|
||||
private val headers: Map<String, String>,
|
||||
private val networkTimeoutSeconds: Long = Constants.NETWORK_TIMEOUT_SECONDS,
|
||||
) {
|
||||
|
||||
fun build(): VisaApi {
|
||||
val okHttpClient = createOkHttpClient()
|
||||
val retrofit = createRetrofit(okHttpClient)
|
||||
return retrofit.create(VisaApi::class.java)
|
||||
}
|
||||
|
||||
private fun createOkHttpClient(): OkHttpClient {
|
||||
val builder = OkHttpClient.Builder().apply {
|
||||
connectTimeout(networkTimeoutSeconds, TimeUnit.SECONDS)
|
||||
readTimeout(networkTimeoutSeconds, TimeUnit.SECONDS)
|
||||
writeTimeout(networkTimeoutSeconds, TimeUnit.SECONDS)
|
||||
|
||||
if (isNetworkLoggingEnabled) {
|
||||
addInterceptor(createNetworkLoggingInterceptor())
|
||||
}
|
||||
|
||||
if (headers.isNotEmpty()) {
|
||||
addInterceptor { chain ->
|
||||
val request = chain.request().newBuilder().apply {
|
||||
headers.forEach { (key, value) -> addHeader(key, value) }
|
||||
}.build()
|
||||
|
||||
chain.proceed(request)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
private fun createRetrofit(okHttpClient: OkHttpClient): Retrofit {
|
||||
val baseUrl = if (useDevApi) Constants.VISA_API_DEV_URL else Constants.VISA_API_PROD_URL
|
||||
|
||||
return Retrofit.Builder()
|
||||
.addConverterFactory(MoshiConverterFactory.create(moshi))
|
||||
.addCallAdapterFactory(ApiResponseCallAdapterFactory.create())
|
||||
.baseUrl(baseUrl)
|
||||
.client(okHttpClient)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
private fun createNetworkLoggingInterceptor(): Interceptor {
|
||||
return LoggingInterceptor.Builder()
|
||||
.setLevel(Level.BODY)
|
||||
.log(Log.VERBOSE)
|
||||
.tag(NETWORK_LOGS_TAG)
|
||||
.build()
|
||||
}
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
package com.tangem.lib.visa.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import org.joda.time.DateTime
|
||||
import java.math.BigDecimal
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class VisaTxHistoryResponse(
|
||||
@Json(name = "card_wallet_address")
|
||||
val cardWalletAddress: String,
|
||||
@Json(name = "transactions")
|
||||
val transactions: List<Transaction>,
|
||||
) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class Transaction(
|
||||
@Json(name = "auth_code")
|
||||
val authCode: String?,
|
||||
@Json(name = "billing_amount")
|
||||
val billingAmount: BigDecimal,
|
||||
@Json(name = "billing_currency_code")
|
||||
val billingCurrencyCode: Int,
|
||||
@Json(name = "blockchain_amount")
|
||||
val blockchainAmount: BigDecimal,
|
||||
@Json(name = "blockchain_coin_name")
|
||||
val blockchainCoinName: String,
|
||||
@Json(name = "blockchain_fee")
|
||||
val blockchainFee: BigDecimal,
|
||||
// @Json(name = "local_dt")
|
||||
// val localDate: DateTime?,
|
||||
@Json(name = "merchant_category_code")
|
||||
val merchantCategoryCode: String?,
|
||||
@Json(name = "merchant_city")
|
||||
val merchantCity: String?,
|
||||
@Json(name = "merchant_country_code")
|
||||
val merchantCountryCode: String?,
|
||||
@Json(name = "merchant_name")
|
||||
val merchantName: String?,
|
||||
@Json(name = "requests")
|
||||
val requests: List<Request>,
|
||||
@Json(name = "rrn")
|
||||
val rrn: String?,
|
||||
@Json(name = "transaction_amount")
|
||||
val transactionAmount: BigDecimal,
|
||||
@Json(name = "transaction_currency_code")
|
||||
val transactionCurrencyCode: Int,
|
||||
@Json(name = "transaction_dt")
|
||||
val transactionDt: DateTime,
|
||||
@Json(name = "transaction_id")
|
||||
val transactionId: Long,
|
||||
@Json(name = "transaction_status")
|
||||
val transactionStatus: String,
|
||||
@Json(name = "transaction_type")
|
||||
val transactionType: String,
|
||||
) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class Request(
|
||||
@Json(name = "billing_amount")
|
||||
val billingAmount: BigDecimal,
|
||||
@Json(name = "billing_currency_code")
|
||||
val billingCurrencyCode: Int,
|
||||
@Json(name = "blockchain_amount")
|
||||
val blockchainAmount: BigDecimal,
|
||||
@Json(name = "blockchain_fee")
|
||||
val blockchainFee: BigDecimal,
|
||||
@Json(name = "error_code")
|
||||
val errorCode: Int,
|
||||
@Json(name = "request_dt")
|
||||
val requestDt: DateTime,
|
||||
@Json(name = "request_status")
|
||||
val requestStatus: String,
|
||||
@Json(name = "request_type")
|
||||
val requestType: String,
|
||||
@Json(name = "transaction_amount")
|
||||
val transactionAmount: BigDecimal,
|
||||
@Json(name = "transaction_currency_code")
|
||||
val transactionCurrencyCode: Int,
|
||||
@Json(name = "transaction_request_id")
|
||||
val transactionRequestId: Long,
|
||||
@Json(name = "tx_hash")
|
||||
val txHash: String?,
|
||||
@Json(name = "tx_status")
|
||||
val txStatus: String?,
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue