block_io 1.0.5 → 1.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0940811390b9b507fed0e47b2a04769206f6942c
4
- data.tar.gz: ec335dcad5f5a0b8cb70524ac3a619e5e70094c5
3
+ metadata.gz: d0ac0a444bdd6e778287026a7d9e89ef91b25ddd
4
+ data.tar.gz: 7e9bb72332639245c289c04f474be22ea512eba9
5
5
  SHA512:
6
- metadata.gz: 27f8d7f35c2d73438f0faf47e1d57b8d866dfeefde4a9080c1618eb0dd623b205caed1e345782dae052ad2039f470c0ec1a7476bfea832e67429e9916f3f8749
7
- data.tar.gz: e0b5606867ac6a6618732c3ca2c05fb48822a68ee00de2728a2bf283d6514b963d53609a23ee43809adba88b5384c9ba62b26cc5bd740f0937ed6ccf2734b231
6
+ metadata.gz: d06356ff689a5e4a8f30787d1683c2277b4237120daad993e4dac9b564c975d284427c8a147fe61194c1cef06cfb663cfff91bc26c0f86a8a42f3ee3aa58fa86
7
+ data.tar.gz: 36554afd1641aed6eee40442178a16d337a6174a263f559eefdaf7e63915edbe56a726d738bb8feaa4c69851b984e6b4106149070a13de1a81995de7be175118
data/README.md CHANGED
@@ -14,10 +14,12 @@ And then execute:
14
14
 
15
15
  Or install it yourself as:
16
16
 
17
- $ gem install block_io -v=1.0.4
17
+ $ gem install block_io -v=1.0.6
18
18
 
19
19
  ## Changelog
20
20
 
21
+ *01/21/15*: Added ability to sweep coins from one address to another.
22
+ *11/04/14*: Fix issue with nil parameters in an API call.
21
23
  *11/03/14*: Reduce dependence on OpenSSL. PBKDF2 function is now Ruby-based. Should work well with Heroku's libraries.
22
24
  *10/18/14*: Now using deterministic signatures (RFC6979), and BIP62 to hinder transaction malleability.
23
25
 
@@ -0,0 +1,24 @@
1
+ # Example script for sweeping all coins from a given address
2
+ # Must use the API Key for the Network the address belongs to
3
+ # Must also provide the Private Key to the sweep address in Wallet Import Format (WIF)
4
+ #
5
+ # Contact support@block.io if you have any issues
6
+
7
+ require "block_io"
8
+
9
+ BlockIo.set_options :api_key => 'YOUR API KEY', :pin => 'PIN NOT NEEDED', :version => 2
10
+
11
+ to_address = 'SWEEP COINS TO THIS ADDRESS'
12
+
13
+ from_address = 'SWEEP COINS FROM THIS ADDRESS'
14
+ private_key = 'PRIVATE KEY FOR FROM_ADDRESS'
15
+
16
+ begin
17
+ response = BlockIo.sweep_from_address(:to_address => to_address, :private_key => private_key, :from_address => from_address)
18
+
19
+ puts "Sweep Complete: #{response['data']['amount_sent']} #{response['data']['network']} swept from #{from_address} to #{to_address}."
20
+ puts "Transaction ID: #{response['data']['txid']}"
21
+ puts "Network Fee Incurred: #{response['data']['network_fee']} #{response['data']['network']}"
22
+ rescue Exception => e
23
+ puts "Sweep failed: #{e}"
24
+ end
@@ -36,9 +36,12 @@ module BlockIo
36
36
  method_name = m.to_s
37
37
 
38
38
  if ['withdraw', 'withdraw_from_address', 'withdraw_from_addresses', 'withdraw_from_user', 'withdraw_from_users', 'withdraw_from_label', 'withdraw_from_labels'].include?(m.to_s) then
39
-
39
+ # need to withdraw from an address
40
40
  self.withdraw(args.first, m.to_s)
41
41
 
42
+ elsif ['sweep_from_address'].include?(m.to_s) then
43
+ # need to sweep from an address
44
+ self.sweep(args.first, m.to_s)
42
45
  else
43
46
  params = get_params(args.first)
44
47
  self.api_call([method_name, params])
@@ -96,6 +99,51 @@ module BlockIo
96
99
 
97
100
  end
98
101
 
102
+ def self.sweep(args = {}, method_name = 'sweep_from_address')
103
+ # sweep coins from a given address + key
104
+
105
+ raise Exception.new("No private_key provided.") unless args.has_key?(:private_key)
106
+
107
+ key = Key.from_wif(args[:private_key])
108
+
109
+ args[:public_key] = key.public_key # so Block.io can match things up
110
+ args.delete(:private_key) # the key must never leave this machine
111
+
112
+ params = get_params(args)
113
+
114
+ response = self.api_call([method_name, params])
115
+
116
+ if response['data'].has_key?('reference_id') then
117
+ # Block.io's asking us to provide some client-side signatures, let's get to it
118
+
119
+ # let's sign all the inputs we can
120
+ inputs = response['data']['inputs']
121
+
122
+ inputs.each do |input|
123
+ # iterate over all signers
124
+
125
+ input['signers'].each do |signer|
126
+ # if our public key matches this signer's public key, sign the data
127
+
128
+ signer['signed_data'] = key.sign(input['data_to_sign']) if signer['signer_public_key'] == key.public_key
129
+
130
+ end
131
+
132
+ end
133
+
134
+ # the response object is now signed, let's stringify it and finalize this withdrawal
135
+
136
+ response = self.api_call(['sign_and_finalize_sweep',{:signature_data => response['data'].to_json}])
137
+
138
+ # if we provided all the required signatures, this transaction went through
139
+ # otherwise Block.io responded with data asking for more signatures
140
+ # the latter will be the case for dTrust addresses
141
+ end
142
+
143
+ return response
144
+
145
+ end
146
+
99
147
 
