Skip to content

Commit

Permalink
feat: skip v1/assets endpoint [OTE-346] (#394)
Browse files Browse the repository at this point in the history
  • Loading branch information
yogurtandjam authored Jun 1, 2024
1 parent 5f2e7e5 commit 19de38d
Show file tree
Hide file tree
Showing 15 changed files with 865 additions and 77 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ allprojects {
}

group = "exchange.dydx.abacus"
version = "1.7.46"
version = "1.7.47"

repositories {
google()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ interface IRouterProcessor {

fun updateTokensDefaults(modified: MutableMap<String, Any>, selectedChainId: String?)
fun defaultChainId(): String?
fun selectedTokenSymbol(tokenAddress: String?): String?
fun selectedTokenDecimals(tokenAddress: String?): String?
fun selectedTokenSymbol(tokenAddress: String?, selectedChainId: String?): String?
fun selectedTokenDecimals(tokenAddress: String?, selectedChainId: String?): String?
fun filteredTokens(chainId: String?): List<Any>?
fun defaultTokenAddress(chainId: String?): String?
fun chainResources(chainId: String?): Map<String, Any>?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package exchange.dydx.abacus.processor.router.skip

import exchange.dydx.abacus.output.input.SelectionOption
import exchange.dydx.abacus.output.input.TransferInputChainResource
import exchange.dydx.abacus.output.input.TransferInputTokenResource
import exchange.dydx.abacus.processor.base.BaseProcessor
import exchange.dydx.abacus.processor.router.IRouterProcessor
import exchange.dydx.abacus.processor.router.SharedRouterProcessor
import exchange.dydx.abacus.protocols.ParserProtocol
import exchange.dydx.abacus.state.internalstate.InternalTransferInputState
import exchange.dydx.abacus.state.manager.CctpConfig.cctpChainIds
import exchange.dydx.abacus.utils.mutable
import exchange.dydx.abacus.utils.safeSet

Expand All @@ -20,6 +22,8 @@ internal class SkipProcessor(
// possibly want to use a different variable so we aren't stuck with this bad type
// actual type of the tokens payload is Map<str, Map<str, List<Map<str, Any>>>>
override var tokens: List<Any>? = null

var skipTokens: Map<String, Map<String, List<Map<String, Any>>>>? = null
override var exchangeDestinationChainId: String? = null
val sharedRouterProcessor = SharedRouterProcessor(parser)

Expand Down Expand Up @@ -56,7 +60,24 @@ internal class SkipProcessor(
existing: Map<String, Any>?,
payload: Map<String, Any>
): Map<String, Any>? {
throw NotImplementedError("receivedTokens is not implemented in SkipProcessor!")
if (this.chains != null && this.skipTokens != null) {
return existing
}

val chainToAssetsMap = payload["chain_to_assets_map"] as Map<String, Map<String, List<Map<String, Any>>>>?

var modified = mutableMapOf<String, Any>()
existing?.let {
modified = it.mutable()
}
if (chainToAssetsMap == null) {
return existing
}
val selectedChainId = defaultChainId()
this.skipTokens = chainToAssetsMap
updateTokensDefaults(modified, selectedChainId)

return modified
}

override fun receivedRoute(
Expand Down Expand Up @@ -89,10 +110,9 @@ internal class SkipProcessor(

override fun updateTokensDefaults(modified: MutableMap<String, Any>, selectedChainId: String?) {
val tokenOptions = tokenOptions(selectedChainId)
modified.safeSet("transfer.depositOptions.assets", tokenOptions)
modified.safeSet("transfer.withdrawalOptions.assets", tokenOptions)
internalState.tokens = tokenOptions
modified.safeSet("transfer.token", defaultTokenAddress(selectedChainId))
modified.safeSet("transfer.resources.tokenResources", tokenResources(selectedChainId))
internalState.tokenResources = tokenResources(selectedChainId)
}

override fun defaultChainId(): String? {
Expand All @@ -101,20 +121,45 @@ internal class SkipProcessor(
return parser.asString(selectedChain?.get("chain_id"))
}

override fun selectedTokenSymbol(tokenAddress: String?): String? {
throw NotImplementedError("selectedTokenSymbol is not implemented in SkipProcessor!")
override fun selectedTokenSymbol(tokenAddress: String?, selectedChainId: String?): String? {
val tokensList = filteredTokens(selectedChainId)
tokensList?.find {
parser.asString(parser.asNativeMap(it)?.get("denom")) == tokenAddress
}?.let {
return parser.asString(parser.asNativeMap(it)?.get("symbol"))
}
return null
}

override fun selectedTokenDecimals(tokenAddress: String?): String? {
throw NotImplementedError("selectedTokenDecimals is not implemented in SkipProcessor!")
override fun selectedTokenDecimals(tokenAddress: String?, selectedChainId: String?): String? {
val tokensList = filteredTokens(selectedChainId)
tokensList?.find {
parser.asString(parser.asNativeMap(it)?.get("denom")) == tokenAddress
}?.let {
return parser.asString(parser.asNativeMap(it)?.get("decimals"))
}
return null
}

override fun filteredTokens(chainId: String?): List<Any>? {
throw NotImplementedError("filteredTokens is not implemented in SkipProcessor!")
val chainIdToUse = chainId ?: defaultChainId()
val assetsMapForChainId = parser.asNativeMap(this.skipTokens?.get(chainIdToUse))
return parser.asNativeList(assetsMapForChainId?.get("assets"))
}

override fun defaultTokenAddress(chainId: String?): String? {
throw NotImplementedError("defaultTokenAddress is not implemented in SkipProcessor!")
return chainId?.let { cid ->
// Retrieve the list of filtered tokens for the given chainId
val filteredTokens = this.filteredTokens(cid)?.mapNotNull {
parser.asString(parser.asNativeMap(it)?.get("denom"))
}.orEmpty()
// Find a matching CctpChainTokenInfo and check if its tokenAddress is in the filtered tokens
cctpChainIds?.firstOrNull { it.chainId == cid && filteredTokens.contains(it.tokenAddress) }?.tokenAddress
?: run {
// Fallback to the first token's address from the filtered list if no CctpChainTokenInfo match is found
filteredTokens.firstOrNull()
}
}
}

override fun chainResources(chainId: String?): Map<String, TransferInputChainResource>? {
Expand All @@ -132,8 +177,17 @@ internal class SkipProcessor(
return chainResources
}

override fun tokenResources(chainId: String?): Map<String, Any>? {
throw NotImplementedError("tokenResources is not implemented in SkipProcessor!")
override fun tokenResources(chainId: String?): Map<String, TransferInputTokenResource>? {
val tokenResources = mutableMapOf<String, TransferInputTokenResource>()
filteredTokens(chainId)?.forEach {
parser.asString(parser.asNativeMap(it)?.get("denom"))?.let { key ->
val processor = SkipTokenResourceProcessor(parser)
parser.asNativeMap(it)?.let { payload ->
tokenResources[key] = processor.received(payload)
}
}
}
return tokenResources
}

override fun chainOptions(): List<SelectionOption> {
Expand All @@ -154,7 +208,18 @@ internal class SkipProcessor(
return options
}

override fun tokenOptions(chainId: String?): List<Any> {
throw NotImplementedError("tokenOptions is not implemented in SkipProcessor!")
override fun tokenOptions(chainId: String?): List<SelectionOption> {
val processor = SkipTokenProcessor(parser)
val options = mutableListOf<SelectionOption>()
val tokensForSelectedChain = filteredTokens(chainId)
tokensForSelectedChain?.let {
for (asset in it) {
parser.asNativeMap(asset)?.let { _asset ->
options.add(processor.received(_asset))
}
}
}
options.sortBy { parser.asString(it.stringKey) }
return options
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
package exchange.dydx.abacus.processor.router.skip

import exchange.dydx.abacus.processor.base.BaseProcessor
import exchange.dydx.abacus.output.input.SelectionOption
import exchange.dydx.abacus.protocols.ParserProtocol

internal class SkipTokenProcessor(parser: ParserProtocol) : BaseProcessor(parser) {
private val keyMap = mapOf(
"string" to mapOf(
"name" to "stringKey",
"denom" to "type",
"logo_uri" to "iconUrl",
),
)

override fun received(
existing: Map<String, Any>?,
internal class SkipTokenProcessor(private val parser: ParserProtocol) {
fun received(
payload: Map<String, Any>
): Map<String, Any> {
return transform(existing, payload, keyMap)
): SelectionOption {
return SelectionOption(
stringKey = parser.asString(payload["name"]),
string = parser.asString(payload["name"]),
type = parser.asString(payload["denom"]) ?: "",
iconUrl = parser.asString(payload["logo_uri"]),
)
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
package exchange.dydx.abacus.processor.router.skip

import exchange.dydx.abacus.processor.base.BaseProcessor
import exchange.dydx.abacus.output.input.TransferInputTokenResource
import exchange.dydx.abacus.protocols.ParserProtocol

internal class SkipTokenResourceProcessor(parser: ParserProtocol) : BaseProcessor(parser) {
private val keyMap = mapOf(
"string" to mapOf(
"name" to "name",
"denom" to "address",
"symbol" to "symbol",
"decimals" to "decimals",
"logo_uri" to "iconUrl",
),
)

override fun received(
existing: Map<String, Any>?,
internal class SkipTokenResourceProcessor(
private val parser: ParserProtocol
) {
fun received(
payload: Map<String, Any>
): Map<String, Any> {
return transform(existing, payload, keyMap)
): TransferInputTokenResource {
return TransferInputTokenResource(
name = parser.asString(payload["name"]),
address = parser.asString(payload["denom"]),
symbol = parser.asString(payload["symbol"]),
decimals = parser.asInt(payload["decimals"]),
iconUrl = parser.asString(payload["logo_uri"]),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ internal class SquidProcessor(
return parser.asString(selectedChain?.get("chainId"))
}

override fun selectedTokenSymbol(tokenAddress: String?): String? {
override fun selectedTokenSymbol(tokenAddress: String?, selectedChainId: String?): String? {
this.tokens?.find {
parser.asString(parser.asNativeMap(it)?.get("address")) == tokenAddress
}?.let {
Expand All @@ -193,7 +193,7 @@ internal class SquidProcessor(
return null
}

override fun selectedTokenDecimals(tokenAddress: String?): String? {
override fun selectedTokenDecimals(tokenAddress: String?, selectedChainId: String?): String? {
this.tokens?.find {
parser.asString(parser.asNativeMap(it)?.get("address")) == tokenAddress
}?.let {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ private fun V4StateManagerAdaptor.retrieveDepositRouteV1(state: PerpetualState?)
val fromChain = state?.input?.transfer?.chain
val fromToken = state?.input?.transfer?.token
val fromAmount = parser.asDecimal(state?.input?.transfer?.size?.size)?.let {
val decimals = parser.asInt(stateMachine.squidProcessor.selectedTokenDecimals(fromToken))
val decimals = parser.asInt(stateMachine.squidProcessor.selectedTokenDecimals(tokenAddress = fromToken, selectedChainId = fromChain))
if (decimals != null) {
(it * Numeric.decimal.TEN.pow(decimals)).toBigInteger()
} else {
Expand Down Expand Up @@ -144,7 +144,7 @@ private fun V4StateManagerAdaptor.retrieveDepositRouteV2(state: PerpetualState?)
val fromChain = state?.input?.transfer?.chain
val fromToken = state?.input?.transfer?.token
val fromAmount = parser.asDecimal(state?.input?.transfer?.size?.size)?.let {
val decimals = parser.asInt(stateMachine.squidProcessor.selectedTokenDecimals(fromToken))
val decimals = parser.asInt(stateMachine.squidProcessor.selectedTokenDecimals(tokenAddress = fromToken, selectedChainId = fromChain))
if (decimals != null) {
(it * Numeric.decimal.TEN.pow(decimals)).toBigInteger()
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ class V4StateManagerConfigs(
return "$skipHost/v1/info/chains?include_evm=true"
}

fun skipV1Assets(): String {
return "$skipHost/v1/fungible/assets?include_evm_assets=true"
}

fun nobleDenom(): String? {
return "uusdc"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ internal fun TradingStateMachine.routerChains(payload: String): StateChanges? {
}
}

internal fun TradingStateMachine.squidTokens(payload: String): StateChanges? {
internal fun TradingStateMachine.routerTokens(payload: String): StateChanges? {
val json = parser.decodeJsonObject(payload)
return if (json != null) {
input = squidProcessor.receivedTokens(input, json)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,18 +192,19 @@ fun TradingStateMachine.transfer(
return StateResponse(state, changes, if (error != null) iListOf(error) else null)
}

private fun TradingStateMachine.updateTransferToTokenType(transfer: MutableMap<String, Any>, token: String) {
private fun TradingStateMachine.updateTransferToTokenType(transfer: MutableMap<String, Any>, tokenAddress: String) {
val selectedChainId = transfer["chain"] as? String
if (transfer["type"] == "TRANSFER_OUT") {
transfer.safeSet("size.usdcSize", null)
transfer.safeSet("size.size", null)
} else {
transfer.safeSet(
"resources.tokenSymbol",
squidProcessor.selectedTokenSymbol(token),
squidProcessor.selectedTokenSymbol(tokenAddress = tokenAddress, selectedChainId = selectedChainId),
)
transfer.safeSet(
"resources.tokenDecimals",
squidProcessor.selectedTokenDecimals(token),
squidProcessor.selectedTokenDecimals(tokenAddress = tokenAddress, selectedChainId = selectedChainId),
)
}
transfer.safeSet("route", null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import exchange.dydx.abacus.state.manager.pendingCctpWithdraw
import exchange.dydx.abacus.state.model.TradingStateMachine
import exchange.dydx.abacus.state.model.TransferInputField
import exchange.dydx.abacus.state.model.routerChains
import exchange.dydx.abacus.state.model.routerTokens
import exchange.dydx.abacus.state.model.squidRoute
import exchange.dydx.abacus.state.model.squidRouteV2
import exchange.dydx.abacus.state.model.squidStatus
Expand Down Expand Up @@ -81,6 +82,19 @@ internal class OnboardingSupervisor(
}
}

@Suppress("UnusedPrivateMember")
private fun retrieveSkipTransferTokens() {
val oldState = stateMachine.state
val tokensUrl = helper.configs.skipV1Assets()
// add API key injection
// val header = iMapOf("authorization" to skipAPIKey)
helper.get(tokensUrl, null, null) { _, response, httpCode, _ ->
if (helper.success(httpCode) && response != null) {
update(stateMachine.routerTokens(response), oldState)
}
}
}

private fun retrieveTransferAssets() {
val oldState = stateMachine.state
val url = helper.configs.squidV2Assets()
Expand Down Expand Up @@ -183,7 +197,7 @@ internal class OnboardingSupervisor(
val fromToken = state?.input?.transfer?.token
val fromAmount = helper.parser.asDecimal(state?.input?.transfer?.size?.size)?.let {
val decimals =
helper.parser.asInt(stateMachine.squidProcessor.selectedTokenDecimals(fromToken))
helper.parser.asInt(stateMachine.squidProcessor.selectedTokenDecimals(tokenAddress = fromToken, selectedChainId = fromChain))
if (decimals != null) {
(it * Numeric.decimal.TEN.pow(decimals)).toBigInteger()
} else {
Expand Down Expand Up @@ -245,7 +259,7 @@ internal class OnboardingSupervisor(
val fromToken = state?.input?.transfer?.token
val fromAmount = helper.parser.asDecimal(state?.input?.transfer?.size?.size)?.let {
val decimals =
helper.parser.asInt(stateMachine.squidProcessor.selectedTokenDecimals(fromToken))
helper.parser.asInt(stateMachine.squidProcessor.selectedTokenDecimals(tokenAddress = fromToken, selectedChainId = fromChain))
if (decimals != null) {
(it * Numeric.decimal.TEN.pow(decimals)).toBigInteger()
} else {
Expand Down
Loading

0 comments on commit 19de38d

Please sign in to comment.