appchain.rb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AppChain
4
+ class Transaction
5
+ attr_accessor :to, :nonce, :quota, :valid_until_block, :data, :value, :chain_id, :version
6
+
7
+ # @param nonce [String]
8
+ # @param valid_until_block [Integer]
9
+ # @param chain_id [Integer]
10
+ # @param version [Integer]
11
+ # @param to [String]
12
+ # @param data [String]
13
+ # @param value: [String | Integer] hex string or decimal integer
14
+ # @param quota [Integer]
15
+ #
16
+ # @return [void]
17
+ def initialize(nonce:, valid_until_block:, chain_id:, version: 0, to: nil, data: nil, value: "0", quota: 1_000_000)
18
+ @to = to
19
+ @nonce = nonce
20
+ @quota = quota
21
+ @valid_until_block = valid_until_block
22
+ @data = data
23
+ @chain_id = chain_id
24
+ @version = version
25
+ @value = if value.is_a?(Integer)
26
+ Utils.to_hex(value)
27
+ else
28
+ value
29
+ end
30
+ end
31
+
32
+ def self.from_hash(hash)
33
+ h = hash.map { |k, v| { k.to_sym => v } }.reduce({}, :merge)
34
+
35
+ new(
36
+ nonce: h[:nonce],
37
+ valid_until_block: h[:valid_until_block],
38
+ chain_id: h[:chain_id],
39
+ to: h[:to],
40
+ data: h[:data],
41
+ version: h[:version] || 0,
42
+ value: h[:value] || "0",
43
+ quota: h[:quota] || 1_000_000
44
+ )
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ciri/utils"
4
+ require "ciri/crypto"
5
+
6
+ module AppChain
7
+ class TransactionSigner
8
+ class << self
9
+ # sign transaction
10
+ #
11
+ # @param transaction [AppChain::Transaction]
12
+ # @param private_key [String]
13
+ def encode(transaction, private_key)
14
+ tx = AppChain::Protos::Transaction.new
15
+
16
+ tx.nonce = transaction.nonce
17
+ to = AppChain::Utils.remove_hex_prefix(transaction.to)&.downcase
18
+ tx.to = to unless to.nil?
19
+ tx.quota = transaction.quota
20
+ tx.data = AppChain::Utils.to_bytes(transaction.data)
21
+ tx.version = transaction.version
22
+ tx.value = process_value(transaction.value)
23
+ tx.chain_id = transaction.chain_id
24
+ tx.valid_until_block = transaction.valid_until_block
25
+
26
+ encoded_tx = Protos::Transaction.encode(tx)
27
+
28
+ private_key_bytes = AppChain::Utils.to_bytes(private_key)
29
+
30
+ protobuf_hash = Utils.keccak256(encoded_tx)
31
+
32
+ signature = Ciri::Crypto.ecdsa_signature(private_key_bytes, protobuf_hash).signature
33
+
34
+ unverified_tx = Protos::UnverifiedTransaction.new(transaction: tx, signature: signature)
35
+
36
+ encoded_unverified_tx = Protos::UnverifiedTransaction.encode(unverified_tx)
37
+
38
+ AppChain::Utils.from_bytes(encoded_unverified_tx)
39
+ end
40
+
41
+ # unsign transaction
42
+ #
43
+ # @param tx_content [String] hex string
44
+ def decode(tx_content)
45
+ content_bytes = AppChain::Utils.to_bytes(tx_content)
46
+ unverified_transaction = Protos::UnverifiedTransaction.decode(content_bytes)
47
+
48
+ signature = unverified_transaction["signature"]
49
+
50
+ transaction = unverified_transaction["transaction"]
51
+ msg = Protos::Transaction.encode(transaction)
52
+ msg_hash = AppChain::Utils.keccak256(msg)
53
+ pubkey = Ciri::Crypto.ecdsa_recover(msg_hash, signature)
54
+ pubkey_hex = Utils.from_bytes(pubkey[1..-1])
55
+
56
+ from_address = Utils.keccak256(pubkey[1..-1])[-20..-1]
57
+ from_address_hex = Utils.from_bytes(from_address)
58
+
59
+ sender = {
60
+ "address" => from_address_hex,
61
+ "public_key" => pubkey_hex
62
+ }
63
+
64
+ {
65
+ "unverified_transaction" => unverified_transaction,
66
+ "sender" => sender
67
+ }
68
+ end
69
+
70
+ private
71
+
72
+ # @param value [String] hex string with or without `0x` prefix
73
+ # @return [String] byte code string
74
+ def process_value(value)
75
+ AppChain::Utils.to_bytes(AppChain::Utils.remove_hex_prefix(value).rjust(64, "0"))
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AppChain
4
+ class Utils
5
+ HEX_PREFIX = "0x"
6
+
7
+ class << self
8
+ # add `0x` prefix to hex string
9
+ #
10
+ # @param hex [String]
11
+ def add_hex_prefix(hex)
12
+ return if hex.nil?
13
+ return hex if hex.start_with?(HEX_PREFIX)
14
+
15
+ HEX_PREFIX + hex
16
+ end
17
+
18
+ # remove `0x` prefix from hex string
19
+ #
20
+ # @param hex [String]
21
+ def remove_hex_prefix(hex)
22
+ return if hex.nil?
23
+ return hex.gsub(HEX_PREFIX, "") if hex.start_with?(HEX_PREFIX)
24
+
25
+ hex
26
+ end
27
+
28
+ # convert decimal value to hex string without `0x` prefix
29
+ #
30
+ # @param decimal [Integer]
31
+ # @return [String]
32
+ def to_hex(decimal)
33
+ add_hex_prefix decimal.to_s(16)
34
+ end
35
+
36
+ # convert hex string to decimal value
37
+ #
38
+ # @param hex [String]
39
+ # @return [Integer]
40
+ def to_decimal(hex)
41
+ hex.hex
42
+ end
43
+
44
+ # to byte code value
45
+ # remove `0x` prefix first
46
+ #
47
+ # @param str [String] normal string
48
+ # @return [String] byte code string
49
+ def to_bytes(str)
50
+ [AppChain::Utils.remove_hex_prefix(str)].pack("H*")
51
+ end
52
+
53
+ # byte code to string value, with `0x` prefix
54
+ #
55
+ # @param bytes_str [String] byte code string
56
+ # @return [String] normal string
57
+ def from_bytes(bytes_str)
58
+ AppChain::Utils.add_hex_prefix(bytes_str.unpack1("H*"))
59
+ end
60
+
61
+ # keccak 256 hash
62
+ #
63
+ def keccak256(*data)
64
+ Ciri::Utils.keccak(*data)
65
+ end
66
+
67
+ # get nonce
68
+ #
69
+ # @return [String]
70
+ def nonce
71
+ SecureRandom.hex
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AppChain
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "web3/eth"
4
+
5
+ module Web3
6
+ module Eth
7
+ class Contract
8
+ class ContractInstance
9
+ def function_data(method_name, *args)
10
+ @contract.function_data(method_name.to_s, args)
11
+ end
12
+ end
13
+
14
+ class ContractMethod
15
+ def function_data(args)
16
+ ["0x" + signature_hash + encode_hex(encode_abi(input_types, args)), output_types]
17
+ end
18
+ end
19
+
20
+ def function_data(method_name, args)
21
+ function = functions[method_name]
22
+ raise "No method found in ABI: #{method_name}" unless function
23
+
24
+ function.function_data args
25
+ end
26
+ end
27
+ end
28
+ end
metadata ADDED
@@ -0,0 +1,226 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: appchain.rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - classicalliu
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-10-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.11'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.11'
69
+ - !ruby/object:Gem::Dependency
70
+ name: awesome_print
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.8'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.8'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.59'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.59'
97
+ - !ruby/object:Gem::Dependency
98
+ name: google-protobuf
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.6'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3.6'
111
+ - !ruby/object:Gem::Dependency
112
+ name: ciri-crypto
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '='
116
+ - !ruby/object:Gem::Version
117
+ version: 0.1.1
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '='
123
+ - !ruby/object:Gem::Version
124
+ version: 0.1.1
125
+ - !ruby/object:Gem::Dependency
126
+ name: faraday
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 0.15.3
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 0.15.3
139
+ - !ruby/object:Gem::Dependency
140
+ name: activesupport
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: 5.2.1
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: 5.2.1
153
+ - !ruby/object:Gem::Dependency
154
+ name: web3-eth
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: 0.2.16
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: 0.2.16
167
+ description: Ruby Nervos AppChain SDK for signature and rpc call
168
+ email:
169
+ - classicalliu@gmail.com
170
+ executables: []
171
+ extensions: []
172
+ extra_rdoc_files: []
173
+ files:
174
+ - ".gitignore"
175
+ - ".gitmodules"
176
+ - ".pryrc"
177
+ - ".rspec"
178
+ - ".rubocop.yml"
179
+ - ".travis.yml"
180
+ - CODE_OF_CONDUCT.md
181
+ - Gemfile
182
+ - Gemfile.lock
183
+ - LICENSE.txt
184
+ - README.md
185
+ - Rakefile
186
+ - appchain.gemspec
187
+ - bin/console
188
+ - bin/setup
189
+ - lib/appchain.rb
190
+ - lib/appchain/address.rb
191
+ - lib/appchain/client.rb
192
+ - lib/appchain/contract.rb
193
+ - lib/appchain/http.rb
194
+ - lib/appchain/protos/blockchain_pb.rb
195
+ - lib/appchain/rpc.rb
196
+ - lib/appchain/transaction.rb
197
+ - lib/appchain/transaction_signer.rb
198
+ - lib/appchain/utils.rb
199
+ - lib/appchain/version.rb
200
+ - lib/web3_eth/contract.rb
201
+ homepage: https://github.com/cryptape/appchain.rb
202
+ licenses:
203
+ - MIT
204
+ metadata:
205
+ allowed_push_host: https://rubygems.org
206
+ post_install_message:
207
+ rdoc_options: []
208
+ require_paths:
209
+ - lib
210
+ required_ruby_version: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - ">="
213
+ - !ruby/object:Gem::Version
214
+ version: '0'
215
+ required_rubygems_version: !ruby/object:Gem::Requirement
216
+ requirements:
217
+ - - ">="
218
+ - !ruby/object:Gem::Version
219
+ version: '0'
220
+ requirements: []
221
+ rubyforge_project:
222
+ rubygems_version: 2.7.6
223
+ signing_key:
224
+ specification_version: 4
225
+ summary: Ruby Nervos AppChain SDK
226
+ test_files: []