diff --git a/_data/chains/eip155-1.json b/_data/chains/eip155-1.json index 4966310f..16c91853 100644 --- a/_data/chains/eip155-1.json +++ b/_data/chains/eip155-1.json @@ -22,5 +22,10 @@ "slip44": 60, "ens": { "registry":"0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e" - } + }, + "explorers": [{ + "name": "etherscan", + "url": "https://etherscan.io", + "standard": "EIP3091" + }] } diff --git a/src/main/kotlin/org/ethereum/lists/chains/Env.kt b/src/main/kotlin/org/ethereum/lists/chains/Env.kt index 1c35811c..a1c92e40 100644 --- a/src/main/kotlin/org/ethereum/lists/chains/Env.kt +++ b/src/main/kotlin/org/ethereum/lists/chains/Env.kt @@ -20,7 +20,8 @@ val mandatory_fields = listOf( val optionalFields = listOf( "slip44", "ens", - "icon" + "icon", + "explorers" ) val moshi: Moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build() diff --git a/src/main/kotlin/org/ethereum/lists/chains/Main.kt b/src/main/kotlin/org/ethereum/lists/chains/Main.kt index 6bf1537e..08936482 100644 --- a/src/main/kotlin/org/ethereum/lists/chains/Main.kt +++ b/src/main/kotlin/org/ethereum/lists/chains/Main.kt @@ -103,11 +103,35 @@ fun checkChain(chainFile: File, connectRPC: Boolean) { } jsonObject["icon"]?.let { - if (!File(iconsPath,"$it.json").exists()) { + if (!File(iconsPath, "$it.json").exists()) { error("The Icon $it does not exist - was used in ${chainFile.name}") } } + jsonObject["explorers"]?.let { + if (it !is JsonArray<*>) { + throw (ExplorersMustBeArray()) + } + + it.forEach { explorer -> + if (explorer !is JsonObject) { + error("explorer must be object") + } + + if (explorer["name"] == null) { + throw(ExplorerMustHaveName()) + } + + val url = explorer["url"] + if (url == null || url !is String || !url.startsWith("https://")) { + throw(ExplorerInvalidUrl()) + } + + if (explorer["standard"] != "EIP3091") { + throw(ExplorerStandardMustBeEIP3091()) + } + } + } jsonObject["ens"]?.let { if (it !is JsonObject) { throw ENSMustBeObject() diff --git a/src/main/kotlin/org/ethereum/lists/chains/model/Exceptions.kt b/src/main/kotlin/org/ethereum/lists/chains/model/Exceptions.kt index a6451307..82ea8c74 100644 --- a/src/main/kotlin/org/ethereum/lists/chains/model/Exceptions.kt +++ b/src/main/kotlin/org/ethereum/lists/chains/model/Exceptions.kt @@ -11,4 +11,8 @@ class ENSMustHaveOnlyRegistry: Exception("ens can only have a registry currently class ENSRegistryAddressMustBeValid: Exception("ens registry must have valid address") class NameMustBeUnique(dup: String): Exception(" name must be unique - but found `$dup` more than once") class ShortNameMustBeUnique(dup: String): Exception("short name must be unique - but found `$dup` more than once") -class UnsupportedNamespace(): Exception("So far only the EIP155 namespace is supported") \ No newline at end of file +class UnsupportedNamespace(): Exception("So far only the EIP155 namespace is supported") +class ExplorersMustBeArray: Exception("explorers must be an array") +class ExplorerMustHaveName: Exception("Explorer must have name") +class ExplorerInvalidUrl: Exception("Explorer have url starting with https://") +class ExplorerStandardMustBeEIP3091: Exception("explorer standard must be EIP3091 - currently the only one supported") diff --git a/src/test/kotlin/TheChainChecker.kt b/src/test/kotlin/org/ethereum/lists/chains/TheChainChecker.kt similarity index 73% rename from src/test/kotlin/TheChainChecker.kt rename to src/test/kotlin/org/ethereum/lists/chains/TheChainChecker.kt index 54ba0f21..cdbfff01 100644 --- a/src/test/kotlin/TheChainChecker.kt +++ b/src/test/kotlin/org/ethereum/lists/chains/TheChainChecker.kt @@ -1,5 +1,6 @@ +package org.ethereum.lists.chains + import com.squareup.moshi.JsonEncodingException -import org.ethereum.lists.chains.* import org.ethereum.lists.chains.model.* import org.junit.Before import org.junit.Test @@ -20,6 +21,13 @@ class TheChainChecker { checkChain(file, false) } + @Test + fun shouldPassForValidChainWithExplorers() { + val file = getFile("valid/withexplorer/eip155-1.json") + + checkChain(file, false) + } + @Test(expected = FileNameMustMatchChainId::class) fun shouldFailForInvalidFilename() { val file = getFile("invalid/eip155-invalid_filename.json") @@ -103,6 +111,31 @@ class TheChainChecker { checkChain(getFile("invalid/sameshortname/eip155-1.json"), false) } + @Test(expected = ExplorersMustBeArray::class) + fun shouldFailWhenExplorerIsNotArray() { + checkChain(getFile("invalid/explorersnotarray/eip155-1.json"), false) + } + + @Test(expected = ExplorerStandardMustBeEIP3091::class) + fun shouldFailOnWrongExplorerStandard() { + checkChain(getFile("invalid/wrongexplorerstandard/eip155-1.json"), false) + } + + @Test(expected = ExplorerMustHaveName::class) + fun shouldFailOnNoExplorerName() { + checkChain(getFile("invalid/explorernoname/eip155-1.json"), false) + } + + @Test(expected = ExplorerInvalidUrl::class) + fun shouldFailOnInvalidUrl() { + checkChain(getFile("invalid/explorerinvalidurl/eip155-1.json"), false) + } + + @Test(expected = ExplorerInvalidUrl::class) + fun shouldFailOnMissingURL() { + checkChain(getFile("invalid/explorermissingurl/eip155-1.json"), false) + } + @Test fun canParse2chains() { checkChain(getFile("valid/eip155-1.json"), false) diff --git a/src/test/resources/test_chains/invalid/explorerinvalidurl/eip155-1.json b/src/test/resources/test_chains/invalid/explorerinvalidurl/eip155-1.json new file mode 100644 index 00000000..90475a77 --- /dev/null +++ b/src/test/resources/test_chains/invalid/explorerinvalidurl/eip155-1.json @@ -0,0 +1,24 @@ +{ + "name": "Ethereum Mainnet", + "shortName": "eth", + "chain": "ETH", + "network": "mainnet", + "chainId": 1, + "networkId": 1, + "rpc": [ + "https://mainnet.infura.io/v3/${INFURA_API_KEY}", + "https://api.mycryptoapi.com/eth" + ], + "faucets": [], + "infoURL": "https://ethereum.org", + "nativeCurrency": { + "name": "Ether", + "symbol": "ETH", + "decimals": 18 + }, + "explorers": [{ + "name": "yolo", + "url": "failme", + "standard": "EIP3091" + }] +} \ No newline at end of file diff --git a/src/test/resources/test_chains/invalid/explorermissingurl/eip155-1.json b/src/test/resources/test_chains/invalid/explorermissingurl/eip155-1.json new file mode 100644 index 00000000..025499d0 --- /dev/null +++ b/src/test/resources/test_chains/invalid/explorermissingurl/eip155-1.json @@ -0,0 +1,23 @@ +{ + "name": "Ethereum Mainnet", + "shortName": "eth", + "chain": "ETH", + "network": "mainnet", + "chainId": 1, + "networkId": 1, + "rpc": [ + "https://mainnet.infura.io/v3/${INFURA_API_KEY}", + "https://api.mycryptoapi.com/eth" + ], + "faucets": [], + "infoURL": "https://ethereum.org", + "nativeCurrency": { + "name": "Ether", + "symbol": "ETH", + "decimals": 18 + }, + "explorers": [{ + "name": "yolo", + "standard": "EIP3091" + }] +} \ No newline at end of file diff --git a/src/test/resources/test_chains/invalid/explorernoname/eip155-1.json b/src/test/resources/test_chains/invalid/explorernoname/eip155-1.json new file mode 100644 index 00000000..38d9fd6f --- /dev/null +++ b/src/test/resources/test_chains/invalid/explorernoname/eip155-1.json @@ -0,0 +1,23 @@ +{ + "name": "Ethereum Mainnet", + "shortName": "eth", + "chain": "ETH", + "network": "mainnet", + "chainId": 1, + "networkId": 1, + "rpc": [ + "https://mainnet.infura.io/v3/${INFURA_API_KEY}", + "https://api.mycryptoapi.com/eth" + ], + "faucets": [], + "infoURL": "https://ethereum.org", + "nativeCurrency": { + "name": "Ether", + "symbol": "ETH", + "decimals": 18 + }, + "explorers": [{ + "url": "https://etherscan.io", + "standard": "EIP3091" + }] +} \ No newline at end of file diff --git a/src/test/resources/test_chains/invalid/explorersnotarray/eip155-1.json b/src/test/resources/test_chains/invalid/explorersnotarray/eip155-1.json new file mode 100644 index 00000000..9895ba6d --- /dev/null +++ b/src/test/resources/test_chains/invalid/explorersnotarray/eip155-1.json @@ -0,0 +1,20 @@ +{ + "name": "Ethereum Mainnet", + "shortName": "eth", + "chain": "ETH", + "network": "mainnet", + "chainId": 1, + "networkId": 1, + "rpc": [ + "https://mainnet.infura.io/v3/${INFURA_API_KEY}", + "https://api.mycryptoapi.com/eth" + ], + "faucets": [], + "infoURL": "https://ethereum.org", + "nativeCurrency": { + "name": "Ether", + "symbol": "ETH", + "decimals": 18 + }, + "explorers": "should_fail" +} \ No newline at end of file diff --git a/src/test/resources/test_chains/invalid/wrongexplorerstandard/eip155-1.json b/src/test/resources/test_chains/invalid/wrongexplorerstandard/eip155-1.json new file mode 100644 index 00000000..c3f128fd --- /dev/null +++ b/src/test/resources/test_chains/invalid/wrongexplorerstandard/eip155-1.json @@ -0,0 +1,24 @@ +{ + "name": "Ethereum Mainnet", + "shortName": "eth", + "chain": "ETH", + "network": "mainnet", + "chainId": 1, + "networkId": 1, + "rpc": [ + "https://mainnet.infura.io/v3/${INFURA_API_KEY}", + "https://api.mycryptoapi.com/eth" + ], + "faucets": [], + "infoURL": "https://ethereum.org", + "nativeCurrency": { + "name": "Ether", + "symbol": "ETH", + "decimals": 18 + }, + "explorers": [{ + "name": "etherscan", + "url": "https://etherscan.io", + "standard": "failme" + }] +} \ No newline at end of file diff --git a/src/test/resources/test_chains/valid/withexplorer/eip155-1.json b/src/test/resources/test_chains/valid/withexplorer/eip155-1.json new file mode 100644 index 00000000..ef4eeb20 --- /dev/null +++ b/src/test/resources/test_chains/valid/withexplorer/eip155-1.json @@ -0,0 +1,26 @@ +{ + "name": "Ethereum Mainnet", + "shortName": "eth", + "chain": "ETH", + "network": "mainnet", + "chainId": 1, + "networkId": 1, + "rpc": [ + "https://mainnet.infura.io/v3/${INFURA_API_KEY}", + "https://api.mycryptoapi.com/eth" + ], + "faucets": [], + "infoURL": "https://ethereum.org", + "nativeCurrency": { + "name": "Ether", + "symbol": "ETH", + "decimals": 18 + }, + "explorers": [ + { + "name": "etherscan", + "url": "https://etherscan.io", + "standard": "EIP3091" + } + ] +}