diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 186b71557..ac33e9944 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/kotlin/org/ethereum/lists/tokens/Constant.kt b/src/main/kotlin/org/ethereum/lists/tokens/Constant.kt index 2ff757d68..807a06bc7 100644 --- a/src/main/kotlin/org/ethereum/lists/tokens/Constant.kt +++ b/src/main/kotlin/org/ethereum/lists/tokens/Constant.kt @@ -5,7 +5,7 @@ import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory import java.io.File val mandatoryFields = listOf("name", "symbol", "address", "decimals") -val optionalFields = listOf("comment", "logo", "support", "community", "website", "github", "img-16x16", "img-128x128", "social", "ens_address", "deprecation", "type", "invalid_erc20_symbol", "invalid_erc20_decimals", "address_eip1191") +val optionalFields = listOf("comment", "logo", "support", "community", "website", "github", "img-16x16", "img-128x128", "social", "ens_address", "deprecation", "type", "invalid_erc20_symbol", "invalid_erc20_decimals", "address_eip1191", "suspicious") val outDir = File("build/output") val allNetworksTokenDir = File("tokens") diff --git a/src/main/kotlin/org/ethereum/lists/tokens/TokenChecker.kt b/src/main/kotlin/org/ethereum/lists/tokens/TokenChecker.kt index 29e73eaee..14d672055 100644 --- a/src/main/kotlin/org/ethereum/lists/tokens/TokenChecker.kt +++ b/src/main/kotlin/org/ethereum/lists/tokens/TokenChecker.kt @@ -41,6 +41,8 @@ val onChainIgnore by lazy { File("onChainIgnore.lst").readText().split("\n") } +val rpc by lazy { getMin3RPC(listOf("https://in3-v2.slock.it/mainnet/nd-1")) } + suspend fun checkTokenFile(file: File, onChainCheck: Boolean = false, chainId: ChainId? = null) { val handle = file.name.removeSuffix(".json") if (onChainCheck && (notToProcessFiles.contains(handle) || onChainIgnore.contains(handle))) { @@ -49,18 +51,18 @@ suspend fun checkTokenFile(file: File, onChainCheck: Boolean = false, chainId: C val jsonObject = Klaxon().parseJsonObject(file.reader()) val address = Address(jsonObject["address"] as String) - val address_eip1191 = if (jsonObject["address_eip1191"] != null) Address(jsonObject["address_eip1191"] as String) else null + val addressEIP1191 = if (jsonObject["address_eip1191"] != null) Address(jsonObject["address_eip1191"] as String) else null when { !address.isValid() -> throw InvalidAddress(address) - address_eip1191 != null && !(address_eip1191.isValid()) -> throw InvalidAddress(address) + addressEIP1191 != null && !(addressEIP1191.isValid()) -> throw InvalidAddress(address) (!address.hasValidERC55Checksum()) -> throw InvalidChecksum(address.toString() + " expected: " + address.withERC55Checksum()) - (address_eip1191 != null && chainId != null && !address_eip1191.hasValidERC1191Checksum(chainId)) - -> throw Invalid1191Checksum(address_eip1191.toString() + " expected: " + address_eip1191.withERC1191Checksum(chainId)) + (addressEIP1191 != null && chainId != null && !addressEIP1191.hasValidERC1191Checksum(chainId)) + -> throw Invalid1191Checksum(addressEIP1191.toString() + " expected: " + addressEIP1191.withERC1191Checksum(chainId)) file.name != "${address.hex}.json" -> throw InvalidFileName() } @@ -76,7 +78,7 @@ suspend fun checkTokenFile(file: File, onChainCheck: Boolean = false, chainId: C val symbol = jsonObject["symbol"] as String if (onChainCheck) { - val rpc = getMin3RPC(listOf("https://in3-v2.slock.it/mainnet/nd-1")) + val contract = ERC20RPCConnector(address, rpc) if (jsonObject["invalid_erc20_decimals"] as? Boolean != true) { diff --git a/src/main/kotlin/org/ethereum/lists/tokens/model/RedFlags.kt b/src/main/kotlin/org/ethereum/lists/tokens/model/RedFlags.kt new file mode 100644 index 000000000..c5ff5a5e1 --- /dev/null +++ b/src/main/kotlin/org/ethereum/lists/tokens/model/RedFlags.kt @@ -0,0 +1,5 @@ +package org.ethereum.lists.tokens.model + +data class RedFlags(val type: String, + val comment: String? = null, + val url: String? = null) \ No newline at end of file diff --git a/src/main/kotlin/org/ethereum/lists/tokens/model/Token.kt b/src/main/kotlin/org/ethereum/lists/tokens/model/Token.kt index ecd675889..50f7f79ca 100644 --- a/src/main/kotlin/org/ethereum/lists/tokens/model/Token.kt +++ b/src/main/kotlin/org/ethereum/lists/tokens/model/Token.kt @@ -14,4 +14,5 @@ data class Token(val symbol: String, val support: Support? = null, val social: Social? = null, val deprecation: Deprecation? = null, - val address_eip1191: String? = null) \ No newline at end of file + val address_eip1191: String? = null, + val red_flags: List? = null) \ No newline at end of file diff --git a/src/test/kotlin/TheTokenChecker.kt b/src/test/kotlin/TheTokenChecker.kt index 2d89ce549..0d8ec71da 100644 --- a/src/test/kotlin/TheTokenChecker.kt +++ b/src/test/kotlin/TheTokenChecker.kt @@ -27,6 +27,27 @@ class TheTokenChecker { checkTokenFile(file) } + @Test + fun shouldPassForValidTokenWithSuspiciousField(): Unit = runBlocking { + val file = getFile("valid_with_optional_suspicious_field/0x6475A7FA6Ed2D5180F0e0a07c2d951D12C0EDB91.json") + + checkTokenFile(file) + } + + @Test + fun shouldPassForValidTokenWithSuspiciousFieldSmall(): Unit = runBlocking { + val file = getFile("valid_with_optional_suspicious_field_small/0x6475A7FA6Ed2D5180F0e0a07c2d951D12C0EDB91.json") + + checkTokenFile(file) + } + + @Test(expected = InvalidJSON::class) + fun shouldFailForNoRedFlagType(): Unit = runBlocking { + val file = getFile("invalidvalid_with_optional_suspicious_field_no_type/0x6475A7FA6Ed2D5180F0e0a07c2d951D12C0EDB91.json") + + checkTokenFile(file) + } + @Test fun shouldPassForValidTokenWithDeprecationMigrationNewChain(): Unit = runBlocking { diff --git a/src/test/resources/test_tokens/invalidvalid_with_optional_suspicious_field_no_type/0x6475A7FA6Ed2D5180F0e0a07c2d951D12C0EDB91.json b/src/test/resources/test_tokens/invalidvalid_with_optional_suspicious_field_no_type/0x6475A7FA6Ed2D5180F0e0a07c2d951D12C0EDB91.json new file mode 100644 index 000000000..d2b8b6f03 --- /dev/null +++ b/src/test/resources/test_tokens/invalidvalid_with_optional_suspicious_field_no_type/0x6475A7FA6Ed2D5180F0e0a07c2d951D12C0EDB91.json @@ -0,0 +1,15 @@ +{ + "symbol": "NONE", + "name": "None", + "address": "0x6475A7FA6Ed2D5180F0e0a07c2d951D12C0EDB91", + "decimals": 0, + "support": { + "email": "ligi@ethereum.org" + }, + "social": { + "github": "https://github.com/walleth/contracts/tree/master/NoneToken" + }, + "red_flags": [{ + "url": "http://fake.info/token" + }] +} diff --git a/src/test/resources/test_tokens/valid_with_optional_suspicious_field/0x6475A7FA6Ed2D5180F0e0a07c2d951D12C0EDB91.json b/src/test/resources/test_tokens/valid_with_optional_suspicious_field/0x6475A7FA6Ed2D5180F0e0a07c2d951D12C0EDB91.json new file mode 100644 index 000000000..e87cc8e89 --- /dev/null +++ b/src/test/resources/test_tokens/valid_with_optional_suspicious_field/0x6475A7FA6Ed2D5180F0e0a07c2d951D12C0EDB91.json @@ -0,0 +1,17 @@ +{ + "symbol": "NONE", + "name": "None", + "address": "0x6475A7FA6Ed2D5180F0e0a07c2d951D12C0EDB91", + "decimals": 0, + "support": { + "email": "ligi@ethereum.org" + }, + "social": { + "github": "https://github.com/walleth/contracts/tree/master/NoneToken" + }, + "red_flags": [{ + "type": "suspicious", + "comment": "fake scam token", + "url": "http://fake.info/token" + }] +} diff --git a/src/test/resources/test_tokens/valid_with_optional_suspicious_field_small/0x6475A7FA6Ed2D5180F0e0a07c2d951D12C0EDB91.json b/src/test/resources/test_tokens/valid_with_optional_suspicious_field_small/0x6475A7FA6Ed2D5180F0e0a07c2d951D12C0EDB91.json new file mode 100644 index 000000000..a3f70429f --- /dev/null +++ b/src/test/resources/test_tokens/valid_with_optional_suspicious_field_small/0x6475A7FA6Ed2D5180F0e0a07c2d951D12C0EDB91.json @@ -0,0 +1,15 @@ +{ + "symbol": "NONE", + "name": "None", + "address": "0x6475A7FA6Ed2D5180F0e0a07c2d951D12C0EDB91", + "decimals": 0, + "support": { + "email": "ligi@ethereum.org" + }, + "social": { + "github": "https://github.com/walleth/contracts/tree/master/NoneToken" + }, + "red_flags": [{ + "type": "suspicious" + }] +}