onchain 3.2 → 3.03
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/onchain.rb +3 -1
- data/lib/onchain/block_chain.rb +13 -6
- data/lib/onchain/payments.rb +88 -0
- data/lib/onchain/providers/bitcoind_api.rb +25 -73
- data/lib/onchain/providers/blockchaininfo_api.rb +2 -13
- data/lib/onchain/providers/blockr_api.rb +0 -11
- data/lib/onchain/providers/insight_api.rb +0 -11
- data/lib/onchain/sweeper.rb +139 -0
- data/lib/onchain/transaction.rb +1 -13
- metadata +4 -17
- data/lib/onchain/exchange_rates.rb +0 -87
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fd3dee9b9c3e89866a52611e36e4fec6c510675c
|
4
|
+
data.tar.gz: dfec0707b7aa380e6c6189f7065ada17b991dd93
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4c363a289b43d919c7850de400ae48f3226fe8851cb770148b34ce084549cccb6f654538596a16bd0da586441273cc699696c2cc03772d23f7ef8e351aa31848
|
7
|
+
data.tar.gz: 3a16f3eabf4e6306c89ed07fcae622cfd5d481afbb86676b50142293d6a0e2e48d753df0d699eb474d818f34a5c8d46d29e1e793ad85f3da31f5b3696d0aa1f8
|
data/lib/onchain.rb
CHANGED
@@ -3,11 +3,13 @@ require 'onchain/providers/blockchaininfo_api.rb'
|
|
3
3
|
require 'onchain/providers/blockr_api.rb'
|
4
4
|
require 'onchain/providers/insight_api.rb'
|
5
5
|
require 'onchain/providers/bitcoind_api.rb'
|
6
|
+
require 'onchain/sweeper.rb'
|
7
|
+
require 'onchain/payments.rb'
|
6
8
|
require 'onchain/transaction.rb'
|
7
|
-
require 'onchain/exchange_rates.rb'
|
8
9
|
require 'money-tree'
|
9
10
|
require 'bitcoin'
|
10
11
|
|
12
|
+
|
11
13
|
# Setup the bitcoin gem for zcash
|
12
14
|
module Bitcoin
|
13
15
|
|
data/lib/onchain/block_chain.rb
CHANGED
@@ -62,6 +62,17 @@ class OnChain::BlockChain
|
|
62
62
|
end
|
63
63
|
|
64
64
|
end
|
65
|
+
|
66
|
+
def get_history_for_addresses(addresses, network = :bitcoin)
|
67
|
+
history = []
|
68
|
+
addresses.each do |address|
|
69
|
+
res = address_history(address, network)
|
70
|
+
res.each do |r|
|
71
|
+
history << r
|
72
|
+
end
|
73
|
+
end
|
74
|
+
return history
|
75
|
+
end
|
65
76
|
|
66
77
|
# Given a list of addresses, return those
|
67
78
|
# that don't have balances in the cahce.
|
@@ -107,7 +118,7 @@ class OnChain::BlockChain
|
|
107
118
|
end
|
108
119
|
|
109
120
|
def get_balance_satoshi(address, network = :bitcoin)
|
110
|
-
return (get_balance(address, network).to_f * 100000000).to_i
|
121
|
+
return (get_balance(address, network = :bitcoin).to_f * 100000000).to_i
|
111
122
|
end
|
112
123
|
|
113
124
|
def get_available_suppliers(method_name, network)
|
@@ -123,7 +134,7 @@ class OnChain::BlockChain
|
|
123
134
|
next
|
124
135
|
end
|
125
136
|
|
126
|
-
if supplier == :insight and ! [:bitcoin].include? network
|
137
|
+
if supplier == :insight and ! [:bitcoin, :testnet3].include? network
|
127
138
|
next
|
128
139
|
end
|
129
140
|
|
@@ -147,10 +158,6 @@ class OnChain::BlockChain
|
|
147
158
|
next
|
148
159
|
end
|
149
160
|
|
150
|
-
if supplier == :insight and method_name.to_s == 'get_address_info'
|
151
|
-
next
|
152
|
-
end
|
153
|
-
|
154
161
|
if supplier == :blockr and network == :bitcoin and method_name.to_s == 'get_history_for_addresses'
|
155
162
|
next
|
156
163
|
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
class OnChain::Payments
|
2
|
+
class << self
|
3
|
+
|
4
|
+
FEE = 50000
|
5
|
+
|
6
|
+
def get_address_from_redemption_script(redemption_script)
|
7
|
+
|
8
|
+
sbin = OnChain.hex_to_bin(redemption_script)
|
9
|
+
hex = OnChain.bin_to_hex(sbin)
|
10
|
+
fund_address = Bitcoin.hash160_to_p2sh_address(Bitcoin.hash160(hex))
|
11
|
+
|
12
|
+
return fund_address
|
13
|
+
end
|
14
|
+
|
15
|
+
def hex_to_script(hex)
|
16
|
+
return Bitcoin::Script.new(OnChain::hex_to_bin(hex))
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_payment_tx(redemption_script, payments)
|
20
|
+
|
21
|
+
begin
|
22
|
+
|
23
|
+
fund_address = get_address_from_redemption_script(redemption_script)
|
24
|
+
|
25
|
+
tx = Bitcoin::Protocol::Tx.new
|
26
|
+
|
27
|
+
total_amount = FEE
|
28
|
+
|
29
|
+
payments.each do |payment|
|
30
|
+
if payment[1].is_a?(String)
|
31
|
+
payment[1] = payment[1].to_i
|
32
|
+
end
|
33
|
+
total_amount = total_amount + payment[1]
|
34
|
+
end
|
35
|
+
|
36
|
+
total_in_fund = OnChain::BlockChain.get_balance_satoshi(fund_address)
|
37
|
+
|
38
|
+
# Do we have enough in the fund.
|
39
|
+
if(total_amount > total_in_fund)
|
40
|
+
return 'Balance is not enough to cover payment'
|
41
|
+
end
|
42
|
+
|
43
|
+
# OK, let's get some inputs
|
44
|
+
amount_so_far = 0
|
45
|
+
unspent = OnChain::BlockChain.get_unspent_outs(fund_address)
|
46
|
+
unspent.each do |spent|
|
47
|
+
|
48
|
+
txin = Bitcoin::Protocol::TxIn.new
|
49
|
+
|
50
|
+
txin.prev_out = spent[0].scan(/../).map { |x| x.hex }.pack('c*').reverse
|
51
|
+
txin.prev_out_index = spent[1]
|
52
|
+
txin.script = hex_to_script(redemption_script).to_payload
|
53
|
+
|
54
|
+
tx.add_in(txin)
|
55
|
+
|
56
|
+
amount_so_far = amount_so_far + spent[3].to_i
|
57
|
+
if amount_so_far >= total_amount
|
58
|
+
next
|
59
|
+
end
|
60
|
+
end
|
61
|
+
change = amount_so_far - total_amount
|
62
|
+
|
63
|
+
payments.each do |payment|
|
64
|
+
|
65
|
+
txout = Bitcoin::Protocol::TxOut.new(payment[1],
|
66
|
+
Bitcoin::Script.to_address_script(payment[0]))
|
67
|
+
|
68
|
+
tx.add_out(txout)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Send the chnage back.
|
72
|
+
if total_in_fund > total_amount
|
73
|
+
|
74
|
+
txout = Bitcoin::Protocol::TxOut.new(total_in_fund - total_amount,
|
75
|
+
Bitcoin::Script.to_address_script(fund_address))
|
76
|
+
|
77
|
+
tx.add_out(txout)
|
78
|
+
end
|
79
|
+
|
80
|
+
return tx
|
81
|
+
|
82
|
+
rescue Exception => e
|
83
|
+
return 'Unable to parse payment :: ' + e.to_s
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
@@ -5,45 +5,14 @@ class OnChain::BlockChain
|
|
5
5
|
|
6
6
|
# Get last 20 transactions
|
7
7
|
def bitcoind_address_history(address, network = :bitcoin)
|
8
|
-
|
9
|
-
|
10
|
-
result = execute_remote_command('searchrawtransactions ' + address + ' 1 0 20 0', network)
|
11
|
-
cache_write(network.to_s + ' history ' + address, result, BALANCE_CACHE_FOR)
|
12
|
-
end
|
13
|
-
|
14
|
-
result = cache_read(network.to_s + ' history ' + address)
|
8
|
+
|
9
|
+
result = execute_remote_command('searchrawtransactions ' + address + ' 1 0 20 0', network)
|
15
10
|
|
16
11
|
json = JSON.parse result
|
17
12
|
|
18
13
|
return parse_bitcoind_address_tx(address, json, network)
|
19
14
|
|
20
15
|
end
|
21
|
-
|
22
|
-
def bitcoind_get_history_for_addresses(addresses, network = :bitcoin)
|
23
|
-
|
24
|
-
commands = []
|
25
|
-
if cache_read(network.to_s + ' history ' + addresses[0]) == nil
|
26
|
-
addresses.each do |address|
|
27
|
-
commands << 'searchrawtransactions ' + address + ' 1 0 20 0'
|
28
|
-
end
|
29
|
-
histories = OnChain::BlockChain.execute_remote_command(commands, :zclassic)
|
30
|
-
|
31
|
-
index = 0
|
32
|
-
histories.each_line do |history|
|
33
|
-
cache_write(network.to_s + ' history ' + addresses[index], history, BALANCE_CACHE_FOR)
|
34
|
-
index = index + 1
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
history = []
|
39
|
-
addresses.each do |address|
|
40
|
-
res = bitcoind_address_history(address, network)
|
41
|
-
res.each do |r|
|
42
|
-
history << r
|
43
|
-
end
|
44
|
-
end
|
45
|
-
return history
|
46
|
-
end
|
47
16
|
|
48
17
|
def parse_bitcoind_address_tx(address, json, network)
|
49
18
|
|
@@ -86,10 +55,12 @@ class OnChain::BlockChain
|
|
86
55
|
|
87
56
|
def bitcoind_send_tx(tx_hex, network = :bitcoin)
|
88
57
|
|
89
|
-
execute_remote_command('sendrawtransaction ' + tx_hex, network)
|
58
|
+
remote = execute_remote_command('sendrawtransaction ' + tx_hex, network)
|
59
|
+
|
60
|
+
#res = JSON.parse(remote)
|
90
61
|
|
91
|
-
mess = '
|
92
|
-
stat = '
|
62
|
+
mess = 'Unknown'
|
63
|
+
stat = 'Unknown'
|
93
64
|
tx_hash = 'Unknown'
|
94
65
|
|
95
66
|
ret = "{\"status\":\"#{stat}\",\"data\":\"#{tx_hash}\",\"code\":200,\"message\":\"#{mess}\"}"
|
@@ -98,14 +69,21 @@ class OnChain::BlockChain
|
|
98
69
|
|
99
70
|
def bitcoind_get_balance(address, network = :bitcoin)
|
100
71
|
|
101
|
-
if cache_read(
|
72
|
+
if cache_read(address) == nil
|
102
73
|
|
103
|
-
|
74
|
+
outs = bitcoind_get_unspent_outs(address, network)
|
104
75
|
|
105
|
-
|
76
|
+
puts outs.to_s
|
77
|
+
|
78
|
+
bal = 0
|
79
|
+
outs.each do |out|
|
80
|
+
bal += out[3].to_i
|
81
|
+
end
|
82
|
+
|
83
|
+
cache_write(address, bal, BALANCE_CACHE_FOR)
|
106
84
|
end
|
107
85
|
|
108
|
-
bal = cache_read(
|
86
|
+
bal = cache_read(address)
|
109
87
|
if bal.class == Fixnum
|
110
88
|
bal = bal.to_f
|
111
89
|
end
|
@@ -115,22 +93,6 @@ class OnChain::BlockChain
|
|
115
93
|
|
116
94
|
def bitcoind_get_all_balances(addresses, network = :bitcoin)
|
117
95
|
|
118
|
-
|
119
|
-
# if first address is missing get them all.
|
120
|
-
commands = []
|
121
|
-
if cache_read(network.to_s + ' ' + addresses[0]) == nil
|
122
|
-
addresses.each do |address|
|
123
|
-
commands << 'getallbalance ' + address + ' 0'
|
124
|
-
end
|
125
|
-
balances = OnChain::BlockChain.execute_remote_command(commands, :zclassic)
|
126
|
-
|
127
|
-
index = 0
|
128
|
-
balances.each_line do |line|
|
129
|
-
cache_write(network.to_s + ' ' + addresses[index], line.to_f, BALANCE_CACHE_FOR)
|
130
|
-
index = index + 1
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
96
|
addresses.each do |address|
|
135
97
|
bitcoind_get_balance(address, network)
|
136
98
|
end
|
@@ -138,7 +100,7 @@ class OnChain::BlockChain
|
|
138
100
|
|
139
101
|
def bitcoind_get_unspent_outs(address, network = :bitcoin)
|
140
102
|
|
141
|
-
result = execute_remote_command('listallunspent ' + address + ' 1
|
103
|
+
result = execute_remote_command('listallunspent ' + address + ' 1', network)
|
142
104
|
|
143
105
|
json = JSON.parse result
|
144
106
|
|
@@ -162,34 +124,24 @@ class OnChain::BlockChain
|
|
162
124
|
|
163
125
|
# Run the command via ssh. For this to work you need
|
164
126
|
# to create the follwing ENV vars.
|
165
|
-
def execute_remote_command(
|
127
|
+
def execute_remote_command(cmd, network)
|
166
128
|
|
167
129
|
host = ENV[network.to_s.upcase + '_HOST']
|
168
130
|
username = ENV[network.to_s.upcase + '_USER']
|
169
131
|
password = ENV[network.to_s.upcase + '_PASSWORD']
|
170
|
-
|
132
|
+
cmd = ENV[network.to_s.upcase + '_CLI_CMD'] + ' ' + cmd
|
171
133
|
|
172
134
|
stdout = ""
|
135
|
+
stderr = ""
|
173
136
|
begin
|
174
137
|
Net::SSH.start(host, username,
|
175
138
|
:password => password,
|
176
139
|
:auth_methods => [ 'password' ],
|
177
140
|
:number_of_password_prompts => 0) do |ssh|
|
178
|
-
|
179
|
-
if ! commands.is_a?(Array)
|
180
|
-
commands = [commands]
|
181
|
-
end
|
182
|
-
|
183
|
-
commands.each do |command|
|
184
|
-
|
185
|
-
cmdout = ""
|
186
|
-
|
187
|
-
ssh.exec! prefix + ' '+ command do |channel, stream, data|
|
188
|
-
cmdout << data if stream == :stdout
|
189
|
-
end
|
190
141
|
|
191
|
-
|
192
|
-
stdout <<
|
142
|
+
ssh.exec! cmd do |channel, stream, data|
|
143
|
+
stdout << data if stream == :stdout
|
144
|
+
stderr << data if stream == :stderr
|
193
145
|
end
|
194
146
|
end
|
195
147
|
rescue Timeout::Error
|
@@ -8,17 +8,6 @@ class OnChain::BlockChain
|
|
8
8
|
|
9
9
|
blockinfo_parse_address_tx(address, json)
|
10
10
|
end
|
11
|
-
|
12
|
-
def blockinfo_get_history_for_addresses(addresses, network = :bitcoin)
|
13
|
-
history = []
|
14
|
-
addresses.each do |address|
|
15
|
-
res = blockinfo_address_history(address, network)
|
16
|
-
res.each do |r|
|
17
|
-
history << r
|
18
|
-
end
|
19
|
-
end
|
20
|
-
return history
|
21
|
-
end
|
22
11
|
|
23
12
|
def blockinfo_parse_address_tx(address, json)
|
24
13
|
|
@@ -92,7 +81,7 @@ class OnChain::BlockChain
|
|
92
81
|
end
|
93
82
|
end
|
94
83
|
|
95
|
-
def blockinfo_get_unspent_outs(address
|
84
|
+
def blockinfo_get_unspent_outs(address)
|
96
85
|
base_url = "https://blockchain.info/unspent?active=#{address}"
|
97
86
|
json = fetch_response(base_url, true)
|
98
87
|
|
@@ -129,7 +118,7 @@ class OnChain::BlockChain
|
|
129
118
|
|
130
119
|
def blockinfo_get_transaction(txhash)
|
131
120
|
base = "https://blockchain.info/rawtx/#{txhash}?format=hex"
|
132
|
-
return fetch_response(URI::encode(base)
|
121
|
+
return fetch_response(URI::encode(base))
|
133
122
|
end
|
134
123
|
|
135
124
|
def block_chain(cmd, address, params = "")
|
@@ -14,17 +14,6 @@ class OnChain::BlockChain
|
|
14
14
|
|
15
15
|
return parse_address_tx(address, json, network)
|
16
16
|
end
|
17
|
-
|
18
|
-
def blockr_get_history_for_addresses(addresses, network = :bitcoin)
|
19
|
-
history = []
|
20
|
-
addresses.each do |address|
|
21
|
-
res = blockr_address_history(address, network)
|
22
|
-
res.each do |r|
|
23
|
-
history << r
|
24
|
-
end
|
25
|
-
end
|
26
|
-
return history
|
27
|
-
end
|
28
17
|
|
29
18
|
def parse_address_tx(address, json, network)
|
30
19
|
|
@@ -18,17 +18,6 @@ class OnChain::BlockChain
|
|
18
18
|
return parse_insight_address_tx(address, json, network)
|
19
19
|
|
20
20
|
end
|
21
|
-
|
22
|
-
def insight_get_history_for_addresses(addresses, network = :bitcoin)
|
23
|
-
history = []
|
24
|
-
addresses.each do |address|
|
25
|
-
res = insight_address_history(address, network)
|
26
|
-
res.each do |r|
|
27
|
-
history << r
|
28
|
-
end
|
29
|
-
end
|
30
|
-
return history
|
31
|
-
end
|
32
21
|
|
33
22
|
def parse_insight_address_tx(address, json, network)
|
34
23
|
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
|
3
|
+
class OnChain::Sweeper
|
4
|
+
class << self
|
5
|
+
|
6
|
+
# Turn a bunch of master keys into a redemption scriopt
|
7
|
+
# i.e. derive the path.
|
8
|
+
def multi_sig_address_from_mpks(minimum_sigs, mpks, path)
|
9
|
+
|
10
|
+
rs = generate_redemption_script_from_mpks(minimum_sigs, mpks, path)
|
11
|
+
|
12
|
+
return generate_address_of_redemption_script(rs)
|
13
|
+
end
|
14
|
+
|
15
|
+
def generate_redemption_script_from_mpks(minimum_sigs, mpks, path)
|
16
|
+
|
17
|
+
addresses = []
|
18
|
+
mpks.each do |mpk|
|
19
|
+
master = MoneyTree::Node.from_serialized_address(mpk)
|
20
|
+
m = master.node_for_path(path)
|
21
|
+
addresses << m.public_key.to_hex
|
22
|
+
end
|
23
|
+
|
24
|
+
return generate_redemption_script(minimum_sigs, addresses)
|
25
|
+
end
|
26
|
+
|
27
|
+
def generate_redemption_script(minimum_sigs, addresses)
|
28
|
+
address, redeem_script = Bitcoin.pubkeys_to_p2sh_multisig_address(minimum_sigs, *addresses)
|
29
|
+
return redeem_script.hth
|
30
|
+
end
|
31
|
+
|
32
|
+
def generate_address_of_redemption_script(redemption_script)
|
33
|
+
hash160 = Bitcoin.hash160(redemption_script)
|
34
|
+
|
35
|
+
return Bitcoin.hash160_to_p2sh_address(hash160)
|
36
|
+
end
|
37
|
+
|
38
|
+
def get_block_height
|
39
|
+
return Chain.get_latest_block["height"].to_i
|
40
|
+
end
|
41
|
+
|
42
|
+
# With a bunch of HD wallet paths, build a transaction
|
43
|
+
# That pays all the coins to a certain address
|
44
|
+
def sweep(minimum_sigs, mpks, path, limit, last_block_checked)
|
45
|
+
|
46
|
+
block_height_now = get_block_height
|
47
|
+
|
48
|
+
to_sweep = {}
|
49
|
+
# Get all the addresses we are interested in.
|
50
|
+
for i in 0..limit do
|
51
|
+
r = path.sub('#{index}', i.to_s)
|
52
|
+
a = multi_sig_address_from_mpks(minimum_sigs, mpks, r)
|
53
|
+
# store address as lookup for path.
|
54
|
+
to_sweep[a] = r
|
55
|
+
end
|
56
|
+
|
57
|
+
incoming_coins = []
|
58
|
+
|
59
|
+
to_sweep.each do |address, path|
|
60
|
+
|
61
|
+
txs = Chain.get_address_transactions(address)
|
62
|
+
|
63
|
+
txs.each do |tx|
|
64
|
+
|
65
|
+
block_height = tx["block_height"].to_i
|
66
|
+
if block_height > last_block_checked
|
67
|
+
|
68
|
+
tx["outputs"].each do |output|
|
69
|
+
output["addresses"].each do |address|
|
70
|
+
if to_sweep[address] != nil
|
71
|
+
incoming_coins << [address,
|
72
|
+
to_sweep[address],
|
73
|
+
output["value"],
|
74
|
+
output["transaction_hash"],
|
75
|
+
output["output_index"],
|
76
|
+
output["script"]]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
else
|
82
|
+
break
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
return incoming_coins, block_height_now
|
88
|
+
end
|
89
|
+
|
90
|
+
def create_payment_tx_from_sweep(minimum_sigs, incoming, destination_address, mpks)
|
91
|
+
|
92
|
+
tx = Bitcoin::Protocol::Tx.new
|
93
|
+
total_amount = 0
|
94
|
+
|
95
|
+
incoming.each do |output|
|
96
|
+
|
97
|
+
txin = Bitcoin::Protocol::TxIn.new
|
98
|
+
|
99
|
+
rs = generate_redemption_script_from_mpks(minimum_sigs, mpks, output[1])
|
100
|
+
|
101
|
+
txin.prev_out = OnChain.hex_to_bin(output[3]).reverse
|
102
|
+
txin.prev_out_index = output[4]
|
103
|
+
txin.script = OnChain.hex_to_bin(rs)
|
104
|
+
|
105
|
+
tx.add_in(txin)
|
106
|
+
|
107
|
+
total_amount = total_amount + output[2].to_i
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
total_amount = total_amount - 10000
|
112
|
+
|
113
|
+
if total_amount < 0
|
114
|
+
return "Not enough coins to create a transaction."
|
115
|
+
end
|
116
|
+
|
117
|
+
# Add an output and we're done.
|
118
|
+
txout = Bitcoin::Protocol::TxOut.new(total_amount,
|
119
|
+
Bitcoin::Script.to_address_script(destination_address))
|
120
|
+
|
121
|
+
tx.add_out(txout)
|
122
|
+
|
123
|
+
paths = incoming.map { |i| i[1] }
|
124
|
+
|
125
|
+
return OnChain.bin_to_hex(tx.to_payload), paths
|
126
|
+
end
|
127
|
+
|
128
|
+
def post_tx_for_signing(tx_hex, paths, address)
|
129
|
+
|
130
|
+
return HTTParty.post('https://onchain.herokuapp.com/api/v1/transaction',
|
131
|
+
:body => { :tx => tx_hex,
|
132
|
+
:address => address,
|
133
|
+
:meta_data => paths.join(','),
|
134
|
+
:user_email => ENV['ONCHAIN_EMAIL'],
|
135
|
+
:user_token => ENV['ONCHAIN_TOKEN'] })
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
end
|
data/lib/onchain/transaction.rb
CHANGED
@@ -11,7 +11,6 @@ class OnChain::Transaction
|
|
11
11
|
input_amount = 0
|
12
12
|
# Let's add up the value of all the inputs.
|
13
13
|
tx.in.each_with_index do |txin, index|
|
14
|
-
|
15
14
|
prev_hash = txin.to_hash['prev_out']['hash']
|
16
15
|
prev_index = txin.to_hash['prev_out']['n']
|
17
16
|
|
@@ -117,17 +116,6 @@ class OnChain::Transaction
|
|
117
116
|
|
118
117
|
end
|
119
118
|
|
120
|
-
def generate_redemption_script(minimum_sigs, addresses)
|
121
|
-
address, redeem_script = Bitcoin.pubkeys_to_p2sh_multisig_address(minimum_sigs, *addresses)
|
122
|
-
return redeem_script.hth
|
123
|
-
end
|
124
|
-
|
125
|
-
def generate_address_of_redemption_script(redemption_script)
|
126
|
-
hash160 = Bitcoin.hash160(redemption_script)
|
127
|
-
|
128
|
-
return Bitcoin.hash160_to_p2sh_address(hash160)
|
129
|
-
end
|
130
|
-
|
131
119
|
# Like create_single_address_transaction but for multi sig wallets.
|
132
120
|
def create_transaction_with_fee(redemption_scripts, address, amount, fee_percent, fee_addr)
|
133
121
|
|
@@ -136,7 +124,7 @@ class OnChain::Transaction
|
|
136
124
|
total_amount = amount + fee
|
137
125
|
|
138
126
|
addresses = redemption_scripts.map { |rs|
|
139
|
-
generate_address_of_redemption_script(rs)
|
127
|
+
OnChain::Sweeper.generate_address_of_redemption_script(rs)
|
140
128
|
}
|
141
129
|
|
142
130
|
unspents, indexes, change = OnChain::BlockChain.get_unspent_for_amount(addresses, total_amount)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: onchain
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '3.
|
4
|
+
version: '3.03'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Number 6
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-11-
|
11
|
+
date: 2016-11-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -94,20 +94,6 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: google_currency
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - ">="
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
104
|
-
type: :runtime
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - ">="
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
111
97
|
description: Call 3rd party API's but also switch API's if a 3rd party is down
|
112
98
|
email:
|
113
99
|
- support@onchain.io
|
@@ -117,11 +103,12 @@ extra_rdoc_files: []
|
|
117
103
|
files:
|
118
104
|
- lib/onchain.rb
|
119
105
|
- lib/onchain/block_chain.rb
|
120
|
-
- lib/onchain/
|
106
|
+
- lib/onchain/payments.rb
|
121
107
|
- lib/onchain/providers/bitcoind_api.rb
|
122
108
|
- lib/onchain/providers/blockchaininfo_api.rb
|
123
109
|
- lib/onchain/providers/blockr_api.rb
|
124
110
|
- lib/onchain/providers/insight_api.rb
|
111
|
+
- lib/onchain/sweeper.rb
|
125
112
|
- lib/onchain/transaction.rb
|
126
113
|
homepage: https://github.com/onchain/onchain-gem
|
127
114
|
licenses: []
|
@@ -1,87 +0,0 @@
|
|
1
|
-
require 'httparty'
|
2
|
-
require 'cgi'
|
3
|
-
require 'money'
|
4
|
-
require 'money/bank/google_currency'
|
5
|
-
|
6
|
-
class OnChain::ExchangeRate
|
7
|
-
|
8
|
-
class << self
|
9
|
-
|
10
|
-
BALANCE_RATE_FOR = 120
|
11
|
-
|
12
|
-
def bitcoin_exchange_rate(currency)
|
13
|
-
begin
|
14
|
-
ticker = "BTC-" + currency.to_s
|
15
|
-
|
16
|
-
if OnChain::BlockChain.cache_read(ticker) == nil
|
17
|
-
if currency == :USD
|
18
|
-
begin
|
19
|
-
r = HTTParty.get("https://www.bitstamp.net/api/ticker/")
|
20
|
-
j = JSON.parse r.response.body
|
21
|
-
rate = j["last"]
|
22
|
-
OnChain::BlockChain.cache_write(ticker, rate, BALANCE_RATE_FOR)
|
23
|
-
rescue
|
24
|
-
r = HTTParty.get("https://blockchain.info/ticker")
|
25
|
-
j = JSON.parse r.response.body
|
26
|
-
OnChain::BlockChain.cache_write(ticker, j["USD"]["last"], BALANCE_RATE_FOR)
|
27
|
-
end
|
28
|
-
|
29
|
-
elsif currency == :EUR
|
30
|
-
|
31
|
-
Money.default_bank = Money::Bank::GoogleCurrency.new
|
32
|
-
|
33
|
-
btc_usd = exchange_rate(:USD).to_f
|
34
|
-
|
35
|
-
money = Money.new(1_00, "USD")
|
36
|
-
|
37
|
-
usd_eur = money.exchange_to(:EUR).to_f
|
38
|
-
|
39
|
-
rate = usd_eur * btc_usd
|
40
|
-
|
41
|
-
OnChain::BlockChain.cache_write(ticker, rate.to_s, BALANCE_RATE_FOR)
|
42
|
-
|
43
|
-
elsif currency == :GBP
|
44
|
-
|
45
|
-
Money.default_bank = Money::Bank::GoogleCurrency.new
|
46
|
-
|
47
|
-
btc_usd = exchange_rate(:USD).to_f
|
48
|
-
|
49
|
-
money = Money.new(1_00, "USD")
|
50
|
-
|
51
|
-
usd_gbp = money.exchange_to(:GBP).to_f
|
52
|
-
|
53
|
-
rate = usd_gbp * btc_usd
|
54
|
-
|
55
|
-
OnChain::BlockChain.cache_write(ticker, rate.to_s, BALANCE_RATE_FOR)
|
56
|
-
|
57
|
-
else
|
58
|
-
OnChain::BlockChain.cache_write(ticker, "0", BALANCE_RATE_FOR)
|
59
|
-
end
|
60
|
-
|
61
|
-
end
|
62
|
-
return OnChain::BlockChain.cache_read(ticker)
|
63
|
-
rescue Exception => e
|
64
|
-
puts e.to_s
|
65
|
-
'0'
|
66
|
-
end
|
67
|
-
|
68
|
-
end
|
69
|
-
|
70
|
-
def alt_exchange_rate(alt_currency)
|
71
|
-
|
72
|
-
url = 'https://api.coinmarketcap.com/v1/ticker/' + alt_currency.to_s + '/'
|
73
|
-
|
74
|
-
begin
|
75
|
-
resp = OnChain::BlockChain.fetch_response(url)
|
76
|
-
|
77
|
-
return resp[0]['price_btc'].to_f
|
78
|
-
rescue => e
|
79
|
-
puts e.to_s
|
80
|
-
return 0.0
|
81
|
-
end
|
82
|
-
|
83
|
-
end
|
84
|
-
|
85
|
-
end
|
86
|
-
|
87
|
-
end
|