# frozen_string_literal: true
require "bigdecimal"
require "em-http"
require "em_promise"
require "em-synchrony/em-http" # For apost vs post
require "json"
require "securerandom"
class Electrum
def initialize(rpc_uri:, rpc_username:, rpc_password:)
@rpc_uri = URI(rpc_uri)
@rpc_username = rpc_username
@rpc_password = rpc_password
end
def createnewaddress
rpc_call(:createnewaddress, {}).then { |r| r["result"] }
end
def getaddresshistory(address)
rpc_call(:getaddresshistory, address: address).then { |r| r["result"] }
end
def gettransaction(tx_hash)
rpc_call(:gettransaction, txid: tx_hash).then { |tx|
rpc_call(:deserialize, [tx["result"]])
}.then do |tx|
Transaction.new(self, tx_hash, tx["result"])
end
end
def get_tx_status(tx_hash)
rpc_call(:get_tx_status, txid: tx_hash).then { |r| r["result"] }
end
def notify(address, url)
rpc_call(:notify, address: address, URL: url).then { |r| r["result"] }
end
class Transaction
def initialize(electrum, tx_hash, tx)
@electrum = electrum
@tx_hash = tx_hash
@tx = tx
end
def confirmations
@electrum.get_tx_status(@tx_hash).then { |r| r["confirmations"] }
end
def amount_for(*addresses)
BigDecimal(
@tx["outputs"]
.select { |o| addresses.include?(o["address"]) }
.map { |o| o["value_sats"] }
.sum
) * 0.00000001
end
end
protected
def rpc_call(method, params)
post_json(
jsonrpc: "2.0",
id: SecureRandom.hex,
method: method.to_s,
params: params
).then { |res| JSON.parse(res.response) }
end
def post_json(data)
EM::HttpRequest.new(
@rpc_uri,
tls: { verify_peer: true }
).apost(
head: {
"Authorization" => [@rpc_username, @rpc_password],
"Content-Type" => "application/json"
},
body: data.to_json
)
end
end