Class: Sibit::Sochain
- Inherits:
-
Object
- Object
- Sibit::Sochain
- Defined in:
- lib/sibit/sochain.rb
Overview
SoChain API (formerly known as Block.io).
Documentation: https://sochain.com/api
- Author
Yegor Bugayenko (yegor256@gmail.com)
- Copyright
Copyright (c) 2019-2026 Yegor Bugayenko
- License
MIT
Instance Method Summary collapse
-
#balance(address) ⇒ Object
Gets the balance of the address, in satoshi.
-
#block(hash) ⇒ Object
This method should fetch a block and return it as a hash.
-
#fees ⇒ Object
Get recommended fees, in satoshi per byte.
-
#height(hash) ⇒ Object
The height of the block, identified by hash.
-
#initialize(log: Loog::NULL, http: Sibit::Http.new, network: 'BTC') ⇒ Sochain
constructor
Constructor.
-
#latest ⇒ Object
Gets the hash of the latest block.
-
#next_of(hash) ⇒ Object
Get hash of the block after this one.
-
#price(currency = 'USD') ⇒ Object
Current price of BTC in USD (float returned).
-
#push(hex) ⇒ Object
Push this transaction (in hex format) to the network.
-
#utxos(sources) ⇒ Object
Fetch all unspent outputs per address.
Constructor Details
Instance Method Details
#balance(address) ⇒ Object
Gets the balance of the address, in satoshi.
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/sibit/sochain.rb', line 71 def balance(address) data = Sibit::Json.new(http: @http, log: @log).get( Iri.new('https://sochain.com/api/v2/get_address_balance').append(@network).append(address) )['data'] if data.nil? @log.debug("The balance of #{address} is probably zero (not found)") return 0 end confirmed = data['confirmed_balance'] if confirmed.nil? @log.debug("The balance of #{address} is probably zero (no confirmed_balance)") return 0 end b = Integer((Float(confirmed) * 100_000_000).round) @log.debug("The balance of #{address} is #{b} satoshi") b end |
#block(hash) ⇒ Object
This method should fetch a block and return it as a hash.
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/sibit/sochain.rb', line 151 def block(hash) data = Sibit::Json.new(http: @http, log: @log).get( Iri.new('https://sochain.com/api/v2/block').append(@network).append(hash) )['data'] raise(Sibit::Error, "The block #{hash} not found") if data.nil? nxt = data['next_blockhash'] nxt = nil if nxt == '0000000000000000000000000000000000000000000000000000000000000000' { provider: self.class.name, hash: data['blockhash'], orphan: data['is_orphan'] == true, next: nxt, previous: data['previous_blockhash'], txns: (data['txs'] || []).map do |t| unless t.is_a?(Hash) raise(Sibit::NotSupportedError, "SoChain returned bare txid #{t} without outputs") end { hash: t['txid'], outputs: (t['outputs'] || []).map do |o| { address: o['address'], value: Integer((Float(o['value']) * 100_000_000).round) } end } end } end |
#fees ⇒ Object
Get recommended fees, in satoshi per byte.
90 91 92 |
# File 'lib/sibit/sochain.rb', line 90 def fees raise(Sibit::NotSupportedError, 'SoChain doesn\'t provide recommended fees') end |
#height(hash) ⇒ Object
The height of the block, identified by hash.
46 47 48 49 50 51 52 53 54 55 |
# File 'lib/sibit/sochain.rb', line 46 def height(hash) data = Sibit::Json.new(http: @http, log: @log).get( Iri.new('https://sochain.com/api/v2/block').append(@network).append(hash) )['data'] raise(Sibit::Error, "The block #{hash} not found") if data.nil? h = data['block_no'] raise(Sibit::Error, "The block #{hash} found but the height is absent") if h.nil? @log.debug("The height of #{hash} is #{h}") Integer(h) end |
#latest ⇒ Object
Gets the hash of the latest block.
95 96 97 98 99 100 101 102 103 104 |
# File 'lib/sibit/sochain.rb', line 95 def latest data = Sibit::Json.new(http: @http, log: @log).get( Iri.new('https://sochain.com/api/v2/get_info').append(@network) )['data'] raise(Sibit::Error, 'The latest block info not found') if data.nil? hash = data['blockhash'] raise(Sibit::Error, 'The latest block hash is absent') if hash.nil? @log.debug("The latest block hash is #{hash}") hash end |
#next_of(hash) ⇒ Object
Get hash of the block after this one.
58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/sibit/sochain.rb', line 58 def next_of(hash) data = Sibit::Json.new(http: @http, log: @log).get( Iri.new('https://sochain.com/api/v2/block').append(@network).append(hash) )['data'] raise(Sibit::Error, "The block #{hash} not found") if data.nil? nxt = data['next_blockhash'] nxt = nil if nxt == '0000000000000000000000000000000000000000000000000000000000000000' @log.debug("In SoChain the block #{hash} is the latest, there is no next block") if nxt.nil? @log.debug("The next block of #{hash} is #{nxt}") unless nxt.nil? nxt end |
#price(currency = 'USD') ⇒ Object
Current price of BTC in USD (float returned).
31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/sibit/sochain.rb', line 31 def price(currency = 'USD') data = Sibit::Json.new(http: @http, log: @log).get( Iri.new('https://sochain.com/api/v2/get_price').append(@network).append(currency) )['data'] raise(Sibit::Error, "No price data returned for #{@network}/#{currency}") if data.nil? prices = data['prices'] if prices.nil? || prices.empty? raise(Sibit::Error, "No price quotes for #{@network}/#{currency}") end price = Float(prices[0]['price']) @log.debug("The price of #{@network} is #{price} #{currency}") price end |
#push(hex) ⇒ Object
Push this transaction (in hex format) to the network. SoChain expects a
JSON payload with the tx_hex field on POST /send_tx/network.
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/sibit/sochain.rb', line 132 def push(hex) uri = URI(Iri.new('https://sochain.com/api/v2/send_tx').append(@network).to_s) res = @http.client(uri).post( uri.path, JSON.generate(tx_hex: hex), { 'Accept' => 'application/json', 'Content-Type' => 'application/json', 'Accept-Charset' => 'UTF-8', 'Accept-Encoding' => '' } ) unless res.code == '200' raise(Sibit::Error, "Failed to push transaction to #{uri}: #{res.code}\n#{res.body}") end @log.debug("Transaction (#{hex.length} chars in hex) has been pushed to SoChain") end |
#utxos(sources) ⇒ Object
Fetch all unspent outputs per address. The argument is an array of Bitcoin addresses.
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/sibit/sochain.rb', line 108 def utxos(sources) out = [] sources.each do |address| data = Sibit::Json.new(http: @http, log: @log).get( Iri.new('https://sochain.com/api/v2/get_tx_unspent').append(@network).append(address) )['data'] raise(Sibit::Error, "The address #{address} unspent lookup returned no data") if data.nil? txs = data['txs'] raise(Sibit::Error, "The address #{address} unspent lookup returned no txs") if txs.nil? txs.each do |u| out << { value: Integer((Float(u['value']) * 100_000_000).round), hash: u['txid'], index: u['output_no'], confirmations: u['confirmations'], script: [u['script_hex']].pack('H*') } end end out end |