iost_sdk 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/lib/iost_sdk/crypto.rb +144 -0
  3. data/lib/iost_sdk/errors.rb +10 -0
  4. data/lib/iost_sdk/http/client.rb +58 -0
  5. data/lib/iost_sdk/http/get_account.rb +17 -0
  6. data/lib/iost_sdk/http/get_block_by_hash.rb +17 -0
  7. data/lib/iost_sdk/http/get_block_by_number.rb +17 -0
  8. data/lib/iost_sdk/http/get_chain_info.rb +17 -0
  9. data/lib/iost_sdk/http/get_contract.rb +17 -0
  10. data/lib/iost_sdk/http/get_contract_storage.rb +25 -0
  11. data/lib/iost_sdk/http/get_contract_storage_fields.rb +25 -0
  12. data/lib/iost_sdk/http/get_gas_ratio.rb +17 -0
  13. data/lib/iost_sdk/http/get_node_info.rb +17 -0
  14. data/lib/iost_sdk/http/get_ram_info.rb +17 -0
  15. data/lib/iost_sdk/http/get_token_balance.rb +17 -0
  16. data/lib/iost_sdk/http/get_tx_by_hash.rb +17 -0
  17. data/lib/iost_sdk/http/get_tx_receipt_by_tx_hash.rb +17 -0
  18. data/lib/iost_sdk/http/http_request_error.rb +11 -0
  19. data/lib/iost_sdk/http/send_tx.rb +26 -0
  20. data/lib/iost_sdk/models/abi.rb +20 -0
  21. data/lib/iost_sdk/models/account.rb +32 -0
  22. data/lib/iost_sdk/models/account_ram_info.rb +19 -0
  23. data/lib/iost_sdk/models/action.rb +24 -0
  24. data/lib/iost_sdk/models/amount_limit.rb +22 -0
  25. data/lib/iost_sdk/models/block.rb +30 -0
  26. data/lib/iost_sdk/models/block_info.rb +19 -0
  27. data/lib/iost_sdk/models/chain_info.rb +25 -0
  28. data/lib/iost_sdk/models/contract.rb +22 -0
  29. data/lib/iost_sdk/models/frozen_balance.rb +18 -0
  30. data/lib/iost_sdk/models/gas_info.rb +23 -0
  31. data/lib/iost_sdk/models/gas_ratio.rb +18 -0
  32. data/lib/iost_sdk/models/info.rb +19 -0
  33. data/lib/iost_sdk/models/network_info.rb +20 -0
  34. data/lib/iost_sdk/models/node_info.rb +21 -0
  35. data/lib/iost_sdk/models/peer_info.rb +18 -0
  36. data/lib/iost_sdk/models/permission.rb +20 -0
  37. data/lib/iost_sdk/models/permission_group.rb +19 -0
  38. data/lib/iost_sdk/models/permission_item.rb +20 -0
  39. data/lib/iost_sdk/models/pledge_info.rb +18 -0
  40. data/lib/iost_sdk/models/query/contract_storage.rb +24 -0
  41. data/lib/iost_sdk/models/query/contract_storage_fields.rb +23 -0
  42. data/lib/iost_sdk/models/query/signed_transaction.rb +114 -0
  43. data/lib/iost_sdk/models/query/transaction.rb +75 -0
  44. data/lib/iost_sdk/models/ram_info.rb +21 -0
  45. data/lib/iost_sdk/models/receipt.rb +18 -0
  46. data/lib/iost_sdk/models/signature.rb +42 -0
  47. data/lib/iost_sdk/models/token_balance.rb +19 -0
  48. data/lib/iost_sdk/models/transaction.rb +32 -0
  49. data/lib/iost_sdk/models/transaction_info.rb +19 -0
  50. data/lib/iost_sdk/models/tx_receipt.rb +24 -0
  51. data/lib/iost_sdk/models/util/serializer.rb +52 -0
  52. data/lib/iost_sdk/models/vote_info.rb +19 -0
  53. data/lib/iost_sdk/models.rb +276 -0
  54. data/lib/iost_sdk/string.rb +11 -0
  55. data/lib/iost_sdk/version.rb +3 -0
  56. data/lib/iost_sdk.rb +141 -0
  57. metadata +255 -0
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'iost_sdk/models'
4
+ require 'iost_sdk/models/receipt'
5
+
6
+ module IOSTSdk
7
+ module Models
8
+ class TxReceipt
9
+ include Models
10
+
11
+ def self.attr_names
12
+ [
13
+ 'tx_hash',
14
+ 'gas_usage',
15
+ 'ram_usage',
16
+ 'status_code',
17
+ 'message',
18
+ 'returns',
19
+ 'receipts'
20
+ ]
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IOSTSdk
4
+ module Models
5
+ module Util
6
+ module Serializer
7
+ def self.int32_to_bytes(int32)
8
+ [int32].pack('L>').unpack('C*')
9
+ end
10
+
11
+ def self.int64_to_bytes(int64)
12
+ [int64].pack('Q>').unpack('C*')
13
+ end
14
+
15
+ def self.string_to_bytes(str)
16
+ int32_to_bytes(str.size) + str.unpack('C*')
17
+ end
18
+
19
+ def self.array_to_bytes(arr, size_prefix=true)
20
+ return int32_to_bytes(0) if !arr || arr.empty?
21
+
22
+ data_bytes = arr.map do |elem|
23
+ if elem.class.name == 'Integer'
24
+ int64_to_bytes(elem)
25
+ elsif elem.class.name == 'String'
26
+ string_to_bytes(elem)
27
+ elsif elem.class.name == 'Array'
28
+ array_to_bytes(elem)
29
+ elsif elem.class.name == 'Hash'
30
+ hash_to_bytes(elem)
31
+ elsif elem.respond_to?(:raw_data_bytes)
32
+ raw_data_bytes = array_to_bytes(elem.raw_data_bytes, false)
33
+ (int32_to_bytes(raw_data_bytes.size) + raw_data_bytes).flatten
34
+ end
35
+ end
36
+
37
+ data_bytes.flatten!
38
+
39
+ size_prefix ? int32_to_bytes(arr.size) + data_bytes : data_bytes
40
+ end
41
+
42
+ def self.hash_to_bytes(h)
43
+ return int32_to_bytes(0) if !h || h.empty?
44
+
45
+ # hash to array of key-value pairs, sorted by key
46
+ key_value_pairs = h.sort.map { |k, v| [k.to_s, v] }.flatten
47
+ int32_to_bytes(h.size) + array_to_bytes(key_value_pairs, false)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'iost_sdk/models'
4
+
5
+ module IOSTSdk
6
+ module Models
7
+ class VoteInfo
8
+ include Models
9
+
10
+ def self.attr_names
11
+ [
12
+ 'option',
13
+ 'votes',
14
+ 'cleared_votes'
15
+ ]
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,276 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'iost_sdk/string'
5
+
6
+ module IOSTSdk
7
+ module Models
8
+ MODEL_REGISTRY = {
9
+ # query
10
+ 'IOSTSdk::Models::Query::ContractStorage' => {},
11
+ 'IOSTSdk::Models::Query::ContractStorageFields' => {},
12
+ 'IOSTSdk::Models::Query::Transaction' => {
13
+ 'actions' => {
14
+ mode: :list,
15
+ class: 'IOSTSdk::Models::Action'
16
+ },
17
+ 'amount_limit' => {
18
+ mode: :list,
19
+ class: 'IOSTSdk::Models::AmountLimit'
20
+ },
21
+ 'signatures' => {
22
+ mode: :list,
23
+ class: 'IOSTSdk::Models::Signature'
24
+ }
25
+ },
26
+ 'IOSTSdk::Models::Query::SignedTransaction' => {
27
+ 'actions' => {
28
+ mode: :list,
29
+ class: 'IOSTSdk::Models::Action'
30
+ },
31
+ 'amount_limit' => {
32
+ mode: :list,
33
+ class: 'IOSTSdk::Models::AmountLimit'
34
+ },
35
+ 'signatures' => {
36
+ mode: :list,
37
+ class: 'IOSTSdk::Models::Signature'
38
+ },
39
+ 'publisher_sigs' => {
40
+ mode: :list,
41
+ class: 'IOSTSdk::Models::Signature'
42
+ }
43
+ },
44
+ # result
45
+ 'IOSTSdk::Models::NodeInfo' => {
46
+ 'network' => {
47
+ mode: :object,
48
+ class: 'IOSTSdk::Models::NetworkInfo'
49
+ }
50
+ },
51
+ 'IOSTSdk::Models::NetworkInfo' => {
52
+ 'peer_info' => {
53
+ mode: :list,
54
+ class: 'IOSTSdk::Models::PeerInfo'
55
+ }
56
+ },
57
+ 'IOSTSdk::Models::Info' => {},
58
+ 'IOSTSdk::Models::VoteInfo' => {},
59
+ 'IOSTSdk::Models::PeerInfo' => {},
60
+ 'IOSTSdk::Models::ChainInfo' => {},
61
+ 'IOSTSdk::Models::GasRatio' => {},
62
+ 'IOSTSdk::Models::RAMInfo' => {},
63
+ 'IOSTSdk::Models::Action' => {},
64
+ 'IOSTSdk::Models::AmountLimit' => {},
65
+ 'IOSTSdk::Models::Receipt' => {},
66
+ 'IOSTSdk::Models::TxReceipt' => {
67
+ 'receipts' => {
68
+ mode: :list,
69
+ class: 'IOSTSdk::Models::Receipt'
70
+ }
71
+ },
72
+ 'IOSTSdk::Models::Transaction' => {
73
+ 'actions' => {
74
+ mode: :list,
75
+ class: 'IOSTSdk::Models::Action'
76
+ },
77
+ 'amount_limit' => {
78
+ mode: :list,
79
+ class: 'IOSTSdk::Models::AmountLimit'
80
+ },
81
+ 'tx_receipt' => {
82
+ mode: :object,
83
+ class: 'IOSTSdk::Models::TxReceipt'
84
+ }
85
+ },
86
+ 'IOSTSdk::Models::TransactionInfo' => {
87
+ 'transaction' => {
88
+ mode: :object,
89
+ class: 'IOSTSdk::Models::Transaction'
90
+ }
91
+ },
92
+ 'IOSTSdk::Models::Block' => {
93
+ 'transactions' => {
94
+ mode: :list,
95
+ class: 'IOSTSdk::Models::Transaction'
96
+ },
97
+ 'info' => {
98
+ mode: :object,
99
+ class: 'IOSTSdk::Models::Info'
100
+ }
101
+ },
102
+ 'IOSTSdk::Models::BlockInfo' => {
103
+ 'block' => {
104
+ mode: :object,
105
+ class: 'IOSTSdk::Models::Block'
106
+ }
107
+ },
108
+ 'IOSTSdk::Models::AccountRAMInfo' => {},
109
+ 'IOSTSdk::Models::FrozenBalance' => {},
110
+ 'IOSTSdk::Models::PledgeInfo' => {},
111
+ 'IOSTSdk::Models::GasInfo' => {
112
+ 'pledged_info' => {
113
+ mode: :list,
114
+ class: 'IOSTSdk::Models::PledgeInfo'
115
+ }
116
+ },
117
+ 'IOSTSdk::Models::PermissionItem' => {},
118
+ 'IOSTSdk::Models::PermissionGroup' => {
119
+ 'items' => {
120
+ mode: :list,
121
+ class: 'IOSTSdk::Models::PermissionItem'
122
+ }
123
+ },
124
+ 'IOSTSdk::Models::Permission' => {
125
+ 'items' => {
126
+ mode: :list,
127
+ class: 'IOSTSdk::Models::PermissionItem'
128
+ }
129
+ },
130
+ 'IOSTSdk::Models::Account' => {
131
+ 'gas_info' => {
132
+ mode: :object,
133
+ class: 'IOSTSdk::Models::GasInfo'
134
+ },
135
+ 'ram_info' => {
136
+ mode: :object,
137
+ class: 'IOSTSdk::Models::AccountRAMInfo'
138
+ },
139
+ 'permissions' => {
140
+ mode: :hash,
141
+ class: 'IOSTSdk::Models::Permission'
142
+ },
143
+ 'groups' => {
144
+ mode: :hash,
145
+ class: 'IOSTSdk::Models::PermissionGroup'
146
+ },
147
+ 'frozen_balances' => {
148
+ mode: :list,
149
+ class: 'IOSTSdk::Models::FrozenBalance'
150
+ },
151
+ 'vote_infos' => {
152
+ mode: :list,
153
+ class: 'IOSTSdk::Models::VoteInfo'
154
+ }
155
+ },
156
+ 'IOSTSdk::Models::TokenBalance' => {
157
+ 'frozen_balances' => {
158
+ mode: :list,
159
+ class: 'IOSTSdk::Models::FrozenBalance'
160
+ }
161
+ },
162
+ 'IOSTSdk::Models::ABI' => {
163
+ 'amount_limit' => {
164
+ mode: :list,
165
+ class: 'IOSTSdk::Models::AmountLimit'
166
+ }
167
+ },
168
+ 'IOSTSdk::Models::Contract' => {
169
+ 'abis' => {
170
+ mode: :list,
171
+ class: 'IOSTSdk::Models::ABI'
172
+ }
173
+ },
174
+ 'IOSTSdk::Models::Signature' => {}
175
+ }.freeze
176
+
177
+ def self.included base
178
+ base.send :include, InstanceMethods
179
+ base.extend ClassMethods
180
+ end
181
+
182
+ module ClassMethods
183
+ end
184
+
185
+ module InstanceMethods
186
+ require 'iost_sdk/errors'
187
+
188
+ # Creates an instance of a model from the JSON string.
189
+ #
190
+ # @param model_data [Hash] the JSON string of the model data
191
+ # @return an instance of +model_class+ if +model_data+ is valid.
192
+ def populate(model_data:)
193
+ # if nil, short-curcuit
194
+ return nil unless model_data
195
+
196
+ # the model class is expected implement "attr_names" method
197
+ model_attr_names = self.class.attr_names || []
198
+ # proceed ONLY if actual data has a subset of keys of what's defined by the class
199
+ unless Set.new(model_data.keys).subset?(Set.new(model_attr_names))
200
+ raise IOSTSdk::Errors::InvalidModelDataError.new(
201
+ self.class.name,
202
+ model_attr_names,
203
+ model_data.keys
204
+ )
205
+ end
206
+ # create the model
207
+ model_attr_names.each do |k|
208
+ v = model_data[k]
209
+ # set the instance var
210
+ instance_variable_set("@#{k}", parse(data_key: k, data_value: v))
211
+ # define the attr_reader
212
+ self.class.send(:define_method, k.to_sym) do
213
+ instance_variable_get("@#{k}")
214
+ end
215
+ end
216
+
217
+ self
218
+ end
219
+ end
220
+
221
+ def parse(data_key:, data_value:)
222
+ # if nil, short-curcuit
223
+ return nil unless data_value
224
+
225
+ if IOSTSdk::Models::MODEL_REGISTRY[self.class.name].has_key?(data_key)
226
+ instruction = IOSTSdk::Models::MODEL_REGISTRY[self.class.name][data_key]
227
+ mode = instruction[:mode]
228
+ class_name = instruction[:class]
229
+ clazz = IOSTSdk::String.classify(class_name)
230
+
231
+ case mode
232
+ when :object
233
+ clazz.new.populate(model_data: data_value)
234
+ when :list
235
+ data_value.empty? ? [] : data_value.map { |item| clazz.new.populate(model_data: item) }
236
+ when :hash
237
+ if data_value.empty?
238
+ {}
239
+ else
240
+ data_value.each_with_object({}) do |(v_key, v_value), memo|
241
+ memo[v_key] = clazz.new.populate(model_data: v_value)
242
+ end
243
+ end
244
+ end
245
+ else
246
+ data_value
247
+ end
248
+ end
249
+
250
+ def raw_data
251
+ raw_data = instance_variables.each_with_object({}) do |var_name, memo|
252
+ n = var_name.to_s[1..-1].to_sym
253
+ v = send(n)
254
+
255
+ final_v = if IOSTSdk::Models::MODEL_REGISTRY[self.class.name].has_key?(n.to_s)
256
+ mode = IOSTSdk::Models::MODEL_REGISTRY[self.class.name][n.to_s][:mode]
257
+ case mode
258
+ when :object
259
+ v.raw_data
260
+ when :list
261
+ v.map(&:raw_data)
262
+ when :hash
263
+ v.each_with_object({}) do |(v_key, v_value), memo|
264
+ memo[v_key] = v_value.raw_data
265
+ end
266
+ end
267
+ else
268
+ v
269
+ end
270
+ memo[n] = final_v
271
+ end
272
+
273
+ raw_data
274
+ end
275
+ end
276
+ end
@@ -0,0 +1,11 @@
1
+ module IOSTSdk
2
+ module String
3
+ def self.camelize(str)
4
+ str.to_s.split('_').map(&:capitalize).join
5
+ end
6
+
7
+ def self.classify(fq_class_name)
8
+ fq_class_name.split('::').inject(Object) { |o, c| o.const_get c }
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module IOSTSdk
2
+ VERSION = ENV['IOST_SDK_VERSION'] || '0.1.0'
3
+ end
data/lib/iost_sdk.rb ADDED
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'iost_sdk/version'
4
+ require 'iost_sdk/crypto'
5
+ require 'iost_sdk/errors'
6
+ require 'iost_sdk/http/client'
7
+ require 'iost_sdk/models/query/transaction'
8
+ require 'iost_sdk/models/query/signed_transaction'
9
+
10
+ module IOSTSdk
11
+ class Main
12
+ attr_accessor :gas_limit, :gas_ratio, :delay,
13
+ :expiration, :approval_limit_amount,
14
+ :transaction
15
+
16
+ DEFAULTS = {
17
+ gas_limit: 2_000_000,
18
+ gas_ratio: 1,
19
+ delay: 0,
20
+ expiration: 90,
21
+ approval_limit_amount: :unlimited
22
+ }.freeze
23
+
24
+ #
25
+ # @param endpoint [String] a URL of the JSON RPC endpoint of IOST
26
+ def initialize(endpoint:)
27
+ @endpoint = endpoint
28
+
29
+ DEFAULTS.each do |k, v|
30
+ instance_variable_set("@#{k}".to_sym, v)
31
+ end
32
+ end
33
+
34
+ def send(account_name:, key_pair:)
35
+ if @transaction
36
+ client = IOSTSdk::Http::Client.new(base_url: @endpoint)
37
+ client.send_tx(
38
+ transaction: @transaction,
39
+ account_name: account_name,
40
+ key_pair: key_pair
41
+ )
42
+ end
43
+ end
44
+
45
+ # Create an instance of IOSTSdk::Models::Transaction with an action to call the ABI.
46
+ #
47
+ # @param contract_id [String] a Contract's ID
48
+ # @param abi_name [String] the name of an ABI to call
49
+ # @param abi_args [any] args to the ABI
50
+ # @return a new instance of Transaction
51
+ def call_abi(contract_id:, abi_name:, abi_args:)
52
+ transaction = init_transaction
53
+ transaction.add_action(contract_id: contract_id, action_name: abi_name, action_data: abi_args)
54
+ transaction.add_approve(token: '*', amount: :unlimited)
55
+ transaction.set_time_params(expiration: expiration, delay: delay)
56
+
57
+ @transaction = transaction
58
+ self
59
+ end
60
+
61
+ # Create an instance IOSTSdk::Models::Transaction with an action to transfer tokens
62
+ #
63
+ # @param token [String] name of the token in the transfer
64
+ # @param from [String] sender
65
+ # @param to [String] recipient
66
+ # @param amount [Integer] amount to transfer
67
+ # @param memo [String] memo/notes for the transfer
68
+ # @return a new instance of Transaction
69
+ def transfer(token:, from:, to:, amount:, memo:)
70
+ call_abi(
71
+ contract_id: 'token.iost',
72
+ abi_name: :transfer,
73
+ abi_args: [token, from, to, amount, memo]
74
+ )
75
+ @transaction.add_approve(token: :iost, amount: amount)
76
+ @transaction.set_time_params(expiration: expiration, delay: delay)
77
+
78
+ self
79
+ end
80
+
81
+ # Create an instance IOSTSdk::Models::Transaction to create a new account
82
+ #
83
+ # @param name [String] the name of the account to be created
84
+ # @param creator [String] the name of the account that's creating a new account
85
+ # @param owner_key [IOSTSdk::Crypto::KeyPair] the owner key of the new account
86
+ # @param active_key [IOSTSdk::Crypto::KeyPair] the active key of the new account
87
+ # @param initial_ram [Integer] the initial RAM of the new account
88
+ # @param initial_gas_pledge [Integer] the initial gas pledge of the new account
89
+ def new_account(name:, creator:, owner_key:, active_key:, initial_ram:, initial_gas_pledge:)
90
+ transaction = init_transaction
91
+ transaction.add_action(
92
+ contract_id: 'auth.iost',
93
+ action_name: :signUp,
94
+ action_data: [name, owner_key.id, active_key.id]
95
+ )
96
+
97
+ if initial_ram > 10
98
+ transaction.add_action(
99
+ contract_id: 'ram.iost',
100
+ action_name: :buy,
101
+ action_data: [creator, name, initial_ram]
102
+ )
103
+ end
104
+
105
+ if initial_gas_pledge > 0
106
+ transaction.add_action(
107
+ contract_id: 'ram.iost',
108
+ action_name: :buy,
109
+ action_data: [creator, name, initial_gas_pledge.to_s]
110
+ )
111
+ end
112
+
113
+ transaction.set_time_params(expiration: expiration, delay: delay)
114
+ transaction.add_approve(token: '*', amount: approval_limit_amount)
115
+
116
+ @transaction = transaction
117
+ self
118
+ end
119
+
120
+ private
121
+
122
+ def init_transaction
123
+ time_now = Time.now.utc.to_i * 1_000_000
124
+ transaction = IOSTSdk::Models::Query::Transaction.new.populate(
125
+ model_data: {
126
+ 'time' => time_now,
127
+ 'expiration' => time_now + delay * 1_000_000,
128
+ 'gas_ratio' => gas_ratio,
129
+ 'gas_limit' => gas_limit,
130
+ 'delay' => delay,
131
+ 'chain_id' => 0,
132
+ 'signers' => [],
133
+ 'actions' => [],
134
+ 'amount_limit' => [],
135
+ 'signatures' => []
136
+ }
137
+ )
138
+ transaction
139
+ end
140
+ end
141
+ end