blockchain 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 018e78fa4e59f75c5e786819ca080b696ef6dd33
4
+ data.tar.gz: 02d086845dd8c96c335e4cbb358c7ba9648b3149
5
+ SHA512:
6
+ metadata.gz: 51da40ee452dd3107775d4fad95c76983bf29976e25e0abd420ae3dbf0740f3e9d7e958e57681e178903cd950812dff5b2efc311f593f1c2c28fb94894726ebf
7
+ data.tar.gz: 7a6ff5c6980ece9c49d1b1165ec830e02b37b56f559f7e70ea15bdc69d4da15dec3a303e3f6873cb391cec3314497203f70ade6679b105c74669eb0deaf3f968
data/.gitignore ADDED
@@ -0,0 +1,34 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /lib/bundler/man/
26
+
27
+ # for a library or gem, you might want to ignore these files since the code is
28
+ # intended to run in multiple environments; otherwise, check them in:
29
+ # Gemfile.lock
30
+ # .ruby-version
31
+ # .ruby-gemset
32
+
33
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
34
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in blockchain.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Blockchain
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,46 @@
1
+ #Blockchain API library (Ruby, v1)
2
+
3
+ An official Ruby gem for interacting with the Blockchain.info API.
4
+
5
+ ###Getting started
6
+
7
+ Installation via RubyGems:
8
+
9
+ ```
10
+ $ gem install blockchain
11
+ ```
12
+
13
+ Manual installation:
14
+ ```
15
+ $ git clone https://github.com/blockchain/api-v1-client-ruby
16
+ $ cd api-v1-client-ruby
17
+ $ rake install
18
+ ```
19
+
20
+ The gem consists of the following functionality:
21
+
22
+ * `blockexplorer` ([docs](docs/blockexplorer.md)) ([api/blockchain_api][api1])
23
+ * `createwallet` ([docs](docs/createwallet.md)) ([api/create_wallet][api2])
24
+ * `exchangerates` ([docs](docs/exchangerates.md)) ([api/exchange\_rates\_api][api3])
25
+ * `receive` ([docs](docs/receive.md)) ([api/api_receive][api4])
26
+ * `statistics` ([docs](docs/statistics.md)) ([api/charts_api][api5])
27
+ * `wallet` ([docs](docs/wallet.md)) ([api/blockchain\_wallet\_api][api6])
28
+
29
+ The main module is called `Blockchain`
30
+
31
+ ###Error handling
32
+
33
+ All functions may raise exceptions caused by incorrectly passed parameters or other problems. If a call is rejected server-side, the `APIException` exception will be raised.
34
+
35
+ ###Request limits and API keys
36
+
37
+ In order to prevent abuse some API methods require an API key approved with some basic contact information and a description of its intended use. Please request an API key [here](https://blockchain.info/api/api_create_code).
38
+
39
+ The same API key can be used to bypass the request limiter.
40
+
41
+ [api1]: https://blockchain.info/api/blockchain_api
42
+ [api2]: https://blockchain.info/api/create_wallet
43
+ [api3]: https://blockchain.info/api/exchange_rates_api
44
+ [api4]: https://blockchain.info/api/api_receive
45
+ [api5]: https://blockchain.info/api/charts_api
46
+ [api6]: https://blockchain.info/api/blockchain_wallet_api
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'blockchain/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "blockchain"
8
+ spec.version = Blockchain::VERSION
9
+ spec.authors = ["Blockchain"]
10
+ spec.email = ["support@blockchain.zendesk.com"]
11
+ spec.summary = %q{Blockchain API library (Ruby, v1)}
12
+ spec.description = %q{Blockchain API library (Ruby, v1)}
13
+ spec.homepage = "https://github.com/blockchain/api-v1-client-ruby"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ end
@@ -0,0 +1,117 @@
1
+ ##Block explorer functionality
2
+
3
+ All functions support an optional parameter called `api_code`. It won't be listed with every function description.
4
+
5
+ ####`get_block`
6
+ Get a single block based on a block index or hash. Returns a `Block` object.
7
+
8
+ Params:
9
+ ```
10
+ block_id : str - block index or hash
11
+ ```
12
+
13
+ Usage:
14
+ ```ruby
15
+ require 'blockchain'
16
+
17
+ block = Blockchain::get_block('000000000000000016f9a2c3e0f4c1245ff24856a79c34806969f5084f410680')
18
+ ```
19
+
20
+ ####`get_tx`
21
+ Get a single transaction based on a transaction index or hash. Returns a `Transaction` object.
22
+
23
+ Params:
24
+ ```
25
+ tx_id : str - transaction index or hash
26
+ ```
27
+
28
+ Usage:
29
+ ```ruby
30
+ tx = Blockchain::get_tx('d4af240386cdacab4ca666d178afc88280b620ae308ae8d2585e9ab8fc664a94')
31
+ ```
32
+
33
+ ####`get_block_height`
34
+ Get an array of blocks at the specified height. Returns an array of `Block` objects.
35
+
36
+ Params:
37
+ ```
38
+ height : int - block height
39
+ ```
40
+
41
+ Usage:
42
+ ```ruby
43
+ blocks = Blockchain::get_block_height(2570)
44
+ ```
45
+
46
+ ####`get_address`
47
+ Get a single address and its transactions. Returns an `Address` object.
48
+
49
+ Params:
50
+ ```
51
+ address : str - address in the base58 or hash160 format
52
+ ```
53
+
54
+ Usage:
55
+ ```ruby
56
+ address = Blockchain::get_address('1HS9RLmKvJ7D1ZYgfPExJZQZA1DMU3DEVd')
57
+ ```
58
+
59
+ ####`get_unspent_outputs`
60
+ Get an array of unspent outputs for an address. Returns an array of `UnspentOutput` objects.
61
+
62
+ Params:
63
+ ```
64
+ address : str - address in the base58 or hash160 format
65
+ ```
66
+
67
+ Usage:
68
+ ```ruby
69
+ outs = Blockchain::get_unspent_outputs('1HS9RLmKvJ7D1ZYgfPExJZQZA1DMU3DEVd')
70
+ ```
71
+
72
+ ####`get_latest_block`
73
+ Get the latest block on the main chain. Returns a `LatestBlock` object.
74
+
75
+ Usage:
76
+ ```ruby
77
+ latest_block = Blockchain::get_latest_block()
78
+ ```
79
+
80
+ ####`get_unconfirmed_tx`
81
+ Get a list of currently unconfirmed transactions. Returns an array of `Transaction` objects.
82
+
83
+ Usage:
84
+ ```ruby
85
+ txs = Blockchain::get_unconfirmed_tx()
86
+ ```
87
+
88
+ ####`get_blocks`
89
+ Get a list of blocks for a specific day or mining pool. Returns an array of `SimpleBlock` objects.
90
+
91
+ Params:
92
+ ```
93
+ time : int - unix time in ms (optional)
94
+ pool_name : str - pool name (optional)
95
+ ```
96
+ At least one parameter is required.
97
+
98
+ Usage:
99
+ ```ruby
100
+ blocks = Blockchain::get_blocks(pool_name = 'Discus Fish')
101
+ ```
102
+
103
+ ####`get_inventory_data`
104
+ Get inventory data for recent blocks and addresses (up to 1 hour old). Returns an `InventoryData` object.
105
+
106
+ Params:
107
+ ```
108
+ hash : str - tx or block hash
109
+ ```
110
+
111
+ Usage:
112
+ ```ruby
113
+ inv = Blockchain::get_inventory_data('d4af240386cdacab4ca666d178afc88280b620ae308ae8d2585e9ab8fc664a94')
114
+ ```
115
+
116
+ Note regarding `Input` objects: if coinbase transaction, only `script` and `script_siq` will be populated.
117
+
@@ -0,0 +1,20 @@
1
+ ##Create Wallet functionality
2
+
3
+ ####`create_wallet`
4
+ Create a new Blockchain.info wallet. It can be created containing a pre-generated private key or will otherwise generate a new private key. Returns a `CreateWalletResponse` instance.
5
+
6
+ Params:
7
+ ```
8
+ password : str - password for the new wallet. At least 10 characters.
9
+ api_code : str - API code with the create wallets permission
10
+ priv : str - private key to add to the wallet (optional, keyword)
11
+ label : str - label for the first address in the wallet (optional, keyword)
12
+ email : str - email to associate with the new wallet (optional, keyword)
13
+ ```
14
+
15
+ Usage:
16
+ ```ruby
17
+ require 'blockchain'
18
+
19
+ wallet = Blockchain::create_wallet('1234password', '58ck39ajuiw', label: 'Test wallet')
20
+ ```
@@ -0,0 +1,32 @@
1
+ ##Exchange rates functionality
2
+
3
+ All functions support an optional parameter called `api_code`. It won't be listed with every function description.
4
+
5
+ ####`get_ticker`
6
+ Call the 'ticker' method and return a dictionary of `Currency` objects. Keys are currency symbols (str) and values are `Currency` objects.
7
+
8
+
9
+ Usage:
10
+ ```ruby
11
+ require 'blockchain'
12
+
13
+ ticker = Blockchain::get_ticker()
14
+ #print the 15 min price for every currency
15
+ ticker.keys.each do |key|
16
+ puts ticker[key].p15min
17
+ end
18
+ ```
19
+
20
+ ####`to_btc`
21
+ Call the 'tobtc' method and convert x value in the provided currency to BTC. Returns a `float`.
22
+
23
+ Params:
24
+ ```
25
+ ccy : str - currency code
26
+ value : float
27
+ ```
28
+
29
+ Usage:
30
+ ```ruby
31
+ btc_amount = Blockchain::to_btc('USD', 4342.11)
32
+ ```
data/docs/receive.md ADDED
@@ -0,0 +1,19 @@
1
+ ##Receive functionality
2
+
3
+ ####`receive`
4
+ Call the 'api/receive' endpoint and create a forwarding address. Returns a `ReceiveResponse` object.
5
+
6
+ Params:
7
+ ```
8
+ dest_addr : str
9
+ callback : str
10
+ api_code : str (optional)
11
+ ```
12
+
13
+ Usage:
14
+ ```ruby
15
+ require 'blockchain'
16
+
17
+ resp = Blockchain::receive('1hNapz1CuH4DhnV1DFHH7hafwDE8FJRheA', 'http://your.url.com')
18
+
19
+ ```
@@ -0,0 +1,16 @@
1
+ ## Statistics functionality
2
+
3
+ ####`get`
4
+ Get network statistics. Returns a `StatisticsResponse` object.
5
+
6
+ Params:
7
+ ```
8
+ api_code : str (optional)
9
+ ```
10
+
11
+ Usage:
12
+ ```ruby
13
+ require 'blockchain'
14
+
15
+ stats = Blockchain::get_statistics()
16
+ ```
data/docs/wallet.md ADDED
@@ -0,0 +1,148 @@
1
+ ##`wallet` module
2
+
3
+ An instance of the `Wallet` class needs to be initialized before it can be used.
4
+
5
+ Constructor params:
6
+ ```
7
+ identifier : str
8
+ password : str
9
+ second_password : str (optional)
10
+ api_code : str (optional)
11
+ ```
12
+
13
+ Usage:
14
+ ```ruby
15
+ require 'blockchain'
16
+
17
+ wallet = Blockchain::Wallet.new('ada4e4b6-3c9f-11e4-baad-164230d1df67', 'password123')
18
+ ```
19
+
20
+ ####`send`
21
+ Send bitcoin from your wallet to a single address. Returns a `PaymentResponse` object.
22
+
23
+ Params:
24
+ ```
25
+ to : str - receiving address
26
+ amount : int - amount to send (in satoshi)
27
+ from_address : str - specific address to send from (optional, keyword)
28
+ fee : int - transaction fee in satoshi. Must be greater than default (optional, keyword)
29
+ note : str - public note to include with the transaction (optional, keyword)
30
+ ```
31
+
32
+ Usage:
33
+ ```ruby
34
+ payment = wallet.send('1NAF7GbdyRg3miHNrw2bGxrd63tfMEmJob', 1000000, from_address: '1A8JiWcwvpY7tAopUkSnGuEYHmzGYfZPiq')
35
+
36
+ puts payment.tx_hash
37
+ ```
38
+
39
+ ####`send_many`
40
+ Send bitcoin from your wallet to multiple addresses. Returns a `PaymentResponse` object.
41
+
42
+ Params:
43
+ ```
44
+ recipients : dictionary - dictionary with the structure of 'address':amount
45
+ from_address : str - specific address to send from (optional, keyword)
46
+ fee : int - transaction fee in satoshi. Must be greater than default (optional, keyword)
47
+ note : str - public note to include with the transaction (optional, keyword)
48
+ ```
49
+
50
+ Usage:
51
+ ```ruby
52
+ recipients = { '1NAF7GbdyRg3miHNrw2bGxrd63tfMEmJob' => 1428300,
53
+ '1A8JiWcwvpY7tAopUkSnGuEYHmzGYfZPiq' => 234522117 }
54
+ payment = wallet.send_many(recipients)
55
+
56
+ puts payment.tx_hash
57
+ ```
58
+
59
+ ####`get_balance`
60
+ Fetch the wallet balance. Includes unconfirmed transactions and possibly double spends. Returns the wallet balance in satoshi.
61
+
62
+ Usage:
63
+ ```ruby
64
+ puts wallet.get_balance()
65
+ ```
66
+
67
+ ####`list_addresses`
68
+ List all active addresses in the wallet. Returns an array of `Address` objects.
69
+
70
+ Params:
71
+ ```
72
+ confirmations : int - minimum number of confirmations transactions must have before being included in balance of addresses (optional)
73
+ ```
74
+
75
+ Usage:
76
+ ```ruby
77
+ addresses = wallet.list_addresses()
78
+ addresses.each do |a|
79
+ puts a.balance
80
+ end
81
+
82
+ ```
83
+
84
+ ####`get_address`
85
+ Retrieve an address from the wallet. Returns an `Address` object.
86
+
87
+ Params:
88
+ ```
89
+ confirmations : int - minimum number of confirmations transactions must have before being included in the balance (optional)
90
+ ```
91
+
92
+ Usage:
93
+ ```ruby
94
+ addr = wallet.get_address('1NAF7GbdyRg3miHNrw2bGxrd63tfMEmJob', confirmations = 2)
95
+ puts addr.balance
96
+ ```
97
+
98
+ ####`new_address`
99
+ Generate a new address and add it to the wallet. Returns an `Address` object.
100
+
101
+ Params:
102
+ ```
103
+ label : str - label to attach to the address (optional, keyword)
104
+ ```
105
+
106
+ Usage:
107
+ ```ruby
108
+ newaddr = wallet.new_address('test_label')
109
+ ```
110
+
111
+ ####`archive_address`
112
+ Archive an address. Returns a string representation of the archived address.
113
+
114
+ Params:
115
+ ```
116
+ address : str - address to archive
117
+ ```
118
+
119
+ Usage:
120
+ ```ruby
121
+ wallet.archive_address('1NAF7GbdyRg3miHNrw2bGxrd63tfMEmJob')
122
+ ```
123
+
124
+ ####`unarchive_address`
125
+ Unarchive an address. Returns a string representation of the unarchived address.
126
+
127
+ Params:
128
+ ```
129
+ address : str - address to unarchive
130
+ ```
131
+
132
+ Usage:
133
+ ```ruby
134
+ wallet.unarchive_address('1NAF7GbdyRg3miHNrw2bGxrd63tfMEmJob')
135
+ ```
136
+
137
+ ####`consolidate`
138
+ Consolidate the wallet addresses. Returns a string array of consolidated addresses.
139
+
140
+ Params:
141
+ ```
142
+ days : int - addresses which have not received any transactions in at least this many days will be consolidated.
143
+ ```
144
+
145
+ Usage:
146
+ ```ruby
147
+ wallet.consolidate(50)
148
+ ```
data/lib/blockchain.rb ADDED
@@ -0,0 +1,11 @@
1
+ require "blockchain/version"
2
+ require "blockchain/blockexplorer"
3
+ require "blockchain/createwallet"
4
+ require "blockchain/exchangerates"
5
+ require "blockchain/receive"
6
+ require "blockchain/statistics"
7
+ require "blockchain/wallet"
8
+
9
+ module Blockchain
10
+
11
+ end
@@ -0,0 +1,298 @@
1
+ require 'json'
2
+ require_relative 'util'
3
+
4
+ module Blockchain
5
+
6
+ def self.get_block(block_id, api_code = nil)
7
+ params = api_code.nil? ? { } : { 'api_code' => api_code }
8
+ resource = 'rawblock/' + block_id
9
+ response = Blockchain::call_api(resource, method: 'get', data: params)
10
+ return Block.new(JSON.parse(response))
11
+ end
12
+
13
+ def self.get_tx(tx_id, api_code = nil)
14
+ params = api_code.nil? ? { } : { 'api_code' => api_code }
15
+ resource = 'rawtx/' + tx_id
16
+ response = Blockchain::call_api(resource, method: 'get', data: params)
17
+ return Transaction.new(JSON.parse(response))
18
+ end
19
+
20
+ def self.get_block_height(height, api_code = nil)
21
+ params = { 'format' => 'json' }
22
+ if !api_code.nil? then params['api_code'] = api_code end
23
+ resource = "block-height/#{height}"
24
+ response = Blockchain::call_api(resource, method: 'get', data: params)
25
+ return JSON.parse(response)['blocks'].map{ |b| Block.new(b) }
26
+ end
27
+
28
+ def self.get_address(address, api_code = nil)
29
+ params = api_code.nil? ? { } : { 'api_code' => api_code }
30
+ resource = 'rawaddr/' + address
31
+ response = Blockchain::call_api(resource, method: 'get', data: params)
32
+ return Address.new(JSON.parse(response))
33
+ end
34
+
35
+ def self.get_unspent_outputs(address, api_code = nil)
36
+ params = { 'active' => address }
37
+ if !api_code.nil? then params['api_code'] = api_code end
38
+ resource = 'unspent'
39
+ response = Blockchain::call_api(resource, method: 'get', data: params)
40
+ return JSON.parse(response)['unspent_outputs'].map{ |o| UnspentOutput.new(o) }
41
+ end
42
+
43
+ def self.get_unconfirmed_tx(api_code = nil)
44
+ params = { 'format' => 'json' }
45
+ if !api_code.nil? then params['api_code'] = api_code end
46
+ resource = 'unconfirmed-transactions'
47
+ response = Blockchain::call_api(resource, method: 'get', data: params)
48
+ return JSON.parse(response)['txs'].map{ |t| Transaction.new(t) }
49
+ end
50
+
51
+ def self.get_blocks(api_code = nil, time: nil, pool_name: nil)
52
+ params = { 'format' => 'json' }
53
+ if !api_code.nil? then params['api_code'] = api_code end
54
+ resource = "blocks/"
55
+ if !time.nil?
56
+ resource += time.to_s
57
+ elsif !pool_name.nil?
58
+ resource += pool_name
59
+ end
60
+ response = Blockchain::call_api(resource, method: 'get', data: params)
61
+ return JSON.parse(response)['blocks'].map{ |b| SimpleBlock.new(b) }
62
+ end
63
+
64
+ def self.get_latest_block(api_code = nil)
65
+ params = {}
66
+ if !api_code.nil? then params['api_code'] = api_code end
67
+ resource = 'latestblock'
68
+ response = Blockchain::call_api(resource, method: 'get', data: params)
69
+ return LatestBlock.new(JSON.parse(response))
70
+ end
71
+
72
+ def self.get_inventory_data(hash, api_code = nil)
73
+ params = { 'format' => 'json' }
74
+ if !api_code.nil? then params['api_code'] = api_code end
75
+ resource = "inv/#{hash}"
76
+ response = Blockchain::call_api(resource, method: 'get', data: params)
77
+ return InventoryData.new(JSON.parse(response))
78
+ end
79
+
80
+ class SimpleBlock
81
+ attr_reader :height
82
+ attr_reader :hash
83
+ attr_reader :time
84
+ attr_reader :main_chain
85
+
86
+ def initialize(b)
87
+ @height = b['height']
88
+ @hash = b['hash']
89
+ @time = b['time']
90
+ @main_chain = b['main_chain']
91
+ end
92
+ end
93
+
94
+ class LatestBlock
95
+ attr_reader :hash
96
+ attr_reader :time
97
+ attr_reader :block_index
98
+ attr_reader :height
99
+ attr_reader :tx_indexes
100
+
101
+ def initialize(b)
102
+ @hash = b['hash']
103
+ @time = b['time']
104
+ @block_index = b['block_index']
105
+ @height = b['height']
106
+ @tx_indexes = b['txIndexes']
107
+ end
108
+ end
109
+
110
+ class UnspentOutput
111
+ attr_reader :tx_hash
112
+ attr_reader :tx_index
113
+ attr_reader :tx_output_n
114
+ attr_reader :script
115
+ attr_reader :value
116
+ attr_reader :value_hex
117
+ attr_reader :confirmations
118
+
119
+ def initialize(o)
120
+ @tx_hash = o['tx_hash']
121
+ @tx_index = o['tx_index']
122
+ @tx_output_n = o['tx_output_n']
123
+ @script = o['script']
124
+ @value = o['value']
125
+ @value_hex = o['value_hex']
126
+ @confirmations = o['confirmations']
127
+ end
128
+ end
129
+
130
+ class Address
131
+ attr_reader :hash160
132
+ attr_reader :address
133
+ attr_reader :n_tx
134
+ attr_reader :total_received
135
+ attr_reader :total_sent
136
+ attr_reader :final_balance
137
+ attr_reader :transactions
138
+
139
+ def initialize(a)
140
+ @hash160 = a['hash160']
141
+ @address = a['address']
142
+ @n_tx = a['n_tx']
143
+ @total_received = a['total_received']
144
+ @total_sent = a['total_sent']
145
+ @final_balance = a['final_balance']
146
+ @transactions = a['txs'].map{ |tx| Transaction.new(tx) }
147
+ end
148
+ end
149
+
150
+ class Input
151
+ attr_reader :n
152
+ attr_reader :value
153
+ attr_reader :address
154
+ attr_reader :tx_index
155
+ attr_reader :type
156
+ attr_reader :script
157
+ attr_reader :script_sig
158
+ attr_reader :sequence
159
+
160
+ def initialize(i)
161
+ obj = i['prev_out']
162
+ if !obj.nil?
163
+ # regular TX
164
+ @n = obj['n']
165
+ @value = obj['value']
166
+ @address = obj['addr']
167
+ @tx_index = obj['tx_index']
168
+ @type = obj['type']
169
+ @script = obj['script']
170
+ @script_sig = i['script']
171
+ @sequence = i['sequence']
172
+ else
173
+ # coinbase TX
174
+ @script_sig = i['script']
175
+ @sequence = i['sequence']
176
+ end
177
+ end
178
+ end
179
+
180
+ class Output
181
+ attr_reader :n
182
+ attr_reader :value
183
+ attr_reader :address
184
+ attr_reader :tx_index
185
+ attr_reader :script
186
+ attr_reader :spent
187
+
188
+ def initialize(o)
189
+ @n = o['n']
190
+ @value = o['value']
191
+ @address = o['addr']
192
+ @tx_index = o['tx_index']
193
+ @script = o['script']
194
+ @spent = o['spent']
195
+ end
196
+ end
197
+
198
+ class Transaction
199
+ attr_reader :double_spend
200
+ attr_reader :block_height
201
+ attr_reader :time
202
+ attr_reader :relayed_by
203
+ attr_reader :hash
204
+ attr_reader :tx_index
205
+ attr_reader :version
206
+ attr_reader :size
207
+ attr_reader :inputs
208
+ attr_reader :outputs
209
+
210
+ def initialize(t)
211
+ @double_spend = t.fetch('double_spend', false)
212
+ @block_height = t.fetch('block_height', false)
213
+ @time = t['time']
214
+ @relayed_by = t['relayed_by']
215
+ @hash = t['hash']
216
+ @tx_index = t['tx_index']
217
+ @version = t['ver']
218
+ @size = t['size']
219
+ @inputs = t['inputs'].map{ |i| Input.new(i) }
220
+ @outputs = t['out'].map{ |o| Output.new(o) }
221
+
222
+ if @block_height.nil?
223
+ @block_height = -1
224
+ end
225
+ end
226
+
227
+ def adjust_block_height(h)
228
+ @block_height = h
229
+ end
230
+ end
231
+
232
+
233
+ class Block
234
+ attr_reader :hash
235
+ attr_reader :version
236
+ attr_reader :previous_block
237
+ attr_reader :merkle_root
238
+ attr_reader :time
239
+ attr_reader :bits
240
+ attr_reader :fee
241
+ attr_reader :nonce
242
+ attr_reader :n_tx
243
+ attr_reader :size
244
+ attr_reader :block_index
245
+ attr_reader :main_chain
246
+ attr_reader :height
247
+ attr_reader :received_time
248
+ attr_reader :relayed_by
249
+ attr_reader :transactions
250
+
251
+ def initialize(b)
252
+ @hash = b['hash']
253
+ @version = b['ver']
254
+ @previous_block = b['prev_block']
255
+ @merkle_root = b['mrkl_root']
256
+ @time = b['time']
257
+ @bits = b['bits']
258
+ @fee = b['fee']
259
+ @nonce = b['nonce']
260
+ @n_tx = b['n_tx']
261
+ @size = b['size']
262
+ @block_index = b['block_index']
263
+ @main_chain = b['main_chain']
264
+ @height = b['height']
265
+ @received_time = b['received_time']
266
+ @relayed_by = b['relayed_by']
267
+ @transactions = b['tx'].map{ |tx| Transaction.new(tx) }
268
+ @transactions.each do |tx|
269
+ tx.adjust_block_height(@height)
270
+ end
271
+
272
+ if @received_time.nil?
273
+ @received_time = @time
274
+ end
275
+ end
276
+ end
277
+
278
+ class InventoryData
279
+ attr_reader :hash
280
+ attr_reader :type
281
+ attr_reader :initial_time
282
+ attr_reader :initial_ip
283
+ attr_reader :nconnected
284
+ attr_reader :relayed_count
285
+ attr_reader :relayed_percent
286
+
287
+ def initialize(i)
288
+ @hash = i['hash']
289
+ @type = i['type']
290
+ @initial_time = i['initial_time'].to_i
291
+ @initial_ip = i['initial_ip']
292
+ @nconnected = i['nconnected'].to_i
293
+ @relayed_count = i['relayed_count'].to_i
294
+ @relayed_percent = i['relayed_percent'].to_i
295
+ end
296
+ end
297
+
298
+ end
@@ -0,0 +1,39 @@
1
+ require 'json'
2
+ require_relative 'util'
3
+
4
+ module Blockchain
5
+
6
+ def self.create_wallet(password, api_code, priv: nil, label: nil, email: nil)
7
+
8
+ params = { 'password' => password, 'api_code' => api_code }
9
+
10
+ if !priv.nil?
11
+ params['priv'] = priv
12
+ end
13
+ if !label.nil?
14
+ params['label'] = label
15
+ end
16
+ if !email.nil?
17
+ params['email'] = email
18
+ end
19
+
20
+ response = Blockchain::call_api('api/v2/create_wallet', method: 'post', data: params)
21
+ json_response = JSON.parse(response)
22
+ return CreateWalletResponse.new(json_response['guid'],
23
+ json_response['address'],
24
+ json_response['link'])
25
+ end
26
+
27
+ class CreateWalletResponse
28
+ attr_reader :identifier
29
+ attr_reader :address
30
+ attr_reader :link
31
+
32
+ def initialize(identifier, address, link)
33
+ @identifier = identifier
34
+ @address = address
35
+ @link = link
36
+ end
37
+ end
38
+
39
+ end
@@ -0,0 +1,47 @@
1
+ require 'json'
2
+ require_relative 'util'
3
+
4
+ module Blockchain
5
+
6
+ class Currency
7
+ attr_reader :last
8
+ attr_reader :buy
9
+ attr_reader :sell
10
+ attr_reader :symbol
11
+ attr_reader :p15min
12
+
13
+ def initialize(last, buy, sell, symbol, p15min)
14
+ @last = last
15
+ @buy = buy
16
+ @sell = sell
17
+ @symbol = symbol
18
+ @p15min = p15min
19
+ end
20
+ end
21
+
22
+ def self.get_ticker(api_code = nil)
23
+ params = {}
24
+ if !api_code.nil? then params['api_code'] = api_code end
25
+ response = Blockchain::call_api('ticker', data: params)
26
+ json_response = JSON.parse(response)
27
+
28
+ ticker = {}
29
+ json_response.each do |key,value|
30
+ json_ccy = json_response[key]
31
+ ccy = Currency.new(json_ccy['last'],
32
+ json_ccy['buy'],
33
+ json_ccy['sell'],
34
+ json_ccy['symbol'],
35
+ json_ccy['15m'])
36
+ ticker[key] = ccy
37
+ end
38
+ return ticker
39
+ end
40
+
41
+ def self.to_btc(ccy, value, api_code = nil)
42
+ params = { 'currency' => ccy, 'value' => value}
43
+ if !api_code.nil? then params['api_code'] = api_code end
44
+ return Blockchain::call_api('tobtc', data: params).to_f
45
+ end
46
+
47
+ end
@@ -0,0 +1,32 @@
1
+ require 'json'
2
+ require_relative 'util'
3
+
4
+ module Blockchain
5
+
6
+ class ReceiveResponse
7
+ attr_reader :fee_percent
8
+ attr_reader :destination
9
+ attr_reader :input_address
10
+ attr_reader :callback_url
11
+
12
+ def initialize(fee_percent, dest, input, callback)
13
+ @fee_percent = fee_percent
14
+ @destination = dest
15
+ @input_address = input
16
+ @callback_url = callback
17
+ end
18
+ end
19
+
20
+ def self.receive(dest_addr, callback, api_code = nil)
21
+ params = { 'method' => 'create', 'address' => dest_addr, 'callback' => callback }
22
+ if !api_code.nil? then params['api_code'] = api_code end
23
+ resp = Blockchain::call_api('api/receive', method: 'post', data: params)
24
+ json_resp = JSON.parse(resp)
25
+ receive_response = ReceiveResponse.new(json_resp['fee_percent'],
26
+ json_resp['destination'],
27
+ json_resp['input_address'],
28
+ json_resp['callback_url'])
29
+ return receive_response
30
+ end
31
+
32
+ end
@@ -0,0 +1,62 @@
1
+ require 'json'
2
+ require_relative 'util'
3
+
4
+ module Blockchain
5
+
6
+ def self.get_statistics(api_code = nil)
7
+ params = { 'format' => 'json' }
8
+ if !api_code.nil? then params['api_code'] = api_code end
9
+ response = Blockchain::call_api('stats', method: 'get', data: params)
10
+ json_response = JSON.parse(response)
11
+ return StatisticsResponse.new(json_response)
12
+ end
13
+
14
+ class StatisticsResponse
15
+ attr_reader :trade_volume_btc
16
+ attr_reader :miners_revenue_usd
17
+ attr_reader :btc_mined
18
+ attr_reader :trade_volume_usd
19
+ attr_reader :difficulty
20
+ attr_reader :minutes_between_blocks
21
+ attr_reader :days_destroyed
22
+ attr_reader :number_of_transactions
23
+ attr_reader :hash_rate
24
+ attr_reader :timestamp
25
+ attr_reader :mined_blocks
26
+ attr_reader :blocks_size
27
+ attr_reader :total_fees_btc
28
+ attr_reader :total_btc_sent
29
+ attr_reader :estimated_btc_sent
30
+ attr_reader :total_btc
31
+ attr_reader :total_blocks
32
+ attr_reader :next_retarget
33
+ attr_reader :estimated_transaction_volume_usd
34
+ attr_reader :miners_revenue_btc
35
+ attr_reader :market_price_usd
36
+
37
+ def initialize(s)
38
+ @trade_volume_btc = s['trade_volume_btc']
39
+ @miners_revenue_usd = s['miners_revenue_usd']
40
+ @btc_mined = s['n_btc_mined']
41
+ @trade_volume_usd = s['trade_volume_usd']
42
+ @difficulty = s['difficulty']
43
+ @minutes_between_blocks = s['minutes_between_blocks']
44
+ @days_destroyed = s['days_destroyed']
45
+ @number_of_transactions = s['n_tx']
46
+ @hash_rate = s['hash_rate']
47
+ @timestamp = s['timestamp']
48
+ @mined_blocks = s['n_blocks_mined']
49
+ @blocks_size = s['blocks_size']
50
+ @total_fees_btc = s['total_fees_btc']
51
+ @total_btc_sent = s['total_btc_sent']
52
+ @estimated_btc_sent = s['estimated_btc_sent']
53
+ @total_btc = s['totalbc']
54
+ @total_blocks = s['n_blocks_total']
55
+ @next_retarget = s['nextretarget']
56
+ @estimated_transaction_volume_usd = s['estimated_transaction_volume_usd']
57
+ @miners_revenue_btc = s['miners_revenue_btc']
58
+ @market_price_usd = s['market_price_usd']
59
+ end
60
+ end
61
+
62
+ end
@@ -0,0 +1,32 @@
1
+ require 'net/http'
2
+
3
+ module Blockchain
4
+
5
+ class APIException < StandardError
6
+ end
7
+
8
+ BASE_URL = "https://blockchain.info/"
9
+
10
+ def self.call_api(resource, method: 'get', data: nil)
11
+ url = URI.parse(BASE_URL + resource)
12
+ http = Net::HTTP.new(url.host, url.port)
13
+ http.use_ssl = true
14
+
15
+ request = nil
16
+ if method == 'get'
17
+ url.query = data.nil? ? nil : URI.encode_www_form(data)
18
+ request = Net::HTTP::Get.new(url.request_uri)
19
+ elsif method == 'post'
20
+ request = Net::HTTP::Post.new(url.request_uri)
21
+ request.content_type = 'application/x-www-form-urlencoded'
22
+ if data != nil then request.set_form_data(data) else {} end
23
+ end
24
+
25
+ response = http.request(request)
26
+ if response.code != '200'
27
+ raise APIException, response.body
28
+ end
29
+ return response.body
30
+ end
31
+
32
+ end
@@ -0,0 +1,3 @@
1
+ module Blockchain
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,167 @@
1
+ require 'json'
2
+ require_relative 'util'
3
+
4
+ module Blockchain
5
+
6
+ class Wallet
7
+
8
+ def initialize(identifier, password, second_password = nil, api_code = nil)
9
+ @identifier = identifier
10
+ @password = password
11
+ @second_password = second_password
12
+ @api_code = api_code
13
+ end
14
+
15
+ def send(to, amount, from_address: nil, fee: nil, note: nil)
16
+ recipient = { to => amount }
17
+ return send_many(recipient, from_address: from_address, fee: fee, note: note)
18
+ end
19
+
20
+ def send_many(recipients, from_address: nil, fee: nil, note: nil)
21
+ params = build_basic_request()
22
+ method = ''
23
+
24
+ if recipients.size == 1
25
+ params['to'] = recipients.keys[0]
26
+ params['amount'] = recipients.values[0]
27
+ method = 'payment'
28
+ else
29
+ params['recipients'] = JSON.dump(recipients)
30
+ method = 'sendmany'
31
+ end
32
+
33
+ if !from_address.nil?
34
+ params['from'] = from_address
35
+ end
36
+ if !fee.nil?
37
+ params['fee'] = fee
38
+ end
39
+ if !note.nil?
40
+ params['note'] = note
41
+ end
42
+
43
+ response = Blockchain::call_api("merchant/#{@identifier}/#{method}", method: 'post', data: params)
44
+ json_response = parse_json(response)
45
+ return PaymentResponse.new(
46
+ json_response['message'],
47
+ json_response['tx_hash'],
48
+ json_response['notice'])
49
+ end
50
+
51
+ def get_balance()
52
+ response = resp = Blockchain::call_api("merchant/#{@identifier}/balance", method: 'get', data: build_basic_request())
53
+ json_response = parse_json(response)
54
+ return json_response['balance']
55
+ end
56
+
57
+ def list_addresses(confirmations = 0)
58
+ params = build_basic_request()
59
+ params['confirmations'] = confirmations
60
+ response = Blockchain::call_api("merchant/#{@identifier}/list", method: 'get', data: params)
61
+ json_response = parse_json(response)
62
+
63
+ addresses = []
64
+ json_response['addresses'].each do |a|
65
+ addr = WalletAddress.new(a['balance'],
66
+ a['address'],
67
+ a['label'],
68
+ a['total_received'])
69
+ addresses.push(addr)
70
+ end
71
+ return addresses
72
+ end
73
+
74
+ def get_address(address, confirmations = 0)
75
+ params = build_basic_request()
76
+ params['address'] = address
77
+ params['confirmations'] = confirmations
78
+ response = Blockchain::call_api("merchant/#{@identifier}/address_balance", method: 'get', data: params)
79
+ json_response = parse_json(response)
80
+ return WalletAddress.new(json_response['balance'],
81
+ json_response['address'],
82
+ nil,
83
+ json_response['total_received'])
84
+ end
85
+
86
+ def new_address(label = nil)
87
+ params = build_basic_request()
88
+ if !label.nil? then params['label'] = label end
89
+ response = Blockchain::call_api("merchant/#{@identifier}/new_address", method: 'post', data: params)
90
+ json_response = parse_json(response)
91
+ return WalletAddress.new(0,
92
+ json_response['address'],
93
+ json_response['label'],
94
+ 0)
95
+ end
96
+
97
+ def archive_address(address)
98
+ params = build_basic_request()
99
+ params['address'] = address
100
+ response = Blockchain::call_api("merchant/#{@identifier}/archive_address", method: 'post', data: params)
101
+ json_response = parse_json(response)
102
+ return json_response['archived']
103
+ end
104
+
105
+ def unarchive_address(address)
106
+ params = build_basic_request()
107
+ params['address'] = address
108
+ response = Blockchain::call_api("merchant/#{@identifier}/unarchive_address", method: 'post', data: params)
109
+ json_response = parse_json(response)
110
+ return json_response['active']
111
+ end
112
+
113
+ def consolidate(days)
114
+ params = build_basic_request()
115
+ params['days'] = days
116
+ response = Blockchain::call_api("merchant/#{@identifier}/auto_consolidate", method: 'post', data: params)
117
+ json_response = parse_json(response)
118
+ return json_response['consolidated']
119
+ end
120
+
121
+ def build_basic_request()
122
+ params = { 'password' => @password }
123
+ if !@second_password.nil?
124
+ params['second_password'] = @second_password
125
+ end
126
+ if !@api_code.nil?
127
+ params['api_code'] = @api_code
128
+ end
129
+ return params
130
+ end
131
+
132
+ # convenience method that parses a response into json AND makes sure there are no errors
133
+ def parse_json(response)
134
+ json_response = JSON.parse(response)
135
+ error = json_response['error']
136
+ if !error.nil? then raise APIException.new(error) end
137
+ return json_response
138
+ end
139
+ end
140
+
141
+ class WalletAddress
142
+ attr_reader :balance
143
+ attr_reader :address
144
+ attr_reader :label
145
+ attr_reader :total_received
146
+
147
+ def initialize(balance, address, label, total_received)
148
+ @balance = balance
149
+ @address = address
150
+ @label = label
151
+ @total_received = total_received
152
+ end
153
+ end
154
+
155
+ class PaymentResponse
156
+ attr_reader :message
157
+ attr_reader :tx_hash
158
+ attr_reader :notice
159
+
160
+ def initialize(message, tx_hash, notice)
161
+ @message = message
162
+ @tx_hash = tx_hash
163
+ @notice = notice
164
+ end
165
+ end
166
+
167
+ end
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: blockchain
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Blockchain
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ description: Blockchain API library (Ruby, v1)
42
+ email:
43
+ - support@blockchain.zendesk.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - Gemfile
50
+ - LICENSE.txt
51
+ - README.md
52
+ - Rakefile
53
+ - blockchain.gemspec
54
+ - docs/blockexplorer.md
55
+ - docs/createwallet.md
56
+ - docs/exchangerates.md
57
+ - docs/receive.md
58
+ - docs/statistics.md
59
+ - docs/wallet.md
60
+ - lib/blockchain.rb
61
+ - lib/blockchain/blockexplorer.rb
62
+ - lib/blockchain/createwallet.rb
63
+ - lib/blockchain/exchangerates.rb
64
+ - lib/blockchain/receive.rb
65
+ - lib/blockchain/statistics.rb
66
+ - lib/blockchain/util.rb
67
+ - lib/blockchain/version.rb
68
+ - lib/blockchain/wallet.rb
69
+ homepage: https://github.com/blockchain/api-v1-client-ruby
70
+ licenses:
71
+ - MIT
72
+ metadata: {}
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ requirements: []
88
+ rubyforge_project:
89
+ rubygems_version: 2.2.2
90
+ signing_key:
91
+ specification_version: 4
92
+ summary: Blockchain API library (Ruby, v1)
93
+ test_files: []