Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: skip v1/chains endpoint [OTE-347] #390

Merged
merged 29 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
c9832cb
feat: base skip processor [OTE-345]
yogurtandjam May 27, 2024
d1a1187
refactor: move squid to new dir
yogurtandjam May 28, 2024
13e67e1
make error messages more specific. suppress lint error
yogurtandjam May 28, 2024
e375ef3
lint
yogurtandjam May 28, 2024
7f260a0
lint
yogurtandjam May 28, 2024
e1b4453
lint
yogurtandjam May 28, 2024
2455290
fix rebase
yogurtandjam May 29, 2024
22b02bf
feat: shared router interface [OTE-344]
yogurtandjam May 27, 2024
2ebebaf
dont need this yet
yogurtandjam May 28, 2024
6d50262
refactor: move squid to new dir
yogurtandjam May 28, 2024
b6217cc
feat: skip/v1/chains [OTE-347]
yogurtandjam May 28, 2024
b467ebe
lint
yogurtandjam May 28, 2024
63d56a0
use ambiguous router name for chains prefix
yogurtandjam May 28, 2024
452f19a
add test
yogurtandjam May 28, 2024
3ecfb82
lint
yogurtandjam May 28, 2024
812f8c5
detekt lint
yogurtandjam May 28, 2024
f1d270f
cleanupp
yogurtandjam May 29, 2024
4628488
lint
yogurtandjam May 29, 2024
01119aa
Bump version
mobile-build-bot May 29, 2024
6b85a5b
refactor to not use maps
yogurtandjam May 29, 2024
bbbc67e
finish refactor and update test
yogurtandjam May 30, 2024
8b37a88
update chain resources processor as well
yogurtandjam May 30, 2024
0870bcf
stop importing as wildcard
yogurtandjam May 30, 2024
2706806
lint
yogurtandjam May 30, 2024
58d01b5
Merge branch 'main' into jerms/OTE-347_skip-chains
yogurtandjam May 30, 2024
00eaac3
Bump version
mobile-build-bot May 30, 2024
0589058
update podspec
yogurtandjam May 30, 2024
df1dc42
merge main
yogurtandjam May 30, 2024
21d61ba
Bump version
mobile-build-bot May 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.41"
version = "1.7.42"

