diff --git a/.github/workflows/check-endpoints.yml b/.github/workflows/check-endpoints.yml new file mode 100644 index 0000000..9fe8808 --- /dev/null +++ b/.github/workflows/check-endpoints.yml @@ -0,0 +1,32 @@ +name: Check Endpoints + +on: + pull_request: + paths: + - docs/develop/api/networks.mdx + - scripts/check_endpoints/** + schedule: + - cron: '0 0 * * 0' # This cron expression schedules the workflow to run every Sunday at midnight UTC + workflow_dispatch: # allows manual triggering + + +jobs: + check-endpoints: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.9' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r scripts/check_endpoints/requirements.txt + + - name: Run endpoints check + run: python scripts/check_endpoints/main.py diff --git a/docs/develop/api/networks.mdx b/docs/develop/api/networks.mdx index a1baaa0..462c39b 100644 --- a/docs/develop/api/networks.mdx +++ b/docs/develop/api/networks.mdx @@ -23,45 +23,18 @@ If you are searching for the protobuf interfaces, head over [here](https://buf.b | --------------------------------------------- | ---------------------- | --------------------------------------- | -----------| | `https://evmos.lava.build` | `Ethereum` `JSON-RPC` | [Lava Network](https://lavanet.xyz) | Pruned | | `wss://evmos.lava.build/websocket` | `Ethereum` `WSS` | [Lava Network](https://lavanet.xyz) | Pruned | -| `https://rest.evmos.lava.build` | `Cosmos` `REST` | [Lava Network](https://lavanet.xyz) | Pruned | -| `https://tm.evmos.lava.build` | `Tendermint` `RPC` | [Lava Network](https://lavanet.xyz) | Pruned | -| `wss://tm.evmos.lava.build/websocket` | `Tendermint` `WSS` | [Lava Network](https://lavanet.xyz) | Pruned | -| `grpc.evmos.lava.build:443` | `Cosmos` `gRPC` | [Lava Network](https://lavanet.xyz) | Pruned | -| `https://grpc.evmos.lava.build` | `Cosmos` `Web-gRPC` | [Lava Network](https://lavanet.xyz) | Pruned | +| `https://evmos.rest.lava.build` | `Cosmos` `REST` | [Lava Network](https://lavanet.xyz) | Pruned | +| `https://evmos.tendermintrpc.lava.build` | `Tendermint` `RPC` | [Lava Network](https://lavanet.xyz) | Pruned | +| `wss://evmos.tendermintrpc.lava.build/websocket` | `Tendermint` `WSS` | [Lava Network](https://lavanet.xyz) | Pruned | +| `evmos.grpc.lava.build:443` | `Cosmos` `gRPC` | [Lava Network](https://lavanet.xyz) | Pruned | | `https://evmos-json-rpc.stakely.io` | `Ethereum` `JSON-RPC` | [Stakely](https://stakely.io/) | Pruned | -| `https://evmos-rpc.stakely.io` | `Cosmos` `RPC` | [Stakely](https://stakely.io/) | Pruned | +| `https://evmos-rpc.stakely.io` | `Tendermint` `RPC` | [Stakely](https://stakely.io/) | Pruned | | `https://evmos-lcd.stakely.io` | `Cosmos` `REST` | [Stakely](https://stakely.io/) | Pruned | -| `https://jsonrpc-evmos-ia.cosmosia.notional.ventures/` | `Ethereum` `JSON-RPC` | [Notional](https://notional.ventures/) | Pruned | -| `https://rpc-evmos-ia.cosmosia.notional.ventures:443` | `Tendermint` `RPC` | [Notional](https://notional.ventures/) | Pruned | -| `https://grpc-evmos-ia.cosmosia.notional.ventures:443` | `Tendermint` `gRPC` | [Notional](https://notional.ventures/) | Pruned | -| `https://api-evmos-ia.cosmosia.notional.ventures:443` | `Tendermint` `RPC` | [Notional](https://notional.ventures/) | Pruned | -| `https://rpc.evmos.nodestake.top` | `Tendermint` `RPC` | [NodeStake](https://nodestake.top/) | Pruned | -| `https://grpc.evmos.nodestake.top` | `Cosmos` `gRPC` | [NodeStake](https://nodestake.top/) | Pruned | -| `https://api.evmos.nodestake.top` | `Cosmos` `REST` | [NodeStake](https://nodestake.top/) | Pruned | -| `https://jsonrpc.evmos.nodestake.top` | `Ethereum` `JSON-RPC` | [NodeStake](https://nodestake.top/) | Pruned | -| `https://rpc.evmos.chaintools.tech/` | `Tendermint` `RPC` | [ChainTools](https://chaintools.tech/) | Pruned | -| `https://evmos.grpcui.chaintools.host` | `Cosmos` `gRPC` | [ChainTools](https://chaintools.tech/) | Pruned | -| `https://api.evmos.chaintools.tech/` | `Tendermint` `API` | [ChainTools](https://chaintools.tech/) | Pruned | -| `https://rpc.evmos.silknodes.io` | `Tendermint` `RPC` | [Silk Nodes](https://silknodes.io/) | Pruned | -| `https://grpc.evmos.silknodes.io` | `Cosmos` `gRPC` | [Silk Nodes](https://silknodes.io/) | Pruned | -| `https://api.evmos.silknodes.io` | `Cosmos` `REST` | [Silk Nodes](https://silknodes.io/) | Pruned | | `https://evmos-mainnet.public.blastapi.io` | `Ethereum` `JSON-RPC` | [BLAST](https://blastapi.io/) | Pruned | | `wss://evmos-mainnet.public.blastapi.io` | `Ethereum` `Websocket` | [BLAST](https://blastapi.io/) | Pruned | | `https://evmos-evm.publicnode.com` | `Ethereum` `JSON-RPC` | [PublicNode (by Allnodes)](https://evmos.publicnode.com/) | Pruned | | `https://evmos-rpc.publicnode.com` | `Tendermint` `RPC` | [PublicNode (by Allnodes)](https://evmos.publicnode.com/) | Pruned | | `https://evmos-rest.publicnode.com` | `Cosmos` `REST` | [PublicNode (by Allnodes)](https://evmos.publicnode.com/) | Pruned | -| `https://evmos-api.validatrium.club` | `Tendermint` `API` | [Validatrium](https://validatrium.com/) | Pruned | -| `https://evmos-rpc.validatrium.club` | `Tendermint` `RPC` | [Validatrium](https://validatrium.com/) | Pruned | -| `https://evmos-rpc.gateway.pokt.network` | `Ethereum` `JSON-RPC` | [PocketNetwork](https://www.pokt.network/) | Pruned | -| `https://api-evmos.mms.team:443` | `Cosmos` `REST` | [MMS](https://mms.team/) | Pruned | -| `https://grpc-evmos.mms.team:443` | `Cosmos` `gRPC` | [MMS](https://mms.team/) | Pruned | -| `https://rpc-evmos.mms.team:443` | `Tendermint` `RPC` | [MMS](https://mms.team/) | Pruned | -| `https://jsonrpc-evmos.mms.team:443` | `Ethereum` `JSON-RPC` | [MMS](https://mms.team/) | Pruned | -| `https://web3endpoints.com/evmos-mainnet` | `Ethereum` `JSON-RPC` | [BlockSpaces](https://www.blockspaces.com/web3-infrastructure) | Pruned | -| `https://evmos-rest.antrixy.org` | `Cosmos` `REST` | Antrix Validators | Pruned | -| `https://evmos-grpc.antrixy.org` | `Cosmos` `gRPC` | Antrix Validators | Pruned | -| `https://evmos-rpc.antrixy.org` | `Tendermint` `RPC` | Antrix Validators | Pruned | -| `https://evmos-json.antrixy.org` | `Ethereum` `JSON-RPC` | Antrix Validators | Pruned | | `https://evmos.drpc.org` | `Ethereum` `JSON-RPC` | [dRPC](https://drpc.org/) | Pruned | | `wss://evmos.drpc.org` | `Ethereum` `Websocket` | [dRPC](https://drpc.org/) | Pruned | @@ -76,21 +49,7 @@ If you are searching for the protobuf interfaces, head over [here](https://buf.b | `https://tm.evmos-testnet.lava.build` | `Tendermint` `RPC` | [Lava Network](https://lavanet.xyz) | Pruned | | `wss://tm.evmos-testnet.lava.build/websocket` | `Tendermint` `WSS` | [Lava Network](https://lavanet.xyz) | Pruned | | `grpc.evmos-testnet.lava.build:443` | `Cosmos` `gRPC` | [Lava Network](https://lavanet.xyz) | Pruned | -| `https://grpc.evmos-testnet.lava.build` | `Cosmos` `Web-gRPC` | [Lava Network](https://lavanet.xyz) | Pruned | | `https://evmos-testnet-rpc.polkachu.com:443` | `Tendermint` `RPC` | [Polkachu](https://polkachu.com) | Pruned | -| `https://rpc-t.evmos.nodestake.top` | `Tendermint` `RPC` | [NodeStake](https://nodestake.top/) | Pruned | -| `https://grpc-t.evmos.nodestake.top` | `Cosmos` `gRPC` | [NodeStake](https://nodestake.top/) | Pruned | -| `https://api-t.evmos.nodestake.top` | `Cosmos` `REST` | [NodeStake](https://nodestake.top/) | Pruned | -| `https://jsonrpc-t.evmos.nodestake.top` | `Ethereum` `JSON-RPC` | [NodeStake](https://nodestake.top/) | Pruned | -| `https://evmos-testnet-rpc.qubelabs.io` | `Tendermint` `RPC` | [Qubelabs](https://qubelabs.io/) | Pruned | -| `https://evmos-testnet-lcd.qubelabs.io` | `Cosmos` `REST` | [Qubelabs](https://qubelabs.io/) | Pruned | -| `https://evmos-testnet-grpc.qubelabs.io` | `Cosmos` `gRPC` | [Qubelabs](https://qubelabs.io/) | Pruned | -| `https://evmos-testnet-json.qubelabs.io` | `Ethereum` `JSON-RPC` | [Qubelabs](https://qubelabs.io/) | Pruned | -| `https://evmos-trpc.antrixy.org` | `Tendermint` `RPC` | Antrix Validators | Pruned | -| `https://evmos-trest.antrixy.org` | `Cosmos` `REST` | Antrix Validators | Pruned | -| `https://evmos-tgrpc.antrixy.org` | `Cosmos` `gRPC` | Antrix Validators | Pruned | -| `https://evmos-testnet.drpc.org` | `Ethereum` `JSON-RPC` | [dRPC](https://drpc.org/) | Pruned | -| `wss://evmos-testnet.drpc.org` | `Ethereum` `Websocket` | [dRPC](https://drpc.org/) | Pruned | ## On-Demand Services diff --git a/scripts/.gitignore b/scripts/.gitignore new file mode 100644 index 0000000..345c6b7 --- /dev/null +++ b/scripts/.gitignore @@ -0,0 +1,2 @@ +# Python cache +__pycache__/ diff --git a/scripts/check_endpoints/__init__.py b/scripts/check_endpoints/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/scripts/check_endpoints/__init__.py @@ -0,0 +1 @@ + diff --git a/scripts/check_endpoints/endpoints.py b/scripts/check_endpoints/endpoints.py new file mode 100644 index 0000000..cafb3ff --- /dev/null +++ b/scripts/check_endpoints/endpoints.py @@ -0,0 +1,93 @@ +""" +This file contains the logic to extract the available endpoints +from the Markdown file of the docs. +""" + +import os +import re +from dataclasses import dataclass +from typing import List, Union + + +@dataclass +class Endpoint: + address: str + category: str + provider: str + + +ENDPOINT_PATTERN = re.compile(r'\|\s*`(?P[^`]+)`\s*\|\s*`(?P[^`]+)`\s*`(?P[^`]+)`\s*\|\s*\[(?P[^\]]+)\]'"") + + +def get_endpoint_from_line(line: str) -> Union[Endpoint, None]: + """ + This method extracts the information of a given endpoint + from one line of the Markdown table. + """ + match = ENDPOINT_PATTERN.search(line) + if not match: + return None + + return Endpoint( + address=match.group("endpoint"), + category=f'{match.group("type1")} {match.group("type2")}', + provider=match.group("provider") + ) + + +def extract_endpoints(contents: List[str]) -> List[List[str]]: + """ + This function extracts the available endpoints + for testnet and mainnet from the given file contents. + """ + testnet_endpoints = [] + mainnet_endpoints = [] + + extract_mainnet = False + extract_testnet = False + + for line in contents: + if line[0] not in ["#", "|"]: + continue + + if "### Mainnet" in line: + extract_mainnet = True + extract_testnet = False + continue + elif "### Testnet" in line: + extract_mainnet = False + extract_testnet = True + continue + elif line[0] != "|": + continue + + endpoint = get_endpoint_from_line(line) + if endpoint is None: + continue + + if extract_mainnet: + mainnet_endpoints.append(endpoint) + continue + + if extract_testnet: + testnet_endpoints.append(endpoint) + continue + + raise ValueError(f"unexpected condition: got endpoint {endpoint.address} but neither testnet nor mainnet is active to be extracted") + + return mainnet_endpoints, testnet_endpoints + + +def get_endpoints(file: str) -> List[str]: + """ + This method tries to extract the list of available endpoints from + from the given docs file. + """ + if not os.path.exists(file): + raise FileNotFoundError(f"{file} does not exist") + + with open(file, "r", encoding="utf-8") as f: + contents = f.readlines() + + return extract_endpoints(contents) + diff --git a/scripts/check_endpoints/main.py b/scripts/check_endpoints/main.py new file mode 100644 index 0000000..b9ba656 --- /dev/null +++ b/scripts/check_endpoints/main.py @@ -0,0 +1,50 @@ +""" +This tool checks the list of available endpoints for their functionality. +Any non-responsive endpoints are being flagged to be either discussed +with the corresponding partners or removed. +""" + +from typing import Union +from endpoints import Endpoint, get_endpoints +from queries import query_endpoint + +ENDPOINTS_FILE = "docs/develop/api/networks.mdx" + + +def print_output(endpoint: Endpoint, ok: Union[bool, None]): + ok_emoji = "❓" if ok is None else ("✅" if ok else "❌") + print(f" {ok_emoji} - {endpoint.address}") + + +def check_endpoints(file: str) -> bool: + """ + This function contains the main logic of the script, + which gets the list of available endpoints on the docs + and runs a query to all of the supported endpoint types. + """ + failed_endpoints = [] + mainnet_endpoints, testnet_endpoints = get_endpoints(file) + + print("\n--------------\nChecking mainnet endpoints") + for endpoint in mainnet_endpoints: + ok = query_endpoint(endpoint) + if ok is False: + failed_endpoints.append(endpoint.address) + + print_output(endpoint, ok) + + print("\n--------------\nChecking testnet endpoints") + for endpoint in testnet_endpoints: + ok = query_endpoint(endpoint) + if ok is False: + failed_endpoints.append(endpoint.address) + + print_output(endpoint, ok) + + return failed_endpoints == [] + + +if __name__ == "__main__": + all_passed = check_endpoints(ENDPOINTS_FILE) + if not all_passed: + raise ValueError("some endpoints failed to return a response; check the output") diff --git a/scripts/check_endpoints/queries.py b/scripts/check_endpoints/queries.py new file mode 100644 index 0000000..e53e5f2 --- /dev/null +++ b/scripts/check_endpoints/queries.py @@ -0,0 +1,68 @@ +""" +This file contains the required logic to +call a simple query on a given endpoint +based on the type of endpoint. +""" + +from endpoints import Endpoint +import requests +from typing import Union + + +def query_endpoint(ep: Endpoint) -> Union[bool, None]: + """ + This function queries an endpoint based on its type. + """ + if ep.category == "Ethereum JSON-RPC": + return query_json_rpc(ep.address) + elif ep.category == "Cosmos REST": + return query_cosmos_rest(ep.address) + elif ep.category == "Tendermint RPC": + return query_tendermint_rpc(ep.address) + else: + return None + + +def query_json_rpc(address: str) -> bool: + """ + This method queries the latest block on the Ethereum JSON-RPC. + """ + try: + response = requests.post( + address, + json={ + "jsonrpc":"2.0", + "method":"eth_blockNumber", + "params":[], + "id":83 + } + ) + return response.status_code == requests.codes.OK + except Exception as e: + print(f"failed to query JSON-RPC endpoint {address}: {e}") + return False + + +def query_cosmos_rest(address: str) -> bool: + """ + This method queries the latest block on the Cosmos REST. + """ + try: + full_address = f"{address}/cosmos/base/tendermint/v1beta1/blocks/latest" + response = requests.get(full_address) + return response.status_code == requests.codes.OK + except Exception as e: + print(f"failed to query Cosmos REST endpoint {address}: {e}") + return False + + +def query_tendermint_rpc(address: str) -> bool: + """ + This method queries the latest block on the Tendermint RPC. + """ + try: + response = requests.get(f"{address}/block") + return response.status_code == requests.codes.OK + except Exception as e: + print(f"failed to query Tendermint RPC endpoint {address}: {e}") + return False diff --git a/scripts/check_endpoints/requirements.txt b/scripts/check_endpoints/requirements.txt new file mode 100644 index 0000000..bb5dd08 --- /dev/null +++ b/scripts/check_endpoints/requirements.txt @@ -0,0 +1,11 @@ +certifi==2024.8.30 +charset-normalizer==3.4.0 +exceptiongroup==1.2.0 +idna==3.10 +iniconfig==2.0.0 +packaging==24.0 +pluggy==1.4.0 +pytest==8.1.1 +requests==2.32.3 +tomli==2.0.1 +urllib3==2.2.3 diff --git a/scripts/check_endpoints/test_endpoints.py b/scripts/check_endpoints/test_endpoints.py new file mode 100644 index 0000000..86ee708 --- /dev/null +++ b/scripts/check_endpoints/test_endpoints.py @@ -0,0 +1,28 @@ +""" +This file contains the tests for the logic +that is extracting the available endpoints +from the Markdown file. +""" + +import os +import sys + +sys.path.append(os.path.dirname(__file__)) + +from endpoints import Endpoint, get_endpoint_from_line, get_endpoints + + +def test_get_endpoint_from_line_pass(): + assert get_endpoint_from_line( + "| `https://evmos.lava.build` | `Ethereum` `JSON-RPC` | [Lava Network](https://lavanet.xyz) | Pruned |" + ) == Endpoint( + address="https://evmos.lava.build", + category="Ethereum JSON-RPC", + provider="Lava Network" + ) + + +def test_get_endpoints_pass(): + mainnet, testnet = get_endpoints(os.path.join(os.path.dirname(__file__), "testdata/networks.mdx")) + assert len(mainnet) > 0, "failed to get mainnet endpoints" + assert len(testnet) > 0, "failed to get testnet endpoints" diff --git a/scripts/check_endpoints/test_queries.py b/scripts/check_endpoints/test_queries.py new file mode 100644 index 0000000..0175d11 --- /dev/null +++ b/scripts/check_endpoints/test_queries.py @@ -0,0 +1,35 @@ +""" +This file contains the tests for the endpoint queries. +""" + +import os +import sys + +sys.path.append(os.path.dirname(__file__)) + +from .endpoints import Endpoint +from .queries import query_endpoint + + +def test_query_json_rpc(): + assert query_endpoint(Endpoint( + address="https://evmos.lava.build", + category="Ethereum JSON-RPC", + provider="Lava Network" + )) is True, "expected successful JSON-RPC call" + + +def test_query_cosmos_rest(): + assert query_endpoint(Endpoint( + address="https://evmos.rest.lava.build", + category="Cosmos REST", + provider="Lava Network" + )) is True, "expected successful Cosmos REST call" + + +def test_query_tendermint_rpc(): + assert query_endpoint(Endpoint( + address="https://evmos.tendermintrpc.lava.build", + category="Tendermint RPC", + provider="Lava Network" + )) is True, "expected successful Tendermint RPC call" diff --git a/scripts/check_endpoints/testdata/networks.mdx b/scripts/check_endpoints/testdata/networks.mdx new file mode 100644 index 0000000..a1baaa0 --- /dev/null +++ b/scripts/check_endpoints/testdata/networks.mdx @@ -0,0 +1,104 @@ +--- +sidebar_position: 1 +--- + +# Networks + +## Public Available Endpoints + +Below is a list of publicly available endpoints that you can use to connect to the Evmos mainnet and +public testnets: + +:::tip +You can also use [chainlist.org](https://chainlist.org/) to add the node directly to [Metamask](https://academy.evmos.org/articles/beginner/connect-your-wallet/metamask). +::: + +:::note +If you are searching for the protobuf interfaces, head over [here](https://buf.build/evmos). +::: + +### Mainnet + +| Address | Category | Maintainer | Node Type | +| --------------------------------------------- | ---------------------- | --------------------------------------- | -----------| +| `https://evmos.lava.build` | `Ethereum` `JSON-RPC` | [Lava Network](https://lavanet.xyz) | Pruned | +| `wss://evmos.lava.build/websocket` | `Ethereum` `WSS` | [Lava Network](https://lavanet.xyz) | Pruned | +| `https://rest.evmos.lava.build` | `Cosmos` `REST` | [Lava Network](https://lavanet.xyz) | Pruned | +| `https://tm.evmos.lava.build` | `Tendermint` `RPC` | [Lava Network](https://lavanet.xyz) | Pruned | +| `wss://tm.evmos.lava.build/websocket` | `Tendermint` `WSS` | [Lava Network](https://lavanet.xyz) | Pruned | +| `grpc.evmos.lava.build:443` | `Cosmos` `gRPC` | [Lava Network](https://lavanet.xyz) | Pruned | +| `https://grpc.evmos.lava.build` | `Cosmos` `Web-gRPC` | [Lava Network](https://lavanet.xyz) | Pruned | +| `https://evmos-json-rpc.stakely.io` | `Ethereum` `JSON-RPC` | [Stakely](https://stakely.io/) | Pruned | +| `https://evmos-rpc.stakely.io` | `Cosmos` `RPC` | [Stakely](https://stakely.io/) | Pruned | +| `https://evmos-lcd.stakely.io` | `Cosmos` `REST` | [Stakely](https://stakely.io/) | Pruned | +| `https://jsonrpc-evmos-ia.cosmosia.notional.ventures/` | `Ethereum` `JSON-RPC` | [Notional](https://notional.ventures/) | Pruned | +| `https://rpc-evmos-ia.cosmosia.notional.ventures:443` | `Tendermint` `RPC` | [Notional](https://notional.ventures/) | Pruned | +| `https://grpc-evmos-ia.cosmosia.notional.ventures:443` | `Tendermint` `gRPC` | [Notional](https://notional.ventures/) | Pruned | +| `https://api-evmos-ia.cosmosia.notional.ventures:443` | `Tendermint` `RPC` | [Notional](https://notional.ventures/) | Pruned | +| `https://rpc.evmos.nodestake.top` | `Tendermint` `RPC` | [NodeStake](https://nodestake.top/) | Pruned | +| `https://grpc.evmos.nodestake.top` | `Cosmos` `gRPC` | [NodeStake](https://nodestake.top/) | Pruned | +| `https://api.evmos.nodestake.top` | `Cosmos` `REST` | [NodeStake](https://nodestake.top/) | Pruned | +| `https://jsonrpc.evmos.nodestake.top` | `Ethereum` `JSON-RPC` | [NodeStake](https://nodestake.top/) | Pruned | +| `https://rpc.evmos.chaintools.tech/` | `Tendermint` `RPC` | [ChainTools](https://chaintools.tech/) | Pruned | +| `https://evmos.grpcui.chaintools.host` | `Cosmos` `gRPC` | [ChainTools](https://chaintools.tech/) | Pruned | +| `https://api.evmos.chaintools.tech/` | `Tendermint` `API` | [ChainTools](https://chaintools.tech/) | Pruned | +| `https://rpc.evmos.silknodes.io` | `Tendermint` `RPC` | [Silk Nodes](https://silknodes.io/) | Pruned | +| `https://grpc.evmos.silknodes.io` | `Cosmos` `gRPC` | [Silk Nodes](https://silknodes.io/) | Pruned | +| `https://api.evmos.silknodes.io` | `Cosmos` `REST` | [Silk Nodes](https://silknodes.io/) | Pruned | +| `https://evmos-mainnet.public.blastapi.io` | `Ethereum` `JSON-RPC` | [BLAST](https://blastapi.io/) | Pruned | +| `wss://evmos-mainnet.public.blastapi.io` | `Ethereum` `Websocket` | [BLAST](https://blastapi.io/) | Pruned | +| `https://evmos-evm.publicnode.com` | `Ethereum` `JSON-RPC` | [PublicNode (by Allnodes)](https://evmos.publicnode.com/) | Pruned | +| `https://evmos-rpc.publicnode.com` | `Tendermint` `RPC` | [PublicNode (by Allnodes)](https://evmos.publicnode.com/) | Pruned | +| `https://evmos-rest.publicnode.com` | `Cosmos` `REST` | [PublicNode (by Allnodes)](https://evmos.publicnode.com/) | Pruned | +| `https://evmos-api.validatrium.club` | `Tendermint` `API` | [Validatrium](https://validatrium.com/) | Pruned | +| `https://evmos-rpc.validatrium.club` | `Tendermint` `RPC` | [Validatrium](https://validatrium.com/) | Pruned | +| `https://evmos-rpc.gateway.pokt.network` | `Ethereum` `JSON-RPC` | [PocketNetwork](https://www.pokt.network/) | Pruned | +| `https://api-evmos.mms.team:443` | `Cosmos` `REST` | [MMS](https://mms.team/) | Pruned | +| `https://grpc-evmos.mms.team:443` | `Cosmos` `gRPC` | [MMS](https://mms.team/) | Pruned | +| `https://rpc-evmos.mms.team:443` | `Tendermint` `RPC` | [MMS](https://mms.team/) | Pruned | +| `https://jsonrpc-evmos.mms.team:443` | `Ethereum` `JSON-RPC` | [MMS](https://mms.team/) | Pruned | +| `https://web3endpoints.com/evmos-mainnet` | `Ethereum` `JSON-RPC` | [BlockSpaces](https://www.blockspaces.com/web3-infrastructure) | Pruned | +| `https://evmos-rest.antrixy.org` | `Cosmos` `REST` | Antrix Validators | Pruned | +| `https://evmos-grpc.antrixy.org` | `Cosmos` `gRPC` | Antrix Validators | Pruned | +| `https://evmos-rpc.antrixy.org` | `Tendermint` `RPC` | Antrix Validators | Pruned | +| `https://evmos-json.antrixy.org` | `Ethereum` `JSON-RPC` | Antrix Validators | Pruned | +| `https://evmos.drpc.org` | `Ethereum` `JSON-RPC` | [dRPC](https://drpc.org/) | Pruned | +| `wss://evmos.drpc.org` | `Ethereum` `Websocket` | [dRPC](https://drpc.org/) | Pruned | + + +### Testnet + +| Address | Category | Maintainer | Node Type | +| --------------------------------------------- | ---------------------- | --------------------------------------- | -----------| +| `https://evmos-testnet.lava.build` | `Ethereum` `JSON-RPC` | [Lava Network](https://lavanet.xyz) | Pruned | +| `wss://evmos-testnet.lava.build/websocket` | `Ethereum` `WSS` | [Lava Network](https://lavanet.xyz) | Pruned | +| `https://rest.evmos-testnet.lava.build` | `Cosmos` `REST` | [Lava Network](https://lavanet.xyz) | Pruned | +| `https://tm.evmos-testnet.lava.build` | `Tendermint` `RPC` | [Lava Network](https://lavanet.xyz) | Pruned | +| `wss://tm.evmos-testnet.lava.build/websocket` | `Tendermint` `WSS` | [Lava Network](https://lavanet.xyz) | Pruned | +| `grpc.evmos-testnet.lava.build:443` | `Cosmos` `gRPC` | [Lava Network](https://lavanet.xyz) | Pruned | +| `https://grpc.evmos-testnet.lava.build` | `Cosmos` `Web-gRPC` | [Lava Network](https://lavanet.xyz) | Pruned | +| `https://evmos-testnet-rpc.polkachu.com:443` | `Tendermint` `RPC` | [Polkachu](https://polkachu.com) | Pruned | +| `https://rpc-t.evmos.nodestake.top` | `Tendermint` `RPC` | [NodeStake](https://nodestake.top/) | Pruned | +| `https://grpc-t.evmos.nodestake.top` | `Cosmos` `gRPC` | [NodeStake](https://nodestake.top/) | Pruned | +| `https://api-t.evmos.nodestake.top` | `Cosmos` `REST` | [NodeStake](https://nodestake.top/) | Pruned | +| `https://jsonrpc-t.evmos.nodestake.top` | `Ethereum` `JSON-RPC` | [NodeStake](https://nodestake.top/) | Pruned | +| `https://evmos-testnet-rpc.qubelabs.io` | `Tendermint` `RPC` | [Qubelabs](https://qubelabs.io/) | Pruned | +| `https://evmos-testnet-lcd.qubelabs.io` | `Cosmos` `REST` | [Qubelabs](https://qubelabs.io/) | Pruned | +| `https://evmos-testnet-grpc.qubelabs.io` | `Cosmos` `gRPC` | [Qubelabs](https://qubelabs.io/) | Pruned | +| `https://evmos-testnet-json.qubelabs.io` | `Ethereum` `JSON-RPC` | [Qubelabs](https://qubelabs.io/) | Pruned | +| `https://evmos-trpc.antrixy.org` | `Tendermint` `RPC` | Antrix Validators | Pruned | +| `https://evmos-trest.antrixy.org` | `Cosmos` `REST` | Antrix Validators | Pruned | +| `https://evmos-tgrpc.antrixy.org` | `Cosmos` `gRPC` | Antrix Validators | Pruned | +| `https://evmos-testnet.drpc.org` | `Ethereum` `JSON-RPC` | [dRPC](https://drpc.org/) | Pruned | +| `wss://evmos-testnet.drpc.org` | `Ethereum` `Websocket` | [dRPC](https://drpc.org/) | Pruned | + + +## On-Demand Services + +### Lava + +Lava is an open source protocol that serves as a p2p market for blockchain RPC & APIs. It gives wallets, dapps and indexers the most reliable RPC by optimally routing requests through a globally distributed network of node providers. + +In simpler words, Lava pairs consumers and providers of RPC in a similar way to how Uber connects passengers and drivers. Users of Lava enjoy top quality of service and data reliability & accuracy, ensured by Lava protocol and the crypto-economic framework + +In partnership with Evmos, Lava is the providing a highly reliable, community-powered free public endpoints you can find above. If you’re looking for higher rate-limits and usage analytics, [check out the Lava Gateway](https://gateway.lavanet.xyz?utm_source=evmos-docs&utm_medium=referral&utm_campaign=evmos-iprpc).