Skip to content

Commit

Permalink
Merge pull request #33 from ProtonProtocol/swap_pool
Browse files Browse the repository at this point in the history
Swap pool
  • Loading branch information
Joey Harward authored May 19, 2021
2 parents b078dab + e5d9e22 commit 4e4ce75
Show file tree
Hide file tree
Showing 20 changed files with 368 additions and 260 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
}
```

Expand Down
4 changes: 2 additions & 2 deletions buildSrc/src/main/kotlin/Dependencies.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
18 changes: 12 additions & 6 deletions protonsdk/src/main/java/com/metallicus/protonsdk/ActionsModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -309,12 +309,18 @@ class ActionsModule {
suspend fun signAndPushTransaction(chainUrl: String, pin: String, actions: List<Action>): Resource<JsonObject> {
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())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand All @@ -93,55 +87,82 @@ class CurrencyBalancesModule {
}
}

private fun isValidEmptyToken(contract: String): Boolean {
return (contract == "eosio.token" || contract == "xtokens")
}

suspend fun getTokenCurrencyBalances(
hyperionHistoryUrl: String,
accountName: String,
tokenContractsMap: Map<String, TokenContract>): Resource<List<TokenCurrencyBalance>> {
tokenContractsMap: Map<String, TokenContract>,
addEmptyTokens: Boolean = false
): Resource<List<TokenCurrencyBalance>> {
return try {
val balancesResponse = currencyBalanceRepository.fetchCurrencyBalances(hyperionHistoryUrl, accountName)
if (balancesResponse.isSuccessful) {
val jsonObject = balancesResponse.body()
val tokenArray = jsonObject?.getAsJsonArray("tokens")
val tokenCurrencyBalances = mutableListOf<TokenCurrencyBalance>()

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"
}

tokenArray?.forEach {
val token = it.asJsonObject
val code = token.get("contract").asString
val symbol = token.get("symbol").asString
val amount = token.get("amount").asString
tokenContractsMap.forEach { tokenContractMapEntry ->
val tokenContract = tokenContractMapEntry.value
val contract = tokenContract.contract
val symbol = tokenContract.getSymbol()

val currencyBalanceKey = "$contract:$symbol"

val currencyBalance = CurrencyBalance(contract, symbol)

val tokenContractId = "$code:$symbol"

if (tokenContractsMap.containsKey("$code:$symbol")) {
val currencyBalance = CurrencyBalance(code, symbol, amount)
currencyBalance.tokenContractId = tokenContractId
currencyBalance.accountName = accountName

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()))

tokenContractRepository.addTokenContract(tokenContract)

val currencyBalance = CurrencyBalance(code, symbol, amount)
currencyBalance.tokenContractId = tokenContractId
currencyBalance.accountName = accountName

currencyBalanceRepository.addCurrencyBalance(currencyBalance)
if (currencyBalancesMap.containsKey(currencyBalanceKey)) {
val token = currencyBalancesMap[currencyBalanceKey]?.asJsonObject
currencyBalance.amount = token?.get("amount")?.asString.orEmpty()

val tokenCurrencyBalance = TokenCurrencyBalance(tokenContract, currencyBalance)
tokenCurrencyBalances.add(tokenCurrencyBalance)
} else if (addEmptyTokens && isValidEmptyToken(contract)) { // only add valid empty tokens
val tokenCurrencyBalance = TokenCurrencyBalance(tokenContract, currencyBalance)
tokenCurrencyBalances.add(tokenCurrencyBalance)
}
}
}

val tokenCurrencyBalances = currencyBalanceRepository.getTokenCurrencyBalances(accountName)
// 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)
}
}*/
}

Resource.success(tokenCurrencyBalances)
} else {
Expand Down
129 changes: 127 additions & 2 deletions protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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.*
Expand Down Expand Up @@ -220,6 +221,37 @@ class Proton private constructor(context: Context) {
}
}

fun getMarketContracts(updateExchangeRates: Boolean = false): LiveData<Resource<List<TokenContract>>> = 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<List<TokenContract>> = Resource.error(e)
emit(error)
} catch (e: Exception) {
val error: Resource<List<TokenContract>> = Resource.error(e.localizedMessage.orEmpty())
emit(error)
}
}

fun generatePrivateKey(): Pair<String, String> {
val privateKey = EosPrivateKey()
val publicKeyStr = privateKey.publicKey.toString()
Expand Down Expand Up @@ -392,7 +424,7 @@ class Proton private constructor(context: Context) {
}
}

fun getActiveAccountTokenBalances(): LiveData<Resource<List<TokenCurrencyBalance>>> = liveData {
fun getActiveAccountTokenBalances(addEmptyTokens: Boolean = false): LiveData<Resource<List<TokenCurrencyBalance>>> = liveData {
emit(Resource.loading())

try {
Expand All @@ -407,7 +439,8 @@ class Proton private constructor(context: Context) {
currencyBalancesModule.getTokenCurrencyBalances(
activeAccount.chainProvider.hyperionHistoryUrl,
activeAccount.account.accountName,
tokenContractsMap)
tokenContractsMap,
addEmptyTokens)

emit(tokenBalances)
} catch (e: ProtonException) {
Expand Down Expand Up @@ -916,6 +949,98 @@ class Proton private constructor(context: Context) {
}
}

fun getSwapPools(): LiveData<Resource<SwapPoolData>> = liveData {
emit(Resource.loading())

try {
val tokenContractsMap = getTokenContractsMapAsync()
val activeAccount = getActiveAccountAsync()

val exchangeRateUrl = activeAccount.chainProvider.protonChainUrl + activeAccount.chainProvider.exchangeRatePath

tokenContractsModule.updateExchangeRates(exchangeRateUrl, tokenContractsMap)

val tokenBalancesResource =
currencyBalancesModule.getTokenCurrencyBalances(
activeAccount.chainProvider.hyperionHistoryUrl,
activeAccount.account.accountName,
tokenContractsMap,
true)

when (tokenBalancesResource.status) {
Status.SUCCESS -> {
tokenBalancesResource.data?.let { tokenCurrencyBalances ->
val tokenCurrencyBalancesMap = tokenCurrencyBalances.associateBy {
"${it.tokenContract.contract}:${it.tokenContract.getSymbol()}"
}

val tableRowsResource = getTableRows(
"proton.swaps",
"proton.swaps",
"pools",
"",
"",
250//,
//TableRowsIndexPosition.SECONDARY.indexPositionName
)
when (tableRowsResource.status) {
Status.SUCCESS -> {
val swapPools = mutableListOf<SwapPool>()
val swapPoolTokens = mutableListOf<TokenCurrencyBalance>()

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)
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)
}
}
}

val swapPoolData = SwapPoolData(swapPools, swapPoolTokens.distinct())

emit(Resource.success(swapPoolData))
}
Status.ERROR -> {
val error: Resource<SwapPoolData> =
Resource.error(tableRowsResource.message.orEmpty(), tableRowsResource.code ?: -1)
emit(error)
}
Status.LOADING -> { }
}
}
}
Status.ERROR -> {
val error: Resource<SwapPoolData> =
Resource.error(tokenBalancesResource.message.orEmpty(), tokenBalancesResource.code ?: -1)
emit(error)
}
Status.LOADING -> { }
}
} catch (e: ProtonException) {
val error: Resource<SwapPoolData> = Resource.error(e)
emit(error)
} catch (e: Exception) {
val error: Resource<SwapPoolData> = Resource.error(e.localizedMessage.orEmpty())
emit(error)
}
}

suspend fun getTableRows(
scope: String,
code: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ class TokenContractsModule {

val tokenContractId = "$contract:$symbol"
if (tokenContractsMap.containsKey(tokenContractId)) {
tokenContractsMap[tokenContractId]?.rates = ratesMap

tokenContractRepository.updateRates(tokenContractId, ratesMap, rank)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

/**
Expand Down Expand Up @@ -95,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) {
Expand Down
Loading

0 comments on commit 4e4ce75

Please sign in to comment.