gleeth
An Ethereum library for Gleam, targeting the Erlang (BEAM) runtime. Provides JSON-RPC client, transaction signing, ABI encoding/decoding, and wallet management.
Warning: gleeth has not been audited and is in early development. It is recommended for testnet and development use only. Do not use with real funds in production without thorough independent review.
Installation
gleam add gleeth
Quick start
Read chain state
import gleeth/provider
import gleeth/rpc/methods
pub fn main() {
let assert Ok(p) = provider.new("http://localhost:8545")
// Get the latest block number
let assert Ok(block_number) = methods.get_block_number(p)
// Check an address balance
let assert Ok(balance) = methods.get_balance(
p,
"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
)
}
Sign and send a transaction (builder API)
The builder API accepts human-readable values - no manual hex conversion needed.
import gleeth/crypto/transaction
import gleeth/crypto/wallet
import gleeth/gas
import gleeth/provider
import gleeth/rpc/methods
pub fn main() {
let assert Ok(p) = provider.new("http://localhost:8545")
let assert Ok(w) = wallet.from_private_key_hex("0xac09...")
// Build and sign in a pipeline
let assert Ok(signed) =
transaction.build_legacy()
|> transaction.legacy_to("0x70997970C51812dc3A010C7d01b50e0d17dc79C8")
|> transaction.legacy_value_ether("1.5")
|> transaction.legacy_gas_limit_int(21_000)
|> transaction.legacy_gas_price_gwei("20.0")
|> transaction.legacy_nonce_int(0)
|> transaction.legacy_chain(1)
|> transaction.sign_legacy(w)
// Broadcast and wait for receipt
let assert Ok(tx_hash) = methods.send_raw_transaction(p, signed.raw_transaction)
let assert Ok(receipt) = methods.wait_for_receipt(p, tx_hash)
}
For lower-level control, use create_legacy_transaction with hex strings directly:
pub fn main() {
let assert Ok(p) = provider.new("http://localhost:8545")
let assert Ok(w) = wallet.from_private_key_hex("0xac09...")
// Gas estimation in one call
let sender = wallet.get_address(w)
let assert Ok(est) = gas.estimate_legacy(p, sender, "0x7099...", "0xde0b6b3a7640000", "0x")
let assert Ok(nonce) = methods.get_transaction_count(p, sender, "pending")
let assert Ok(tx) = transaction.create_legacy_transaction(
"0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
"0xde0b6b3a7640000", // 1 ETH in wei hex
est.gas_limit, // from estimation
est.gas_price, // from estimation
nonce, // from RPC
"0x", // no calldata
1, // mainnet
)
let assert Ok(signed) = transaction.sign_transaction(tx, w)
let assert Ok(tx_hash) = methods.send_raw_transaction(p, signed.raw_transaction)
}
Call a contract
import gleeth/provider
import gleeth/rpc/methods
pub fn main() {
let assert Ok(p) = provider.new("http://localhost:8545")
// Call balanceOf(address) on an ERC-20
let assert Ok(result) = methods.call_contract(
p,
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
"0x70a08231000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
)
}
ABI encoding
import gleeth/ethereum/abi/encode
import gleeth/ethereum/abi/types.{Uint, Address, AbiUintValue, AbiAddressValue}
pub fn main() {
// Encode a function call: transfer(address, uint256)
let assert Ok(calldata) = encode.encode_call(
"transfer(address,uint256)",
[Uint(256), Address],
[
AbiAddressValue("0x70997970C51812dc3A010C7d01b50e0d17dc79C8"),
AbiUintValue(1000000),
],
)
}
Features
- Transaction builder - pipeline API with human-readable values (
value_ether("1.5"),gas_price_gwei("20.0")) - Transaction signing - Legacy (Type 0) and EIP-1559 (Type 2) with EIP-155 replay protection
- Transaction decoding - decode raw transactions, recover sender address
- Gas estimation -
gas.estimate_legacyandgas.estimate_eip1559in a single call - Receipt polling -
wait_for_receiptwith exponential backoff - Nonce manager - local nonce tracking for multi-transaction sequences
- Wei conversions -
wei.from_ether("1.5"),wei.to_gwei(hex),wei.from_int(21000) - JSON-RPC client - block number, balance, call, code, estimate gas, storage, logs, transactions, receipts, fee history
- Provider abstraction - opaque type with URL validation and chain ID caching
- ABI system - full encoding/decoding for all Solidity types, calldata decoding, revert reason decoding, JSON ABI parsing, event log decoding
- EIP-55 addresses -
address.checksumandaddress.is_valid_checksum - EIP-191 signing -
sign_personal_message,recover_personal_message,verify_personal_message - Wallet management - key generation, message signing, signature recovery
- Crypto primitives - keccak256 (via ex_keccak NIF), secp256k1 (via ex_secp256k1 NIF)
- RLP encoding/decoding - per Ethereum Yellow Paper spec
Requirements
- Gleam >= 1.14.0
- Erlang/OTP >= 27
- Elixir (for ex_keccak and ex_secp256k1 NIF compilation)
Run mix local.hex --force before first build if Elixir is freshly installed.
Development
gleam build # Compile
gleam test # Run all tests
gleam format # Format code
gleam docs build # Generate documentation
Further documentation can be found at https://hexdocs.pm/gleeth.