diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/processor/router/IRouterProcessor.kt b/src/commonMain/kotlin/exchange.dydx.abacus/processor/router/IRouterProcessor.kt index a9c7b44b5..8e8d48f5a 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/processor/router/IRouterProcessor.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/processor/router/IRouterProcessor.kt @@ -40,8 +40,8 @@ interface IRouterProcessor { fun updateTokensDefaults(modified: MutableMap, 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? fun defaultTokenAddress(chainId: String?): String? fun chainResources(chainId: String?): Map? diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/processor/router/skip/SkipProcessor.kt b/src/commonMain/kotlin/exchange.dydx.abacus/processor/router/skip/SkipProcessor.kt index 24d7c5349..968f5911f 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/processor/router/skip/SkipProcessor.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/processor/router/skip/SkipProcessor.kt @@ -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 @@ -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>>> override var tokens: List? = null + + var skipTokens: Map>>>? = null override var exchangeDestinationChainId: String? = null val sharedRouterProcessor = SharedRouterProcessor(parser) @@ -56,7 +60,24 @@ internal class SkipProcessor( existing: Map?, payload: Map ): Map? { - 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>>>? + + var modified = mutableMapOf() + existing?.let { + modified = it.mutable() + } + if (chainToAssetsMap == null) { + return existing + } + val selectedChainId = defaultChainId() + this.skipTokens = chainToAssetsMap + updateTokensDefaults(modified, selectedChainId) + + return modified } override fun receivedRoute( @@ -89,10 +110,9 @@ internal class SkipProcessor( override fun updateTokensDefaults(modified: MutableMap, 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? { @@ -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? { - 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? { @@ -132,8 +177,17 @@ internal class SkipProcessor( return chainResources } - override fun tokenResources(chainId: String?): Map? { - throw NotImplementedError("tokenResources is not implemented in SkipProcessor!") + override fun tokenResources(chainId: String?): Map? { + val tokenResources = mutableMapOf() + 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 { @@ -154,7 +208,18 @@ internal class SkipProcessor( return options } - override fun tokenOptions(chainId: String?): List { - throw NotImplementedError("tokenOptions is not implemented in SkipProcessor!") + override fun tokenOptions(chainId: String?): List { + val processor = SkipTokenProcessor(parser) + val options = mutableListOf() + 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 } } diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/processor/router/skip/SkipTokenProcessor.kt b/src/commonMain/kotlin/exchange.dydx.abacus/processor/router/skip/SkipTokenProcessor.kt index 59623ca27..fbfba34ff 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/processor/router/skip/SkipTokenProcessor.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/processor/router/skip/SkipTokenProcessor.kt @@ -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?, +internal class SkipTokenProcessor(private val parser: ParserProtocol) { + fun received( payload: Map - ): Map { - 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"]), + ) } } diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/processor/router/skip/SkipTokenResourceProcessor.kt b/src/commonMain/kotlin/exchange.dydx.abacus/processor/router/skip/SkipTokenResourceProcessor.kt index e5b202a4a..76563a084 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/processor/router/skip/SkipTokenResourceProcessor.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/processor/router/skip/SkipTokenResourceProcessor.kt @@ -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?, +internal class SkipTokenResourceProcessor( + private val parser: ParserProtocol +) { + fun received( payload: Map - ): Map { - 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"]), + ) } } diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/processor/router/squid/SquidProcessor.kt b/src/commonMain/kotlin/exchange.dydx.abacus/processor/router/squid/SquidProcessor.kt index 5e8a2b94d..c0362a6be 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/processor/router/squid/SquidProcessor.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/processor/router/squid/SquidProcessor.kt @@ -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 { @@ -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 { diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/state/manager/V4StateManagerAdaptor+Transfer.kt b/src/commonMain/kotlin/exchange.dydx.abacus/state/manager/V4StateManagerAdaptor+Transfer.kt index ab54bed1b..038fb6385 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/state/manager/V4StateManagerAdaptor+Transfer.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/state/manager/V4StateManagerAdaptor+Transfer.kt @@ -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 { @@ -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 { diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/state/manager/configs/V4StateManagerConfigs.kt b/src/commonMain/kotlin/exchange.dydx.abacus/state/manager/configs/V4StateManagerConfigs.kt index ef36530ee..71967078c 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/state/manager/configs/V4StateManagerConfigs.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/state/manager/configs/V4StateManagerConfigs.kt @@ -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" } diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/state/model/TradingStateMachine+Squid.kt b/src/commonMain/kotlin/exchange.dydx.abacus/state/model/TradingStateMachine+Squid.kt index 156e6858c..a65417958 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/state/model/TradingStateMachine+Squid.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/state/model/TradingStateMachine+Squid.kt @@ -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) diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/state/model/TradingStateMachine+TransferInput.kt b/src/commonMain/kotlin/exchange.dydx.abacus/state/model/TradingStateMachine+TransferInput.kt index ac3500c88..89265d288 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/state/model/TradingStateMachine+TransferInput.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/state/model/TradingStateMachine+TransferInput.kt @@ -192,18 +192,19 @@ fun TradingStateMachine.transfer( return StateResponse(state, changes, if (error != null) iListOf(error) else null) } -private fun TradingStateMachine.updateTransferToTokenType(transfer: MutableMap, token: String) { +private fun TradingStateMachine.updateTransferToTokenType(transfer: MutableMap, 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) diff --git a/src/commonMain/kotlin/exchange.dydx.abacus/state/v2/supervisor/OnboardingSupervisor.kt b/src/commonMain/kotlin/exchange.dydx.abacus/state/v2/supervisor/OnboardingSupervisor.kt index 522114ce1..4214fb79b 100644 --- a/src/commonMain/kotlin/exchange.dydx.abacus/state/v2/supervisor/OnboardingSupervisor.kt +++ b/src/commonMain/kotlin/exchange.dydx.abacus/state/v2/supervisor/OnboardingSupervisor.kt @@ -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 @@ -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() @@ -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 { @@ -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 { diff --git a/src/commonTest/kotlin/exchange.dydx.abacus/payload/v4/V4SquidTests.kt b/src/commonTest/kotlin/exchange.dydx.abacus/payload/v4/V4SquidTests.kt index 1af6d062c..48280110a 100644 --- a/src/commonTest/kotlin/exchange.dydx.abacus/payload/v4/V4SquidTests.kt +++ b/src/commonTest/kotlin/exchange.dydx.abacus/payload/v4/V4SquidTests.kt @@ -2,10 +2,10 @@ package exchange.dydx.abacus.payload.v4 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 -import exchange.dydx.abacus.state.model.squidTokens import exchange.dydx.abacus.state.model.squidV2SdkInfo import exchange.dydx.abacus.state.model.transfer import kotlin.test.Test @@ -50,7 +50,7 @@ class V4SquidTests : V4BaseTests() { var stateChange = perp.routerChains(mock.squidChainsMock.payload) assertNotNull(stateChange) - stateChange = perp.squidTokens(mock.squidTokensMock.payload) + stateChange = perp.routerTokens(mock.squidTokensMock.payload) assertNotNull(stateChange) test({ @@ -115,7 +115,7 @@ class V4SquidTests : V4BaseTests() { var stateChange = perp.routerChains(mock.squidChainsMock.payload) assertNotNull(stateChange) - stateChange = perp.squidTokens(mock.squidTokensMock.payload) + stateChange = perp.routerTokens(mock.squidTokensMock.payload) assertNotNull(stateChange) stateChange = perp.squidRoute(mock.squidRouteMock.payload, 0, null) @@ -151,7 +151,7 @@ class V4SquidTests : V4BaseTests() { var stateChange = perp.routerChains(mock.squidChainsMock.payload) assertNotNull(stateChange) - stateChange = perp.squidTokens(mock.squidTokensMock.payload) + stateChange = perp.routerTokens(mock.squidTokensMock.payload) assertNotNull(stateChange) stateChange = perp.squidRoute(mock.squidRouteMock.errors_payload, 0, null) @@ -199,20 +199,20 @@ class V4SquidTests : V4BaseTests() { fun testSelectedTokenSymbol() { setup() - val stateChange = perp.squidTokens(mock.squidTokensMock.payload) + val stateChange = perp.routerTokens(mock.squidTokensMock.payload) assertNotNull(stateChange) - assertTrue(perp.squidProcessor.selectedTokenSymbol("0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE") == "ETH") + assertTrue(perp.squidProcessor.selectedTokenSymbol("0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", "should_not_matter") == "ETH") } @Test fun testSelectedTokenDecimals() { setup() - val stateChange = perp.squidTokens(mock.squidTokensMock.payload) + val stateChange = perp.routerTokens(mock.squidTokensMock.payload) assertNotNull(stateChange) - assertTrue(perp.squidProcessor.selectedTokenDecimals("0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE") == "18") + assertTrue(perp.squidProcessor.selectedTokenDecimals("0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", "should_not_matter") == "18") } @Test @@ -222,7 +222,7 @@ class V4SquidTests : V4BaseTests() { var stateChange = perp.routerChains(mock.squidChainsMock.payload) assertNotNull(stateChange) - stateChange = perp.squidTokens(mock.squidTokensMock.payload) + stateChange = perp.routerTokens(mock.squidTokensMock.payload) assertNotNull(stateChange) assertTrue(perp.squidProcessor.defaultTokenAddress("1") == "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE") @@ -248,7 +248,7 @@ class V4SquidTests : V4BaseTests() { var stateChange = perp.routerChains(mock.squidChainsMock.payload) assertNotNull(stateChange) - stateChange = perp.squidTokens(mock.squidTokensMock.payload) + stateChange = perp.routerTokens(mock.squidTokensMock.payload) assertNotNull(stateChange) val result = perp.squidProcessor.tokenResources("1") @@ -262,7 +262,7 @@ class V4SquidTests : V4BaseTests() { var stateChange = perp.routerChains(mock.squidChainsMock.payload) assertNotNull(stateChange) - stateChange = perp.squidTokens(mock.squidTokensMock.payload) + stateChange = perp.routerTokens(mock.squidTokensMock.payload) assertNotNull(stateChange) val result = perp.squidProcessor.tokenOptions("1") diff --git a/src/commonTest/kotlin/exchange.dydx.abacus/processor/router/skip/SkipProcessorTests.kt b/src/commonTest/kotlin/exchange.dydx.abacus/processor/router/skip/SkipProcessorTests.kt index 465951928..b4db78f6f 100644 --- a/src/commonTest/kotlin/exchange.dydx.abacus/processor/router/skip/SkipProcessorTests.kt +++ b/src/commonTest/kotlin/exchange.dydx.abacus/processor/router/skip/SkipProcessorTests.kt @@ -1,11 +1,14 @@ 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.state.internalstate.InternalTransferInputState import exchange.dydx.abacus.tests.payloads.SkipChainsMock +import exchange.dydx.abacus.tests.payloads.SkipTokensMock import exchange.dydx.abacus.utils.Parser import kotlinx.serialization.json.Json import kotlinx.serialization.json.jsonObject +import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals @@ -16,18 +19,188 @@ internal fun templateToJson(template: String): Map { class SkipProcessorTests { internal val internalState = InternalTransferInputState() - internal val skipProcessor = SkipProcessor(parser = Parser(), internalState = internalState) + internal val parser = Parser() + internal val skipProcessor = SkipProcessor(parser = parser, internalState = internalState) internal val skipChainsMock = SkipChainsMock() + internal val skipTokensMock = SkipTokensMock() + internal val selectedChainId = "osmosis-1" + internal val selectedTokenAddress = "selectedTokenDenom" + internal val selectedTokenSymbol = "selectedTokenSymbol" + internal val selectedTokenDecimals = "15" + internal val selectedChainAssets = listOf( + mapOf( + "denom" to selectedTokenAddress, + "symbol" to selectedTokenSymbol, + "decimals" to selectedTokenDecimals, + "name" to "some-name", + "logo_uri" to "some-logo-uri", + ), + mapOf( + "denom" to "testTokenKeyValue2", + "symbol" to "ARB", + "decimals" to 8, + "name" to "some-name-2", + "logo_uri" to "some-logo-uri-2", + ), + mapOf( + "denom" to "testTokenKeyValue3", + "symbol" to "ETH", + "decimals" to 5, + "name" to "some-name-3", + "logo_uri" to "some-logo-uri-3", + ), + ) + + /** + * Adds tokens to the skipProcessor instance + * This is a reduced scope mock that is to be used for UNIT TESTS ONLY. + * Integration tests should use the skipChainsMock or skipTokensMock structures. + * The test tokens fixture looks like this: + * { + * "osmosis-1": { + * "assets": [ + * { + * "denom": "selectedTokenDenom", + * "symbol": "selectedTokenSymbol", + * "decimals": 15 + * }, + * { + * "denom": "testTokenKeyValue2", + * "symbol": "ARB", + * "decimals": 8 + * }, + * { + * "denom": "testTokenKeyValue3" + * "symbol": "ETH", + * "decimals": 5 + * } + * ] + * }, + * "dont-select": { + * "assets": [ + * {"denom": "shouldNotBeSelectedValue1"}, + * {"denom": "shouldNotBeSelectedValue2"}, + * {"denom": "shouldNotBeSelectedValue3"} + * ] + * } + * } + * + * This makes it easy to know what the filteredTokens output should be + * which in turn helps us know the results of the funs that depend on it. + */ + internal fun addTokens() { + skipProcessor.skipTokens = mapOf( + selectedChainId to mapOf("assets" to selectedChainAssets), + "dont-select" to mapOf( + "assets" to listOf( + mapOf("shouldNotBeSelected1" to "shouldNotBeSelectedValue1"), + mapOf("shouldNotBeSelected2" to "shouldNotBeSelectedValue2"), + mapOf("shouldNotBeSelected3" to "shouldNotBeSelectedValue3"), + ), + ), + ) + } + + @BeforeTest + internal fun setUp() { + addTokens() + } + +// ////////////////// UNIT TESTS ////////////////////// + @Test + fun testFilteredTokens() { + val result = skipProcessor.filteredTokens(chainId = selectedChainId) + val expected = selectedChainAssets + assertEquals(expected, result) + } + + @Test + fun testSelectedTokenSymbol() { + val result = skipProcessor.selectedTokenSymbol(tokenAddress = selectedTokenAddress, selectedChainId = selectedChainId) + val expected = selectedTokenSymbol + assertEquals(expected, result) + } + + @Test + fun testSelectedTokenDecimals() { + val result = skipProcessor.selectedTokenDecimals(tokenAddress = selectedTokenAddress, selectedChainId = selectedChainId) + val expected = selectedTokenDecimals + assertEquals(expected, result) + } + + @Test + fun testDefaultTokenAddress() { + val result = skipProcessor.defaultTokenAddress(selectedChainId) + val expected = selectedTokenAddress + assertEquals(expected, result) + } + + @Test + fun testTokenResources() { + val result = skipProcessor.tokenResources(selectedChainId) + val expected = mapOf( + selectedTokenAddress to TransferInputTokenResource( + address = selectedTokenAddress, + symbol = selectedTokenSymbol, + decimals = parser.asInt(selectedTokenDecimals), + name = "some-name", + iconUrl = "some-logo-uri", + ), + "testTokenKeyValue2" to TransferInputTokenResource( + address = "testTokenKeyValue2", + symbol = "ARB", + decimals = 8, + name = "some-name-2", + iconUrl = "some-logo-uri-2", + ), + "testTokenKeyValue3" to TransferInputTokenResource( + address = "testTokenKeyValue3", + symbol = "ETH", + decimals = 5, + name = "some-name-3", + iconUrl = "some-logo-uri-3", + ), + ) + assertEquals(expected, result) + } + + @Test + fun testTokenOptions() { + val result = skipProcessor.tokenOptions(selectedChainId) + val expected = listOf( + SelectionOption( + stringKey = "some-name", + string = "some-name", + type = selectedTokenAddress, + iconUrl = "some-logo-uri", + ), + SelectionOption( + stringKey = "some-name-2", + string = "some-name-2", + type = "testTokenKeyValue2", + iconUrl = "some-logo-uri-2", + ), + SelectionOption( + stringKey = "some-name-3", + string = "some-name-3", + type = "testTokenKeyValue3", + iconUrl = "some-logo-uri-3", + ), + ) + assertEquals(expected, result) + } + + // /////////////// INTEGRATION TESTS //////////////////// @Test fun testReceivedChains() { + val payload = templateToJson( + skipChainsMock.payload, + ) val modified = skipProcessor.receivedChains( existing = mapOf(), - payload = templateToJson( - skipChainsMock.payload, - ), + payload = 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"), @@ -36,8 +209,6 @@ class SkipProcessorTests { 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", @@ -45,13 +216,90 @@ class SkipProcessorTests { iconUrl = "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/info/logo.png", ), ) + val expectedModified = mapOf( + "transfer" to mapOf( + "chain" to "1", + ), + ) + + assertEquals(expectedChains, internalState.chains) + assertEquals(payload["chains"], skipProcessor.chains) assertEquals(expectedChainResources, internalState.chainResources) + assertEquals(expectedModified, modified) + } + @Test + fun testReceivedTokens() { + val payload = templateToJson(skipTokensMock.payload) + skipProcessor.skipTokens = null + skipProcessor.chains = listOf( + mapOf( + "chain_name" to "aura", + "chain_id" to "1", + "pfm_enabled" to false, + "supports_memo" to true, + "logo_uri" to "https ://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/xstaxy/chain.png", + "bech32_prefix" to "aura", + "chain_type" to "cosmos", + "is_testnet" to false, + ), + ) + val modified = skipProcessor.receivedTokens( + existing = mapOf(), + payload = payload, + ) val expectedModified = mapOf( "transfer" to mapOf( - "chain" to "1", + "token" to "0x97e6E0a40a3D02F12d1cEC30ebfbAE04e37C119E", ), ) + val expectedTokens = listOf( + SelectionOption( + stringKey = "Euro Coin", + string = "Euro Coin", + type = "0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c", + iconUrl = "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/euroc.svg", + ), + SelectionOption( + stringKey = "Real Yield USD", + string = "Real Yield USD", + type = "0x97e6E0a40a3D02F12d1cEC30ebfbAE04e37C119E", + iconUrl = "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/yieldusd.svg", + ), + SelectionOption( + stringKey = "Umee native token", + string = "Umee native token", + type = "0x923e030f951A2401426a3407a9bcc7EB715d9a0b", + iconUrl = "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/umee.svg", + ), + ) + val expectedTokenResources = mapOf( + "0x97e6E0a40a3D02F12d1cEC30ebfbAE04e37C119E" to TransferInputTokenResource( + name = "Real Yield USD", + address = "0x97e6E0a40a3D02F12d1cEC30ebfbAE04e37C119E", + symbol = "YieldUSD", + decimals = 18, + iconUrl = "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/yieldusd.svg", + ), + "0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c" to TransferInputTokenResource( + name = "Euro Coin", + address = "0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c", + symbol = "EUROC", + decimals = 6, + iconUrl = "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/euroc.svg", + ), + "0x923e030f951A2401426a3407a9bcc7EB715d9a0b" to TransferInputTokenResource( + name = "Umee native token", + address = "0x923e030f951A2401426a3407a9bcc7EB715d9a0b", + symbol = "UMEE", + decimals = 6, + iconUrl = "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/umee.svg", + ), + ) + assertEquals(expectedModified, modified) + assertEquals(payload["chain_to_assets_map"], skipProcessor.skipTokens) + assertEquals(expectedTokens, internalState.tokens) + assertEquals(expectedTokenResources, internalState.tokenResources) } } diff --git a/src/commonTest/kotlin/exchange.dydx.abacus/tests/payloads/SkipTokensMock.kt b/src/commonTest/kotlin/exchange.dydx.abacus/tests/payloads/SkipTokensMock.kt new file mode 100644 index 000000000..3d3b432eb --- /dev/null +++ b/src/commonTest/kotlin/exchange.dydx.abacus/tests/payloads/SkipTokensMock.kt @@ -0,0 +1,463 @@ +package exchange.dydx.abacus.tests.payloads + +class SkipTokensMock { + internal val defaultChainIdAssets = """{ + "assets": [ + { + "denom": "0x97e6E0a40a3D02F12d1cEC30ebfbAE04e37C119E", + "chain_id": "1", + "origin_denom": "0x97e6E0a40a3D02F12d1cEC30ebfbAE04e37C119E", + "origin_chain_id": "1", + "trace": "", + "is_cw20": false, + "is_evm": true, + "is_svm": false, + "symbol": "YieldUSD", + "name": "Real Yield USD", + "logo_uri": "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/yieldusd.svg", + "decimals": 18, + "token_contract": "0x97e6E0a40a3D02F12d1cEC30ebfbAE04e37C119E", + "recommended_symbol": "YieldUSD" + }, + { + "denom": "0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c", + "chain_id": "1", + "origin_denom": "0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c", + "origin_chain_id": "1", + "trace": "", + "is_cw20": false, + "is_evm": true, + "is_svm": false, + "symbol": "EUROC", + "name": "Euro Coin", + "logo_uri": "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/euroc.svg", + "decimals": 6, + "token_contract": "0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c", + "coingecko_id": "euro-coin", + "recommended_symbol": "EUROC" + }, + { + "denom": "0x923e030f951A2401426a3407a9bcc7EB715d9a0b", + "chain_id": "1", + "origin_denom": "0x923e030f951A2401426a3407a9bcc7EB715d9a0b", + "origin_chain_id": "1", + "trace": "", + "is_cw20": false, + "is_evm": true, + "is_svm": false, + "symbol": "UMEE", + "name": "Umee native token", + "logo_uri": "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/umee.svg", + "decimals": 6, + "token_contract": "0x923e030f951A2401426a3407a9bcc7EB715d9a0b", + "coingecko_id": "umee", + "recommended_symbol": "UMEE" + } + ] + }""" + internal val payload = """{ + "chain_to_assets_map": { + "1": $defaultChainIdAssets, + "5": { + "assets": [ + { + "denom": "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6", + "chain_id": "5", + "origin_denom": "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6", + "origin_chain_id": "5", + "trace": "", + "is_cw20": false, + "is_evm": true, + "is_svm": false, + "symbol": "WETH", + "name": "weth", + "logo_uri": "https://raw.githubusercontent.com/cosmostation/chainlist/main/chain/ethereum/asset/weth.png", + "decimals": 18, + "token_contract": "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6", + "coingecko_id": "weth", + "recommended_symbol": "WETH" + }, + { + "denom": "0x9c3C9283D3e44854697Cd22D3Faa240Cfb032889", + "chain_id": "5", + "origin_denom": "0x9c3C9283D3e44854697Cd22D3Faa240Cfb032889", + "origin_chain_id": "5", + "trace": "", + "is_cw20": false, + "is_evm": true, + "is_svm": false, + "symbol": "WMATIC", + "name": "wmatic-wei", + "logo_uri": "https://raw.githubusercontent.com/cosmostation/chainlist/main/chain/polygon/asset/wmatic.png", + "decimals": 18, + "token_contract": "0x9c3C9283D3e44854697Cd22D3Faa240Cfb032889", + "coingecko_id": "matic-network", + "recommended_symbol": "WMATIC" + }, + { + "denom": "", + "chain_id": "5", + "origin_denom": "", + "origin_chain_id": "5", + "trace": "", + "is_cw20": false, + "is_evm": true, + "is_svm": false, + "symbol": "ETH", + "name": "eth", + "logo_uri": "https://raw.githubusercontent.com/cosmostation/chainlist/main/chain/ethereum/asset/eth.png", + "decimals": 18, + "coingecko_id": "ethereum", + "recommended_symbol": "ETH" + } + ] + }, + "10": { + "assets": [ + { + "denom": "0x789CbBE5d19f04F38Ec9790b28Ecb07ba5617f61", + "chain_id": "10", + "origin_denom": "0x789CbBE5d19f04F38Ec9790b28Ecb07ba5617f61", + "origin_chain_id": "10", + "trace": "", + "is_cw20": false, + "is_evm": true, + "is_svm": false, + "symbol": "stTIA.axl", + "name": "Stride Staked Tia", + "logo_uri": "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/sttia.svg", + "decimals": 6, + "token_contract": "0x789CbBE5d19f04F38Ec9790b28Ecb07ba5617f61", + "coingecko_id": "stride-staked-tia", + "recommended_symbol": "stTIA.axl" + }, + { + "denom": "0xb829b68f57CC546dA7E5806A929e53bE32a4625D", + "chain_id": "10", + "origin_denom": "0xb829b68f57CC546dA7E5806A929e53bE32a4625D", + "origin_chain_id": "10", + "trace": "", + "is_cw20": false, + "is_evm": true, + "is_svm": false, + "symbol": "axlETH", + "name": "Axelar Wrapped ETH", + "logo_uri": "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/weth.svg", + "decimals": 18, + "token_contract": "0xb829b68f57CC546dA7E5806A929e53bE32a4625D", + "coingecko_id": "weth", + "recommended_symbol": "ETH.axl" + }, + { + "denom": "0x4200000000000000000000000000000000000042", + "chain_id": "10", + "origin_denom": "0x4200000000000000000000000000000000000042", + "origin_chain_id": "10", + "trace": "", + "is_cw20": false, + "is_evm": true, + "is_svm": false, + "symbol": "OP", + "name": "Optimism", + "logo_uri": "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/op.svg", + "decimals": 18, + "token_contract": "0x4200000000000000000000000000000000000042", + "coingecko_id": "optimism", + "recommended_symbol": "OP" + } + ] + }, + "56": { + "assets": [ + { + "denom": "0x43a8cab15D06d3a5fE5854D714C37E7E9246F170", + "chain_id": "56", + "origin_denom": "0x43a8cab15D06d3a5fE5854D714C37E7E9246F170", + "origin_chain_id": "56", + "trace": "", + "is_cw20": false, + "is_evm": true, + "is_svm": false, + "symbol": "ORBS", + "name": "Orbs", + "logo_uri": "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/orbs.svg", + "decimals": 18, + "token_contract": "0x43a8cab15D06d3a5fE5854D714C37E7E9246F170", + "coingecko_id": "orbs", + "recommended_symbol": "ORBS" + }, + { + "denom": "0x7C8DbFdB185C088E73999770C93b885295805739", + "chain_id": "56", + "origin_denom": "0x7C8DbFdB185C088E73999770C93b885295805739", + "origin_chain_id": "56", + "trace": "", + "is_cw20": false, + "is_evm": true, + "is_svm": false, + "symbol": "MOON", + "name": "Moonflow", + "logo_uri": "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/moon.svg", + "decimals": 18, + "token_contract": "0x7C8DbFdB185C088E73999770C93b885295805739", + "recommended_symbol": "MOON" + }, + { + "denom": "0xF700D4c708C2be1463E355F337603183D20E0808", + "chain_id": "56", + "origin_denom": "0xF700D4c708C2be1463E355F337603183D20E0808", + "origin_chain_id": "56", + "trace": "", + "is_cw20": false, + "is_evm": true, + "is_svm": false, + "symbol": "GQ", + "name": "Galactic Quadrant", + "logo_uri": "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/gq.svg", + "decimals": 18, + "token_contract": "0xF700D4c708C2be1463E355F337603183D20E0808", + "recommended_symbol": "GQ" + } + ] + }, + "137": { + "assets": [ + { + "denom": "0x1ED2B2b097E92B2Fe95a172dd29840c71294F1d6", + "chain_id": "137", + "origin_denom": "0x1ED2B2b097E92B2Fe95a172dd29840c71294F1d6", + "origin_chain_id": "137", + "trace": "", + "is_cw20": false, + "is_evm": true, + "is_svm": false, + "symbol": "sFRAX", + "name": "Staked FRAX", + "logo_uri": "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/sfrax.svg", + "decimals": 18, + "token_contract": "0x1ED2B2b097E92B2Fe95a172dd29840c71294F1d6", + "recommended_symbol": "sFRAX" + }, + { + "denom": "0x779661872e9C891027099C9E3fd101DCc8B96433", + "chain_id": "137", + "origin_denom": "0x779661872e9C891027099C9E3fd101DCc8B96433", + "origin_chain_id": "137", + "trace": "", + "is_cw20": false, + "is_evm": true, + "is_svm": false, + "symbol": "axlWBTC", + "name": "Axelar Wrapped WBTC", + "logo_uri": "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/wbtc.svg", + "decimals": 8, + "token_contract": "0x779661872e9C891027099C9E3fd101DCc8B96433", + "coingecko_id": "wrapped-bitcoin", + "recommended_symbol": "WBTC.axl" + }, + { + "denom": "0x0294D8eB7857D43FEb1210Db72456d41481f9Ede", + "chain_id": "137", + "origin_denom": "0x0294D8eB7857D43FEb1210Db72456d41481f9Ede", + "origin_chain_id": "137", + "trace": "", + "is_cw20": false, + "is_evm": true, + "is_svm": false, + "symbol": "axlLqdr", + "name": "Axelar Wrapped Lqdr", + "logo_uri": "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/lqdr.svg", + "decimals": 18, + "token_contract": "0x0294D8eB7857D43FEb1210Db72456d41481f9Ede", + "coingecko_id": "liquiddriver", + "recommended_symbol": "Lqdr.axl" + } + ] + }, + "169": { + "assets": [ + { + "denom": "0x6Fae4D9935E2fcb11fC79a64e917fb2BF14DaFaa", + "chain_id": "169", + "origin_denom": "0x6Fae4D9935E2fcb11fC79a64e917fb2BF14DaFaa", + "origin_chain_id": "169", + "trace": "", + "is_cw20": false, + "is_evm": true, + "is_svm": false, + "symbol": "TIA.n", + "name": "TIA.n", + "logo_uri": "https://raw.githubusercontent.com/cosmos/chain-registry/master/celestia/images/celestia.png", + "decimals": 6, + "token_contract": "0x6Fae4D9935E2fcb11fC79a64e917fb2BF14DaFaa", + "coingecko_id": "bridged-tia-hyperlane", + "recommended_symbol": "TIA.n" + } + ] + }, + "250": { + "assets": [ + { + "denom": "0x3bB68cb55Fc9C22511467c18E42D14E8c959c4dA", + "chain_id": "250", + "origin_denom": "0x3bB68cb55Fc9C22511467c18E42D14E8c959c4dA", + "origin_chain_id": "250", + "trace": "", + "is_cw20": false, + "is_evm": true, + "is_svm": false, + "symbol": "axlATOM", + "name": "Axelar Wrapped ATOM", + "logo_uri": "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/atom.svg", + "decimals": 6, + "token_contract": "0x3bB68cb55Fc9C22511467c18E42D14E8c959c4dA", + "coingecko_id": "cosmos", + "recommended_symbol": "ATOM.axl" + }, + { + "denom": "0x11eDFA12d70e8AC9e94DE019eBa278430873f8C3", + "chain_id": "250", + "origin_denom": "0x11eDFA12d70e8AC9e94DE019eBa278430873f8C3", + "origin_chain_id": "250", + "trace": "", + "is_cw20": false, + "is_evm": true, + "is_svm": false, + "symbol": "TORI", + "name": "Teritori", + "logo_uri": "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/tori.svg", + "decimals": 6, + "token_contract": "0x11eDFA12d70e8AC9e94DE019eBa278430873f8C3", + "recommended_symbol": "TORI" + }, + { + "denom": "0x05E7857Cb748F0018C0CBCe3dfd575B0d8677aeF", + "chain_id": "250", + "origin_denom": "0x05E7857Cb748F0018C0CBCe3dfd575B0d8677aeF", + "origin_chain_id": "250", + "trace": "", + "is_cw20": false, + "is_evm": true, + "is_svm": false, + "symbol": "FXS", + "name": "Frax Share", + "logo_uri": "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/fxs.svg", + "decimals": 18, + "token_contract": "0x05E7857Cb748F0018C0CBCe3dfd575B0d8677aeF", + "recommended_symbol": "FXS" + } + ] + }, + "314": { + "assets": [ + { + "denom": "0xEB466342C4d449BC9f53A865D5Cb90586f405215", + "chain_id": "314", + "origin_denom": "0xEB466342C4d449BC9f53A865D5Cb90586f405215", + "origin_chain_id": "314", + "trace": "", + "is_cw20": false, + "is_evm": true, + "is_svm": false, + "symbol": "axlUSDC", + "name": "Axelar Wrapped USDC", + "logo_uri": "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/usdc.svg", + "decimals": 6, + "token_contract": "0xEB466342C4d449BC9f53A865D5Cb90586f405215", + "coingecko_id": "usd-coin", + "recommended_symbol": "USDC.axl" + }, + { + "denom": "0x4AA81D7AB59C775fe6F9F45E6941A0FB8cD692a6", + "chain_id": "314", + "origin_denom": "0x4AA81D7AB59C775fe6F9F45E6941A0FB8cD692a6", + "origin_chain_id": "314", + "trace": "", + "is_cw20": false, + "is_evm": true, + "is_svm": false, + "symbol": "milkTIA", + "name": "milkTIA", + "logo_uri": "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/milktia.svg", + "decimals": 6, + "token_contract": "0x4AA81D7AB59C775fe6F9F45E6941A0FB8cD692a6", + "coingecko_id": "milkyway-staked-tia", + "recommended_symbol": "milkTIA" + }, + { + "denom": "filecoin-native", + "chain_id": "314", + "origin_denom": "filecoin-native", + "origin_chain_id": "314", + "trace": "", + "is_cw20": false, + "is_evm": true, + "is_svm": false, + "symbol": "FIL", + "name": "FIL", + "logo_uri": "https://assets.coingecko.com/coins/images/12817/standard/filecoin.png?1696512609", + "decimals": 18, + "coingecko_id": "filecoin", + "recommended_symbol": "FIL" + } + ] + }, + "1284": { + "assets": [ + { + "denom": "0x151904806a266EEe52700E195D2937891fb8eD59", + "chain_id": "1284", + "origin_denom": "0x151904806a266EEe52700E195D2937891fb8eD59", + "origin_chain_id": "1284", + "trace": "", + "is_cw20": false, + "is_evm": true, + "is_svm": false, + "symbol": "FXS", + "name": "Frax Share", + "logo_uri": "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/fxs.svg", + "decimals": 18, + "token_contract": "0x151904806a266EEe52700E195D2937891fb8eD59", + "recommended_symbol": "FXS" + }, + { + "denom": "0x5Ac3aD1acC0A3EFd6fB89791967656128e86d8C5", + "chain_id": "1284", + "origin_denom": "0x5Ac3aD1acC0A3EFd6fB89791967656128e86d8C5", + "origin_chain_id": "1284", + "trace": "", + "is_cw20": false, + "is_evm": true, + "is_svm": false, + "symbol": "axlKNC", + "name": "Axelar Wrapped KNC", + "logo_uri": "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/knc.svg", + "decimals": 18, + "token_contract": "0x5Ac3aD1acC0A3EFd6fB89791967656128e86d8C5", + "coingecko_id": "kyber-network-crystal", + "recommended_symbol": "KNC.axl" + }, + { + "denom": "0xF2605EaB29c67d06E71372CA9dfA8aDfd2d34BbF", + "chain_id": "1284", + "origin_denom": "0xF2605EaB29c67d06E71372CA9dfA8aDfd2d34BbF", + "origin_chain_id": "1284", + "trace": "", + "is_cw20": false, + "is_evm": true, + "is_svm": false, + "symbol": "axlSTARS", + "name": "Axelar Wrapped STARS", + "logo_uri": "https://raw.githubusercontent.com/axelarnetwork/axelar-configs/main/images/tokens/stars.svg", + "decimals": 6, + "token_contract": "0xF2605EaB29c67d06E71372CA9dfA8aDfd2d34BbF", + "coingecko_id": "stargaze", + "recommended_symbol": "STARS.axl" + } + ] + } + } +} + + """.trimMargin() +} diff --git a/v4_abacus.podspec b/v4_abacus.podspec index 316ebe75f..93de2db73 100644 --- a/v4_abacus.podspec +++ b/v4_abacus.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |spec| - if false + if !Dir.exist?('build/cocoapods/framework/Abacus.framework') || Dir.empty?('build/cocoapods/framework/Abacus.framework') raise " Kotlin framework 'Abacus' doesn't exist yet, so a proper Xcode project can't be generated.