# 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