Updated on 2026-08-14

This commit is contained in:
Tangem 2026-01-13 15:13:18 +03:00
parent ee4c5a872c
commit 1ce06627c8
7 changed files with 38 additions and 15 deletions

View file

@ -1,10 +1,7 @@
package com.tangem.datasource.api.gasless
import com.tangem.datasource.api.common.response.ApiResponse
import com.tangem.datasource.api.gasless.models.GaslessServiceResponse
import com.tangem.datasource.api.gasless.models.GaslessSignedTransactionResultDTO
import com.tangem.datasource.api.gasless.models.GaslessSupportedTokens
import com.tangem.datasource.api.gasless.models.GaslessTransactionRequest
import com.tangem.datasource.api.gasless.models.*
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
@ -18,4 +15,7 @@ interface GaslessTxServiceApi {
suspend fun signGaslessTransaction(
@Body transaction: GaslessTransactionRequest,
): ApiResponse<GaslessServiceResponse<GaslessSignedTransactionResultDTO>>
@GET("api/v1/config/fee-recipient")
suspend fun getFeeRecipient(): ApiResponse<GaslessServiceResponse<GaslessFeeRecipient>>
}

View file

@ -0,0 +1,9 @@
package com.tangem.datasource.api.gasless.models
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class GaslessFeeRecipient(
@Json(name = "feeRecipientAddress") val address: String,
)

View file

@ -37,6 +37,7 @@ import javax.inject.Singleton
internal object NetworkModule {
private const val TANGEM_TECH_MARKETS_SERVICE_TIMEOUT_SECONDS = 60L
private const val TANGEM_GASLESS_SERVICE_TIMEOUT_SECONDS = 60L
private const val STAKE_KIT_API_TIMEOUT_SECONDS = 60L
private const val P2P_ETH_POOL_API_TIMEOUT_SECONDS = 60L
@ -196,6 +197,12 @@ internal object NetworkModule {
return retrofitApiBuilder.build(
apiConfigId = ApiConfig.ID.GaslessTxService,
applyTimeoutAnnotations = false,
timeouts = Timeouts(
callTimeoutSeconds = TANGEM_GASLESS_SERVICE_TIMEOUT_SECONDS,
connectTimeoutSeconds = TANGEM_GASLESS_SERVICE_TIMEOUT_SECONDS,
readTimeoutSeconds = TANGEM_GASLESS_SERVICE_TIMEOUT_SECONDS,
writeTimeoutSeconds = TANGEM_GASLESS_SERVICE_TIMEOUT_SECONDS,
),
)
}
}

View file

