neb 0.1.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 +7 -0
- data/.gitignore +62 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +15 -0
- data/Guardfile +9 -0
- data/LICENSE.txt +21 -0
- data/README.md +123 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/neb/account.rb +55 -0
- data/lib/neb/address.rb +90 -0
- data/lib/neb/base_convert.rb +57 -0
- data/lib/neb/client/admin.rb +95 -0
- data/lib/neb/client/api.rb +104 -0
- data/lib/neb/client/request.rb +43 -0
- data/lib/neb/client/response.rb +36 -0
- data/lib/neb/client.rb +19 -0
- data/lib/neb/configuration.rb +38 -0
- data/lib/neb/constant.rb +35 -0
- data/lib/neb/core_ext.rb +45 -0
- data/lib/neb/exceptions.rb +29 -0
- data/lib/neb/key.rb +133 -0
- data/lib/neb/private_key.rb +91 -0
- data/lib/neb/proto/transaction.proto +40 -0
- data/lib/neb/proto/transaction_pb.rb +30 -0
- data/lib/neb/public_key.rb +87 -0
- data/lib/neb/secp256k1.rb +66 -0
- data/lib/neb/transaction.rb +120 -0
- data/lib/neb/utils.rb +128 -0
- data/lib/neb/version.rb +6 -0
- data/lib/neb.rb +71 -0
- data/neb.gemspec +40 -0
- data/tmp/.keep +0 -0
- metadata +288 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Neb
|
5
|
+
class PublicKey
|
6
|
+
attr_reader :raw
|
7
|
+
|
8
|
+
def initialize(raw)
|
9
|
+
@raw = raw
|
10
|
+
end
|
11
|
+
|
12
|
+
# skip the type flag, 04
|
13
|
+
def to_s
|
14
|
+
encode(:hex)[2..-1]
|
15
|
+
end
|
16
|
+
|
17
|
+
def encode(fmt)
|
18
|
+
case fmt
|
19
|
+
when :decimal
|
20
|
+
value
|
21
|
+
when :bin
|
22
|
+
"\x04#{BaseConvert.encode(value[0], 256, 32)}#{BaseConvert.encode(value[1], 256, 32)}"
|
23
|
+
when :bin_compressed
|
24
|
+
"#{(2+(value[1]%2)).chr}#{BaseConvert.encode(value[0], 256, 32)}"
|
25
|
+
when :hex
|
26
|
+
"04#{BaseConvert.encode(value[0], 16, 64)}#{BaseConvert.encode(value[1], 16, 64)}"
|
27
|
+
when :hex_compressed
|
28
|
+
"0#{2+(value[1]%2)}#{BaseConvert.encode(value[0], 16, 64)}"
|
29
|
+
else
|
30
|
+
raise FormatError, "Invalid format!"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def decode(fmt = nil)
|
35
|
+
fmt ||= format
|
36
|
+
|
37
|
+
case fmt
|
38
|
+
when :decimal
|
39
|
+
raw
|
40
|
+
when :bin
|
41
|
+
[BaseConvert.decode(raw[1, 32], 256), BaseConvert.decode(raw[33, 32], 256)]
|
42
|
+
when :bin_compressed
|
43
|
+
x = BaseConvert.decode raw[1, 32], 256
|
44
|
+
m = x*x*x + Secp256k1::A*x + Secp256k1::B
|
45
|
+
n = Utils.mod_exp(m, (Secp256k1::P+1)/4, Secp256k1::P)
|
46
|
+
q = (n + raw[0].ord) % 2
|
47
|
+
y = q == 1 ? (Secp256k1::P - n) : n
|
48
|
+
[x, y]
|
49
|
+
when :hex
|
50
|
+
[BaseConvert.decode(raw[2, 64], 16), BaseConvert.decode(raw[66, 64], 16)]
|
51
|
+
when :hex_compressed
|
52
|
+
PublicKey.new(Utils.hex_to_bin(raw)).decode :bin_compressed
|
53
|
+
else
|
54
|
+
raise FormatError, "Invalid format!"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def value
|
59
|
+
@value ||= decode
|
60
|
+
end
|
61
|
+
|
62
|
+
def format
|
63
|
+
return :decimal if raw.is_a?(Array)
|
64
|
+
return :bin if raw.size == 65 && raw[0] == "\x04"
|
65
|
+
return :hex if raw.size == 130 && raw[0, 2] == '04'
|
66
|
+
return :bin_compressed if raw.size == 33 && "\x02\x03".include?(raw[0])
|
67
|
+
return :hex_compressed if raw.size == 66 && %w(02 03).include?(raw[0,2])
|
68
|
+
|
69
|
+
raise FormatError, "Pubkey is not in recognized format"
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_address_obj
|
73
|
+
bytes = [
|
74
|
+
BaseConvert.encode(Constant::ADDRESS_PREFIX, 256, 1),
|
75
|
+
BaseConvert.encode(Constant::NORMAL_TYPE, 256, 1),
|
76
|
+
Utils.hash160(encode(:bin))
|
77
|
+
].join
|
78
|
+
|
79
|
+
Address.new(bytes)
|
80
|
+
end
|
81
|
+
|
82
|
+
def to_address
|
83
|
+
to_address_obj.to_s
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Neb
|
5
|
+
module Secp256k1
|
6
|
+
|
7
|
+
# Elliptic curve parameters
|
8
|
+
P = 2**256 - 2**32 - 977
|
9
|
+
N = 115792089237316195423570985008687907852837564279074904382605163141518161494337
|
10
|
+
A = 0
|
11
|
+
B = 7
|
12
|
+
Gx = 55066263022277343669578718895168534326250603453777594175500187360389116729240
|
13
|
+
Gy = 32670510020758816978083085130507043184471273380659243275938904335757337482424
|
14
|
+
G = [Gx, Gy].freeze
|
15
|
+
|
16
|
+
SECP256K1 = 1
|
17
|
+
|
18
|
+
class InvalidPrivateKey < StandardError; end
|
19
|
+
|
20
|
+
class << self # extensions
|
21
|
+
|
22
|
+
def sign(msg, priv)
|
23
|
+
priv = PrivateKey.new(priv)
|
24
|
+
privkey = ::Secp256k1::PrivateKey.new(privkey: priv.encode(:bin), raw: true)
|
25
|
+
sig_raw = privkey.ecdsa_sign(msg, raw: true)
|
26
|
+
privkey.ecdsa_serialize_compact(sig_raw) << SECP256K1
|
27
|
+
end
|
28
|
+
|
29
|
+
def priv_to_pub(priv)
|
30
|
+
priv = PrivateKey.new(priv)
|
31
|
+
privkey = ::Secp256k1::PrivateKey.new(privkey: priv.encode(:bin), raw: true)
|
32
|
+
pubkey = privkey.pubkey
|
33
|
+
PublicKey.new(pubkey.serialize).encode(priv.format)
|
34
|
+
end
|
35
|
+
|
36
|
+
def recoverable_sign(msg, privkey)
|
37
|
+
pk = ::Secp256k1::PrivateKey.new(privkey: privkey, raw: true)
|
38
|
+
signature = pk.ecdsa_recoverable_serialize(pk.ecdsa_sign_recoverable(msg, raw: true))
|
39
|
+
|
40
|
+
v = signature[1]
|
41
|
+
r = Utils.big_endian_to_int signature[0][0,32]
|
42
|
+
s = Utils.big_endian_to_int signature[0][32,32]
|
43
|
+
|
44
|
+
[v,r,s]
|
45
|
+
end
|
46
|
+
|
47
|
+
def signature_verify(msg, vrs, pubkey)
|
48
|
+
pk = ::Secp256k1::PublicKey.new(pubkey: pubkey)
|
49
|
+
raw_sig = Utils.zpad_int(vrs[1]) + Utils.zpad_int(vrs[2])
|
50
|
+
|
51
|
+
sig = ::Secp256k1::C::ECDSASignature.new
|
52
|
+
sig[:data].to_ptr.write_bytes(raw_sig)
|
53
|
+
|
54
|
+
pk.ecdsa_verify(msg, sig)
|
55
|
+
end
|
56
|
+
|
57
|
+
def recover_pubkey(msg, vrs, compressed: false)
|
58
|
+
pk = ::Secp256k1::PublicKey.new(flags: ::Secp256k1::ALL_FLAGS)
|
59
|
+
sig = Utils.zpad_int(vrs[1]) + Utils.zpad_int(vrs[2])
|
60
|
+
recsig = pk.ecdsa_recoverable_deserialize(sig, vrs[0])
|
61
|
+
pk.public_key = pk.ecdsa_recover msg, recsig, raw: true
|
62
|
+
pk.serialize compressed: compressed
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Neb
|
5
|
+
class Transaction
|
6
|
+
|
7
|
+
MAX_GAS_PRICE = 1_000_000_000_000
|
8
|
+
MAX_GAS = 50_000_000_000
|
9
|
+
GAS_PRICE = 1_000_000
|
10
|
+
GAS_LIMIT = 20_000
|
11
|
+
|
12
|
+
PAYLOAD_BINARY_TYPE = "binary".freeze
|
13
|
+
PAYLOAD_DEPLOY_TYPE = "deploy".freeze
|
14
|
+
PAYLOAD_CALL_TYPE = "call".freeze
|
15
|
+
|
16
|
+
CHAIN_ID_LIST = {
|
17
|
+
1 => { name: "Mainnet", url: "https://mainnet.nebulas.io" },
|
18
|
+
1001 => { name: "Testnet", url: "https://testnet.nebulas.io" },
|
19
|
+
100 => { name: "Local Nodes", url: "http://127.0.0.1:8685" }
|
20
|
+
}.freeze
|
21
|
+
|
22
|
+
attr_reader :chain_id, :from_account, :to_address, :value, :nonce,
|
23
|
+
:gas_price, :gas_limit, :timestamp, :data
|
24
|
+
attr_reader :hash, :sign
|
25
|
+
|
26
|
+
def initialize(chain_id:, from_account:, to_address:, value:, nonce:,
|
27
|
+
gas_price: GAS_PRICE, gas_limit: GAS_LIMIT, contract: {})
|
28
|
+
@chain_id = chain_id
|
29
|
+
@from_account = from_account
|
30
|
+
@to_address = Address.new(to_address)
|
31
|
+
@value = value
|
32
|
+
@nonce = nonce
|
33
|
+
@gas_price = gas_price
|
34
|
+
@gas_limit = gas_limit
|
35
|
+
@data = parse_contract(contract)
|
36
|
+
@timestamp = Time.now.to_i
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse_contract(contract)
|
40
|
+
payload_type, payload = nil, nil
|
41
|
+
contract.deep_symbolize_keys!
|
42
|
+
|
43
|
+
if contract[:source].present?
|
44
|
+
payload_type = PAYLOAD_DEPLOY_TYPE
|
45
|
+
payload = {
|
46
|
+
source_type: contract[:source_type],
|
47
|
+
source: contract[:source],
|
48
|
+
args: contract[:args]
|
49
|
+
}
|
50
|
+
elsif contract[:function].present?
|
51
|
+
payload_type = PAYLOAD_CALL_TYPE
|
52
|
+
payload = {
|
53
|
+
function: contract[:function],
|
54
|
+
args: contract[:args]
|
55
|
+
}
|
56
|
+
else
|
57
|
+
payload_type = PAYLOAD_BINARY_TYPE
|
58
|
+
if contract.present?
|
59
|
+
payload = {
|
60
|
+
data: BaseConvert.decode(contract[:binary], 256)
|
61
|
+
}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
if payload.present?
|
66
|
+
payload = String.new(JSON.dump(payload.deep_camelize_keys(:upper)).html_safe)
|
67
|
+
{ type: payload_type, payload: payload }
|
68
|
+
else
|
69
|
+
{ type: payload_type }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def to_proto
|
74
|
+
raise UnsignError.new("Must sign_hash first") if sign.blank?
|
75
|
+
|
76
|
+
tx = Corepb::Transaction.new(
|
77
|
+
hash: hash,
|
78
|
+
from: from_account.address_obj.encode(:bin_extended),
|
79
|
+
to: to_address.encode(:bin_extended),
|
80
|
+
value: Utils.zpad(Utils.int_to_big_endian(value), 16),
|
81
|
+
nonce: nonce,
|
82
|
+
timestamp: timestamp,
|
83
|
+
data: Corepb::Data.new(data),
|
84
|
+
chain_id: chain_id,
|
85
|
+
gas_price: Utils.zpad(Utils.int_to_big_endian(gas_price), 16),
|
86
|
+
gas_limit: Utils.zpad(Utils.int_to_big_endian(gas_limit), 16),
|
87
|
+
alg: Secp256k1::SECP256K1,
|
88
|
+
sign: sign
|
89
|
+
)
|
90
|
+
|
91
|
+
tx.to_proto
|
92
|
+
end
|
93
|
+
|
94
|
+
def to_proto_str
|
95
|
+
Utils.encode64(to_proto)
|
96
|
+
end
|
97
|
+
|
98
|
+
def calculate_hash
|
99
|
+
buffer = [
|
100
|
+
from_account.address_obj.encode(:bin_extended),
|
101
|
+
to_address.encode(:bin_extended),
|
102
|
+
Utils.zpad(Utils.int_to_big_endian(value), 16),
|
103
|
+
Utils.zpad(Utils.int_to_big_endian(nonce), 8),
|
104
|
+
Utils.zpad(Utils.int_to_big_endian(timestamp), 8),
|
105
|
+
Corepb::Data.new(data).to_proto,
|
106
|
+
Utils.zpad(Utils.int_to_big_endian(chain_id), 4),
|
107
|
+
Utils.zpad(Utils.int_to_big_endian(gas_price), 16),
|
108
|
+
Utils.zpad(Utils.int_to_big_endian(gas_limit), 16)
|
109
|
+
].join
|
110
|
+
|
111
|
+
Utils.keccak256(buffer)
|
112
|
+
end
|
113
|
+
|
114
|
+
def sign_hash
|
115
|
+
@hash = calculate_hash
|
116
|
+
@sign = Secp256k1.sign(@hash, from_account.private_key)
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
end
|
data/lib/neb/utils.rb
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Neb
|
5
|
+
module Utils
|
6
|
+
extend self
|
7
|
+
|
8
|
+
include Constant
|
9
|
+
|
10
|
+
def to_json(h)
|
11
|
+
JSON.generate(h)
|
12
|
+
end
|
13
|
+
|
14
|
+
def from_json(s)
|
15
|
+
JSON.parse(s, symbolize_names: true)
|
16
|
+
end
|
17
|
+
|
18
|
+
def secure_compare(a, b)
|
19
|
+
ActiveSupport::SecurityUtils.secure_compare(a, b)
|
20
|
+
end
|
21
|
+
|
22
|
+
# args: n, r, p, key_len
|
23
|
+
def scrypt(secret, salt, *args)
|
24
|
+
SCrypt::Engine.scrypt(secret, salt, *args)
|
25
|
+
end
|
26
|
+
|
27
|
+
def aes_encrypt(raw, bin_key, bin_iv)
|
28
|
+
cipher = OpenSSL::Cipher::AES128.new(:ctr)
|
29
|
+
cipher.encrypt
|
30
|
+
cipher.key = bin_key
|
31
|
+
cipher.iv = bin_iv
|
32
|
+
|
33
|
+
result = cipher.update(raw)
|
34
|
+
result += cipher.final
|
35
|
+
result
|
36
|
+
end
|
37
|
+
|
38
|
+
def aes_decrypt(ciphertext, bin_key, bin_iv)
|
39
|
+
cipher = OpenSSL::Cipher::AES128.new(:ctr)
|
40
|
+
cipher.decrypt
|
41
|
+
cipher.key = bin_key
|
42
|
+
cipher.iv = bin_iv
|
43
|
+
|
44
|
+
result = cipher.update(ciphertext)
|
45
|
+
result += cipher.final
|
46
|
+
result
|
47
|
+
end
|
48
|
+
|
49
|
+
def uuid
|
50
|
+
SecureRandom.uuid
|
51
|
+
end
|
52
|
+
|
53
|
+
def encode64(str)
|
54
|
+
Base64.strict_encode64(str)
|
55
|
+
end
|
56
|
+
|
57
|
+
def big_endian_to_int(s)
|
58
|
+
RLP::Sedes.big_endian_int.deserialize(s.sub(/\A(\x00)+/, ''))
|
59
|
+
end
|
60
|
+
|
61
|
+
def int_to_big_endian(n)
|
62
|
+
RLP::Sedes.big_endian_int.serialize(n)
|
63
|
+
end
|
64
|
+
|
65
|
+
def bin_to_hex(bytes)
|
66
|
+
BaseConvert.convert(bytes, 256, 16, bytes.size * 2).force_encoding('utf-8')
|
67
|
+
end
|
68
|
+
|
69
|
+
def hex_to_bin(hex)
|
70
|
+
BaseConvert.convert(hex, 16, 256, hex.size / 2).force_encoding('ascii-8bit')
|
71
|
+
end
|
72
|
+
|
73
|
+
def random_bytes(size = 32)
|
74
|
+
SecureRandom.random_bytes(size)
|
75
|
+
end
|
76
|
+
|
77
|
+
def keccak256(x)
|
78
|
+
SHA3::Digest::SHA256.digest(x)
|
79
|
+
end
|
80
|
+
|
81
|
+
def keccak512(x)
|
82
|
+
SHA3::Digest::SHA512.digest(x)
|
83
|
+
end
|
84
|
+
|
85
|
+
def sha256(x)
|
86
|
+
Digest::SHA256.digest(x)
|
87
|
+
end
|
88
|
+
|
89
|
+
def ripemd160(x)
|
90
|
+
Digest::RMD160.digest(x)
|
91
|
+
end
|
92
|
+
|
93
|
+
def hash160(x)
|
94
|
+
ripemd160(keccak256(x))
|
95
|
+
end
|
96
|
+
|
97
|
+
def base58(x)
|
98
|
+
Base58.binary_to_base58(x, :bitcoin)
|
99
|
+
end
|
100
|
+
alias_method :binary_to_base58, :base58
|
101
|
+
|
102
|
+
def base58_to_binary(b)
|
103
|
+
Base58.base58_to_binary(b, :bitcoin)
|
104
|
+
end
|
105
|
+
|
106
|
+
def lpad(x, symbol, l)
|
107
|
+
return x if x.size >= l
|
108
|
+
symbol * (l - x.size) + x
|
109
|
+
end
|
110
|
+
|
111
|
+
def rpad(x, symbol, l)
|
112
|
+
return x if x.size >= l
|
113
|
+
x + symbol * (l - x.size)
|
114
|
+
end
|
115
|
+
|
116
|
+
def zpad(x, l)
|
117
|
+
lpad(x, BYTE_ZERO, l)
|
118
|
+
end
|
119
|
+
|
120
|
+
def mod_exp(x, y, n)
|
121
|
+
x.to_bn.mod_exp(y, n).to_i
|
122
|
+
end
|
123
|
+
|
124
|
+
def mod_mul(x, y, n)
|
125
|
+
x.to_bn.mod_mul(y, n).to_i
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
data/lib/neb/version.rb
ADDED
data/lib/neb.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "logger"
|
5
|
+
require "pathname"
|
6
|
+
require "digest"
|
7
|
+
require "sha3"
|
8
|
+
require "openssl"
|
9
|
+
require "base58"
|
10
|
+
require "securerandom"
|
11
|
+
require "scrypt"
|
12
|
+
require "active_support/all"
|
13
|
+
require "json"
|
14
|
+
require "forwardable"
|
15
|
+
require "rest-client"
|
16
|
+
require "secp256k1"
|
17
|
+
require "rlp"
|
18
|
+
require "google/protobuf"
|
19
|
+
require "base64"
|
20
|
+
|
21
|
+
require "neb/version"
|
22
|
+
require "neb/exceptions"
|
23
|
+
require "neb/constant"
|
24
|
+
require "neb/utils"
|
25
|
+
require "neb/core_ext"
|
26
|
+
require "neb/configuration"
|
27
|
+
require "neb/base_convert"
|
28
|
+
require "neb/client"
|
29
|
+
require "neb/secp256k1"
|
30
|
+
require "neb/private_key"
|
31
|
+
require "neb/public_key"
|
32
|
+
require "neb/address"
|
33
|
+
require "neb/account"
|
34
|
+
require "neb/key"
|
35
|
+
require "neb/transaction"
|
36
|
+
require "neb/proto/transaction_pb"
|
37
|
+
|
38
|
+
module Neb
|
39
|
+
extend self
|
40
|
+
CONFIG = Configuration.new
|
41
|
+
|
42
|
+
attr_reader :configured, :logger
|
43
|
+
alias_method :configured?, :configured
|
44
|
+
|
45
|
+
def configure(config = {})
|
46
|
+
CONFIG.merge!(config)
|
47
|
+
setup_general_logger!
|
48
|
+
@configured = true
|
49
|
+
end
|
50
|
+
|
51
|
+
def clear!
|
52
|
+
CONFIG.clear
|
53
|
+
@logger = nil
|
54
|
+
@configured = false
|
55
|
+
end
|
56
|
+
|
57
|
+
def root
|
58
|
+
Pathname.new(File.expand_path('../..', __FILE__))
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def setup_general_logger!
|
64
|
+
if [:info, :debug, :error, :warn].all?{ |meth| CONFIG[:log].respond_to?(meth) }
|
65
|
+
@logger = CONFIG[:log]
|
66
|
+
else
|
67
|
+
@logger = ::Logger.new(CONFIG[:log])
|
68
|
+
@logger.formatter = ::Logger::Formatter.new
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/neb.gemspec
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "neb/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "neb"
|
8
|
+
spec.version = Neb::VERSION
|
9
|
+
spec.authors = ["Spirit"]
|
10
|
+
spec.email = ["neverlandxy.naix@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{the Nebulas compatible Ruby API}
|
13
|
+
spec.description = %q{the Nebulas compatible Ruby API}
|
14
|
+
spec.homepage = "https://github.com/NaixSpirit/neb.rb"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
19
|
+
end
|
20
|
+
spec.bindir = "exe"
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.16"
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
26
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
27
|
+
spec.add_development_dependency "pry", "~> 0.11"
|
28
|
+
spec.add_development_dependency "guard", "~> 2.14"
|
29
|
+
spec.add_development_dependency "guard-minitest", "~> 2.4"
|
30
|
+
|
31
|
+
spec.add_dependency "rest-client", "~> 2.0"
|
32
|
+
spec.add_dependency "activesupport", "~> 5"
|
33
|
+
spec.add_dependency "rlp", "~> 0.7.3"
|
34
|
+
spec.add_dependency "bitcoin-secp256k1", "~> 0.4"
|
35
|
+
spec.add_dependency "ffi", "~> 1.9"
|
36
|
+
spec.add_dependency "sha3", "~> 1.0"
|
37
|
+
spec.add_dependency "base58", "~> 0.2"
|
38
|
+
spec.add_dependency "scrypt", "~> 3.0"
|
39
|
+
spec.add_dependency "google-protobuf", "~> 3.5"
|
40
|
+
end
|
data/tmp/.keep
ADDED
File without changes
|