diff --git a/features/swap/data/build.gradle.kts b/features/swap/data/build.gradle.kts index f91ab4c7c0..67d016525d 100644 --- a/features/swap/data/build.gradle.kts +++ b/features/swap/data/build.gradle.kts @@ -15,6 +15,8 @@ dependencies { /** Network */ implementation(deps.retrofit) + implementation(deps.moshi) + implementation(deps.moshi.kotlin) /** Domain */ implementation(projects.domain.tokens.models) diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/ExpressApi.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/ExpressApi.kt new file mode 100644 index 0000000000..7fff572429 --- /dev/null +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/ExpressApi.kt @@ -0,0 +1,64 @@ +package com.tangem.feature.swap + +import com.tangem.datasource.api.common.response.ApiResponse +import com.tangem.feature.swap.models.request.AssetsRequestBody +import com.tangem.feature.swap.models.request.PairsRequestBody +import com.tangem.feature.swap.models.response.* +import retrofit2.http.Body +import retrofit2.http.GET +import retrofit2.http.Header +import retrofit2.http.POST +import retrofit2.http.Query +import java.math.BigDecimal + +/** + * Interface of Tangem Express API (new swap mechanism) + */ +internal interface ExpressApi { + + // TODO move first three params to retrofit interceptor + @POST("assets") + suspend fun getAssets( + @Header("api-key") apiKey: String, + @Header("user-id") userId: String, + @Header("session-id") sessionId: String, + @Body body: AssetsRequestBody, + ): ApiResponse> + + @POST("pairs") + suspend fun getPairs( + @Body body: PairsRequestBody, + ): ApiResponse> + + @GET("providers") + suspend fun getProviders(): ApiResponse> + + @GET("exchange-quote") + suspend fun getExchangeQuote( + @Query("fromContractAddress") fromContractAddress: String, + @Query("fromNetwork") fromNetwork: String, + @Query("toContractAddress") toContractAddress: String, + @Query("toNetwork") toNetwork: String, + @Query("fromAmount") fromAmount: BigDecimal, + @Query("providerId") providerId: Int, + @Query("rateType") rateType: RateType, + ): ApiResponse + + @GET("exchange-data") + suspend fun getExchangeData( + @Query("fromContractAddress") fromContractAddress: String, + @Query("fromNetwork") fromNetwork: String, + @Query("toContractAddress") toContractAddress: String, + @Query("toNetwork") toNetwork: String, + @Query("fromAmount") fromAmount: BigDecimal, + @Query("providerId") providerId: Int, + @Query("rateType") rateType: RateType, + @Query("toAddress") toAddress: String, + ): ApiResponse + + @GET("exchange-results") + suspend fun getExchangeResults( + @Query("txId") txId: String, + ): ApiResponse + +} \ No newline at end of file diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/models/request/AssetsRequestBody.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/models/request/AssetsRequestBody.kt new file mode 100644 index 0000000000..9592830c3c --- /dev/null +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/models/request/AssetsRequestBody.kt @@ -0,0 +1,7 @@ +package com.tangem.feature.swap.models.request + +import com.squareup.moshi.Json + +internal data class AssetsRequestBody( + @Json(name = "filter") val filter: List?, +) diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/models/request/LeastTokenInfo.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/models/request/LeastTokenInfo.kt new file mode 100644 index 0000000000..7c6776fc82 --- /dev/null +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/models/request/LeastTokenInfo.kt @@ -0,0 +1,11 @@ +package com.tangem.feature.swap.models.request + +import com.squareup.moshi.Json + +internal data class LeastTokenInfo( + @Json(name = "contractAddress") + val contractAddress: String, + + @Json(name = "network") + val network: String, +) \ No newline at end of file diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/models/request/PairsRequestBody.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/models/request/PairsRequestBody.kt new file mode 100644 index 0000000000..98ca56b52f --- /dev/null +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/models/request/PairsRequestBody.kt @@ -0,0 +1,11 @@ +package com.tangem.feature.swap.models.request + +import com.squareup.moshi.Json + +internal data class PairsRequestBody( + @Json(name = "from") + val from: List, + + @Json(name = "to") + val to: List, +) diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/models/response/Asset.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/models/response/Asset.kt new file mode 100644 index 0000000000..8d32b5d500 --- /dev/null +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/models/response/Asset.kt @@ -0,0 +1,29 @@ +package com.tangem.feature.swap.models.response + +import com.squareup.moshi.Json + +data class Asset( + @Json(name = "contractAddress") + val contractAddress: String, + + @Json(name = "network") + val network: String, + + @Json(name = "token") + val token: String, + + @Json(name = "name") + val name: String, + + @Json(name = "symbol") + val symbol: String, + + @Json(name = "decimals") + val decimals: Int, + + @Json(name = "isActive") + val isActive: Boolean, + + @Json(name = "exchangeAvailable") + val exchangeAvailable: Boolean +) \ No newline at end of file diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/models/response/ExchangeDataResponse.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/models/response/ExchangeDataResponse.kt new file mode 100644 index 0000000000..96ccbd9b14 --- /dev/null +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/models/response/ExchangeDataResponse.kt @@ -0,0 +1,41 @@ +package com.tangem.feature.swap.models.response + +import com.squareup.moshi.Json +import java.math.BigDecimal + +data class ExchangeDataResponse( + @Json(name = "toAmount") + val toAmount: BigDecimal, + + @Json(name = "txType") + val txType: TxType, + + @Json(name = "txId") + val txId: String, // inner tangem-express transaction id + + @Json(name = "txFrom") + val txFrom: String?, // account for debiting tokens (same as toAddress) if DEX, null if CEX + + @Json(name = "txTo") + val txTo: String, // swap smart-contract address if DEX, address for sending transaction if CEX + + @Json(name = "txData") + val txData: String?, // transaction data if DEX, null if CEX + + @Json(name = "txValue") + val txValue: BigDecimal, // amount (same as fromAmount) + + @Json(name = "externalTxId") + val externalTxId: String?, // null if DEX, provider transaction id if CEX + + @Json(name = "externalTxUrl") + val externalTxUrl: String?, // null if DEX, url of provider exchange status page if CEX +) + +enum class TxType { + @Json(name = "send") + SEND, + + @Json(name = "swap") + SWAP, +} \ No newline at end of file diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/models/response/ExchangeProvider.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/models/response/ExchangeProvider.kt new file mode 100644 index 0000000000..432d4cff79 --- /dev/null +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/models/response/ExchangeProvider.kt @@ -0,0 +1,28 @@ +package com.tangem.feature.swap.models.response + +import com.squareup.moshi.Json + +data class ExchangeProvider( + @Json(name = "id") + val id: Int, + + @Json(name = "name") + val name: String, + + @Json(name = "id") + val type: ExchangeProviderType, + + @Json(name = "imageLarge") + val imageLargeUrl: Int, + + @Json(name = "imageSmall") + val imageSmallUrl: Int, +) + +enum class ExchangeProviderType { + @Json(name = "dex") + DEX, + + @Json(name = "cex") + CEX, +} \ No newline at end of file diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/models/response/ExchangeQuoteResponse.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/models/response/ExchangeQuoteResponse.kt new file mode 100644 index 0000000000..686c0e51f6 --- /dev/null +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/models/response/ExchangeQuoteResponse.kt @@ -0,0 +1,12 @@ +package com.tangem.feature.swap.models.response + +import com.squareup.moshi.Json +import java.math.BigDecimal + +data class ExchangeQuoteResponse( + @Json(name = "toAmount") + val toAmount: BigDecimal, + + @Json(name = "allowanceContract") + val allowanceContract: String?, +) \ No newline at end of file diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/models/response/ExchangeResultsResponse.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/models/response/ExchangeResultsResponse.kt new file mode 100644 index 0000000000..6b4db40e4a --- /dev/null +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/models/response/ExchangeResultsResponse.kt @@ -0,0 +1,42 @@ +package com.tangem.feature.swap.models.response + +import com.squareup.moshi.Json + +data class ExchangeResultsResponse( + @Json(name = "status") + val status: ExchangeResultsStatus, + + @Json(name = "externalStatus") + val externalStatus: String, + + @Json(name = "externalTxUrl") + val externalTxUrl: String, + + @Json(name = "error") + val error: ExchangeResultsError?, +) + +enum class ExchangeResultsStatus { + @Json(name = "processing") + PROCESSING, + + @Json(name = "done") + DONE, + + @Json(name = "failed") + FAILED, + + @Json(name = "refunded") + REFUNDED, + + @Json(name = "verificationRequired") + VERIFICATION_REQUIRED, +} + +data class ExchangeResultsError( + @Json(name = "code") + val code: Int, + + @Json(name = "description") + val description: String, +) \ No newline at end of file diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/models/response/SwapPair.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/models/response/SwapPair.kt new file mode 100644 index 0000000000..4ab2642970 --- /dev/null +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/models/response/SwapPair.kt @@ -0,0 +1,31 @@ +package com.tangem.feature.swap.models.response + +import com.squareup.moshi.Json + +data class SwapPair( + @Json(name = "from") + val from: String, + + @Json(name = "to") + val to: String, + + @Json(name = "providers") + val providers: List, + +) + +data class SwapPairProvider( + @Json(name = "providerId") + val providerId: Int, + + @Json(name = "providerId") + val rateType: RateType, +) + +enum class RateType { + @Json(name = "float") + FLOAT, + + @Json(name = "fixed") + FIXED, +} \ No newline at end of file