blockchain-rpc is a typesafe RPC client for Bitcoin, Ethereum and Omni written for Scala 2.12 or 2.13. Under the hood, it's using http4s, circe and cats-effect. We appreciate external contributions, please check issues for inspiration. For all examples, check: src/main/scala/examples. We're planning a non IO-monad interface soon which makes it easier to use with Java and without Cats-effect knowledge.
Simply add the following dependency to your project.
  libraryDependencies += "com.madewithtea" %% "blockchain-rpc" % "2.5.2"
This is a simple example of how the RPCClient is generally used. We're using Cats Resources here which automatically deallocate any opened resources after use.
import cats.effect.{ExitCode, IO, IOApp}
import scala.concurrent.ExecutionContext.global
import com.madewithtea.blockchainrpc.RPCClient
import com.madewithtea.blockchainrpc.bitcoin.Syntax._
object GetBlockHash extends IOApp {
  def run(args: List[String]): IO[ExitCode] = {
    implicit val ec = global
    RPCClient
      .bitcoin(
        Seq(127.0.0.1),
        username = "user",
        password = "!@#(2009"
      )
      .use { bitcoin =>
        for {
          block <- bitcoin.getBlockByHash(
            "0000000000000000000759de6ab39c2d8fb01e4481ba581761ddc1d50a57358d"
          )
          _ <- IO { println(block) }
        } yield ExitCode(0)
      }
  }
}This example makes use of the EnvConfig import, which automatically configures RPC via ENV flags exported in the shell. The environment flags for it are BLOCKCHAIN_RPC_HOSTS, BLOCKCHAIN_RPC_USERNAME, BLOCKCHAIN_RPC_PASSWORD.
import com.madewithtea.blockchainrpc.Bitcoin
import com.madewithtea.blockchainrpc.{RPCClient, Config}
import com.madewithtea.blockchainrpc.bitcoin.Syntax._
object CatchupFromZero extends IOApp {
  def loop(rpc: Bitcoin, current: Long = 0L, until: Long = 10L): IO[Unit] =
    for {
      block <- rpc.getBlockByHeight(current)
      _ <- IO { println(block) }
      l <- if (current + 1 < until) loop(rpc, current + 1, until) else IO.unit
    } yield l
  def run(args: List[String]): IO[ExitCode] = {
    implicit val ec = global
    implicit val config = Config.fromEnv
    RPCClient
      .bitcoin(config.hosts, config.port, config.username, config.password)
      .use { rpc =>
        for {
          _ <- loop(rpc)
        } yield ExitCode(0)
      }
  }
}In this example, the Ethereum syntax is used to fetch a specific block. It uses HexTools to parse the blocknumber and prints the contents of the block. RPC configuration is acquired from the env vars BLOCKCHAIN_RPC_HOSTS, BLOCKCHAIN_RPC_USERNAME, and BLOCKCHAIN_RPC_PASSWORD.
package com.madewithtea.blockchainrpc.examples.ethereum
import cats.effect.{ExitCode, IO, IOApp}
import scala.concurrent.ExecutionContext.global
import com.madewithtea.blockchainrpc.{RPCClient, Config}
import com.madewithtea.blockchainrpc.ethereum.Syntax._
import com.madewithtea.blockchainrpc.ethereum.HexTools
object GetEthereumBlockByHash extends IOApp {
  def run(args: List[String]): IO[ExitCode] = {
    implicit val ec = global
    implicit val config = Config.fromEnv
    RPCClient
      .ethereum(
        config.hosts,
        config.port,
        config.username,
        config.password
      )
      .use { ethereum =>
        for {
          block <- ethereum.getBlockByHash(
            "0x3bad41c70c9efac92490e8a74ab816558bbdada0984f2bcfa4cb1522ddb3ca16"
          )
          _ <- IO { println(s"block ${HexTools.parseQuantity(block.number)}: $block") }
        } yield ExitCode(0)
      }
  }
}
| blockchain-rpc method | description | bitcoin rpc method | 
|---|---|---|
| getBlockHash(height: Long) | Gets the block hash at a specific height | getblockhash | 
| getBestBlockHash() | Gets the block tip hash | getbestblockhash | 
| getBlockByHash(hash: String) | Gets the block with transaction ids | getblock | 
| getBlockByHeight(height: Long) | Gets the block with transaction ids | getblockhash, getblock | 
| getTransaction(hash: String) | Gets raw transaction data | getrawtransaction | 
| getTransactions(hashes: Seq[String]) | Gets raw transaction data | batch of getrawtransaction | 
| estimateSmartFee(height: Long) | Estimates fee for include in block n | estimatesmartfee | 
| getNextBlockHash() | Gets next block hash subscription | usage of ZeroMQ | 
| blockchain-rpc method | description | ethereum rpc method | 
|---|---|---|
| getBlockByHeight(long: Height) | Get a block by height | eth_getBlockByNumber | 
| getBlockByHash(hash: String) | Get a block by hash | eth_getBlockByHash | 
| getBestBlockHeight | Get the best block height | eth_blockNumber | 
| getTransaction(hash: String) | Get a transaction by hash | eth_getTransactionByHash | 
| getTransactions(hashes: Seq[String]) | Get a batch of transaction by hash | eth_getTransactionByHash | 
| getReceiptByHash(hash: String) | Get a transaction receipt by hash | eth_getTransactionReceipt | 
| getReceiptsByHash(hashes: Seq[String]) | Get transaction receipts by hashes | Batch of eth_getTransactionReceipt | 
| variable | description | type | 
|---|---|---|
BLOCKCHAIN_RPC_HOSTS | 
Comma-seperated IP list or hostname of full nodes | String | 
BLOCKCHAIN_RPC_USERNAME | 
RPC username | Optional String | 
BLOCKCHAIN_RPC_PASSWORD | 
RPC password | Optional String | 
BLOCKCHAIN_RPC_PORT | 
RPC port when not default | Optional Int | 
BLOCKCHAIN_RPC_ZEROMQ_PORT | 
ZeroMQ port when not default | Optional Int |