diff --git a/src/main/kotlin/io/emeraldpay/dshackle/config/MainConfig.kt b/src/main/kotlin/io/emeraldpay/dshackle/config/MainConfig.kt index dac4bd1a..13915be9 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/config/MainConfig.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/config/MainConfig.kt @@ -22,5 +22,6 @@ class MainConfig { var cache: CacheConfig? = null var proxy: ProxyConfig? = null var upstreams: UpstreamsConfig? = null + var tokens: TokensConfig? = null } \ No newline at end of file diff --git a/src/main/kotlin/io/emeraldpay/dshackle/config/MainConfigReader.kt b/src/main/kotlin/io/emeraldpay/dshackle/config/MainConfigReader.kt index 0ac3653a..2af182b8 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/config/MainConfigReader.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/config/MainConfigReader.kt @@ -32,6 +32,7 @@ class MainConfigReader( private val proxyConfigReader = ProxyConfigReader() private val upstreamsConfigReader = UpstreamsConfigReader(fileResolver) private val cacheConfigReader = CacheConfigReader() + private val tokensConfigReader = TokensConfigReader() fun read(input: InputStream): MainConfig? { val configNode = readNode(input) @@ -59,6 +60,9 @@ class MainConfigReader( cacheConfigReader.read(input)?.let { config.cache = it } + tokensConfigReader.read(input)?.let { + config.tokens = it + } return config } diff --git a/src/main/kotlin/io/emeraldpay/dshackle/config/TokensConfig.kt b/src/main/kotlin/io/emeraldpay/dshackle/config/TokensConfig.kt new file mode 100644 index 00000000..d9bd5e95 --- /dev/null +++ b/src/main/kotlin/io/emeraldpay/dshackle/config/TokensConfig.kt @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2020 EmeraldPay, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.emeraldpay.dshackle.config + +import io.emeraldpay.dshackle.BlockchainType +import io.emeraldpay.grpc.Chain +import io.infinitape.etherjar.domain.Address + +class TokensConfig( + val tokens: List +) { + + class Token { + // reference id, used by get balance and others + var id: String? = null + var blockchain: Chain? = null + + // coin name + var name: String? = null + var type: Type? = null; + var address: String? = null + + fun validate(): String? { + return when { + id.isNullOrBlank() -> "id" + blockchain == null -> "blockchain" + name.isNullOrBlank() -> "name" + type == null -> type + address.isNullOrBlank() -> "address" + blockchain != null + && BlockchainType.fromBlockchain(blockchain!!) == BlockchainType.ETHEREUM + && !Address.isValidAddress(address) -> "address" + else -> null + } + } + } + + enum class Type { + ERC20 + } + +} \ No newline at end of file diff --git a/src/main/kotlin/io/emeraldpay/dshackle/config/TokensConfigReader.kt b/src/main/kotlin/io/emeraldpay/dshackle/config/TokensConfigReader.kt new file mode 100644 index 00000000..70bdbb38 --- /dev/null +++ b/src/main/kotlin/io/emeraldpay/dshackle/config/TokensConfigReader.kt @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2020 EmeraldPay, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.emeraldpay.dshackle.config + +import org.slf4j.LoggerFactory +import org.yaml.snakeyaml.nodes.MappingNode +import java.io.InputStream + +class TokensConfigReader : YamlConfigReader(), ConfigReader { + + private val log = LoggerFactory.getLogger(TokensConfigReader::class.java) + + fun read(input: InputStream): TokensConfig? { + val configNode = readNode(input) + return read(configNode) + } + + override fun read(input: MappingNode?): TokensConfig? { + val tokens = getList(input, "tokens")?.value?.map { node -> + val token = TokensConfig.Token() + token.id = getValueAsString(node, "id") + token.blockchain = getValueAsString(node, "blockchain")?.let { + getBlockchain(it) + } + token.address = getValueAsString(node, "address") + token.name = getValueAsString(node, "name") + token.type = getValueAsString(node, "type")?.let { + if (it.toUpperCase() == "ERC-20") { + TokensConfig.Type.ERC20 + } else { + log.warn("Invalid token type: $it") + null + } + } + token + }?.filter { token -> + val invalidField = token.validate() + if (invalidField != null) { + log.error("Failed to parse token ${token.id}. Invalid field: $invalidField") + false + } else { + true + } + } + return tokens?.let { + TokensConfig(it) + } + } + +} \ No newline at end of file diff --git a/src/test/groovy/io/emeraldpay/dshackle/config/TokensConfigReaderSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/config/TokensConfigReaderSpec.groovy new file mode 100644 index 00000000..4ef8c3a4 --- /dev/null +++ b/src/test/groovy/io/emeraldpay/dshackle/config/TokensConfigReaderSpec.groovy @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2020 EmeraldPay, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.emeraldpay.dshackle.config + +import io.emeraldpay.grpc.Chain +import spock.lang.Specification + +class TokensConfigReaderSpec extends Specification { + + TokensConfigReader reader = new TokensConfigReader() + + def "Read basic"() { + setup: + def config = this.class.getClassLoader().getResourceAsStream("tokens/basic.yaml") + when: + def act = reader.read(config) + + then: + act != null + act.tokens.size() == 2 + with(act.tokens[0]) { + id == "dai" + blockchain == Chain.ETHEREUM + name == "DAI" + type == TokensConfig.Type.ERC20 + address == "0x6B175474E89094C44Da98b954EedeAC495271d0F" + } + with(act.tokens[1]) { + id == "tether" + blockchain == Chain.ETHEREUM + name == "Tether" + type == TokensConfig.Type.ERC20 + address == "0xdac17f958d2ee523a2206206994597c13d831ec7" + } + + } +} diff --git a/src/test/resources/tokens/basic.yaml b/src/test/resources/tokens/basic.yaml new file mode 100644 index 00000000..aa512ddb --- /dev/null +++ b/src/test/resources/tokens/basic.yaml @@ -0,0 +1,11 @@ +tokens: + - id: dai + blockchain: ethereum + name: DAI + type: ERC-20 + address: 0x6B175474E89094C44Da98b954EedeAC495271d0F + - id: tether + blockchain: ethereum + name: Tether + type: ERC-20 + address: 0xdac17f958d2ee523a2206206994597c13d831ec7 \ No newline at end of file