blockcypher-ruby 0.2.4 → 0.2.6

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.
Files changed (24) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +8 -3
  3. data/lib/blockcypher-ruby.rb +1 -0
  4. data/lib/blockcypher/api.rb +75 -41
  5. data/spec/blockcypher/api_spec.rb +100 -57
  6. data/spec/config.yml.sample +2 -0
  7. data/spec/fixtures/vcr_cassettes/BlockCypher_Api/Asset_API/Asset_Transfer/should_transfer_asset.yml +1349 -0
  8. data/spec/fixtures/vcr_cassettes/BlockCypher_Api/Asset_API/Generate_Asset_Address/should_include_private_public_oap_address_original_address_hashes.yml +51 -0
  9. data/spec/fixtures/vcr_cassettes/BlockCypher_Api/Asset_API/Issue_Asset/should_issue_asset.yml +156 -0
  10. data/spec/fixtures/vcr_cassettes/BlockCypher_Api/_address_final_balance/should_get_the_balance_of_an_address.yml +102 -0
  11. data/spec/fixtures/vcr_cassettes/BlockCypher_Api/_address_generate/should_generate_new_addresses.yml +97 -0
  12. data/spec/fixtures/vcr_cassettes/BlockCypher_Api/_create_forwarding_address/allows_creating_a_payment_forward_with_a_callback.yml +100 -0
  13. data/spec/fixtures/vcr_cassettes/BlockCypher_Api/_create_forwarding_address/allows_creating_a_payment_forward_with_a_callback_and_confirmation_notifications_enabled.yml +101 -0
  14. data/spec/fixtures/vcr_cassettes/BlockCypher_Api/_create_forwarding_address/allows_creating_a_payment_forward_with_options.yml +102 -0
  15. data/spec/fixtures/vcr_cassettes/BlockCypher_Api/_create_forwarding_address/creates_a_payment_forward.yml +99 -0
  16. data/spec/fixtures/vcr_cassettes/BlockCypher_Api/_create_forwarding_address/is_possible_to_use_the_alias_create_payments_forwarding.yml +99 -0
  17. data/spec/fixtures/vcr_cassettes/BlockCypher_Api/_delete_forwarding_address/deletes_all_previously_created_forwarding_addresses.yml +269 -0
  18. data/spec/fixtures/vcr_cassettes/BlockCypher_Api/_faucet/should_fund_a_bcy_test_address_with_the_faucet.yml +96 -0
  19. data/spec/fixtures/vcr_cassettes/BlockCypher_Api/_list_forwarding_addresses/lists_all_forwading_addresses_created_for_a_given_token.yml +119 -0
  20. data/spec/fixtures/vcr_cassettes/BlockCypher_Api/_transaction_new/should_call_the_txs/new_api.yml +187 -0
  21. data/spec/fixtures/vcr_cassettes/BlockCypher_Api/_transaction_sign_and_send/should_call_txs/send_api.yml +187 -0
  22. data/spec/spec_helper.rb +15 -0
  23. data/spec/support/vcr.rb +10 -0
  24. metadata +66 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: dfbc37a64ab4a52a21b42e53205f82a3e714ec6b
4
- data.tar.gz: 90369729738d15f05be790985b558d8d0684ea4a
2
+ SHA256:
3
+ metadata.gz: d4d54eab1d965239db06020543ac99c61dd1e3779b83d7f74f640e06a96ab728
4
+ data.tar.gz: 560ff7e2e88f1dd61d494f89925c5f04e76bba825e959b4a8d3a182a094b0b0c
5
5
  SHA512:
6
- metadata.gz: c8eb9097474353ca1ab9918880cb1e02f406753af16717f26b3b20b8e2b578d8b901d534e9f079bdada946115355d6d5a77723ca7be091d442504d23cc421a98
7
- data.tar.gz: 5f48d97c217b03ebb401b52f3d06aba9a248625a05631d3f650e0c87731f540adee7dca47b5f466e9dd73d9ba2f51b8a50e9ab9a8d39ce3562b897c0f65e425b
6
+ metadata.gz: 3c64b0ca05d8c0cd0ffec4b3805c3abc8b7010439de254d39dabb3fe74595782737b35e8326bbead96aee04c49167f2c9293e699b013adacfb895d2d1f25a6d2
7
+ data.tar.gz: a84fc2cb516483d768076731cf4dc0e89258e3946bdb065e6783b4e8fc9f3aa9e0d630a290c83458e14f41983a90801b768c2bf15b8aa275de18bece43cff1be
data/README.md CHANGED
@@ -13,7 +13,7 @@ Simply using rubygems:
13
13
  Add this line to your application's Gemfile:
