diff --git a/Gemfile.lock b/Gemfile.lock index fbeb8792..545deed4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -69,4 +69,4 @@ DEPENDENCIES tzinfo-data BUNDLED WITH - 1.16.3 + 2.1.4 diff --git a/README.md b/README.md index 804db61b..75e68120 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ # EVM-based Chains -Listed by chainId according to EIP-155 - -Data source available on `_data/chains.json` +The source data is in _data/chains. Each chain has its own file with the filename being the [CAIP-2](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-2.md) representation as name and `.json` ans extension. ## Example @@ -24,14 +22,48 @@ Data source available on `_data/chains.json` "infoURL": "https://ethereum.org", "shortName": "eth", "chainId": 1, - "networkId": 1 + "networkId": 1, + "icon": "ethereum", + "explorers": [{ + "name": "etherscan", + "url": "https://etherscan.io", + "icon": "etherscan", + "standard": "EIP3091" + }] } ``` +when an icon is used in either the network or a explorer there must be a json in _data/icons with the name used (e.g. in the above example there must be a `ethereum.json` and a `etherscan.json` in there) - the icon jsons look like this: + +```json + +[ + { + "url": "ipfs://QmdwQDr6vmBtXmK2TmknkEuZNoaDqTasFdZdu3DRw8b2wt", + "width": 1000, + "height": 1628, + "format": "png" + } +] + +``` + +where: + * the URL must be a IPFS url that is publicly resolveable + * width and height are optional - but when one is there then the other must be there also + * format is either "png", "jpg" or "svg" + +## Aggregation + +There are also aggregated json files with all chains automatically assembled: + * https://chainid.network/chains.json + * https://chainid.network/chains_mini.json (miniaturized - fewer fields for smaller filesize) + ## Usages - * [chainlist.org](https://chainlist.org) + * [chainlist.org](https://chainlist.org) or [networklist-org.vercel.app](https://networklist-org.vercel.app) as a staging version with a more up-to-date list * [chainid.network](https://chainid.network) * [WallETH](https://walleth.org) * [TREZOR](https://trezor.io) + * [networks.vercel.app](https://networks.vercel.app) * Your project - contact us to add it here! diff --git a/_data/chains/eip155-1.json b/_data/chains/eip155-1.json index 5851ad07..16c91853 100644 --- a/_data/chains/eip155-1.json +++ b/_data/chains/eip155-1.json @@ -2,6 +2,7 @@ "name": "Ethereum Mainnet", "chain": "ETH", "network": "mainnet", + "icon": "ethereum", "rpc": [ "https://mainnet.infura.io/v3/${INFURA_API_KEY}", "wss://mainnet.infura.io/ws/v3/${INFURA_API_KEY}", @@ -21,5 +22,10 @@ "slip44": 60, "ens": { "registry":"0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e" - } + }, + "explorers": [{ + "name": "etherscan", + "url": "https://etherscan.io", + "standard": "EIP3091" + }] } diff --git a/_data/chains/eip155-1024.json b/_data/chains/eip155-1024.json index b44a4b08..a7b2d0ad 100644 --- a/_data/chains/eip155-1024.json +++ b/_data/chains/eip155-1024.json @@ -2,7 +2,11 @@ "name": "Clover Mainnet", "chain": "Clover", "network": "clover mainnet", - "rpc": [], + "rpc": [ + "https://rpc-ivy.clover.finance", + "https://rpc-ivy-2.clover.finance", + "https://rpc-ivy-3.clover.finance" + ], "faucets": [], "nativeCurrency": { "name": "Clover", @@ -13,4 +17,4 @@ "shortName": "clv", "chainId": 1024, "networkId": 1024 -} \ No newline at end of file +} diff --git a/_data/chains/eip155-1139.json b/_data/chains/eip155-1139.json index c558969b..2dcea8e9 100644 --- a/_data/chains/eip155-1139.json +++ b/_data/chains/eip155-1139.json @@ -9,7 +9,7 @@ "symbol": "MATH", "decimals": 18 }, - "infoURL": "https://mathwallet.org", + "infoURL": "https://mathchain.org", "shortName": "MATH", "chainId": 1139, "networkId": 1139 diff --git a/_data/chains/eip155-1140.json b/_data/chains/eip155-1140.json index bd8be432..fc15213f 100644 --- a/_data/chains/eip155-1140.json +++ b/_data/chains/eip155-1140.json @@ -2,14 +2,18 @@ "name": "MathChain Testnet", "chain": "MATH", "network": "testnet", - "rpc": [], - "faucets": [], + "rpc": [ + "https://galois-hk.maiziqianbao.net/rpc" + ], + "faucets": [ + "https://scan.boka.network/#/Galois/faucet" + ], "nativeCurrency": { "name": "MathChain", "symbol": "MATH", "decimals": 18 }, - "infoURL": "https://mathwallet.org/", + "infoURL": "https://mathchain.org", "shortName": "tMATH", "chainId": 1140, "networkId": 1140 diff --git a/_data/chains/eip155-128.json b/_data/chains/eip155-128.json index c4501974..0566bc7d 100644 --- a/_data/chains/eip155-128.json +++ b/_data/chains/eip155-128.json @@ -12,7 +12,7 @@ "symbol": "HT", "decimals": 18 }, - "infoURL": "https://www.hecochain.com", + "infoURL": "https://hecoinfo.com", "shortName": "heco", "chainId": 128, "networkId": 128 diff --git a/_data/chains/eip155-1666600000.json b/_data/chains/eip155-1666600000.json index 01b727eb..c3804555 100644 --- a/_data/chains/eip155-1666600000.json +++ b/_data/chains/eip155-1666600000.json @@ -3,7 +3,7 @@ "chain": "Harmony", "network": "mainnet", "rpc": [ - "https://rpc.s0.t.hmny.io" + "https://api.harmony.one" ], "faucets": [ ], diff --git a/_data/chains/eip155-1666600001.json b/_data/chains/eip155-1666600001.json index 8caa1872..0a1bedaa 100644 --- a/_data/chains/eip155-1666600001.json +++ b/_data/chains/eip155-1666600001.json @@ -3,7 +3,7 @@ "chain": "Harmony", "network": "mainnet", "rpc": [ - "https://rpc.s1.t.hmny.io" + "https://s1.api.harmony.one" ], "faucets": [ ], diff --git a/_data/chains/eip155-1666600002.json b/_data/chains/eip155-1666600002.json index e21f9021..e1f9aec0 100644 --- a/_data/chains/eip155-1666600002.json +++ b/_data/chains/eip155-1666600002.json @@ -3,7 +3,7 @@ "chain": "Harmony", "network": "mainnet", "rpc": [ - "https://rpc.s2.t.hmny.io" + "https://s2.api.harmony.one" ], "faucets": [ ], diff --git a/_data/chains/eip155-1666600003.json b/_data/chains/eip155-1666600003.json index 49d813a1..14a228db 100644 --- a/_data/chains/eip155-1666600003.json +++ b/_data/chains/eip155-1666600003.json @@ -3,7 +3,7 @@ "chain": "Harmony", "network": "mainnet", "rpc": [ - "https://rpc.s3.t.hmny.io" + "https://s3.api.harmony.one" ], "faucets": [ ], diff --git a/_data/chains/eip155-1666700000.json b/_data/chains/eip155-1666700000.json new file mode 100644 index 00000000..f276861a --- /dev/null +++ b/_data/chains/eip155-1666700000.json @@ -0,0 +1,20 @@ +{ + "name": "Harmony Testnet Shard 0", + "chain": "Harmony", + "network": "testnet", + "rpc": [ + "https://api.s0.b.hmny.io" + ], + "faucets": [ + ], + "nativeCurrency": { + "name": "ONE", + "symbol": "ONE", + "decimals": 18 + }, + "infoURL": "https://www.harmony.one/", + "shortName": "hmy-b-s0", + "chainId": 1666700000, + "networkId": 1666700000 + } + \ No newline at end of file diff --git a/_data/chains/eip155-1666700001.json b/_data/chains/eip155-1666700001.json new file mode 100644 index 00000000..7fb96936 --- /dev/null +++ b/_data/chains/eip155-1666700001.json @@ -0,0 +1,20 @@ +{ + "name": "Harmony Testnet Shard 1", + "chain": "Harmony", + "network": "testnet", + "rpc": [ + "https://api.s1.b.hmny.io" + ], + "faucets": [ + ], + "nativeCurrency": { + "name": "ONE", + "symbol": "ONE", + "decimals": 18 + }, + "infoURL": "https://www.harmony.one/", + "shortName": "hmy-b-s1", + "chainId": 1666700001, + "networkId": 1666700001 + } + \ No newline at end of file diff --git a/_data/chains/eip155-1666700002.json b/_data/chains/eip155-1666700002.json new file mode 100644 index 00000000..c81c44e6 --- /dev/null +++ b/_data/chains/eip155-1666700002.json @@ -0,0 +1,20 @@ +{ + "name": "Harmony Testnet Shard 2", + "chain": "Harmony", + "network": "testnet", + "rpc": [ + "https://api.s2.b.hmny.io" + ], + "faucets": [ + ], + "nativeCurrency": { + "name": "ONE", + "symbol": "ONE", + "decimals": 18 + }, + "infoURL": "https://www.harmony.one/", + "shortName": "hmy-b-s2", + "chainId": 1666700002, + "networkId": 1666700002 + } + \ No newline at end of file diff --git a/_data/chains/eip155-1666700003.json b/_data/chains/eip155-1666700003.json new file mode 100644 index 00000000..98a9bb30 --- /dev/null +++ b/_data/chains/eip155-1666700003.json @@ -0,0 +1,20 @@ +{ + "name": "Harmony Testnet Shard 3", + "chain": "Harmony", + "network": "testnet", + "rpc": [ + "https://api.s3.b.hmny.io" + ], + "faucets": [ + ], + "nativeCurrency": { + "name": "ONE", + "symbol": "ONE", + "decimals": 18 + }, + "infoURL": "https://www.harmony.one/", + "shortName": "hmy-b-s3", + "chainId": 1666700003, + "networkId": 1666700003 + } + \ No newline at end of file diff --git a/_data/chains/eip155-22.json b/_data/chains/eip155-22.json new file mode 100644 index 00000000..a16e1df8 --- /dev/null +++ b/_data/chains/eip155-22.json @@ -0,0 +1,16 @@ +{ + "name": "ELA-DID-Sidechain Mainnet", + "chain": "ETH", + "network": "mainnet", + "rpc": [], + "faucets": [], + "nativeCurrency": { + "name": "Elastos", + "symbol": "ELA", + "decimals": 18 + }, + "infoURL": "https://www.elastos.org/", + "shortName": "eladid", + "chainId": 22, + "networkId": 22 +} diff --git a/_data/chains/eip155-23.json b/_data/chains/eip155-23.json new file mode 100644 index 00000000..aeb18471 --- /dev/null +++ b/_data/chains/eip155-23.json @@ -0,0 +1,16 @@ +{ + "name": "ELA-DID-Sidechain Testnet", + "chain": "ETH", + "network": "testnet", + "rpc": [], + "faucets": [], + "nativeCurrency": { + "name": "Elastos", + "symbol": "tELA", + "decimals": 18 + }, + "infoURL": "https://elaeth.io/", + "shortName": "eladidt", + "chainId": 23, + "networkId": 23 +} diff --git a/_data/chains/eip155-24734.json b/_data/chains/eip155-24734.json new file mode 100644 index 00000000..013a3394 --- /dev/null +++ b/_data/chains/eip155-24734.json @@ -0,0 +1,18 @@ +{ + "name": "MintMe.com Coin", + "chain": "MINTME", + "network": "mainnet", + "rpc": [ + "https://node1.mintme.com" + ], + "faucets": [], + "nativeCurrency": { + "name": "MintMe.com Coin", + "symbol": "MINTME", + "decimals": 18 + }, + "infoURL": "https://www.mintme.com", + "shortName": "mintme", + "chainId": 24734, + "networkId": 37480 +} diff --git a/_data/chains/eip155-256.json b/_data/chains/eip155-256.json index 8b9f530b..8efc1196 100644 --- a/_data/chains/eip155-256.json +++ b/_data/chains/eip155-256.json @@ -14,7 +14,7 @@ "symbol": "htt", "decimals": 18 }, - "infoURL": "https://www.hecochain.com", + "infoURL": "https://testnet.hecoinfo.com", "shortName": "hecot", "chainId": 256, "networkId": 256 diff --git a/_data/chains/eip155-269.json b/_data/chains/eip155-269.json index da686d34..a6e7142e 100644 --- a/_data/chains/eip155-269.json +++ b/_data/chains/eip155-269.json @@ -3,7 +3,7 @@ "chain": "HPB", "network": "mainnet", "rpc": [ - "https://node.hpb.blue" + "https://hpb.app" ], "faucets": [], "nativeCurrency": { @@ -11,7 +11,7 @@ "symbol": "HPB", "decimals": 18 }, - "infoURL": "https://hpb.io", + "infoURL": "https://hpbscan.org/", "shortName": "hpb", "chainId": 269, "networkId": 100, diff --git a/_data/chains/eip155-44.json b/_data/chains/eip155-44.json new file mode 100644 index 00000000..5eedd4eb --- /dev/null +++ b/_data/chains/eip155-44.json @@ -0,0 +1,16 @@ +{ + "name": "Darwinia Crab Network", + "chain": "crab", + "network": "Crab network", + "rpc": [], + "faucets": [], + "nativeCurrency": { + "name": "Crab Token", + "symbol": "CRING", + "decimals": 9 + }, + "infoURL": "https://crab.network/", + "shortName": "crab", + "chainId": 44, + "networkId": 44 +} diff --git a/_data/chains/eip155-4689.json b/_data/chains/eip155-4689.json new file mode 100644 index 00000000..cf20a828 --- /dev/null +++ b/_data/chains/eip155-4689.json @@ -0,0 +1,19 @@ +{ + "name": "IoTeX Network Mainnet", + "chain": "IOTX", + "network": "mainnet", + "rpc": [ + "https://babel-api.mainnet.iotex.one" + ], + "faucets": [ + ], + "nativeCurrency": { + "name": "IoTeX", + "symbol": "IOTX", + "decimals": 18 + }, + "infoURL": "https://iotex.io", + "shortName": "iotex-mainnet", + "chainId": 4689, + "networkId": 4689 +} diff --git a/_data/chains/eip155-4690.json b/_data/chains/eip155-4690.json new file mode 100644 index 00000000..574627b6 --- /dev/null +++ b/_data/chains/eip155-4690.json @@ -0,0 +1,19 @@ +{ + "name": "IoTeX Network Testnet", + "chain": "IOTX", + "network": "testnet", + "rpc": [ + "https://babel-api.testnet.iotex.one" + ], + "faucets": [ + ], + "nativeCurrency": { + "name": "IoTeX", + "symbol": "IOTX", + "decimals": 18 + }, + "infoURL": "https://iotex.io", + "shortName": "iotex-testnet", + "chainId": 4690, + "networkId": 4690 +} diff --git a/_data/chains/eip155-65.json b/_data/chains/eip155-65.json index 967d2f6b..35811e0e 100644 --- a/_data/chains/eip155-65.json +++ b/_data/chains/eip155-65.json @@ -3,7 +3,7 @@ "chain": "okexchain", "network": "testnet", "rpc": [ - "https://exchaintest.okexcn.com" + "https://exchaintestrpc.okex.org" ], "faucets": ["https://www.okex.com/drawdex"], "nativeCurrency": { @@ -15,4 +15,4 @@ "shortName": "tokt", "chainId": 65, "networkId": 65 -} \ No newline at end of file +} diff --git a/_data/chains/eip155-66.json b/_data/chains/eip155-66.json index 911a1cc9..f3046cb5 100644 --- a/_data/chains/eip155-66.json +++ b/_data/chains/eip155-66.json @@ -3,7 +3,7 @@ "chain": "okexchain", "network": "mainnet", "rpc": [ - "https://exchain.okexcn.com" + "https://exchainrpc.okex.org" ], "faucets": [], "nativeCurrency": { @@ -15,4 +15,4 @@ "shortName": "okt", "chainId": 66, "networkId": 66 -} \ No newline at end of file +} diff --git a/_data/chains/eip155-8029.json b/_data/chains/eip155-8029.json new file mode 100644 index 00000000..4176357a --- /dev/null +++ b/_data/chains/eip155-8029.json @@ -0,0 +1,18 @@ +{ + "name": "MDGL Testnet", + "chain": "MDGL", + "network": "testnet", + "rpc": [ + "https://testnet.mdgl.io" + ], + "faucets": [], + "nativeCurrency": { + "name": "MDGL Token", + "symbol": "MDGLT", + "decimals": 18 + }, + "infoURL": "https://mdgl.io", + "shortName": "mdgl", + "chainId": 8029, + "networkId": 8029 +} diff --git a/_data/chains/eip155-8285.json b/_data/chains/eip155-8285.json new file mode 100644 index 00000000..fe29d1e2 --- /dev/null +++ b/_data/chains/eip155-8285.json @@ -0,0 +1,19 @@ +{ + "name": "KorthoTest", + "chain": "Kortho", + "network": "Test", + "rpc": [ + "https://www.krotho-test.net" + ], + "faucets": [ + ], + "nativeCurrency": { + "name": "Kortho Test", + "symbol": "KTO", + "decimals": 11 + }, + "infoURL": "https://www.kortho.io/", + "shortName": "Kortho", + "chainId": 8285, + "networkId": 8285 +} \ No newline at end of file diff --git a/_data/icons/ethereum.json b/_data/icons/ethereum.json new file mode 100644 index 00000000..80490121 --- /dev/null +++ b/_data/icons/ethereum.json @@ -0,0 +1,8 @@ +[ + { + "url":"ipfs://QmdwQDr6vmBtXmK2TmknkEuZNoaDqTasFdZdu3DRw8b2wt", + "width":1000, + "height":1628, + "format":"png" + } +] diff --git a/build.gradle b/build.gradle index 24b11f04..c5222b79 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ buildscript { ext { - KOTLIN_VERSION = "1.4.31" - KETHEREUM_VERSION = "0.83.4" + KOTLIN_VERSION = "1.4.32" + KETHEREUM_VERSION = "0.83.6" } repositories { @@ -35,7 +35,7 @@ dependencies { implementation "com.github.komputing.kethereum:crypto_impl_bouncycastle:${KETHEREUM_VERSION}" implementation 'com.beust:klaxon:5.4' - implementation 'com.squareup.moshi:moshi-kotlin:1.11.0' + implementation 'com.squareup.moshi:moshi-kotlin:1.12.0' implementation 'com.squareup.okhttp3:okhttp:4.7.2' testImplementation "org.jetbrains.kotlin:kotlin-test" diff --git a/chains.json b/chains.json index 9c454546..4305db5f 100644 --- a/chains.json +++ b/chains.json @@ -13,6 +13,7 @@ permalink: chains.json "nativeCurrency": {"name":"{{chain.nativeCurrency["name"]}}","symbol":"{{chain.nativeCurrency["symbol"]}}","decimals":{{chain.nativeCurrency["decimals"]}}}, "rpc": [{% for rpc in chain.rpc %}"{{ rpc }}"{% unless forloop.last %},{% endunless %}{%endfor%}], "faucets": [{% for faucet in chain.faucets %}"{{ faucet }}"{% unless forloop.last %},{% endunless %}{%endfor%}], + "explorers": [{% for explorer in chain.explorers %}{"name":"{{explorer.name}}","url":"{{explorer.url}}"{% if explorer.icon != null %},"icon":"{{explorer.icon}}"{% endif %},"standard":"{{explorer.standard}}"}{% unless forloop.last %},{% endunless %}{%endfor%}], "infoURL": "{{ chain.infoURL }}" }{% unless forloop.last %},{% endunless %}{% endif %}{% endfor %} ] diff --git a/src/main/kotlin/org/ethereum/lists/chains/Env.kt b/src/main/kotlin/org/ethereum/lists/chains/Env.kt index f96c8d02..a1c92e40 100644 --- a/src/main/kotlin/org/ethereum/lists/chains/Env.kt +++ b/src/main/kotlin/org/ethereum/lists/chains/Env.kt @@ -19,7 +19,9 @@ val mandatory_fields = listOf( ) val optionalFields = listOf( "slip44", - "ens" + "ens", + "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 74cee68a..08936482 100644 --- a/src/main/kotlin/org/ethereum/lists/chains/Main.kt +++ b/src/main/kotlin/org/ethereum/lists/chains/Main.kt @@ -1,5 +1,6 @@ package org.ethereum.lists.chains +import com.beust.klaxon.JsonArray import java.io.File import com.beust.klaxon.JsonObject import com.beust.klaxon.Klaxon @@ -8,16 +9,23 @@ import org.kethereum.erc55.isValid import org.kethereum.model.Address import org.kethereum.rpc.HttpEthereumRPC -val parsedShortNames= mutableSetOf() -val parsedNames= mutableSetOf() +val parsedShortNames = mutableSetOf() +val parsedNames = mutableSetOf() + +val iconsPath = File("_data/icons") fun main(args: Array) { - val allFiles = File("_data/chains").listFiles()?:return + val allFiles = File("_data/chains").listFiles() ?: return allFiles.filter { !it.isDirectory }.forEach { checkChain(it, args.contains("rpcConnect")) } + val allIcons = iconsPath.listFiles() ?: return + allIcons.forEach { + checkIcon(it) + } + allFiles.filter { it.isDirectory }.forEach { if (it.name != "deprecated") { error("the only directory allowed is 'deprecated'") @@ -25,23 +33,60 @@ fun main(args: Array) { } } -fun checkChain(it: File, connectRPC: Boolean) { - println("processing $it") +fun checkIcon(icon: File) { + println("checking Icon " + icon.name) + val obj: JsonArray<*> = Klaxon().parseJsonArray(icon.reader()) + println("found variants " + obj.size) + obj.forEach { it -> + if (it !is JsonObject) { + error("Icon variant must be an object") + } - parseWithMoshi(it) + val url = it["url"] ?: error("Icon must have a URL") - val jsonObject = Klaxon().parseJsonObject(it.reader()) + if (url !is String || !url.startsWith("ipfs://")) { + error("url must start with ipfs://") + } + + val width = it["width"] + val height = it["height"] + if (width != null || height != null) { + if (height == null || width == null) { + error("If icon has width or height it needs to have both") + } + + if (width !is Int) { + error("Icon width must be Int") + } + if (height !is Int) { + error("Icon height must be Int") + } + } + + val format = it["format"] + if (format !is String || (format != "png" && format != "svg")) { + error("Icon format must be a png or svg but was $format") + } + } +} + +fun checkChain(chainFile: File, connectRPC: Boolean) { + println("processing $chainFile") + + parseWithMoshi(chainFile) + + val jsonObject = Klaxon().parseJsonObject(chainFile.reader()) val chainAsLong = getNumber(jsonObject, "chainId") - if (it.nameWithoutExtension.startsWith("eip155-")) { - if (chainAsLong != it.nameWithoutExtension.replace("eip155-","").toLongOrNull()) { + if (chainFile.nameWithoutExtension.startsWith("eip155-")) { + if (chainAsLong != chainFile.nameWithoutExtension.replace("eip155-", "").toLongOrNull()) { throw(FileNameMustMatchChainId()) } } else { throw(UnsupportedNamespace()) } - if (it.extension != "json") { + if (chainFile.extension != "json") { throw(ExtensionMustBeJSON()) } @@ -57,6 +102,36 @@ fun checkChain(it: File, connectRPC: Boolean) { throw ShouldHaveNoMissingFields(missingFields) } + jsonObject["icon"]?.let { + 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" + } + ] +}