From 94c5cac77b12d6e13ee122febf95b8547e08f927 Mon Sep 17 00:00:00 2001 From: Joey Harward Date: Tue, 20 Apr 2021 16:43:13 -0400 Subject: [PATCH 1/8] swap pool init --- .../java/com/metallicus/protonsdk/Proton.kt | 48 ++++++++++++++++++ .../metallicus/protonsdk/model/SwapPool.kt | 49 +++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 protonsdk/src/main/java/com/metallicus/protonsdk/model/SwapPool.kt diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt index 06c4a600..49417ef2 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt @@ -23,6 +23,7 @@ package com.metallicus.protonsdk import android.content.Context import androidx.lifecycle.* +import com.google.gson.Gson import com.google.gson.JsonObject import com.metallicus.protonsdk.api.TableRowsIndexPosition import com.metallicus.protonsdk.common.* @@ -862,6 +863,53 @@ class Proton private constructor(context: Context) { } } + fun getSwapPools(): LiveData>> = liveData { + emit(Resource.loading()) + + try { + val resource = getTableRows( + "proton.swaps", + "proton.swaps", + "pools", + "", + "", + 250//, + //TableRowsIndexPosition.SECONDARY.indexPositionName + ) + when (resource.status) { + Status.SUCCESS -> { + val swapPools = mutableListOf() + + val gson = Gson() + + resource.data?.let { tableJson -> + val rows = tableJson.get("rows").asJsonArray + rows.forEach { + val swapPoolJsonObject = it.asJsonObject + + val swapPool = gson.fromJson(swapPoolJsonObject, SwapPool::class.java) + + swapPools.add(swapPool) + } + } + + emit(Resource.success(swapPools)) + } + Status.ERROR -> { + val error: Resource> = Resource.error(resource.message.orEmpty(), resource.code ?: -1) + emit(error) + } + Status.LOADING -> { } + } + } catch (e: ProtonException) { + val error: Resource> = Resource.error(e) + emit(error) + } catch (e: Exception) { + val error: Resource> = Resource.error(e.localizedMessage.orEmpty()) + emit(error) + } + } + suspend fun getTableRows( scope: String, code: String, diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/model/SwapPool.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/model/SwapPool.kt new file mode 100644 index 00000000..68b51143 --- /dev/null +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/model/SwapPool.kt @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021 Proton Chain LLC, Delaware + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.metallicus.protonsdk.model + +import com.google.gson.annotations.SerializedName + +data class SwapPool( + @SerializedName("lt_symbol") val symbol: String, + @SerializedName("creator") val creator: String, + @SerializedName("memo") val memo: String, + @SerializedName("pool1")val pool1: SwapPoolAsset, + @SerializedName("pool2") val pool2: SwapPoolAsset, + @SerializedName("hash") val hash: String, + @SerializedName("fee") val fee: SwapPoolFee, + @SerializedName("active") val active: Int, + @SerializedName("reserved") val reserved: Int +) { + +} + +data class SwapPoolAsset( + @SerializedName("quantity") val quantity: String, + @SerializedName("contract") val contract: String +) + +data class SwapPoolFee( + @SerializedName("exchange_fee") val exchangeFee: Long, + @SerializedName("add_liquidity_fee") val addLiquidityFee: Long, + @SerializedName("remove_liquidity_fee") val removeLiquidityFee: Long +) \ No newline at end of file From 52d8c1d2f5d8b43c4715e679088df90ed2294562 Mon Sep 17 00:00:00 2001 From: Joey Harward Date: Mon, 26 Apr 2021 12:15:03 -0400 Subject: [PATCH 2/8] swap pool updates simplifying token currency balances adding token contract map access --- buildSrc/src/main/kotlin/Dependencies.kt | 4 +- .../com/metallicus/protonsdk/ActionsModule.kt | 18 +- .../protonsdk/CurrencyBalancesModule.kt | 53 ++++-- .../java/com/metallicus/protonsdk/Proton.kt | 169 ++++++++++++------ .../protonsdk/TokenContractsModule.kt | 6 +- .../com/metallicus/protonsdk/db/ProtonDb.kt | 6 +- .../protonsdk/model/CurrencyBalance.kt | 13 +- .../metallicus/protonsdk/model/SwapPool.kt | 29 ++- .../protonsdk/model/TokenCurrencyBalance.kt | 12 +- 9 files changed, 197 insertions(+), 113 deletions(-) diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index e70ffaa8..37fd3f20 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -23,8 +23,8 @@ const val kotlinVersion = "1.4.32" const val orchidVersion = "0.21.1" object ProtonSdk { - const val versionCode = 38 - const val versionName = "0.9.5" + const val versionCode = 39 + const val versionName = "0.9.6" } object BuildPlugins { diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/ActionsModule.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/ActionsModule.kt index 99aee0e8..5a0b7952 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/ActionsModule.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/ActionsModule.kt @@ -309,12 +309,18 @@ class ActionsModule { suspend fun signAndPushTransaction(chainUrl: String, pin: String, actions: List): Resource { return try { val signedTransactionResource = signTransaction(chainUrl, pin, actions) - if (signedTransactionResource.status == Status.SUCCESS) { - signedTransactionResource.data?.let { - pushTransaction(chainUrl, it) - } ?: Resource.error("No SignedTransaction") - } else { - Resource.error(signedTransactionResource.message.orEmpty(), signedTransactionResource.code ?: -1) + when (signedTransactionResource.status) { + Status.SUCCESS -> { + signedTransactionResource.data?.let { + pushTransaction(chainUrl, it) + } ?: Resource.error("No SignedTransaction") + } + Status.ERROR -> { + Resource.error(signedTransactionResource.message.orEmpty(), signedTransactionResource.code ?: -1) + } + Status.LOADING -> { + Resource.loading() + } } } catch (e: Exception) { Resource.error(e.localizedMessage.orEmpty()) diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/CurrencyBalancesModule.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/CurrencyBalancesModule.kt index aa18a8f6..1c20ef7e 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/CurrencyBalancesModule.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/CurrencyBalancesModule.kt @@ -61,23 +61,17 @@ class CurrencyBalancesModule { tokenContract.getSymbol() == it.asJsonObject.get("symbol").asString }?.asJsonObject - val tokenContractId = tokenContract.id + val currencyBalance = CurrencyBalance(tokenContract.contract, tokenContract.getSymbol()) tokenJsonObject?.let { token -> - val code = token.get("contract").asString - val symbol = token.get("symbol").asString val amount = token.get("amount").asString - val currencyBalance = CurrencyBalance(code, symbol, amount) - currencyBalance.tokenContractId = tokenContractId - currencyBalance.accountName = accountName - - currencyBalanceRepository.addCurrencyBalance(currencyBalance) + currencyBalance.amount = amount } - val tokenCurrencyBalances = currencyBalanceRepository.getTokenCurrencyBalance(accountName, tokenContractId) + val tokenCurrencyBalance = TokenCurrencyBalance(tokenContract, currencyBalance) - Resource.success(tokenCurrencyBalances) + Resource.success(tokenCurrencyBalance) } else { val msg = balancesResponse.errorBody()?.string() val errorMsg = if (msg.isNullOrEmpty()) { @@ -96,13 +90,40 @@ class CurrencyBalancesModule { suspend fun getTokenCurrencyBalances( hyperionHistoryUrl: String, accountName: String, - tokenContractsMap: Map): Resource> { + tokenContractsMap: Map): Resource> { return try { val balancesResponse = currencyBalanceRepository.fetchCurrencyBalances(hyperionHistoryUrl, accountName) if (balancesResponse.isSuccessful) { val jsonObject = balancesResponse.body() val tokenArray = jsonObject?.getAsJsonArray("tokens") + + + + + val currencyBalancesMap = tokenArray?.associateBy { + val token = it.asJsonObject + "${token.get("contract")}:${token.get("symbol")}" + } + + val tokenCurrencyBalances = mutableListOf() + + tokenContractsMap.forEach { tokenContractMapEntry -> + val tokenContract = tokenContractMapEntry.value + val currencyBalance = CurrencyBalance(tokenContract.contract, tokenContract.getSymbol()) + + val tokenCurrencyBalance = TokenCurrencyBalance(tokenContract, currencyBalance) + tokenCurrencyBalances.add(tokenCurrencyBalance) + } + + + + + + + + + tokenArray?.forEach { val token = it.asJsonObject val code = token.get("contract").asString @@ -113,10 +134,8 @@ class CurrencyBalancesModule { if (tokenContractsMap.containsKey("$code:$symbol")) { val currencyBalance = CurrencyBalance(code, symbol, amount) - currencyBalance.tokenContractId = tokenContractId - currencyBalance.accountName = accountName - currencyBalanceRepository.addCurrencyBalance(currencyBalance) + //currencyBalanceRepository.addCurrencyBalance(currencyBalance) } else { val precision = token.get("precision").asInt val precisionSymbol = "$precision,$symbol" @@ -134,14 +153,12 @@ class CurrencyBalancesModule { tokenContractRepository.addTokenContract(tokenContract) val currencyBalance = CurrencyBalance(code, symbol, amount) - currencyBalance.tokenContractId = tokenContractId - currencyBalance.accountName = accountName - currencyBalanceRepository.addCurrencyBalance(currencyBalance) + //currencyBalanceRepository.addCurrencyBalance(currencyBalance) } } - val tokenCurrencyBalances = currencyBalanceRepository.getTokenCurrencyBalances(accountName) + //val tokenCurrencyBalances = currencyBalanceRepository.getTokenCurrencyBalances(accountName) Resource.success(tokenCurrencyBalances) } else { diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt index 49417ef2..3d4fa1ce 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt @@ -164,11 +164,28 @@ class Proton private constructor(context: Context) { } } - fun getTokenContracts(): LiveData>> = liveData { + private suspend fun getTokenContractsMapAsync(): Map { + val tokenContracts = getTokenContractsAsync() + return tokenContracts.associateBy { "${it.contract}:${it.getSymbol()}" } + } + + fun getTokenContracts(updateExchangeRates: Boolean = false): LiveData>> = liveData { emit(Resource.loading()) try { val tokenContracts = getTokenContractsAsync() + + if (updateExchangeRates) { + val activeAccount = getActiveAccountAsync() + + val tokenContractsMap = tokenContracts.associateBy { "${it.contract}:${it.getSymbol()}" } + + val exchangeRateUrl = + activeAccount.chainProvider.protonChainUrl + activeAccount.chainProvider.exchangeRatePath + + tokenContractsModule.updateExchangeRates(exchangeRateUrl, tokenContractsMap) + } + emit(Resource.success(tokenContracts)) } catch (e: ProtonException) { val error: Resource> = Resource.error(e) @@ -179,6 +196,31 @@ class Proton private constructor(context: Context) { } } + fun getTokenContractsMap(updateExchangeRates: Boolean = false): LiveData>> = liveData { + emit(Resource.loading()) + + try { + val tokenContractsMap = getTokenContractsMapAsync() + + if (updateExchangeRates) { + val activeAccount = getActiveAccountAsync() + + val exchangeRateUrl = + activeAccount.chainProvider.protonChainUrl + activeAccount.chainProvider.exchangeRatePath + + tokenContractsModule.updateExchangeRates(exchangeRateUrl, tokenContractsMap) + } + + emit(Resource.success(tokenContractsMap)) + } catch (e: ProtonException) { + val error: Resource> = Resource.error(e) + emit(error) + } catch (e: Exception) { + val error: Resource> = Resource.error(e.localizedMessage.orEmpty()) + emit(error) + } + } + fun generatePrivateKey(): Pair { val privateKey = EosPrivateKey() val publicKeyStr = privateKey.publicKey.toString() @@ -351,44 +393,13 @@ class Proton private constructor(context: Context) { } } - fun getTokenContractPrices(): LiveData>> = liveData { - emit(Resource.loading()) - - try { - val tokenContracts = getTokenContractsAsync() - val activeAccount = getActiveAccountAsync() - - val tokenContractsMap = mutableMapOf() - tokenContracts.forEach { - tokenContractsMap["${it.contract}:${it.getSymbol()}"] = it.id - } - - val exchangeRateUrl = activeAccount.chainProvider.protonChainUrl + activeAccount.chainProvider.exchangeRatePath - - tokenContractsModule.updateExchangeRates(exchangeRateUrl, tokenContractsMap) - - emit(Resource.success(getTokenContractsAsync())) - } catch (e: ProtonException) { - val error: Resource> = Resource.error(e) - emit(error) - } catch (e: Exception) { - val error: Resource> = Resource.error(e.localizedMessage.orEmpty()) - emit(error) - } - } - fun getActiveAccountTokenBalances(): LiveData>> = liveData { emit(Resource.loading()) try { - val tokenContracts = getTokenContractsAsync() + val tokenContractsMap = getTokenContractsMapAsync() val activeAccount = getActiveAccountAsync() - val tokenContractsMap = mutableMapOf() - tokenContracts.forEach { - tokenContractsMap["${it.contract}:${it.getSymbol()}"] = it.id - } - val exchangeRateUrl = activeAccount.chainProvider.protonChainUrl + activeAccount.chainProvider.exchangeRatePath tokenContractsModule.updateExchangeRates(exchangeRateUrl, tokenContractsMap) @@ -863,49 +874,91 @@ class Proton private constructor(context: Context) { } } - fun getSwapPools(): LiveData>> = liveData { + fun getSwapPoolMap(): LiveData>> = liveData { emit(Resource.loading()) try { - val resource = getTableRows( - "proton.swaps", - "proton.swaps", - "pools", - "", - "", - 250//, - //TableRowsIndexPosition.SECONDARY.indexPositionName - ) - when (resource.status) { - Status.SUCCESS -> { - val swapPools = mutableListOf() + val tokenContractsMap = getTokenContractsMapAsync() + val activeAccount = getActiveAccountAsync() - val gson = Gson() + val exchangeRateUrl = activeAccount.chainProvider.protonChainUrl + activeAccount.chainProvider.exchangeRatePath + + tokenContractsModule.updateExchangeRates(exchangeRateUrl, tokenContractsMap) - resource.data?.let { tableJson -> - val rows = tableJson.get("rows").asJsonArray - rows.forEach { - val swapPoolJsonObject = it.asJsonObject + val tokenBalancesResource = + currencyBalancesModule.getTokenCurrencyBalances( + activeAccount.chainProvider.hyperionHistoryUrl, + activeAccount.account.accountName, + tokenContractsMap) - val swapPool = gson.fromJson(swapPoolJsonObject, SwapPool::class.java) + when (tokenBalancesResource.status) { + Status.SUCCESS -> { + tokenBalancesResource.data?.let { tokenCurrencyBalances -> + val tokenCurrencyBalancesMap = tokenCurrencyBalances.associateBy { + "${it.tokenContract.contract}:${it.tokenContract.getSymbol()}" + } - swapPools.add(swapPool) + val tableRowsResource = getTableRows( + "proton.swaps", + "proton.swaps", + "pools", + "", + "", + 250//, + //TableRowsIndexPosition.SECONDARY.indexPositionName + ) + when (tableRowsResource.status) { + Status.SUCCESS -> { + val poolMap = mutableMapOf() + + val gson = Gson() + + tableRowsResource.data?.let { tableJson -> + val rows = tableJson.get("rows").asJsonArray + rows.forEach { + val swapPoolJsonObject = it.asJsonObject + + val swapPool = gson.fromJson(swapPoolJsonObject, SwapPool::class.java) + + poolMap[swapPool.getPool1Symbol()] = swapPool + } + } + + val poolGraph = mutableMapOf() + + poolMap.forEach { + val symbol = it.key + val rate = it.value.getPool1Rate() + val contract = it.value.getPool1Contract() + + tokenCurrencyBalancesMap["$contract:$symbol"]?.let { tokenCurrencyBalance -> + poolGraph[symbol] = SwapPoolMapEntry(rate, tokenCurrencyBalance) + } + } + + emit(Resource.success(poolGraph)) + } + Status.ERROR -> { + val error: Resource> = + Resource.error(tableRowsResource.message.orEmpty(), tableRowsResource.code ?: -1) + emit(error) + } + Status.LOADING -> { } } } - - emit(Resource.success(swapPools)) } Status.ERROR -> { - val error: Resource> = Resource.error(resource.message.orEmpty(), resource.code ?: -1) + val error: Resource> = + Resource.error(tokenBalancesResource.message.orEmpty(), tokenBalancesResource.code ?: -1) emit(error) } Status.LOADING -> { } } } catch (e: ProtonException) { - val error: Resource> = Resource.error(e) + val error: Resource> = Resource.error(e) emit(error) } catch (e: Exception) { - val error: Resource> = Resource.error(e.localizedMessage.orEmpty()) + val error: Resource> = Resource.error(e.localizedMessage.orEmpty()) emit(error) } } diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/TokenContractsModule.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/TokenContractsModule.kt index a794db40..758ebab2 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/TokenContractsModule.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/TokenContractsModule.kt @@ -57,7 +57,7 @@ class TokenContractsModule { return tokenContractRepository.getTokenContracts() } - suspend fun updateExchangeRates(exchangeRatesUrl: String, tokenContractIdsMap: Map) { + suspend fun updateExchangeRates(exchangeRatesUrl: String, tokenContractsMap: Map) { try { val exchangeRatesResponse = tokenContractRepository.fetchExchangeRates(exchangeRatesUrl) if (exchangeRatesResponse.isSuccessful) { @@ -78,8 +78,8 @@ class TokenContractsModule { ratesMap[currency] = rate } - val tokenContractId = tokenContractIdsMap.getOrElse("$contract:$symbol") { null } - if (tokenContractId != null) { + val tokenContractId = "$contract:$symbol" + if (tokenContractsMap.containsKey(tokenContractId)) { tokenContractRepository.updateRates(tokenContractId, ratesMap, rank) } } diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/db/ProtonDb.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/db/ProtonDb.kt index ed7b12e9..abe6438d 100755 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/db/ProtonDb.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/db/ProtonDb.kt @@ -32,10 +32,10 @@ import com.metallicus.protonsdk.model.* TokenContract::class, Account::class, //AccountContact::class, - CurrencyBalance::class, + //CurrencyBalance::class, Action::class, ESRSession::class], - version = 31, + version = 32, exportSchema = false ) @TypeConverters(DefaultTypeConverters::class, EOSTypeConverters::class, ProtonTypeConverters::class) @@ -43,7 +43,7 @@ abstract class ProtonDb : RoomDatabase() { abstract fun chainProviderDao(): ChainProviderDao abstract fun tokenContractDao(): TokenContractDao abstract fun accountDao(): AccountDao - abstract fun currencyBalanceDao(): CurrencyBalanceDao +// abstract fun currencyBalanceDao(): CurrencyBalanceDao // abstract fun accountContactDao(): AccountContactDao abstract fun actionDao(): ActionDao abstract fun esrSessionDao(): ESRSessionDao diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/model/CurrencyBalance.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/model/CurrencyBalance.kt index 2318e584..5079785a 100755 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/model/CurrencyBalance.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/model/CurrencyBalance.kt @@ -21,24 +21,13 @@ */ package com.metallicus.protonsdk.model -import androidx.annotation.NonNull -import androidx.room.* import com.google.gson.annotations.SerializedName -@Entity( - indices = [(Index("tokenContractId", "accountName", "contract", "symbol"))], - primaryKeys = ["tokenContractId", "accountName"]) data class CurrencyBalance( @SerializedName("contract") val contract: String, @SerializedName("symbol") val symbol: String, - @SerializedName("amount") val amount: String + @SerializedName("amount") var amount: String = "0.0" ) { - @NonNull - lateinit var tokenContractId: String - - @NonNull - lateinit var accountName: String - fun getAmountDouble(): Double { return amount.toDouble() } diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/model/SwapPool.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/model/SwapPool.kt index 68b51143..7c50f7c2 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/model/SwapPool.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/model/SwapPool.kt @@ -27,14 +27,36 @@ data class SwapPool( @SerializedName("lt_symbol") val symbol: String, @SerializedName("creator") val creator: String, @SerializedName("memo") val memo: String, - @SerializedName("pool1")val pool1: SwapPoolAsset, + @SerializedName("pool1") val pool1: SwapPoolAsset, @SerializedName("pool2") val pool2: SwapPoolAsset, @SerializedName("hash") val hash: String, @SerializedName("fee") val fee: SwapPoolFee, @SerializedName("active") val active: Int, @SerializedName("reserved") val reserved: Int ) { + fun getPool1Symbol(): String { + return memo.split("<>")[0] + } + fun getPool2Symbol(): String { + return memo.split("<>")[1] + } + + fun getPool1Amount(): Double { + return pool1.quantity.substringBefore(" ").toDouble() + } + + fun getPool2Amount(): Double { + return pool2.quantity.substringBefore(" ").toDouble() + } + + fun getPool1Rate(): Double { + return getPool1Amount() / getPool2Amount() + } + + fun getPool1Contract(): String { + return pool1.contract + } } data class SwapPoolAsset( @@ -46,4 +68,9 @@ data class SwapPoolFee( @SerializedName("exchange_fee") val exchangeFee: Long, @SerializedName("add_liquidity_fee") val addLiquidityFee: Long, @SerializedName("remove_liquidity_fee") val removeLiquidityFee: Long +) + +data class SwapPoolMapEntry( + val rate: Double, + val tokenCurrencyBalance: TokenCurrencyBalance ) \ No newline at end of file diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/model/TokenCurrencyBalance.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/model/TokenCurrencyBalance.kt index e45cdf61..73a47dbe 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/model/TokenCurrencyBalance.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/model/TokenCurrencyBalance.kt @@ -21,20 +21,12 @@ */ package com.metallicus.protonsdk.model -import androidx.room.Embedded -import androidx.room.Relation import java.text.NumberFormat import java.util.* data class TokenCurrencyBalance( - @Embedded - val currencyBalance: CurrencyBalance, - - @Relation( - parentColumn = "tokenContractId", - entityColumn = "id" - ) - val tokenContract: TokenContract + val tokenContract: TokenContract, + val currencyBalance: CurrencyBalance ) { fun isSystemToken(): Boolean { return (tokenContract.isSystemToken) From 6109926a7ec6eb5506d40a1a4bd5c008ae642f8e Mon Sep 17 00:00:00 2001 From: Joey Harward Date: Mon, 26 Apr 2021 23:18:04 -0400 Subject: [PATCH 3/8] allowing zero balance currency balances no longer saving currency balances to db --- .../protonsdk/CurrencyBalancesModule.kt | 112 +++++++++--------- .../java/com/metallicus/protonsdk/Proton.kt | 5 +- .../protonsdk/TokenContractsModule.kt | 2 + .../com/metallicus/protonsdk/WorkersModule.kt | 5 +- .../protonsdk/db/CurrencyBalanceDao.kt | 49 -------- .../metallicus/protonsdk/di/ProtonModule.kt | 10 +- .../repository/CurrencyBalanceRepository.kt | 19 --- 7 files changed, 68 insertions(+), 134 deletions(-) delete mode 100755 protonsdk/src/main/java/com/metallicus/protonsdk/db/CurrencyBalanceDao.kt diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/CurrencyBalancesModule.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/CurrencyBalancesModule.kt index 1c20ef7e..ebb6dd36 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/CurrencyBalancesModule.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/CurrencyBalancesModule.kt @@ -90,76 +90,76 @@ class CurrencyBalancesModule { suspend fun getTokenCurrencyBalances( hyperionHistoryUrl: String, accountName: String, - tokenContractsMap: Map): Resource> { + tokenContractsMap: Map, + addEmptyTokens: Boolean = false + ): Resource> { return try { val balancesResponse = currencyBalanceRepository.fetchCurrencyBalances(hyperionHistoryUrl, accountName) if (balancesResponse.isSuccessful) { - val jsonObject = balancesResponse.body() - val tokenArray = jsonObject?.getAsJsonArray("tokens") - - - - - - val currencyBalancesMap = tokenArray?.associateBy { - val token = it.asJsonObject - "${token.get("contract")}:${token.get("symbol")}" - } - val tokenCurrencyBalances = mutableListOf() - tokenContractsMap.forEach { tokenContractMapEntry -> - val tokenContract = tokenContractMapEntry.value - val currencyBalance = CurrencyBalance(tokenContract.contract, tokenContract.getSymbol()) - - val tokenCurrencyBalance = TokenCurrencyBalance(tokenContract, currencyBalance) - tokenCurrencyBalances.add(tokenCurrencyBalance) - } - - - - - - - - - - tokenArray?.forEach { - val token = it.asJsonObject - val code = token.get("contract").asString - val symbol = token.get("symbol").asString - val amount = token.get("amount").asString + balancesResponse.body()?.getAsJsonArray("tokens")?.let { tokensArray -> + val currencyBalancesMap = tokensArray.associateBy { + val token = it.asJsonObject + val contract = token.get("contract").asString + val symbol = token.get("symbol").asString + "$contract:$symbol" + } - val tokenContractId = "$code:$symbol" + tokenContractsMap.forEach { tokenContractMapEntry -> + val tokenContract = tokenContractMapEntry.value + val contract = tokenContract.contract + val symbol = tokenContract.getSymbol() - if (tokenContractsMap.containsKey("$code:$symbol")) { - val currencyBalance = CurrencyBalance(code, symbol, amount) + val currencyBalanceKey = "$contract:$symbol" - //currencyBalanceRepository.addCurrencyBalance(currencyBalance) - } else { - val precision = token.get("precision").asInt - val precisionSymbol = "$precision,$symbol" - val tokenContract = TokenContract( - id = tokenContractId, - contract = code, - name = symbol, - url = "", - description = "", - iconUrl = "", - precisionSymbol = precisionSymbol, - blacklisted = 0) - tokenContract.rates = mapOf(Pair("USD", TokenContractRate())) + val currencyBalance = CurrencyBalance(contract, symbol) - tokenContractRepository.addTokenContract(tokenContract) + if (currencyBalancesMap.containsKey(currencyBalanceKey)) { + val token = currencyBalancesMap[currencyBalanceKey]?.asJsonObject + currencyBalance.amount = token?.get("amount")?.asString.orEmpty() - val currencyBalance = CurrencyBalance(code, symbol, amount) + val tokenCurrencyBalance = TokenCurrencyBalance(tokenContract, currencyBalance) + tokenCurrencyBalances.add(tokenCurrencyBalance) + } else if (addEmptyTokens) { + val tokenCurrencyBalance = TokenCurrencyBalance(tokenContract, currencyBalance) + tokenCurrencyBalances.add(tokenCurrencyBalance) + } + } - //currencyBalanceRepository.addCurrencyBalance(currencyBalance) + // add custom tokens + currencyBalancesMap.forEach { currencyBalancesMapEntry -> + val token = currencyBalancesMapEntry.value.asJsonObject + val contract = token.get("contract").asString + val symbol = token.get("symbol").asString + + val currencyBalanceKey = "$contract:$symbol" + + if (!tokenContractsMap.containsKey(currencyBalanceKey)) { + val amount = token.get("amount").asString + val precision = token.get("precision").asInt + val precisionSymbol = "$precision,$symbol" + val tokenContract = TokenContract( + id = currencyBalanceKey, + contract = contract, + name = symbol, + url = "", + description = "", + iconUrl = "", + precisionSymbol = precisionSymbol, + blacklisted = 0) + tokenContract.rates = mapOf(Pair("USD", TokenContractRate())) + + tokenContractRepository.addTokenContract(tokenContract) + + val currencyBalance = CurrencyBalance(contract, symbol, amount) + + val tokenCurrencyBalance = TokenCurrencyBalance(tokenContract, currencyBalance) + tokenCurrencyBalances.add(tokenCurrencyBalance) + } } } - //val tokenCurrencyBalances = currencyBalanceRepository.getTokenCurrencyBalances(accountName) - Resource.success(tokenCurrencyBalances) } else { val msg = balancesResponse.errorBody()?.string() diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt index 3d4fa1ce..57a887e9 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt @@ -393,7 +393,7 @@ class Proton private constructor(context: Context) { } } - fun getActiveAccountTokenBalances(): LiveData>> = liveData { + fun getActiveAccountTokenBalances(addEmptyTokens: Boolean = false): LiveData>> = liveData { emit(Resource.loading()) try { @@ -408,7 +408,8 @@ class Proton private constructor(context: Context) { currencyBalancesModule.getTokenCurrencyBalances( activeAccount.chainProvider.hyperionHistoryUrl, activeAccount.account.accountName, - tokenContractsMap) + tokenContractsMap, + addEmptyTokens) emit(tokenBalances) } catch (e: ProtonException) { diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/TokenContractsModule.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/TokenContractsModule.kt index 758ebab2..0320c5e1 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/TokenContractsModule.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/TokenContractsModule.kt @@ -80,6 +80,8 @@ class TokenContractsModule { val tokenContractId = "$contract:$symbol" if (tokenContractsMap.containsKey(tokenContractId)) { + tokenContractsMap[tokenContractId]?.rates = ratesMap + tokenContractRepository.updateRates(tokenContractId, ratesMap, rank) } } diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/WorkersModule.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/WorkersModule.kt index 2c0289f7..c652f762 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/WorkersModule.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/WorkersModule.kt @@ -27,7 +27,6 @@ import androidx.work.* import com.metallicus.protonsdk.common.Prefs import com.metallicus.protonsdk.di.DaggerInjector import com.metallicus.protonsdk.workers.* -import java.util.concurrent.TimeUnit import javax.inject.Inject /** @@ -97,11 +96,11 @@ class WorkersModule { } // start periodic worker to update exchange rates - val updateTokenContractRates = PeriodicWorkRequest.Builder(UpdateTokenContractRatesWorker::class.java, 15L, TimeUnit.MINUTES) + /*val updateTokenContractRates = PeriodicWorkRequest.Builder(UpdateTokenContractRatesWorker::class.java, 15L, TimeUnit.MINUTES) .setConstraints(constraints) .setInitialDelay(1L, TimeUnit.MINUTES) .build() - workManager.enqueueUniquePeriodicWork(UPDATE_RATES, ExistingPeriodicWorkPolicy.REPLACE, updateTokenContractRates) + workManager.enqueueUniquePeriodicWork(UPDATE_RATES, ExistingPeriodicWorkPolicy.REPLACE, updateTokenContractRates)*/ } fun onInitChainProvider(callback: (Boolean, Data?) -> Unit) { diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/db/CurrencyBalanceDao.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/db/CurrencyBalanceDao.kt deleted file mode 100755 index 49aa1be6..00000000 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/db/CurrencyBalanceDao.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2021 Proton Chain LLC, Delaware - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.metallicus.protonsdk.db - -import androidx.room.* -import com.metallicus.protonsdk.model.CurrencyBalance -import com.metallicus.protonsdk.model.TokenCurrencyBalance - -/** - * Interface for database access for [CurrencyBalance] related operations - */ -@Dao -interface CurrencyBalanceDao { - @Insert(onConflict = OnConflictStrategy.REPLACE) - suspend fun insert(currencyBalance: CurrencyBalance) - - @Query("UPDATE currencyBalance SET amount = :amount WHERE accountName = :accountName AND contract = :contract AND symbol = :symbol") - suspend fun updateAmount(accountName: String, contract: String, symbol: String, amount: String) - - @Transaction - @Query("SELECT * FROM currencyBalance WHERE accountName = :accountName AND tokenContractId = :tokenContractId") - suspend fun findByTokenContract(accountName: String, tokenContractId: String): TokenCurrencyBalance - - @Transaction - @Query("SELECT * FROM currencyBalance WHERE accountName = :accountName") - suspend fun findByAccountName(accountName: String): List - - @Query("DELETE FROM currencyBalance") - suspend fun removeAll() -} \ No newline at end of file diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/di/ProtonModule.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/di/ProtonModule.kt index f7c83d74..45eed0fe 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/di/ProtonModule.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/di/ProtonModule.kt @@ -75,11 +75,11 @@ class ProtonModule { // return db.accountContactDao() // } - @Singleton - @Provides - fun provideCurrencyBalanceDao(db: ProtonDb): CurrencyBalanceDao { - return db.currencyBalanceDao() - } +// @Singleton +// @Provides +// fun provideCurrencyBalanceDao(db: ProtonDb): CurrencyBalanceDao { +// return db.currencyBalanceDao() +// } @Singleton @Provides diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/repository/CurrencyBalanceRepository.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/repository/CurrencyBalanceRepository.kt index 9b563870..97d26934 100755 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/repository/CurrencyBalanceRepository.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/repository/CurrencyBalanceRepository.kt @@ -23,34 +23,15 @@ package com.metallicus.protonsdk.repository import com.google.gson.JsonObject import com.metallicus.protonsdk.api.ProtonChainService -import com.metallicus.protonsdk.db.CurrencyBalanceDao -import com.metallicus.protonsdk.model.* import retrofit2.Response import javax.inject.Inject import javax.inject.Singleton @Singleton class CurrencyBalanceRepository @Inject constructor( - private val currencyBalanceDao: CurrencyBalanceDao, private val protonChainService: ProtonChainService ) { - suspend fun removeAll() { - currencyBalanceDao.removeAll() - } - - suspend fun addCurrencyBalance(currencyBalance: CurrencyBalance) { - currencyBalanceDao.insert(currencyBalance) - } - suspend fun fetchCurrencyBalances(chainUrl: String, accountName: String): Response { return protonChainService.getCurrencyBalances("$chainUrl/v2/state/get_tokens", accountName) } - - suspend fun getTokenCurrencyBalance(accountName: String, tokenContractId: String): TokenCurrencyBalance { - return currencyBalanceDao.findByTokenContract(accountName, tokenContractId) - } - - suspend fun getTokenCurrencyBalances(accountName: String): List { - return currencyBalanceDao.findByAccountName(accountName) - } } From f57c05eca0aefd64bd2110ae0ffe2e8dbabcf330 Mon Sep 17 00:00:00 2001 From: Joey Harward Date: Sat, 1 May 2021 23:54:19 -0400 Subject: [PATCH 4/8] bump version --- buildSrc/src/main/kotlin/Dependencies.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index a9416ce1..c40bbb66 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -23,8 +23,8 @@ const val kotlinVersion = "1.4.32" const val orchidVersion = "0.21.1" object ProtonSdk { - const val versionCode = 40 - const val versionName = "1.0.2" + const val versionCode = 41 + const val versionName = "1.0.3" } object BuildPlugins { From f0f37494900be1e902bc79dafe9510e1867d42b3 Mon Sep 17 00:00:00 2001 From: Joey Harward Date: Tue, 4 May 2021 20:15:37 -0400 Subject: [PATCH 5/8] fixed swap pool map --- protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt index 21c0e4c2..b0b97ee5 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt @@ -933,7 +933,8 @@ class Proton private constructor(context: Context) { currencyBalancesModule.getTokenCurrencyBalances( activeAccount.chainProvider.hyperionHistoryUrl, activeAccount.account.accountName, - tokenContractsMap) + tokenContractsMap, + true) when (tokenBalancesResource.status) { Status.SUCCESS -> { From bc1699e4e86a9f764fffe83cd9845b06e62df140 Mon Sep 17 00:00:00 2001 From: Joey Harward Date: Thu, 13 May 2021 12:36:42 -0400 Subject: [PATCH 6/8] simplified swap pool fetching --- README.md | 2 +- .../java/com/metallicus/protonsdk/Proton.kt | 37 +++++++------- .../metallicus/protonsdk/model/SwapPool.kt | 48 +++++++++++++------ protonsdk/src/main/res/values/strings.xml | 4 ++ 4 files changed, 57 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index ff35bee6..e37708be 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Then add the following dependency to your module's build.gradle ```gradle dependencies { ... - implementation "com.metallicus:protonsdk:1.0.2" + implementation "com.metallicus:protonsdk:{latest_version}" } ``` diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt index b0b97ee5..8cc53f03 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt @@ -918,7 +918,7 @@ class Proton private constructor(context: Context) { } } - fun getSwapPoolMap(): LiveData>> = liveData { + fun getSwapPools(): LiveData> = liveData { emit(Resource.loading()) try { @@ -954,7 +954,8 @@ class Proton private constructor(context: Context) { ) when (tableRowsResource.status) { Status.SUCCESS -> { - val poolMap = mutableMapOf() + val swapPools = mutableListOf() + val swapPoolTokens = mutableListOf() val gson = Gson() @@ -965,26 +966,26 @@ class Proton private constructor(context: Context) { val swapPool = gson.fromJson(swapPoolJsonObject, SwapPool::class.java) - poolMap[swapPool.getPool1Symbol()] = swapPool - } - } + val pool1 = "${swapPool.getPool1Contract()}:${swapPool.getPool1Symbol()}" + val pool2 = "${swapPool.getPool2Contract()}:${swapPool.getPool2Symbol()}" - val poolGraph = mutableMapOf() + tokenCurrencyBalancesMap[pool1]?.let { tokenCurrencyBalance -> + swapPoolTokens.add(tokenCurrencyBalance) + } + tokenCurrencyBalancesMap[pool2]?.let { tokenCurrencyBalance -> + swapPoolTokens.add(tokenCurrencyBalance) + } - poolMap.forEach { - val symbol = it.key - val rate = it.value.getPool1Rate() - val contract = it.value.getPool1Contract() - - tokenCurrencyBalancesMap["$contract:$symbol"]?.let { tokenCurrencyBalance -> - poolGraph[symbol] = SwapPoolMapEntry(rate, tokenCurrencyBalance) + swapPools.add(swapPool) } } - emit(Resource.success(poolGraph)) + val swapPoolData = SwapPoolData(swapPools, swapPoolTokens.distinct()) + + emit(Resource.success(swapPoolData)) } Status.ERROR -> { - val error: Resource> = + val error: Resource = Resource.error(tableRowsResource.message.orEmpty(), tableRowsResource.code ?: -1) emit(error) } @@ -993,17 +994,17 @@ class Proton private constructor(context: Context) { } } Status.ERROR -> { - val error: Resource> = + val error: Resource = Resource.error(tokenBalancesResource.message.orEmpty(), tokenBalancesResource.code ?: -1) emit(error) } Status.LOADING -> { } } } catch (e: ProtonException) { - val error: Resource> = Resource.error(e) + val error: Resource = Resource.error(e) emit(error) } catch (e: Exception) { - val error: Resource> = Resource.error(e.localizedMessage.orEmpty()) + val error: Resource = Resource.error(e.localizedMessage.orEmpty()) emit(error) } } diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/model/SwapPool.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/model/SwapPool.kt index 7c50f7c2..ee64e47d 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/model/SwapPool.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/model/SwapPool.kt @@ -27,21 +27,13 @@ data class SwapPool( @SerializedName("lt_symbol") val symbol: String, @SerializedName("creator") val creator: String, @SerializedName("memo") val memo: String, - @SerializedName("pool1") val pool1: SwapPoolAsset, - @SerializedName("pool2") val pool2: SwapPoolAsset, + @SerializedName("pool1") var pool1: SwapPoolAsset, + @SerializedName("pool2") var pool2: SwapPoolAsset, @SerializedName("hash") val hash: String, @SerializedName("fee") val fee: SwapPoolFee, @SerializedName("active") val active: Int, @SerializedName("reserved") val reserved: Int ) { - fun getPool1Symbol(): String { - return memo.split("<>")[0] - } - - fun getPool2Symbol(): String { - return memo.split("<>")[1] - } - fun getPool1Amount(): Double { return pool1.quantity.substringBefore(" ").toDouble() } @@ -50,13 +42,39 @@ data class SwapPool( return pool2.quantity.substringBefore(" ").toDouble() } - fun getPool1Rate(): Double { - return getPool1Amount() / getPool2Amount() + fun getPool1Symbol(): String { + return pool1.quantity.substringAfter(" ") + } + + fun getPool2Symbol(): String { + return pool2.quantity.substringAfter(" ") } fun getPool1Contract(): String { return pool1.contract } + + fun getPool2Contract(): String { + return pool2.contract + } + + fun getFee(): Int { + return fee.exchangeFee.toInt() + } + + fun deepCopy(): SwapPool { + return SwapPool( + symbol, + creator, + memo, + SwapPoolAsset(pool1.quantity, pool1.contract), + SwapPoolAsset(pool2.quantity, pool2.contract), + hash, + SwapPoolFee(fee.exchangeFee, fee.addLiquidityFee, fee.removeLiquidityFee), + active, + reserved + ) + } } data class SwapPoolAsset( @@ -70,7 +88,7 @@ data class SwapPoolFee( @SerializedName("remove_liquidity_fee") val removeLiquidityFee: Long ) -data class SwapPoolMapEntry( - val rate: Double, - val tokenCurrencyBalance: TokenCurrencyBalance +data class SwapPoolData( + val swapPools: List, + val swapPoolTokens: List ) \ No newline at end of file diff --git a/protonsdk/src/main/res/values/strings.xml b/protonsdk/src/main/res/values/strings.xml index 2848ed6c..0755ec1a 100755 --- a/protonsdk/src/main/res/values/strings.xml +++ b/protonsdk/src/main/res/values/strings.xml @@ -22,6 +22,10 @@ eosio.proton kycproviders + proton.swaps + proton.swaps + pools + KeyPair already exists! KeyPair does not exist in Keystore Problem during encryption From 51abe7e914838c9f9d03a153e01e9097ec981fc9 Mon Sep 17 00:00:00 2001 From: Joey Harward Date: Sun, 16 May 2021 23:06:52 -0400 Subject: [PATCH 7/8] only fetch active swap pools completely removed UpdateTokenContractRatesWorker --- .../java/com/metallicus/protonsdk/Proton.kt | 23 ++--- .../com/metallicus/protonsdk/WorkersModule.kt | 7 -- .../metallicus/protonsdk/di/WorkerModule.kt | 5 - .../protonsdk/workers/ProtonWorkerFactory.kt | 6 +- .../workers/UpdateTokenContractRatesWorker.kt | 97 ------------------- 5 files changed, 14 insertions(+), 124 deletions(-) delete mode 100644 protonsdk/src/main/java/com/metallicus/protonsdk/workers/UpdateTokenContractRatesWorker.kt diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt index 8cc53f03..d4cc43f9 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt @@ -965,18 +965,19 @@ class Proton private constructor(context: Context) { val swapPoolJsonObject = it.asJsonObject val swapPool = gson.fromJson(swapPoolJsonObject, SwapPool::class.java) - - val pool1 = "${swapPool.getPool1Contract()}:${swapPool.getPool1Symbol()}" - val pool2 = "${swapPool.getPool2Contract()}:${swapPool.getPool2Symbol()}" - - tokenCurrencyBalancesMap[pool1]?.let { tokenCurrencyBalance -> - swapPoolTokens.add(tokenCurrencyBalance) + if (swapPool.active == 1) { + val pool1 = "${swapPool.getPool1Contract()}:${swapPool.getPool1Symbol()}" + val pool2 = "${swapPool.getPool2Contract()}:${swapPool.getPool2Symbol()}" + + tokenCurrencyBalancesMap[pool1]?.let { tokenCurrencyBalance -> + swapPoolTokens.add(tokenCurrencyBalance) + } + tokenCurrencyBalancesMap[pool2]?.let { tokenCurrencyBalance -> + swapPoolTokens.add(tokenCurrencyBalance) + } + + swapPools.add(swapPool) } - tokenCurrencyBalancesMap[pool2]?.let { tokenCurrencyBalance -> - swapPoolTokens.add(tokenCurrencyBalance) - } - - swapPools.add(swapPool) } } diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/WorkersModule.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/WorkersModule.kt index c652f762..0432bc6c 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/WorkersModule.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/WorkersModule.kt @@ -94,13 +94,6 @@ class WorkersModule { .then(initTokenContracts) .enqueue() } - - // start periodic worker to update exchange rates - /*val updateTokenContractRates = PeriodicWorkRequest.Builder(UpdateTokenContractRatesWorker::class.java, 15L, TimeUnit.MINUTES) - .setConstraints(constraints) - .setInitialDelay(1L, TimeUnit.MINUTES) - .build() - workManager.enqueueUniquePeriodicWork(UPDATE_RATES, ExistingPeriodicWorkPolicy.REPLACE, updateTokenContractRates)*/ } fun onInitChainProvider(callback: (Boolean, Data?) -> Unit) { diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/di/WorkerModule.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/di/WorkerModule.kt index 0cc2a1f9..904fc9aa 100755 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/di/WorkerModule.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/di/WorkerModule.kt @@ -45,11 +45,6 @@ abstract class WorkerModule { @WorkerKey(InitActiveAccountWorker::class) abstract fun bindInitActiveAccountWorker(factory: InitActiveAccountWorker.Factory): ChildWorkerFactory - @Binds - @IntoMap - @WorkerKey(UpdateTokenContractRatesWorker::class) - abstract fun bindUpdateTokenContractRatesWorker(factory: UpdateTokenContractRatesWorker.Factory): ChildWorkerFactory - @Binds abstract fun bindWorkerFactory(factory: ProtonWorkerFactory): WorkerFactory } \ No newline at end of file diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/workers/ProtonWorkerFactory.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/workers/ProtonWorkerFactory.kt index 4813c935..57698612 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/workers/ProtonWorkerFactory.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/workers/ProtonWorkerFactory.kt @@ -38,16 +38,14 @@ class ProtonWorkerFactory @Inject constructor( workerParameters: WorkerParameters ): ListenableWorker? { return try { - val factoryEntry = - workerFactory.entries.find { Class.forName(workerClassName).isAssignableFrom(it.key) } + val factoryEntry = workerFactory.entries.find { Class.forName(workerClassName).isAssignableFrom(it.key) } if (factoryEntry != null) { val factoryProvider = factoryEntry.value factoryProvider.get().create(context, workerParameters) } else { // fallback if no factory was found val workerClass = Class.forName(workerClassName).asSubclass(ListenableWorker::class.java) - val constructor = - workerClass.getDeclaredConstructor(Context::class.java, WorkerParameters::class.java) + val constructor = workerClass.getDeclaredConstructor(Context::class.java, WorkerParameters::class.java) constructor.newInstance(context, workerParameters) } } catch (e: ClassNotFoundException) { diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/workers/UpdateTokenContractRatesWorker.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/workers/UpdateTokenContractRatesWorker.kt deleted file mode 100644 index 94d9c2e9..00000000 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/workers/UpdateTokenContractRatesWorker.kt +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2021 Proton Chain LLC, Delaware - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.metallicus.protonsdk.workers - -import android.content.Context -import androidx.work.CoroutineWorker -import androidx.work.WorkerParameters -import com.google.gson.Gson -import com.metallicus.protonsdk.common.Prefs -import com.metallicus.protonsdk.model.TokenContractRate -import com.metallicus.protonsdk.repository.ChainProviderRepository -import com.metallicus.protonsdk.repository.TokenContractRepository -import com.squareup.inject.assisted.Assisted -import com.squareup.inject.assisted.AssistedInject -import timber.log.Timber -import java.lang.Exception - -class UpdateTokenContractRatesWorker -@AssistedInject constructor( - @Assisted context: Context, - @Assisted params: WorkerParameters, - private val prefs: Prefs, - private val chainProviderRepository: ChainProviderRepository, - private val tokenContractRepository: TokenContractRepository -) : CoroutineWorker(context, params) { - - override suspend fun doWork(): Result { - return try { - val chainProvider = chainProviderRepository.getChainProvider(prefs.activeChainId) - - val tokenContracts = tokenContractRepository.getTokenContracts() - - val tokenContractsMap = mutableMapOf() - tokenContracts.forEach { - tokenContractsMap["${it.contract}:${it.getSymbol()}"] = it.id - } - - val exchangeRateUrl = chainProvider.protonChainUrl + chainProvider.exchangeRatePath - - val exchangeRatesResponse = tokenContractRepository.fetchExchangeRates(exchangeRateUrl) - if (exchangeRatesResponse.isSuccessful) { - val exchangeRatesJsonArray = exchangeRatesResponse.body() - exchangeRatesJsonArray?.forEach { - val exchangeRate = it.asJsonObject - val contract = exchangeRate.get("contract").asString - val symbol = exchangeRate.get("symbol").asString - val rank = exchangeRate.get("rank").asInt - - val ratesMap = mutableMapOf() - - val ratesJsonArray = exchangeRate.get("rates").asJsonArray - ratesJsonArray.forEach { rateJsonElement -> - val rateJsonObj = rateJsonElement.asJsonObject - val currency = rateJsonObj.get("counterCurrency").asString - val rate = Gson().fromJson(rateJsonObj, TokenContractRate::class.java) - ratesMap[currency] = rate - } - - try { - val tokenContractId = tokenContractsMap.getValue("$contract:$symbol") - tokenContractRepository.updateRates(tokenContractId, ratesMap, rank) - } catch (e: Exception) { - Timber.d(e.localizedMessage) - } - } - } - - Result.success() - } catch (e: Exception) { - Timber.d(e) - - Result.failure() - } - } - - @AssistedInject.Factory - interface Factory : ChildWorkerFactory -} \ No newline at end of file From e5d9e225627c127e76831d72d184c7da01afada1 Mon Sep 17 00:00:00 2001 From: Joey Harward Date: Tue, 18 May 2021 22:25:51 -0400 Subject: [PATCH 8/8] optimized chain provider initialization fixed bugs due to new token contracts --- .../protonsdk/CurrencyBalancesModule.kt | 10 ++++-- .../java/com/metallicus/protonsdk/Proton.kt | 31 ++++++++++++++++ .../protonsdk/api/ProtonChainService.kt | 6 ---- .../protonsdk/api/ProtonChainStatsService.kt | 35 +++++++++++++++++++ .../metallicus/protonsdk/di/ProtonModule.kt | 28 +++++++++++++++ .../repository/ChainProviderRepository.kt | 12 +++---- 6 files changed, 106 insertions(+), 16 deletions(-) create mode 100644 protonsdk/src/main/java/com/metallicus/protonsdk/api/ProtonChainStatsService.kt diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/CurrencyBalancesModule.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/CurrencyBalancesModule.kt index ebb6dd36..39a70b21 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/CurrencyBalancesModule.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/CurrencyBalancesModule.kt @@ -87,6 +87,10 @@ class CurrencyBalancesModule { } } + private fun isValidEmptyToken(contract: String): Boolean { + return (contract == "eosio.token" || contract == "xtokens") + } + suspend fun getTokenCurrencyBalances( hyperionHistoryUrl: String, accountName: String, @@ -121,14 +125,14 @@ class CurrencyBalancesModule { val tokenCurrencyBalance = TokenCurrencyBalance(tokenContract, currencyBalance) tokenCurrencyBalances.add(tokenCurrencyBalance) - } else if (addEmptyTokens) { + } else if (addEmptyTokens && isValidEmptyToken(contract)) { // only add valid empty tokens val tokenCurrencyBalance = TokenCurrencyBalance(tokenContract, currencyBalance) tokenCurrencyBalances.add(tokenCurrencyBalance) } } // add custom tokens - currencyBalancesMap.forEach { currencyBalancesMapEntry -> + /*currencyBalancesMap.forEach { currencyBalancesMapEntry -> val token = currencyBalancesMapEntry.value.asJsonObject val contract = token.get("contract").asString val symbol = token.get("symbol").asString @@ -157,7 +161,7 @@ class CurrencyBalancesModule { val tokenCurrencyBalance = TokenCurrencyBalance(tokenContract, currencyBalance) tokenCurrencyBalances.add(tokenCurrencyBalance) } - } + }*/ } Resource.success(tokenCurrencyBalances) diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt index d4cc43f9..701516ef 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt @@ -221,6 +221,37 @@ class Proton private constructor(context: Context) { } } + fun getMarketContracts(updateExchangeRates: Boolean = false): LiveData>> = liveData { + emit(Resource.loading()) + + try { + val tokenContracts = getTokenContractsAsync() + + val marketContracts = tokenContracts.filter { + it.contract == "eosio.token" || it.contract == "xtokens" + } + + if (updateExchangeRates) { + val activeAccount = getActiveAccountAsync() + + val tokenContractsMap = marketContracts.associateBy { "${it.contract}:${it.getSymbol()}" } + + val exchangeRateUrl = + activeAccount.chainProvider.protonChainUrl + activeAccount.chainProvider.exchangeRatePath + + tokenContractsModule.updateExchangeRates(exchangeRateUrl, tokenContractsMap) + } + + emit(Resource.success(marketContracts)) + } catch (e: ProtonException) { + val error: Resource> = Resource.error(e) + emit(error) + } catch (e: Exception) { + val error: Resource> = Resource.error(e.localizedMessage.orEmpty()) + emit(error) + } + } + fun generatePrivateKey(): Pair { val privateKey = EosPrivateKey() val publicKeyStr = privateKey.publicKey.toString() diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/api/ProtonChainService.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/api/ProtonChainService.kt index 951172c1..06c721c4 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/api/ProtonChainService.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/api/ProtonChainService.kt @@ -123,12 +123,6 @@ interface ProtonChainService { @Url url: String, @Body body: JsonToBinBody): Response - @POST//("/v1/chain/get_info") - suspend fun getChainInfo(@Url url: String): Response - - @GET//("/v2/health") - suspend fun getHealth(@Url url: String): Response - @POST//("/v1/chain/get_required_keys") suspend fun getRequiredKeys( @Url url: String, diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/api/ProtonChainStatsService.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/api/ProtonChainStatsService.kt new file mode 100644 index 00000000..42c89c51 --- /dev/null +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/api/ProtonChainStatsService.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021 Proton Chain LLC, Delaware + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.metallicus.protonsdk.api + +import com.google.gson.JsonObject +import com.metallicus.protonsdk.model.* +import retrofit2.Response +import retrofit2.http.* + +interface ProtonChainStatsService { + @POST//("/v1/chain/get_info") + suspend fun getChainInfo(@Url url: String): Response + + @GET//("/v2/health") + suspend fun getHealth(@Url url: String): Response +} \ No newline at end of file diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/di/ProtonModule.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/di/ProtonModule.kt index 45eed0fe..dcff80f4 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/di/ProtonModule.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/di/ProtonModule.kt @@ -27,6 +27,7 @@ import com.google.gson.GsonBuilder import com.metallicus.protonsdk.R import com.metallicus.protonsdk.api.ESRCallbackService import com.metallicus.protonsdk.api.ProtonChainService +import com.metallicus.protonsdk.api.ProtonChainStatsService import com.metallicus.protonsdk.common.SecureKeys import com.metallicus.protonsdk.common.Prefs import com.metallicus.protonsdk.db.* @@ -93,6 +94,33 @@ class ProtonModule { return db.esrSessionDao() } + @Singleton + @Provides + fun provideProtonChainStatsService(context: Context): ProtonChainStatsService { + val logging = HttpLoggingInterceptor() + logging.level = HttpLoggingInterceptor.Level.BODY + + val httpClient = OkHttpClient.Builder() + .callTimeout(10, TimeUnit.SECONDS) + .connectTimeout(10, TimeUnit.SECONDS) + .readTimeout(10, TimeUnit.SECONDS) + .writeTimeout(10, TimeUnit.SECONDS) + .addInterceptor(logging) + + val gson = GsonBuilder() + .registerTypeAdapterFactory(GsonEosTypeAdapterFactory()) + .serializeNulls() +// .excludeFieldsWithoutExposeAnnotation() + .create() + + return Retrofit.Builder() + .baseUrl(context.getString(R.string.defaultProtonChainUrl)) + .addConverterFactory(GsonConverterFactory.create(gson)) + .client(httpClient.build()) + .build() + .create(ProtonChainStatsService::class.java) + } + @Singleton @Provides fun provideProtonChainService(context: Context): ProtonChainService { diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/repository/ChainProviderRepository.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/repository/ChainProviderRepository.kt index b7ce9f80..c62287e4 100755 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/repository/ChainProviderRepository.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/repository/ChainProviderRepository.kt @@ -22,10 +22,7 @@ package com.metallicus.protonsdk.repository import com.google.gson.JsonObject -import com.metallicus.protonsdk.api.AccountBody -import com.metallicus.protonsdk.api.ProtonChainService -import com.metallicus.protonsdk.api.TableRowsBody -import com.metallicus.protonsdk.api.TableRowsIndexPosition +import com.metallicus.protonsdk.api.* import com.metallicus.protonsdk.db.ChainProviderDao import com.metallicus.protonsdk.model.ChainInfo import com.metallicus.protonsdk.model.ChainProvider @@ -36,7 +33,8 @@ import javax.inject.Singleton @Singleton class ChainProviderRepository @Inject constructor( private val chainProviderDao: ChainProviderDao, - private val protonChainService: ProtonChainService + private val protonChainService: ProtonChainService, + private val protonChainStatsService: ProtonChainStatsService ) { suspend fun removeAll() { chainProviderDao.removeAll() @@ -67,11 +65,11 @@ class ChainProviderRepository @Inject constructor( } suspend fun getChainInfo(chainUrl: String): Response { - return protonChainService.getChainInfo("$chainUrl/v1/chain/get_info") + return protonChainStatsService.getChainInfo("$chainUrl/v1/chain/get_info") } suspend fun getHealth(chainUrl: String): Response { - return protonChainService.getHealth("$chainUrl/v2/health") + return protonChainStatsService.getHealth("$chainUrl/v2/health") } suspend fun getAbi(chainUrl: String, accountName: String): Response {