repositories {
google()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,8 @@ data class TransferOutInputOptions(
@Serializable
data class TransferInputChainResource(
val chainName: String?,
val rpc: String?,
val networkName: String?,
val rpc: String? = null,
val networkName: String? = null,
val chainId: Int?,
val iconUrl: String?
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +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 SkipChainProcessor(parser: ParserProtocol) : BaseProcessor(parser) {
private val keyMap = mapOf(
"string" to mapOf(
"chain_name" to "stringKey",
"networkIdentifier" to "stringKey",
"chain_id" to "type",
"logo_uri" to "iconUrl",
),
)

override fun received(
existing: Map<String, Any>?,
internal class SkipChainProcessor(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["network_identifier"]) ?: parser.asString(payload["chain_name"]),
string = parser.asString(payload["network_identifier"]) ?: parser.asString(payload["chain_name"]),
type = parser.asString(payload["chain_id"]) ?: "",
iconUrl = parser.asString(payload["logo_uri"]),
)
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
package exchange.dydx.abacus.processor.router.skip

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

internal class SkipChainResourceProcessor(parser: ParserProtocol) : BaseProcessor(parser) {
private val keyMap = mapOf(
"string" to mapOf(
"chain_name" to "chainName",
"rpc" to "rpc",
"networkName" to "networkName",
"chain_id" to "chainId",
"logo_uri" to "iconUrl",
),
)
internal class SkipChainResourceProcessor(private val parser: ParserProtocol) {

override fun received(
existing: Map<String, Any>?,
fun received(
payload: Map<String, Any>
): Map<String, Any> {
return transform(existing, payload, keyMap)
): TransferInputChainResource {
return TransferInputChainResource(
chainName = parser.asString(payload["chain_name"]),
rpc = parser.asString(payload["rpc"]),
networkName = parser.asString(payload["networkName"]),
chainId = parser.asInt(payload["chain_id"]),
iconUrl = parser.asString(payload["logo_uri"]),
)
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
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.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.utils.mutable
import exchange.dydx.abacus.utils.safeSet

@Suppress("NotImplementedDeclaration")
internal class SkipProcessor(parser: ParserProtocol) : BaseProcessor(parser), IRouterProcessor {
internal class SkipProcessor(
parser: ParserProtocol,
private val internalState: InternalTransferInputState
) : BaseProcessor(parser), IRouterProcessor {
override var chains: List<Any>? = null

// possibly want to use a different variable so we aren't stuck with this bad type
Expand All @@ -26,8 +33,25 @@ internal class SkipProcessor(parser: ParserProtocol) : BaseProcessor(parser), IR
existing: Map<String, Any>?,
payload: Map<String, Any>
): Map<String, Any>? {
throw NotImplementedError("receivedChains is not implemented in SkipProcessor!")
if (this.chains != null) {
return existing
}
this.chains = parser.asNativeList(payload["chains"])
var modified = mutableMapOf<String, Any>()
existing?.let {
modified = it.mutable()
}
val chainOptions = chainOptions()

internalState.chains = chainOptions
val selectedChainId = defaultChainId()
modified.safeSet("transfer.chain", selectedChainId)
selectedChainId?.let {
internalState.chainResources = chainResources(chainId = selectedChainId)
}
return modified
}

override fun receivedTokens(
existing: Map<String, Any>?,
payload: Map<String, Any>
Expand Down Expand Up @@ -72,7 +96,9 @@ internal class SkipProcessor(parser: ParserProtocol) : BaseProcessor(parser), IR
}

override fun defaultChainId(): String? {
throw NotImplementedError("defaultChainId is not implemented in SkipProcessor!")
val selectedChain = parser.asNativeMap(this.chains?.find { parser.asString(parser.asNativeMap(it)?.get("chain_id")) == "1" })

return parser.asString(selectedChain?.get("chain_id"))
}

override fun selectedTokenSymbol(tokenAddress: String?): String? {
Expand All @@ -91,16 +117,41 @@ internal class SkipProcessor(parser: ParserProtocol) : BaseProcessor(parser), IR
throw NotImplementedError("defaultTokenAddress is not implemented in SkipProcessor!")
}

override fun chainResources(chainId: String?): Map<String, Any>? {
throw NotImplementedError("chainResources is not implemented in SkipProcessor!")
override fun chainResources(chainId: String?): Map<String, TransferInputChainResource>? {
val chainResources = mutableMapOf<String, TransferInputChainResource>()
chainId?.let {
this.chains?.find {
parser.asString(parser.asNativeMap(it)?.get("chain_id")) == chainId
}?.let {
val processor = SkipChainResourceProcessor(parser)
parser.asNativeMap(it)?.let { payload ->
chainResources[chainId] = processor.received(payload)
}
}
}
return chainResources
}

override fun tokenResources(chainId: String?): Map<String, Any>? {
throw NotImplementedError("tokenResources is not implemented in SkipProcessor!")
}

override fun chainOptions(): List<Any> {
throw NotImplementedError("chainOptions is not implemented in SkipProcessor!")
override fun chainOptions(): List<SelectionOption> {
val chainProcessor = SkipChainProcessor(parser)
val options = mutableListOf<SelectionOption>()

this.chains?.let {
for (chain in it) {
parser.asNativeMap(chain)?.let { chain ->
if (parser.asString(chain.get("chainType")) != "cosmos") {
options.add(chainProcessor.received(chain))
}
}
}
}

options.sortBy { parser.asString(it.stringKey) }
return options
}

override fun tokenOptions(chainId: String?): List<Any> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ internal class SquidProcessor(
override fun updateTokensDefaults(modified: MutableMap<String, Any>, selectedChainId: String?) {
val tokenOptions = tokenOptions(selectedChainId)
internalState.tokens = tokenOptions
modified.safeSet("transfer.depositOptions.assets", tokenOptions)
modified.safeSet("transfer.withdrawalOptions.assets", tokenOptions)
modified.safeSet("transfer.token", defaultTokenAddress(selectedChainId))
internalState.tokenResources = tokenResources(selectedChainId)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,19 @@ class V4StateManagerConfigs(
return if (environment.isMainNet) "noble-1" else "grand-1"
}

fun skipV1Chains(): String {
return "$skipHost/v1/info/chains?include_evm=true"
}

fun nobleDenom(): String? {
return "uusdc"
}

private val skipHost: String
get() {
return "https://api.skip.money"
}

private val squidV2Host: String
get() {
return if (environment.isMainNet) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import kollections.iListOf
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.jsonObject

internal fun TradingStateMachine.squidChains(payload: String): StateChanges? {
internal fun TradingStateMachine.routerChains(payload: String): StateChanges? {
val json = parser.decodeJsonObject(payload)
return if (json != null) {
input = squidProcessor.receivedChains(input, json)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import exchange.dydx.abacus.state.manager.HumanReadableWithdrawPayload
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.squidRoute
import exchange.dydx.abacus.state.model.squidRouteV2
import exchange.dydx.abacus.state.model.squidStatus
Expand Down Expand Up @@ -69,6 +70,17 @@ internal class OnboardingSupervisor(
retrieveCctpChainIds()
}

@Suppress("UnusedPrivateMember")
private fun retrieveSkipTransferChains() {
val oldState = stateMachine.state
val chainsUrl = helper.configs.skipV1Chains()
helper.get(chainsUrl, null, null) { _, response, httpCode, _ ->
if (helper.success(httpCode) && response != null) {
update(stateMachine.routerChains(response), oldState)
}
}
}

private fun retrieveTransferAssets() {
val oldState = stateMachine.state
val url = helper.configs.squidV2Assets()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package exchange.dydx.abacus.payload.v4

import exchange.dydx.abacus.state.model.TransferInputField
import exchange.dydx.abacus.state.model.squidChains
import exchange.dydx.abacus.state.model.routerChains
import exchange.dydx.abacus.state.model.squidRoute
import exchange.dydx.abacus.state.model.squidRouteV2
import exchange.dydx.abacus.state.model.squidStatus
Expand All @@ -20,7 +20,7 @@ class V4SquidTests : V4BaseTests() {
// Due to the JIT compiler nature for JVM (and Kotlin) and JS, Android/web would ran slow the first round. Second round give more accurate result
setup()

val stateChange = perp.squidChains(mock.squidChainsMock.payload)
val stateChange = perp.routerChains(mock.squidChainsMock.payload)
assertNotNull(stateChange)

test({
Expand All @@ -47,7 +47,7 @@ class V4SquidTests : V4BaseTests() {
// Due to the JIT compiler nature for JVM (and Kotlin) and JS, Android/web would ran slow the first round. Second round give more accurate result
setup()

var stateChange = perp.squidChains(mock.squidChainsMock.payload)
var stateChange = perp.routerChains(mock.squidChainsMock.payload)
assertNotNull(stateChange)

stateChange = perp.squidTokens(mock.squidTokensMock.payload)
Expand Down Expand Up @@ -112,7 +112,7 @@ class V4SquidTests : V4BaseTests() {

perp.transfer("DEPOSIT", TransferInputField.type, 0)

var stateChange = perp.squidChains(mock.squidChainsMock.payload)
var stateChange = perp.routerChains(mock.squidChainsMock.payload)
assertNotNull(stateChange)

stateChange = perp.squidTokens(mock.squidTokensMock.payload)
Expand Down Expand Up @@ -148,7 +148,7 @@ class V4SquidTests : V4BaseTests() {

perp.transfer("DEPOSIT", TransferInputField.type, 0)

var stateChange = perp.squidChains(mock.squidChainsMock.payload)
var stateChange = perp.routerChains(mock.squidChainsMock.payload)
assertNotNull(stateChange)

stateChange = perp.squidTokens(mock.squidTokensMock.payload)
Expand Down Expand Up @@ -219,7 +219,7 @@ class V4SquidTests : V4BaseTests() {
fun testDefaultTokenAddress() {
setup()

var stateChange = perp.squidChains(mock.squidChainsMock.payload)
var stateChange = perp.routerChains(mock.squidChainsMock.payload)
assertNotNull(stateChange)

stateChange = perp.squidTokens(mock.squidTokensMock.payload)
Expand All @@ -232,7 +232,7 @@ class V4SquidTests : V4BaseTests() {
fun testChainResources() {
setup()

val stateChange = perp.squidChains(mock.squidChainsMock.payload)
val stateChange = perp.routerChains(mock.squidChainsMock.payload)
assertNotNull(stateChange)

val result = perp.squidProcessor.chainResources("1")
Expand All @@ -245,7 +245,7 @@ class V4SquidTests : V4BaseTests() {
fun testTokenResources() {
setup()

var stateChange = perp.squidChains(mock.squidChainsMock.payload)
var stateChange = perp.routerChains(mock.squidChainsMock.payload)
assertNotNull(stateChange)

stateChange = perp.squidTokens(mock.squidTokensMock.payload)
Expand All @@ -259,7 +259,7 @@ class V4SquidTests : V4BaseTests() {
fun testTokenOptions() {
setup()

var stateChange = perp.squidChains(mock.squidChainsMock.payload)
var stateChange = perp.routerChains(mock.squidChainsMock.payload)
assertNotNull(stateChange)

stateChange = perp.squidTokens(mock.squidTokensMock.payload)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
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.state.internalstate.InternalTransferInputState
import exchange.dydx.abacus.tests.payloads.SkipChainsMock
import exchange.dydx.abacus.utils.Parser
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.jsonObject
import kotlin.test.Test
import kotlin.test.assertEquals

internal fun templateToJson(template: String): Map<String, Any> {
return Json.parseToJsonElement(template.trimIndent()).jsonObject.toMap()
}

class SkipProcessorTests {

internal val internalState = InternalTransferInputState()
internal val skipProcessor = SkipProcessor(parser = Parser(), internalState = internalState)
internal val skipChainsMock = SkipChainsMock()

@Test
fun testReceivedChains() {
val modified = skipProcessor.receivedChains(
existing = mapOf(),
payload = templateToJson(
skipChainsMock.payload,
),
)

val expectedChains = listOf(
SelectionOption(stringKey = "Ethereum", string = "Ethereum", type = "1", iconUrl = "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/info/logo.png"),
SelectionOption(stringKey = "aura", string = "aura", type = "xstaxy-1", iconUrl = "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/xstaxy/chain.png"),
SelectionOption(stringKey = "cheqd", string = "cheqd", type = "cheqd-mainnet-1", iconUrl = "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/cheqd-mainnet/chain.png"),
SelectionOption(stringKey = "kujira", string = "kujira", type = "kaiyo-1", iconUrl = "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/kaiyo/chain.png"),
SelectionOption(stringKey = "osmosis", string = "osmosis", type = "osmosis-1", iconUrl = "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/osmosis/chain.png"),
SelectionOption(stringKey = "stride", string = "stride", type = "stride-1", iconUrl = "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/stride/chain.png"),
)
assertEquals(expectedChains, internalState.chains)

val expectedChainResources = mapOf(
"1" to TransferInputChainResource(
chainName = "Ethereum",
chainId = 1,
iconUrl = "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/info/logo.png",
),
)
assertEquals(expectedChainResources, internalState.chainResources)

val expectedModified = mapOf(
"transfer" to mapOf(
"chain" to "1",
),
)
assertEquals(expectedModified, modified)
}
}
Loading
Loading