moac 0.4.8

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.
@@ -0,0 +1,7 @@
1
+ module Moac
2
+ class Secp256k1
3
+
4
+ N = 115792089237316195423570985008687907852837564279074904382605163141518161494337
5
+
6
+ end
7
+ end
data/lib/moac/sedes.rb ADDED
@@ -0,0 +1,40 @@
1
+ module Moac
2
+ module Sedes
3
+ include RLP::Sedes
4
+
5
+ extend self
6
+
7
+ def address
8
+ Binary.fixed_length(20, allow_empty: true)
9
+ end
10
+
11
+ def int20
12
+ BigEndianInt.new(20)
13
+ end
14
+
15
+ def int32
16
+ BigEndianInt.new(32)
17
+ end
18
+
19
+ def int256
20
+ BigEndianInt.new(256)
21
+ end
22
+
23
+ def hash32
24
+ Binary.fixed_length(32)
25
+ end
26
+
27
+ def trie_root
28
+ Binary.fixed_length(32, allow_empty: true)
29
+ end
30
+
31
+ def big_endian_int
32
+ RLP::Sedes.big_endian_int
33
+ end
34
+
35
+ def binary
36
+ RLP::Sedes.binary
37
+ end
38
+
39
+ end
40
+ end
data/lib/moac/tx.rb ADDED
@@ -0,0 +1,158 @@
1
+ module Moac
2
+ class Tx
3
+
4
+ include RLP::Sedes::Serializable
5
+ extend Sedes
6
+
7
+ set_serializable_fields({
8
+ nonce: big_endian_int,
9
+ systemContract: big_endian_int,
10
+ gas_price: big_endian_int,
11
+ gas_limit: big_endian_int,
12
+ to: address,
13
+ value: big_endian_int,
14
+ data_bin: binary,
15
+ shardingFlag: big_endian_int,
16
+ via: binary,
17
+ v: big_endian_int,
18
+ r: big_endian_int,
19
+ s: big_endian_int
20
+ })
21
+
22
+ attr_writer :signature
23
+
24
+ def self.decode(data)
25
+ data = Utils.hex_to_bin(data) if data.match(/\A(?:0x)?\h+\Z/)
26
+ deserialize(RLP.decode data)
27
+ end
28
+
29
+ def initialize(params)
30
+
31
+ fields = params.merge({v: Moac.chain_id, r: 0, s: 0})
32
+ fields[:to] = Utils.normalize_address(fields[:to])
33
+
34
+ if params[:data]
35
+ self.data = params.delete(:data)
36
+ fields[:data_bin] = data_bin
37
+ end
38
+ serializable_initialize fields
39
+
40
+ check_transaction_validity
41
+ end
42
+
43
+ def unsigned_encoded
44
+ RLP.encode(unsigned, sedes: sedes)
45
+ end
46
+
47
+ def signing_data
48
+ Utils.bin_to_prefixed_hex unsigned_encoded
49
+ end
50
+
51
+ def encoded
52
+ RLP.encode self
53
+ end
54
+
55
+ def hex
56
+ Utils.bin_to_prefixed_hex encoded
57
+ end
58
+
59
+ def sign(key)
60
+ self.signature = key.sign(unsigned_encoded)
61
+ vrs = Utils.v_r_s_for signature
62
+ self.v = vrs[0]
63
+ self.r = vrs[1]
64
+ self.s = vrs[2]
65
+
66
+ self
67
+ end
68
+
69
+ def to_h
70
+ hash_keys.inject({}) do |hash, field|
71
+ hash[field] = send field
72
+ hash
73
+ end
74
+ end
75
+
76
+ def from
77
+ if signature
78
+ public_key = OpenSsl.recover_compact(signature_hash, signature)
79
+ Utils.public_key_to_address(public_key) if public_key
80
+ end
81
+ end
82
+
83
+ def signature
84
+ return @signature if @signature
85
+ self.signature = [
86
+ Utils.int_to_base256(v),
87
+ Utils.zpad_int(r),
88
+ Utils.zpad_int(s),
89
+ ].join if [v, r, s].all?
90
+ end
91
+
92
+ def hash
93
+ "0x#{Utils.bin_to_hex Utils.keccak256_rlp(self)}"
94
+ end
95
+ alias_method :id, :hash
96
+
97
+ def data_hex
98
+ Utils.bin_to_prefixed_hex data_bin
99
+ end
100
+
101
+ def data_hex=(hex)
102
+ self.data_bin = Utils.hex_to_bin(hex)
103
+ end
104
+
105
+ def data
106
+ Moac.tx_data_hex? ? data_hex : data_bin
107
+ end
108
+
109
+ def data=(string)
110
+ Moac.tx_data_hex? ? self.data_hex=(string) : self.data_bin=(string)
111
+ end
112
+
113
+
114
+ private
115
+
116
+ def hash_keys
117
+ keys = self.class.serializable_fields.keys
118
+ keys.delete(:data_bin)
119
+ keys + [:data]
120
+ end
121
+
122
+ def check_transaction_validity
123
+ if [gas_price, gas_limit, value, nonce].max > UINT_MAX
124
+ raise InvalidTransaction, "Values way too high!"
125
+ elsif gas_limit < intrinsic_gas_used
126
+ raise InvalidTransaction, "Gas limit too low"
127
+ end
128
+ end
129
+
130
+ def intrinsic_gas_used
131
+ num_zero_bytes = data_bin.count(BYTE_ZERO)
132
+ num_non_zero_bytes = data_bin.size - num_zero_bytes
133
+
134
+ Gas::GTXCOST +
135
+ Gas::GTXDATAZERO * num_zero_bytes +
136
+ Gas::GTXDATANONZERO * num_non_zero_bytes
137
+ end
138
+
139
+ def signature_hash
140
+ Utils.keccak256 unsigned_encoded
141
+ end
142
+
143
+ def unsigned
144
+ Tx.new to_h.merge(v: Moac.chain_id, r: 0, s: 0)
145
+ end
146
+
147
+ def sedes
148
+ if Moac.prevent_replays? && !(Moac.replayable_v? v)
149
+ self.class
150
+ else
151
+ UnsignedTx
152
+ end
153
+ end
154
+
155
+ end
156
+
157
+ UnsignedTx = Tx.exclude([:v, :r, :s])
158
+ end
data/lib/moac/utils.rb ADDED
@@ -0,0 +1,126 @@
1
+ module Moac
2
+ module Utils
3
+
4
+ extend self
5
+
6
+ def normalize_address(address)
7
+ if address.nil? || address == ''
8
+ ''
9
+ elsif address.size == 40
10
+ hex_to_bin address
11
+ elsif address.size == 42 && address[0..1] == '0x'
12
+ hex_to_bin address[2..-1]
13
+ else
14
+ address
15
+ end
16
+ end
17
+
18
+ def bin_to_hex(string)
19
+ RLP::Utils.encode_hex string
20
+ end
21
+
22
+ def hex_to_bin(string)
23
+ RLP::Utils.decode_hex remove_hex_prefix(string)
24
+ end
25
+
26
+ def base256_to_int(str)
27
+ RLP::Sedes.big_endian_int.deserialize str.sub(/\A(\x00)+/, '')
28
+ end
29
+
30
+ def int_to_base256(int)
31
+ RLP::Sedes.big_endian_int.serialize int
32
+ end
33
+
34
+ def v_r_s_for(signature)
35
+ [
36
+ signature[0].bytes[0],
37
+ Utils.base256_to_int(signature[1..32]),
38
+ Utils.base256_to_int(signature[33..65]),
39
+ ]
40
+ end
41
+
42
+ def prefix_hex(hex)
43
+ hex.match(/\A0x/) ? hex : "0x#{hex}"
44
+ end
45
+
46
+ def remove_hex_prefix(s)
47
+ s[0,2] == '0x' ? s[2..-1] : s
48
+ end
49
+
50
+ def bin_to_prefixed_hex(binary)
51
+ prefix_hex bin_to_hex(binary)
52
+ end
53
+
54
+ def public_key_to_address(hex)
55
+ bytes = hex_to_bin(hex)
56
+ address_bytes = Utils.keccak256(bytes[1..-1])[-20..-1]
57
+ format_address bin_to_prefixed_hex(address_bytes)
58
+ end
59
+
60
+ def sha256(x)
61
+ Digest::SHA256.digest x
62
+ end
63
+
64
+ def keccak256(x)
65
+ Digest::SHA3.new(256).digest(x)
66
+ end
67
+
68
+ def keccak512(x)
69
+ Digest::SHA3.new(512).digest(x)
70
+ end
71
+
72
+ def keccak256_rlp(x)
73
+ keccak256 RLP.encode(x)
74
+ end
75
+
76
+ def ripemd160(x)
77
+ Digest::RMD160.digest x
78
+ end
79
+
80
+ def hash160(x)
81
+ ripemd160 sha256(x)
82
+ end
83
+
84
+ def zpad(x, l)
85
+ lpad x, BYTE_ZERO, l
86
+ end
87
+
88
+ def zunpad(x)
89
+ x.sub /\A\x00+/, ''
90
+ end
91
+
92
+ def zpad_int(n, l=32)
93
+ zpad encode_int(n), l
94
+ end
95
+
96
+ def zpad_hex(s, l=32)
97
+ zpad decode_hex(s), l
98
+ end
99
+
100
+ def valid_address?(address)
101
+ Address.new(address).valid?
102
+ end
103
+
104
+ def format_address(address)
105
+ Address.new(address).checksummed
106
+ end
107
+
108
+
109
+
110
+ private
111
+
112
+ def lpad(x, symbol, l)
113
+ return x if x.size >= l
114
+ symbol * (l - x.size) + x
115
+ end
116
+
117
+ def encode_int(n)
118
+ unless n.is_a?(Integer) && n >= 0 && n <= UINT_MAX
119
+ raise ArgumentError, "Integer invalid or out of range: #{n}"
120
+ end
121
+
122
+ int_to_base256 n
123
+ end
124
+
125
+ end
126
+ end
@@ -0,0 +1,3 @@
1
+ module Moac
2
+ VERSION = "0.4.8"
3
+ end
data/moac.gemspec ADDED
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'moac/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "moac"
8
+ spec.version = Moac::VERSION
9
+ spec.authors = ["Kwin Song"]
10
+ spec.email = ["songkuoyin@gmail.com"]
11
+
12
+ spec.summary = %q{Simple API to sign Ethereum transactions.}
13
+ spec.description = %q{Library to build, parse, and sign Ethereum transactions.}
14
+ spec.homepage = "https://github.com/songky/ruby-moac"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency 'digest-sha3', '~> 1.1'
23
+ spec.add_dependency 'ffi', '~> 1.0'
24
+ spec.add_dependency 'money-tree', '~> 0.9'
25
+ spec.add_dependency 'rlp', '~> 0.7.3'
26
+ spec.add_dependency 'scrypt', '~> 3.0.5'
27
+
28
+ spec.add_development_dependency 'bundler', '~> 1.12'
29
+ spec.add_development_dependency 'pry', '~> 0.1'
30
+ spec.add_development_dependency 'rake', '~> 10.0'
31
+ spec.add_development_dependency 'rspec', '~> 3.0'
32
+ end
metadata ADDED
@@ -0,0 +1,194 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: moac
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.8
5
+ platform: ruby
6
+ authors:
7
+ - Kwin Song
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-05-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: digest-sha3
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: ffi
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: money-tree
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.9'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.9'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rlp
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.7.3
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.7.3
69
+ - !ruby/object:Gem::Dependency
70
+ name: scrypt
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 3.0.5
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 3.0.5
83
+ - !ruby/object:Gem::Dependency
84
+ name: bundler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.12'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.12'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.1'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.1'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '10.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '10.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '3.0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '3.0'
139
+ description: Library to build, parse, and sign Ethereum transactions.
140
+ email:
141
+ - songkuoyin@gmail.com
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - ".gitignore"
147
+ - ".gitmodules"
148
+ - ".rspec"
149
+ - ".travis.yml"
150
+ - CHANGELOG.md
151
+ - Gemfile
152
+ - LICENSE.txt
153
+ - README.md
154
+ - Rakefile
155
+ - bin/console
156
+ - bin/setup
157
+ - lib/moac.rb
158
+ - lib/moac/address.rb
159
+ - lib/moac/gas.rb
160
+ - lib/moac/key.rb
161
+ - lib/moac/key/decrypter.rb
162
+ - lib/moac/key/encrypter.rb
163
+ - lib/moac/open_ssl.rb
164
+ - lib/moac/secp256k1.rb
165
+ - lib/moac/sedes.rb
166
+ - lib/moac/tx.rb
167
+ - lib/moac/utils.rb
168
+ - lib/moac/version.rb
169
+ - moac.gemspec
170
+ homepage: https://github.com/songky/ruby-moac
171
+ licenses:
172
+ - MIT
173
+ metadata: {}
174
+ post_install_message:
175
+ rdoc_options: []
176
+ require_paths:
177
+ - lib
178
+ required_ruby_version: !ruby/object:Gem::Requirement
179
+ requirements:
180
+ - - ">="
181
+ - !ruby/object:Gem::Version
182
+ version: '0'
183
+ required_rubygems_version: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ requirements: []
189
+ rubyforge_project:
190
+ rubygems_version: 2.6.14
191
+ signing_key:
192
+ specification_version: 4
193
+ summary: Simple API to sign Ethereum transactions.
194
+ test_files: []