blockcypher-ruby 0.2.4 → 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
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