100
148
  private
101
149
 
@@ -139,12 +187,13 @@ module BlockIo
139
187
 
140
188
  class Key
141
189
 
142
- def initialize(privkey = nil)
190
+ def initialize(privkey = nil, compressed = true)
143
191
  # the privkey must be in hex if at all provided
144
192
 
145
193
  @group = ECDSA::Group::Secp256k1
146
194
  @private_key = privkey.to_i(16) || 1 + SecureRandom.random_number(group.order - 1)
147
195
  @public_key = @group.generator.multiply_by_scalar(@private_key)
196
+ @compressed = compressed
148
197
 
149
198
  end
150
199
 
@@ -156,7 +205,7 @@ module BlockIo
156
205
  def public_key
157
206
  # returns the compressed form of the public key to save network fees (shorter scripts)
158
207
 
159
- return ECDSA::Format::PointOctetString.encode(@public_key, compression: true).unpack("H*")[0]
208
+ return ECDSA::Format::PointOctetString.encode(@public_key, compression: @compressed).unpack("H*")[0]
160
209
  end
161
210
 
162
211
  def sign(data)
@@ -189,6 +238,19 @@ module BlockIo
189
238
 
190
239
  return Key.new(hashed_key)
191
240
  end
241
+
242
+ def self.from_wif(wif)
243
+ # returns a new key extracted from the Wallet Import Format provided
244
+ # TODO check against checksum
245
+
246
+ hexkey = Helper.decode_base58(wif)
247
+ actual_key = hexkey[2...66]
248
+
249
+ compressed = hexkey[2..hexkey.length].length-8 > 64 and hexkey[2..hexkey.length][64...66] == '01'
250
+
251
+ return Key.new(actual_key, compressed)
252
+
253
+ end
192
254
 
193
255
  def isPositive(i)
194
256
  sig = "!+-"[i <=> 0]
@@ -304,6 +366,41 @@ module BlockIo
304
366
  aes.iv = iv if iv != nil
305
367
  Base64.strict_encode64(aes.update(data) + aes.final)
306
368
  end
369
+
370
+ # courtesy bitcoin-ruby
371
+
372
+ def self.int_to_base58(int_val, leading_zero_bytes=0)
373
+ alpha = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
374
+ base58_val, base = '', alpha.size
375
+ while int_val > 0
376
+ int_val, remainder = int_val.divmod(base)
377
+ base58_val = alpha[remainder] + base58_val
378
+ end
379
+ base58_val
380
+ end
381
+
382
+ def self.base58_to_int(base58_val)
383
+ alpha = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
384
+ int_val, base = 0, alpha.size
385
+ base58_val.reverse.each_char.with_index do |char,index|
386
+ raise ArgumentError, 'Value not a valid Base58 String.' unless char_index = alpha.index(char)
387
+ int_val += char_index*(base**index)
388
+ end
389
+ int_val
390
+ end
391
+
392
+ def self.encode_base58(hex)
393
+ leading_zero_bytes = (hex.match(/^([0]+)/) ? $1 : '').size / 2
394
+ ("1"*leading_zero_bytes) + Helper.int_to_base58( hex.to_i(16) )
395
+ end
396
+
397
+ def self.decode_base58(base58_val)
398
+ s = Helper.base58_to_int(base58_val).to_s(16); s = (s.bytesize.odd? ? '0'+s : s)
399
+ s = '' if s == '00'
400
+ leading_zero_bytes = (base58_val.match(/^([1]+)/) ? $1 : '').size
401
+ s = ("00"*leading_zero_bytes) + s if leading_zero_bytes > 0
402
+ s
403
+ end
307
404
  end
308
405
 
309
406
  end
@@ -1,3 +1,3 @@
1
1
  module BlockIo
2
- VERSION = "1.0.5"
2
+ VERSION = "1.0.6"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: block_io
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.5
4
+ version: 1.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Atif Nazir
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-04 00:00:00.000000000 Z
11
+ date: 2015-01-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -155,6 +155,7 @@ files:
155
155
  - block_io.gemspec
156
156
  - examples/basic.rb
157
157
  - examples/dtrust.rb
158
+ - examples/sweeper.rb
158
159
  - lib/block_io.rb
159
160
  - lib/block_io/version.rb
160
161
  homepage: https://block.io/api/simple/ruby