@ -69,8 +69,15 @@ class DefaultGaslessTransactionRepository(
}
}
override fun getTokenFeeReceiverAddress(): String {
return TOKEN_RECEIVER_ADDRESS
override suspend fun getTokenFeeReceiverAddress(): String {
return withContext(coroutineDispatcherProvider.io) {
val response = gaslessTxServiceApi.getFeeRecipient().getOrThrow()
if (response.isSuccess) {
response.result.address
} else {
error("Gasless service returned unsuccessful response")
}
}
}
override suspend fun signGaslessTransaction(

View file

@ -34,7 +34,7 @@ class MockedGaslessTransactionRepository(
return networkBlockchain.getChainId() ?: error("ChainId not found for blockchain ${networkBlockchain.name}")
}
override fun getTokenFeeReceiverAddress(): String {
override suspend fun getTokenFeeReceiverAddress(): String {
return TOKEN_RECEIVER_ADDRESS
}

View file

@ -11,7 +11,7 @@ interface GaslessTransactionRepository {
suspend fun getSupportedTokens(network: Network): Set<CryptoCurrency>
fun getTokenFeeReceiverAddress(): String
suspend fun getTokenFeeReceiverAddress(): String
/**
* Sends gasless transaction to the gasless service for signing and returns the signed result.

View file

@ -198,7 +198,7 @@ class TokenFeeCalculatorTest {
val initialFee = createMockEIP1559Fee()
coEvery { mockWalletManager.getGasLimit(any(), any(), any()) } returns Result.Success(BigInteger("60000"))
every { gaslessTransactionRepository.getTokenFeeReceiverAddress() } returns "0xFeeReceiver"
coEvery { gaslessTransactionRepository.getTokenFeeReceiverAddress() } returns "0xFeeReceiver"
every { gaslessTransactionRepository.getBaseGasForTransaction() } returns BigInteger("21000")
// When
@ -231,7 +231,7 @@ class TokenFeeCalculatorTest {
val initialFee = createMockEIP1559Fee()
coEvery { mockWalletManager.getGasLimit(any(), any(), any()) } returns Result.Success(BigInteger("60000"))
every { gaslessTransactionRepository.getTokenFeeReceiverAddress() } returns "0xFeeReceiver"
coEvery { gaslessTransactionRepository.getTokenFeeReceiverAddress() } returns "0xFeeReceiver"
every { gaslessTransactionRepository.getBaseGasForTransaction() } returns BigInteger("21000")
// When
@ -252,7 +252,7 @@ class TokenFeeCalculatorTest {
@Test
fun `calculateTokenFee should return error when fiatRate is null`() = runTest {
coEvery { mockWalletManager.getGasLimit(any(), any(), any()) } returns Result.Success(BigInteger("60000"))
every { gaslessTransactionRepository.getTokenFeeReceiverAddress() } returns "0xFeeReceiver"
coEvery { gaslessTransactionRepository.getTokenFeeReceiverAddress() } returns "0xFeeReceiver"
every { gaslessTransactionRepository.getBaseGasForTransaction() } returns BigInteger("21000")
// Given
val tokenStatus = createMockTokenStatus(
@ -285,7 +285,7 @@ class TokenFeeCalculatorTest {
val failure = Result.Failure(BlockchainSdkError.NPError("Gas limit fetch failed"))
coEvery { mockWalletManager.getGasLimit(any(), any(), any()) } returns failure
every { gaslessTransactionRepository.getTokenFeeReceiverAddress() } returns "0xFeeReceiver"
coEvery { gaslessTransactionRepository.getTokenFeeReceiverAddress() } returns "0xFeeReceiver"
// When
val result = tokenFeeCalculator.calculateTokenFee(
@ -314,7 +314,7 @@ class TokenFeeCalculatorTest {
)
coEvery { mockWalletManager.getGasLimit(any(), any(), any()) } returns Result.Success(BigInteger("60000"))
every { gaslessTransactionRepository.getTokenFeeReceiverAddress() } returns "0xFeeReceiver"
coEvery { gaslessTransactionRepository.getTokenFeeReceiverAddress() } returns "0xFeeReceiver"
every { gaslessTransactionRepository.getBaseGasForTransaction() } returns BigInteger("21000")
// When
@ -332,7 +332,7 @@ class TokenFeeCalculatorTest {
@Test
fun `calculateTokenFee should reject TokenCurrency as initial fee`() = runTest {
coEvery { mockWalletManager.getGasLimit(any(), any(), any()) } returns Result.Success(BigInteger("60000"))
every { gaslessTransactionRepository.getTokenFeeReceiverAddress() } returns "0xFeeReceiver"
coEvery { gaslessTransactionRepository.getTokenFeeReceiverAddress() } returns "0xFeeReceiver"
every { gaslessTransactionRepository.getBaseGasForTransaction() } returns BigInteger("21000")
// Given
@ -389,7 +389,7 @@ class TokenFeeCalculatorTest {
val initialFee = createMockEIP1559Fee()
coEvery { mockWalletManager.getGasLimit(any(), any(), any()) } returns Result.Success(BigInteger("60000"))
every { gaslessTransactionRepository.getTokenFeeReceiverAddress() } returns "0xFeeReceiver"
coEvery { gaslessTransactionRepository.getTokenFeeReceiverAddress() } returns "0xFeeReceiver"
every { gaslessTransactionRepository.getBaseGasForTransaction() } returns BigInteger("21000")
// When