14
14
 
15
15
  ```ruby
16
- gem 'blockcypher-ruby', '~> 0.2.4', :require => 'blockcypher'
16
+ gem 'blockcypher-ruby', '~> 0.2.5'
17
17
  ```
18
18
 
19
19
  And then execute:
@@ -29,7 +29,7 @@ $ git clone https://github.com/blockcypher/ruby-client.git
29
29
  $ cd ruby-client
30
30
  $ bundle
31
31
  $ gem build blockcypher-ruby.gemspec
32
- $ gem install blockcypher-ruby-0.2.4.gem
32
+ $ gem install blockcypher-ruby-0.2.5.gem
33
33
  ```
34
34
 
35
35
  ## Initializing a client
@@ -42,7 +42,12 @@ If you want to use BTC on the main net, which is normally what you want to do, i
42
42
 
43
43
  For more information check the API docs at:
44
44
 
45
- http://dev.blockcypher.com
45
+ https://www.blockcypher.com/dev/bitcoin
46
+
47
+ ## Development
48
+
49
+ - Copy `spec/config.yml.sample` to `spec/config.yml` and put your test API token
50
+ - `rspec spec`
46
51
 
47
52
  ## Contributors
48
53
 
@@ -0,0 +1 @@
1
+ require 'blockcypher'
@@ -1,19 +1,20 @@
1
- module BlockCypher
1
+ # frozen_string_literal: true
2
2
 
3
+ module BlockCypher
3
4
  V1 = 'v1'
4
5
 
5
6
  BTC = 'btc'
6
7
  LTC = 'ltc'
7
8
  DOGE = 'doge'
8
- BCY= 'bcy'
9
+ BCY = 'bcy'
10
+ ETH = 'eth'
9
11
 
10
12
  MAIN_NET = 'main'
11
13
  TEST_NET = 'test'
12
14
  TEST_NET_3 = 'test3'
13
15
 
14
16
  class Api
15
-
16
- class Error < RuntimeError ; end
17
+ class Error < RuntimeError; end
17
18
 
18
19
  attr_reader :api_token
19
20
 
@@ -58,7 +59,7 @@ module BlockCypher
58
59
  ##################
59
60
 
60
61
  def decode_hex(hex)
61
- payload = { 'tx' => hex}
62
+ payload = { 'tx' => hex }
62
63
  api_http_post('/txs/decode', json_payload: payload)
63
64
  end
64
65
 
@@ -68,10 +69,7 @@ module BlockCypher
68
69
  end
69
70
 
70
71
  def send_money(from_address, to_address, satoshi_amount, private_key)
71
-
72
- unless to_address.kind_of? Array
73
- to_address = [to_address]
74
- end
72
+ to_address = [to_address] unless to_address.is_a? Array
75
73
 
76
74
  tx_new = transaction_new([from_address], to_address, satoshi_amount)
77
75
 
@@ -114,13 +112,13 @@ module BlockCypher
114
112
  signatures = []
115
113
 
116
114
  tosign.each do |to_sign_hex|
117
- to_sign_binary = [to_sign_hex].pack("H*")
115
+ to_sign_binary = [to_sign_hex].pack('H*')
118
116
  sig_binary = key.sign(to_sign_binary)
119
- sig_hex = sig_binary.unpack("H*").first
117
+ sig_hex = sig_binary.unpack1('H*')
120
118
  signatures << sig_hex
121
119
  end
122
120
 
123
- return signatures
121
+ signatures
124
122
  end
125
123
 
126
124
  def transaction_new_custom(payload)
@@ -174,23 +172,23 @@ module BlockCypher
174
172
  end
175
173
 
176
174
  def address_generate_multi(pubkeys, script_type)
177
- payload = { 'pubkeys' => pubkeys, 'script_type' => script_type}
175
+ payload = { 'pubkeys' => pubkeys, 'script_type' => script_type }
178
176
  api_http_post('/addrs', json_payload: payload)
179
177
  end
180
178
 
181
179
  def address_details(address, unspent_only: false, limit: 50,
182
180
  before: nil, after: nil, confirmations: nil,
183
- omit_wallet_addresses: false, include_confidence:false)
181
+ omit_wallet_addresses: false, include_confidence: false)
184
182
  query = {
185
183
  unspentOnly: unspent_only,
186
184
  limit: limit,
187
185
  omitWalletAddresses: omit_wallet_addresses,
188
- includeConfidence: include_confidence
186
+ includeConfidence: include_confidence
189
187
  }
190
188
  query[:before] = before if before
191
- query[:after] = after if after
189
+ query[:after] = after if after
192
190
 
193
- api_http_get('/addrs/' + address, query: query )
191
+ api_http_get('/addrs/' + address, query: query)
194
192
  end
195
193
 
196
194
  def address_balance(address, omit_wallet_addresses: false)
@@ -204,13 +202,13 @@ module BlockCypher
204
202
  details['final_balance']
205
203
  end
206
204
 
207
- def address_full_txs(address, limit: 10, before: nil, after: nil,
208
- include_hex: false, omit_wallet_addresses: false, include_confidence:false)
205
+ def address_full_txs(address, limit: 10, before: nil, after: nil,
206
+ include_hex: false, omit_wallet_addresses: false, include_confidence: false)
209
207
  query = {
210
208
  limit: limit,
211
209
  includeHex: include_hex,
212
210
  omitWalletAddresses: omit_wallet_addresses,
213
- includeConfidence: include_confidence
211
+ includeConfidence: include_confidence
214
212
  }
215
213
  query[:before] = before if before
216
214
  query[:after] = after if after
@@ -223,7 +221,7 @@ module BlockCypher
223
221
  ##################
224
222
 
225
223
  def wallet_create(name, addresses)
226
- payload = { 'name' => name, 'addresses' => Array(addresses)}
224
+ payload = { 'name' => name, 'addresses' => Array(addresses) }
227
225
  api_http_post('/wallets', json_payload: payload)
228
226
  end
229
227
 
@@ -243,8 +241,8 @@ module BlockCypher
243
241
  end
244
242
 
245
243
  def wallet_delete_addr(name, addresses)
246
- addrjoin = addresses.join(";")
247
- api_http_delete('/wallets/' + name + '/addresses', query: { address: addrjoin})
244
+ addrjoin = addresses.join(';')
245
+ api_http_delete('/wallets/' + name + '/addresses', query: { address: addrjoin })
248
246
  end
249
247
 
250
248
  def wallet_gen_addr(name)
@@ -259,15 +257,12 @@ module BlockCypher
259
257
  # Events API
260
258
  ##################
261
259
 
262
- def event_webhook_subscribe(url, event, confirmations: nil, hash:nil, address:nil, script:nil)
260
+ def event_webhook_subscribe(url, event, options = {})
263
261
  payload = {
264
262
  url: url,
265
- event: event,
266
- }
267
- payload[:address] = address if address
268
- payload[:hash] = hash if hash
269
- payload[:script] = script if script
270
- payload[:confirmations] = confirmations if confirmations
263
+ event: event
264
+ }.merge(options)
265
+
271
266
  api_http_post('/hooks', json_payload: payload)
272
267
  end
273
268
 
@@ -287,23 +282,61 @@ module BlockCypher
287
282
  # Payments and Forwarding API
288
283
  ##################
289
284
 
290
- def create_forwarding_address(destination, callback_url: nil, enable_confirmations: false)
285
+ def create_forwarding_address(
286
+ destination,
287
+ callback_url: nil,
288
+ enable_confirmations: false,
289
+ mining_fees_satoshis: nil
290
+ )
291
291
  payload = {
292
292
  destination: destination,
293
293
  callback_url: callback_url,
294
- enable_confirmations: enable_confirmations
294
+ enable_confirmations: enable_confirmations,
295
+ mining_fees_satoshis: mining_fees_satoshis
295
296
  }
296
297
  api_http_post('/payments', json_payload: payload)
297
298
  end
298
299
 
299
- alias :create_payments_forwarding :create_forwarding_address
300
+ alias create_payments_forwarding create_forwarding_address
300
301
 
301
302
  def list_forwarding_addresses
302
- api_http_get("/payments")
303
+ api_http_get('/payments')
303
304
  end
304
305
 
305
306
  def delete_forwarding_address(id)
306
- api_http_delete("/payments/" + id)
307
+ api_http_delete('/payments/' + id)
308
+ end
309
+
310
+ #############
311
+ # Asset API #
312
+ #############
313
+
314
+ def generate_asset_address
315
+ api_http_post('/oap/addrs')
316
+ end
317
+
318
+ def issue_asset(from_private, to_address, amount)
319
+ api_http_post('/oap/issue', json_payload: {
320
+ from_private: from_private,
321
+ to_address: to_address,
322
+ amount: amount
323
+ })
324
+ end
325
+
326
+ def transfer_asset(asset_id, from_private, to_address, amount)
327
+ api_http_post("/oap/#{asset_id}/transfer", json_payload: {
328
+ from_private: from_private,
329
+ to_address: to_address,
330
+ amount: amount
331
+ })
332
+ end
333
+
334
+ def asset_txs(asset_id)
335
+ api_http_get("/oap/#{asset_id}/txs")
336
+ end
337
+
338
+ def asset_address(asset_id, oap_address)
339
+ api_http_get("/oap/#{asset_id}/addrs/#{oap_address}")
307
340
  end
308
341
 
309
342
  private
@@ -312,7 +345,7 @@ module BlockCypher
312
345
  uri = endpoint_uri(api_path, query)
313
346
 
314
347
  # Build the connection
315
- http = Net::HTTP.new(uri.host, uri.port)
348
+ http = Net::HTTP.new(uri.host, uri.port)
316
349
  http.use_ssl = true
317
350
 
318
351
  # Build the Request
@@ -332,19 +365,20 @@ module BlockCypher
332
365
  end
333
366
 
334
367
  response = http.request(request)
368
+ response_code = response.code.to_i
335
369
 
336
370
  # Detect errors/return 204 empty body
337
- if response.code == '400'
338
- raise Error.new(uri.to_s + ' Response:' + response.body)
339
- elsif response.code == '204'
371
+ if response_code >= 400
372
+ raise Error, uri.to_s + ' Response:' + response.body
373
+ elsif response_code == 204
340
374
  return nil
341
375
  end
342
376
 
343
377
  # Process the response
344
378
  begin
345
379
  json_response = JSON.parse(response.body)
346
- return json_response
347
- rescue => e
380
+ json_response
381
+ rescue StandardError => e
348
382
  raise "Unable to parse JSON response #{e.inspect}, #{response.body}"
349
383
  end
350
384
  end
@@ -1,47 +1,48 @@
1
- require 'blockcypher'
1
+ # frozen_string_literal: true
2
2
 
3
- module BlockCypher
3
+ require 'spec_helper'
4
4
 
5
- describe Api do
5
+ module BlockCypher
6
+ describe Api, vcr: { record: :once } do
6
7
  let(:api) do
7
8
  BlockCypher::Api.new({
8
- api_token: 'testtoken',
9
- currency: BlockCypher::BCY,
10
- network: BlockCypher::TEST_NET,
11
- version: BlockCypher::V1
12
- })
9
+ api_token: CONFIG[:api_token],
10
+ currency: BlockCypher::BCY,
11
+ network: BlockCypher::TEST_NET,
12
+ version: BlockCypher::V1
13
+ })
13
14
  end
14
15
 
15
- context '#address_generate' do
16
- it 'should generate new addresses' do
17
- $addr1 = api.address_generate
18
- $addr2 = api.address_generate
19
- expect($addr1["address"]).to be_a(String)
20
- expect($addr2["address"]).to be_a(String)
21
- end
22
- end
16
+ let(:addr1) { api.address_generate }
17
+ let(:addr2) { api.address_generate }
18
+ context '#address_generate' do
19
+ it 'should generate new addresses' do
20
+ expect(addr1['address']).to be_a(String)
21
+ expect(addr2['address']).to be_a(String)
22
+ end
23
+ end
23
24
 
24
- let(:address_1) { $addr1["address"].to_s }
25
- let(:address_1_private_key) { $addr1["private"].to_s }
25
+ let(:address_1) { addr1['address'].to_s }
26
+ let(:address_1_private_key) { addr1['private'].to_s }
26
27
 
27
- let(:address_2) { $addr2["address"].to_s }
28
- let(:address_2_private_key) { $addr2["private"].to_s }
28
+ let(:address_2) { addr2['address'].to_s }
29
+ let(:address_2_private_key) { addr2['private'].to_s }
29
30
 
30
- context '#faucet' do
31
- it 'should fund a bcy test address with the faucet' do
32
- res = api.faucet(address_1, 100000)
33
- expect(res["tx_ref"]).to be_a(String)
34
- end
35
- end
31
+ context '#faucet' do
32
+ it 'should fund a bcy test address with the faucet' do
33
+ res = api.faucet(address_1, 100_000)
34
+ expect(res['tx_ref']).to be_a(String)
35
+ end
36
+ end
36
37
 
37
38
  context '#transaction_new' do
38
39
  it 'should call the txs/new api' do
39
40
  input_addresses = [address_1]
40
41
  output_addresses = [address_2]
41
- satoshi_value = 20000
42
+ satoshi_value = 20_000
42
43
  res = api.transaction_new(input_addresses, output_addresses, satoshi_value)
43
- expect(res["tx"]["hash"]).to be_a(String)
44
- expect(res["tx"]["hash"].length).to be(64)
44
+ expect(res['tx']['hash']).to be_a(String)
45
+ expect(res['tx']['hash'].length).to be(64)
45
46
  end
46
47
  end
47
48
 
@@ -49,12 +50,12 @@ module BlockCypher
49
50
  it 'should call txs/send api' do
50
51
  input_addresses = [address_1]
51
52
  output_addresses = [address_2]
52
- satoshi_value = 10000
53
+ satoshi_value = 10_000
53
54
 
54
55
  new_tx = api.transaction_new(input_addresses, output_addresses, satoshi_value)
55
56
  res = api.transaction_sign_and_send(new_tx, address_1_private_key)
56
- expect(res["tx"]["hash"]).to be_a(String)
57
- expect(res["tx"]["hash"].length).to be(64)
57
+ expect(res['tx']['hash']).to be_a(String)
58
+ expect(res['tx']['hash'].length).to be(64)
58
59
  end
59
60
  end
60
61
 
@@ -67,47 +68,44 @@ module BlockCypher
67
68
  end
68
69
 
69
70
  context '#create_forwarding_address' do
70
-
71
71
  it 'creates a payment forward' do
72
72
  forward_details = api.create_forwarding_address(address_1)
73
- expect(forward_details["input_address"]).to be_a(String)
74
- expect(forward_details["input_address"].length).to be(34) # Ok this isn't strictly true but..
75
- end
76
-
77
- it 'allows creating a payment forward with a callback' do
78
- forward_details = api.create_forwarding_address(address_1, callback_url: "http://test.com/foo")
79
- expect(forward_details["callback_url"]).to eql("http://test.com/foo")
80
- expect(forward_details["enable_confirmations"]).to be nil
73
+ expect(forward_details['input_address']).to be_a(String)
74
+ expect(forward_details['input_address'].length).to be(34) # Ok this isn't strictly true but..
81
75
  end
82
76
 
83
- it 'allows creating a payment forward with a callback and confirmation notifications enabled' do
84
- forward_details = api.create_forwarding_address(address_1, callback_url: "http://test.com/foo", enable_confirmations: true)
85
- expect(forward_details["callback_url"]).to eql("http://test.com/foo")
86
- expect(forward_details["enable_confirmations"]).to be true
77
+ it 'allows creating a payment forward with options' do
78
+ forward_details = api.create_forwarding_address(address_1, {
79
+ callback_url: 'http://test.com/foo',
80
+ enable_confirmations: true,
81
+ mining_fees_satoshis: 20_000
82
+ })
83
+ expect(forward_details['callback_url']).to eql('http://test.com/foo')
84
+ expect(forward_details['enable_confirmations']).to be true
85
+ expect(forward_details['mining_fees_satoshis']).to be 20_000
87
86
  end
88
87
 
89
88
  it 'is possible to use the alias create_payments_forwarding' do
90
89
  forward_details = api.create_payments_forwarding(address_1)
91
- expect(forward_details["input_address"]).to be_a(String)
90
+ expect(forward_details['input_address']).to be_a(String)
92
91
  end
93
-
94
92
  end
95
93
 
96
94
  context '#list_forwarding_addresses' do
97
95
  it 'lists all forwading addresses created for a given token' do
98
96
  forwarding_addresses = api.list_forwarding_addresses
99
- expect(forwarding_addresses.first["destination"]).to eql(address_1)
97
+ expect(forwarding_addresses.first['destination']).to eql(address_1)
100
98
  end
101
99
  end
102
100
 
103
- context '#delete_forwarding_address' do
104
- it 'deletes all previously created forwarding addresses' do
105
- forwarding_addresses = api.list_forwarding_addresses
106
- forwarding_addresses.each{|x| api.delete_forwarding_address(x["id"])}
107
- forwarding_addresses = api.list_forwarding_addresses
108
- expect(forwarding_addresses.any? == false)
109
- end
110
- end
101
+ context '#delete_forwarding_address' do
102
+ it 'deletes all previously created forwarding addresses' do
103
+ forwarding_addresses = api.list_forwarding_addresses
104
+ forwarding_addresses.each { |x| api.delete_forwarding_address(x['id']) }
105
+ forwarding_addresses = api.list_forwarding_addresses
106
+ expect(forwarding_addresses.any? == false)
107
+ end
108
+ end
111
109
 
112
110
  describe '#endpoint_uri' do
113
111
  it 'should encode query into URI' do
@@ -122,6 +120,51 @@ module BlockCypher
122
120
  end
123
121
  end
124
122
 
125
- end
123
+ describe 'Asset API' do
124
+ describe 'Generate Asset Address' do
125
+ it 'should include private, public, oap_address, original_address hashes' do
126
+ res = api.generate_asset_address
127
+ expect(res).to include('private', 'public', 'oap_address', 'original_address')
128
+ end
129
+ end
126
130
 
131
+ describe 'Issue Asset' do
132
+ it 'should issue asset' do
133
+ asset_address = api.generate_asset_address
134
+ api.faucet(asset_address['original_address'], 1_000_000)
135
+ res = api.issue_asset(asset_address['private'], asset_address['oap_address'], 1000)
136
+
137
+ expect(res).to include(
138
+ 'ver',
139
+ 'assetid',
140
+ 'oap_meta',
141
+ 'hash',
142
+ 'received',
143
+ 'double_spend',
144
+ 'inputs',
145
+ 'outputs'
146
+ )
147
+ end
148
+ end
149
+
150
+ describe 'Asset Transfer' do
151
+ it 'should transfer asset' do
152
+ asset_address = api.generate_asset_address
153
+ asset_address_to = api.generate_asset_address
154
+ api.faucet(asset_address['original_address'], 100_000_000)
155
+ asset = api.issue_asset(asset_address['private'], asset_address['oap_address'], 1000)
156
+
157
+ puts 'waiting asset to been issued'
158
+ begin
159
+ printf('|')
160
+ check_address = api.asset_address(asset['assetid'], asset_address['oap_address'])
161
+ sleep(1)
162
+ end while check_address['n_tx'] == 0
163
+
164
+ res = api.transfer_asset(asset['assetid'], asset_address['private'], asset_address_to['oap_address'], 100)
165
+ expect(res).to include('assetid')
166
+ end
167
+ end
168
+ end
169
+ end
127
170
  end