Exth
View SourceExth is an Elixir client for interacting with EVM-compatible blockchain nodes via JSON-RPC. It provides a robust, type-safe interface for making Ethereum RPC calls.
Features
- 🔒 Type Safety: Comprehensive type specs and validation
- 🔄 Transport Agnostic: Pluggable transport system (HTTP, WebSocket, IPC)
- 🎯 Smart Defaults: Sensible defaults with full configurability
- 🛡️ Error Handling: Detailed error reporting and recovery
- 📦 Batch Support: Efficient batch request processing
- 🔌 Protocol Compliance: Full JSON-RPC 2.0 specification support
Installation
Add exth
to your list of dependencies in mix.exs
:
def deps do
[
{:exth, "~> 0.1.0"},
# Optional dependencies:
# Mint for Tesla adapter
{:mint, "~> 1.7"}
]
end
Usage
Exth offers two ways to interact with EVM nodes:
- Provider (High-Level): Define a provider module with convenient function names and no need to pass client references.
- Client (Low-Level): Direct client usage with more control, requiring explicit client handling.
Provider (Recommended)
defmodule MyProvider do
use Exth.Provider,
transport_type: :http,
rpc_url: "https://YOUR-RPC-URL"
end
{:ok, block_number} = MyProvider.block_number()
{:ok, balance} = MyProvider.get_balance(
"0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"latest"
)
{:ok, block} = MyProvider.get_block_by_number("0x1", true)
{:ok, tx_hash} = MyProvider.send_raw_transaction("0x...")
The Provider approach is recommended for most use cases as it provides:
- ✨ Clean, intuitive function names
- 🔒 Type-safe parameters
- 📝 Better documentation and IDE support
- 🎯 No need to manage client references
Client
alias Exth.Client
# 1. Define a client
{:ok, client} = Client.new(
transport_type: :http,
rpc_url: "https://YOUR-RPC-URL"
)
# 2. Make RPC calls with explicit client
{:ok, block_number} = Client.request(client, "eth_blockNumber", [])
{:ok, balance} = Client.request(
client,
"eth_getBalance",
["0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "latest"]
)
{:ok, block} = Client.request(
client,
"eth_getBlockByNumber",
["0x1", true]
)
{:ok, tx_hash} = Client.request(
client,
"eth_sendRawTransaction",
["0x..."]
)
Use the Client approach when you need:
- 🔧 Direct control over RPC calls
- 🔄 Dynamic method names
- 🛠️ Custom parameter handling
- 🎛️ Flexible client management (multiple clients, runtime configuration)
Transport Options
Exth uses a pluggable transport system that supports different communication protocols. Each transport type can be configured with specific options:
HTTP Transport
The default HTTP transport is built on Tesla, providing a robust HTTP client with middleware support:
# Provider configuration
defmodule MyProvider do
use Exth.Provider,
transport_type: :http,
rpc_url: "https://eth-mainnet.example.com",
# Optional HTTP-specific configuration
adapter: Tesla.Adapter.Mint, # Default HTTP adapter
headers: [{"authorization", "Bearer token"}],
timeout: 30_000, # Request timeout in ms
end
# Direct client configuration
{:ok, client} = Exth.Client.new(
transport_type: :http,
rpc_url: "https://eth-mainnet.example.com",
adapter: Tesla.Adapter.Mint,
headers: [{"authorization", "Bearer token"}],
timeout: 30_000
)
- ✨ HTTP (
:http
)- Built on Tesla HTTP client
- Configurable adapters (Mint, Hackney, etc.)
- Configurable headers and timeouts
Custom Transport
Implement your own transport by creating a module and implementing the
Exth.Transport.Transportable
protocol:
defmodule MyCustomTransport do
# Transport struct should be whatever you need
defstruct [:config]
end
defimpl Exth.Transport.Transportable, for: MyCustomTransport do
def new(transport, opts) do
# Initialize your transport configuration
%MyCustomTransport{config: opts}
end
def call(transport, request) do
# Handle the JSON-RPC request
# Return {:ok, response} or {:error, reason}
end
end
# Use your custom transport
defmodule MyProvider do
use Exth.Provider,
transport_type: :custom,
module: MyCustomTransport,
rpc_url: "custom://endpoint",
# Additional custom options
custom_option: "value"
end
# Direct client configuration
{:ok, client} = Exth.Client.new(
transport_type: :custom,
rpc_url: "https://eth-mainnet.example.com",
module: MyCustomTransport,
custom_option: "value"
)
- 🔧 Custom (
:custom
)- Full control over transport implementation
- Custom state management
Examples
Check out our examples directory for practical usage examples:
- multichain.exs : Working with multiple chains/providers
- More examples coming soon!
To run an example:
mix run --no-mix-exs examples/multichain.exs
Requirements
- Elixir ~> 1.18
- Erlang/OTP 26 or later
Contributing
- Fork it
- Create your feature branch (
git checkout -b feature/my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin feature/my-new-feature
) - Create new Pull Request
License
This project is licensed under the MIT License. See LICENSE for details.