ton-client-ruby 1.0.0 → 1.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.
@@ -0,0 +1,325 @@
1
+ require 'byebug'
2
+ require 'json'
3
+ require File.dirname(__FILE__) + '/helpers.rb'
4
+
5
+ class CodeGenerator
6
+ include InstanceHelpers
7
+
8
+ attr_accessor :types
9
+ attr_accessor :root_dir
10
+
11
+ TAB = " "
12
+
13
+ def initialize(types, root_dir)
14
+ @types = types
15
+ @root_dir = root_dir
16
+ end
17
+
18
+ def generate_self_code
19
+ generateModules(types)
20
+ generateReadme(types)
21
+ end
22
+
23
+ private
24
+
25
+ def generateModules(types)
26
+ types.modules.each do |mod|
27
+ modulesFolder = root_dir + "/lib/ton-client-ruby/Client"
28
+ moduleFilePath = "#{modulesFolder}/#{mod.name.capitalize}.rb"
29
+ newModuleContent = ""
30
+ if mod.name == "client"
31
+ newModuleContent = generateClientModule(mod, types.modules)
32
+ else
33
+ newModuleContent = generateModule(mod)
34
+ end
35
+ if File.exists?(moduleFilePath)
36
+ File.delete(moduleFilePath)
37
+ end
38
+ File.open(moduleFilePath, 'w+') { |f| f.write(newModuleContent) }
39
+ end
40
+
41
+ p 'generate_self_code ok'
42
+ end
43
+
44
+ def generateReadme(types)
45
+ readmePath = root_dir + "/README.md"
46
+ content = %{
47
+ # Ruby Client for Free TON SDK
48
+
49
+ [![GEM](https://img.shields.io/badge/ruby-gem-green)]()
50
+
51
+ ## Install
52
+
53
+ Install gem
54
+ ```bash
55
+ gem install ton-client-ruby
56
+ ```
57
+
58
+ Install TON-SDK
59
+ ```bash
60
+ ton-client-ruby setup
61
+ # result - path to dylib file for ton-client-ruby configuration
62
+ ```
63
+
64
+ ### Manual build FreeTON SDK
65
+ 0. Install Rust to your OS
66
+ 1. git clone https://github.com/tonlabs/TON-SDK
67
+ 2. cd ./TON-SDK
68
+ 3. cargo update
69
+ 4. cargo build --release
70
+
71
+ ## Usage
72
+
73
+ ```ruby
74
+ # For MAcOS
75
+ TonClient.configure { |config| config.ffi_lib(./TON-SDK/target/release/libton_client.dylib) }
76
+ # For Linux
77
+ # TonClient.configure { |config| config.ffi_lib(./TON-SDK/target/release/libton_client.so) }
78
+
79
+ client = TonClient.create(config: {network: {server_address: "net.ton.dev"}})
80
+
81
+ # All methods are asynchronous
82
+
83
+ # example: call method for Crypto module
84
+ payload = {composite: '17ED48941A08F981'}
85
+ client.crypto.factorize(payload) do |response|
86
+ p response.result['factors']
87
+ end
88
+
89
+ # e.g. ...
90
+ ```\n\n
91
+ }
92
+ content << "## All Modules, methods and types\n\n"
93
+
94
+ # types
95
+ content << "<details>\n#{TAB}<summary>Types</summary>\n\n"
96
+
97
+ content << "#{customTypes()}\n"
98
+
99
+ types.modules.each do |mod|
100
+ (mod.enums || []).each do |type|
101
+ content << checkComment(type.summary, 0) if type.summary
102
+ content << checkComment(type.description, 0) if type.description
103
+ content << "\n- #### #{type.name}\n"
104
+ (type.cases || []).each do |enum_case|
105
+ content << "#{checkComment(enum_case.summary, 1).gsub(/#/, '')}" if enum_case.summary
106
+ content << "#{checkComment(enum_case.description, 1).gsub(/#/, '')}" if enum_case.description
107
+ content << "#{TAB}- case #{enum_case.name} = #{enum_case.value}\n\n"
108
+ end
109
+ end
110
+
111
+ (mod.types || []).each do |type|
112
+ content << checkComment(type.summary, 0) if type.summary
113
+ content << checkComment(type.description, 0) if type.description
114
+ content << "\n- #### #{type.name}\n"
115
+ (type.fields || []).each do |field|
116
+ content << "#{checkComment(field.summary, 1).gsub(/#/, '')}\n" if field.summary
117
+ content << "#{checkComment(field.description, 1).gsub(/#/, '')}\n" if field.description
118
+ content << "#{TAB}- #{field.name}: #{field.type}\n\n"
119
+ end
120
+ end
121
+ end
122
+ content << "</details>\n\n"
123
+
124
+ # methods
125
+ types.modules.each do |mod|
126
+ content << "<details>\n#{TAB}<summary>#{mod.name&.upcase}</summary>\n\n"
127
+ (mod.functions || []).each do |function|
128
+ content << "```ruby\n"
129
+ content << checkComment(function.summary, 2) if function.summary
130
+ content << checkComment(function.description, 2) if function.description
131
+ content << "\n#{TAB}#{TAB}def #{function.name}"
132
+ if function.arguments.empty?
133
+ content << "(&block)\n"
134
+ else
135
+ content << "(payload, &block)\n"
136
+ end
137
+ content << getFunctionComment(function, types)
138
+ content << "```\n"
139
+ end
140
+ content << "</details>\n\n"
141
+ end
142
+
143
+ content << %{
144
+ \n## Tests
145
+
146
+ 1. create __.env.test__ file inside root directory of this library with variables
147
+
148
+ example for NodeSE
149
+ ```
150
+ spec_ffi=./TON-SDK/target/release/libton_client.dylib
151
+ server_address=http://localhost:80
152
+ giver_abi_name=GiverNodeSE
153
+ giver_amount=10000000000
154
+ ```
155
+ 2. Run tests: inside folder of this library execute this commands
156
+ **rspec spec/binding.rb**
157
+ **rspec spec/client.rb**
158
+ **rspec spec/context.rb**
159
+ **rspec spec/abi.rb**
160
+ **rspec spec/boc.rb**
161
+ **rspec spec/crypto.rb**
162
+ **rspec spec/net.rb**
163
+ **rspec spec/processing.rb**
164
+ **rspec spec/tvm.rb**
165
+ **rspec spec/utils.rb**
166
+
167
+ \n## Update\n\n
168
+ ```\n
169
+ curl https://raw.githubusercontent.com/tonlabs/TON-SDK/master/tools/api.json > api.json\n\n
170
+ ton-client-ruby update api.json\n
171
+ ```\n
172
+ }
173
+ content = checkContent(content)
174
+ if File.exists?(readmePath)
175
+ File.delete(readmePath)
176
+ end
177
+ File.open(readmePath, 'w+') { |f| f.write(content) }
178
+ end
179
+
180
+ private def checkContent(content)
181
+ content.gsub!(/^([\s]+)# RESPONSE/, "\n\\1# RESPONSE")
182
+ content.gsub(/<Optional>/i, '&lt;Optional&gt;')
183
+ end
184
+
185
+ def customTypes
186
+ content = %{
187
+ - #### #{lib_prefix}MnemonicDictionary
188
+ #{TAB}- case TON = 0
189
+ #{TAB}- case ENGLISH = 1
190
+ #{TAB}- case CHINESE_SIMPLIFIED = 2
191
+ #{TAB}- case CHINESE_TRADITIONAL = 3
192
+ #{TAB}- case FRENCH = 4
193
+ #{TAB}- case ITALIAN = 5
194
+ #{TAB}- case JAPANESE = 6
195
+ #{TAB}- case KOREAN = 7
196
+ #{TAB}- case SPANISH = 8
197
+ }
198
+ content
199
+ end
200
+
201
+ private def checkComment(string, tabs = 1)
202
+ replacedString = "\n"
203
+ tab = ""
204
+ tabs.times do |i|
205
+ tab << TAB
206
+ end
207
+ comment = "#"
208
+ replacedString << "#{tab}#{comment} "
209
+ symbolsWithSpace = "\\.|\\:|\\!|\\?|\\;"
210
+ regxp = /([^#{symbolsWithSpace}])\n/
211
+ result = string
212
+ result.gsub!(/\n+/, "\n")
213
+ result.gsub!(/ \n/, "\n#{comment} ")
214
+ result.gsub!(/(#{symbolsWithSpace})\s*\n/, "\\1#{replacedString}")
215
+ result.gsub!(regxp, "\\1")
216
+ "#{tab}# #{result}"
217
+ end
218
+
219
+ private def generateClientModule(mod, modules)
220
+ content = "module TonClient\n\n#{TAB}class #{mod.name.capitalize}\n#{TAB}#{TAB}include CommonInstanceHelpers\n\n"
221
+ content << "#{TAB}#{TAB}attr_reader :core, :context\n"
222
+ content << "#{TAB}#{TAB}private_accessor "
223
+ modules.each_with_index do |m, i|
224
+ next if m.name.downcase == 'client'
225
+ content << ((modules.size - 1) == i ? ":_#{m.name}\n" : ":_#{m.name}, ")
226
+ end
227
+ content << "#{TAB}#{TAB}MODULE = self.to_s.downcase.gsub(/^(.+::|)(\\w+)$/, '\\2').freeze\n\n"
228
+ content << "#{TAB}#{TAB}def initialize(context: Context.new, core: TonClient::TonBinding)\n"
229
+ content << "#{TAB}#{TAB}#{TAB}@context = context\n"
230
+ content << "#{TAB}#{TAB}#{TAB}@core = core\n#{TAB}#{TAB}end\n\n"
231
+ content << "#{TAB}#{TAB}def destroy_context\n"
232
+ content << "#{TAB}#{TAB}#{TAB}core.tc_destroy_context(context.id)\n#{TAB}#{TAB}end\n\n"
233
+ modules.each_with_index do |m, i|
234
+ next if m.name.downcase == 'client'
235
+ content << "#{TAB}#{TAB}def #{m.name}\n"
236
+ content << "#{TAB}#{TAB}#{TAB}_#{m.name} ||= #{m.name.capitalize}.new(context: context)\n"
237
+ content << "#{TAB}#{TAB}end\n\n"
238
+ end
239
+
240
+ mod.functions.each do |func|
241
+ content << gen_function(func, types)
242
+ end
243
+
244
+ content << "#{TAB}end\n"
245
+ content << "end\n\n"
246
+
247
+ content
248
+ end
249
+
250
+ private def generateModule(mod)
251
+ content = "module TonClient\n\n#{TAB}class #{mod.name.capitalize}\n#{TAB}#{TAB}include CommonInstanceHelpers\n\n"
252
+ content << "#{TAB}#{TAB}attr_reader :core, :context\n"
253
+ content << "#{TAB}#{TAB}MODULE = self.to_s.downcase.gsub(/^(.+::|)(\\w+)$/, '\\2').freeze\n\n"
254
+ content << "#{TAB}#{TAB}def initialize(context: Context.new, core: TonClient::TonBinding)\n"
255
+ content << "#{TAB}#{TAB}#{TAB}@context = context\n"
256
+ content << "#{TAB}#{TAB}#{TAB}@core = core\n"
257
+ content << "#{TAB}#{TAB}end\n\n"
258
+
259
+ mod.functions.each do |func|
260
+ content << gen_function(func, types)
261
+ end
262
+
263
+ content << "#{TAB}end\n"
264
+ content << "end\n\n"
265
+
266
+ content
267
+ end
268
+
269
+ private def gen_function(function, types)
270
+ content = getFunctionComment(function, types)
271
+ content << "#{TAB}#{TAB}def #{function.name}"
272
+ if function.arguments.empty?
273
+ content << "(&block)\n"
274
+ content << "#{TAB}#{TAB}#{TAB}core.requestLibrary(context: context.id, method_name: full_method_name(MODULE, __method__.to_s), payload: {}, &block)\n"
275
+ else
276
+ content << "(payload, &block)\n"
277
+ content << "#{TAB}#{TAB}#{TAB}core.requestLibrary(context: context.id, method_name: full_method_name(MODULE, __method__.to_s), payload: payload, &block)\n"
278
+ end
279
+ content << "#{TAB}#{TAB}end\n\n"
280
+
281
+ content
282
+ end
283
+
284
+ def getFunctionComment(function, types)
285
+ content = ''
286
+ if argument = function.arguments.first
287
+ content << "#{TAB}#{TAB}# INPUT: #{argument.type}\n"
288
+ if types.all_types[argument.type].respond_to?(:fields)
289
+ types.all_types[argument.type].fields.each do |arg|
290
+ content << "#{TAB}#{TAB}# #{arg.name}: #{arg.type} - "
291
+ content << "#{TAB}#{TAB}# #{checkComment(arg.summary, 2)}" if arg.summary
292
+ content << "#{TAB}#{TAB}# #{checkComment(arg.description, 2)}" if arg.description
293
+ content << "\n"
294
+ end
295
+ elsif types.all_types[argument.type].respond_to?(:cases)
296
+ end
297
+ end
298
+
299
+ if types.all_types[function.result]
300
+ content << "#{TAB}#{TAB}# RESPONSE: #{function.result}\n"
301
+ if types.all_types[function.result].respond_to?(:fields)
302
+ types.all_types[function.result].fields.each do |arg|
303
+ content << "#{TAB}#{TAB}# #{arg.name}: #{arg.type} - "
304
+ content << "#{TAB}#{TAB}# #{checkComment(arg.summary, 2)}" if arg.summary
305
+ content << "#{TAB}#{TAB}# #{checkComment(arg.description, 2)}" if arg.description
306
+ content << "\n"
307
+ end
308
+ elsif types.all_types[function.result].respond_to?(:cases)
309
+ end
310
+ end
311
+
312
+ content
313
+ end
314
+ end
315
+
316
+
317
+
318
+
319
+
320
+
321
+
322
+
323
+
324
+
325
+
@@ -0,0 +1,13 @@
1
+ require 'json'
2
+ require 'byebug'
3
+
4
+ module InstanceHelpers
5
+
6
+ def lib_prefix
7
+ ''
8
+ end
9
+
10
+ def lib_enum_postfix
11
+ ''
12
+ end
13
+ end
@@ -3,6 +3,7 @@ require "base64"
3
3
  require 'json'
4
4
  require 'byebug'
5
5
  require 'dotenv'
6
+ require 'fileutils'
6
7
  require 'ton-client-ruby/Helpers/CommonHelpers.rb'
7
8
  require 'ton-client-ruby/Binding/struct.rb'
8
9
  require 'ton-client-ruby/Binding/binding.rb'
@@ -147,14 +147,11 @@ module TonClient
147
147
  end
148
148
 
149
149
  if string[:content].address > 1
150
- # string = string[:content].read_string(string[:len]).force_encoding('UTF-8') + ''
151
- # tc_destroy_string(tc_string_handle) if is_ref
152
- # return string
153
- return string[:content].read_string(string[:len]).force_encoding('UTF-8') + ''
150
+ string = string[:content].read_string(string[:len]).force_encoding('UTF-8') + ''
151
+ tc_destroy_string(tc_string_handle) if is_ref
152
+ return string
154
153
  end
155
154
  nil
156
- ensure
157
- tc_destroy_string(tc_string_handle) if is_ref
158
155
  end
159
156
 
160
157
  def self.read_string_to_hash(tc_string_handle_t_ref)
@@ -1,5 +1,5 @@
1
1
  module TonClient
2
-
2
+
3
3
  class Abi
4
4
  include CommonInstanceHelpers
5
5
 
@@ -11,42 +11,124 @@ module TonClient
11
11
  @core = core
12
12
  end
13
13
 
14
+ # INPUT: ParamsOfEncodeMessageBody
15
+ # abi: Value - # # Contract ABI.
16
+ # call_set: CallSet - # # Function call parameters. # # Must be specified in non deploy message.
17
+ # In case of deploy message contains parameters of constructor.
18
+ # is_internal: Boolean - # # True if internal message body must be encoded.
19
+ # signer: Signer - # # Signing parameters.
20
+ # processing_try_index: Number<Optional> - # # Processing try index. # # Used in message processing with retries.
21
+ # Encoder uses the provided try index to calculate messageexpiration time.
22
+ # Expiration timeouts will grow with every retry.
23
+ # Default value is 0.
24
+ # RESPONSE: ResultOfEncodeMessageBody
25
+ # body: String - # # Message body BOC encoded with `base64`.
26
+ # data_to_sign: String<Optional> - # # Optional data to sign. # # Encoded with `base64`.
27
+ # # Presents when `message` is unsigned. Can be used for externalmessage signing. Is this case you need to sing this data andproduce signed message using `abi.attach_signature`.
14
28
  def encode_message_body(payload, &block)
15
29
  core.requestLibrary(context: context.id, method_name: full_method_name(MODULE, __method__.to_s), payload: payload, &block)
16
30
  end
17
31
 
32
+ # INPUT: ParamsOfAttachSignatureToMessageBody
33
+ # abi: Value - # # Contract ABI
34
+ # public_key: String - # # Public key. # # Must be encoded with `hex`.
35
+ # message: String - # # Unsigned message body BOC. # # Must be encoded with `base64`.
36
+ # signature: String - # # Signature. # # Must be encoded with `hex`.
37
+ # RESPONSE: ResultOfAttachSignatureToMessageBody
38
+ # body: String -
18
39
  def attach_signature_to_message_body(payload, &block)
19
40
  core.requestLibrary(context: context.id, method_name: full_method_name(MODULE, __method__.to_s), payload: payload, &block)
20
41
  end
21
42
 
43
+ # INPUT: ParamsOfEncodeMessage
44
+ # abi: Value - # # Contract ABI.
45
+ # address: String<Optional> - # # Target address the message will be sent to. # # Must be specified in case of non-deploy message.
46
+ # deploy_set: DeploySet<Optional> - # # Deploy parameters. # # Must be specified in case of deploy message.
47
+ # call_set: CallSet<Optional> - # # Function call parameters. # # Must be specified in case of non-deploy message.
48
+ # In case of deploy message it is optional and contains parametersof the functions that will to be called upon deploy transaction.
49
+ # signer: Signer - # # Signing parameters.
50
+ # processing_try_index: Number<Optional> - # # Processing try index. # # Used in message processing with retries (if contract's ABI includes "expire" header).
51
+ # Encoder uses the provided try index to calculate messageexpiration time. The 1st message expiration time is specified inClient config.
52
+ # Expiration timeouts will grow with every retry.
53
+ # Retry grow factor is set in Client config:
54
+ # <.....add config parameter with default value here>Default value is 0.
55
+ # RESPONSE: ResultOfEncodeMessage
56
+ # message: String - # # Message BOC encoded with `base64`.
57
+ # data_to_sign: String<Optional> - # # Optional data to be signed encoded in `base64`. # # Returned in case of `Signer::External`. Can be used for externalmessage signing. Is this case you need to use this data to create signature andthen produce signed message using `abi.attach_signature`.
58
+ # address: String - # # Destination address.
59
+ # message_id: String - # # Message id.
22
60
  def encode_message(payload, &block)
23
61
  core.requestLibrary(context: context.id, method_name: full_method_name(MODULE, __method__.to_s), payload: payload, &block)
24
62
  end
25
63
 
64
+ # INPUT: ParamsOfEncodeInternalMessage
65
+ # abi: Value<Optional> - # # Contract ABI. # # Can be None if both deploy_set and call_set are None.
66
+ # address: String<Optional> - # # Target address the message will be sent to. # # Must be specified in case of non-deploy message.
67
+ # src_address: String<Optional> - # # Source address of the message.
68
+ # deploy_set: DeploySet<Optional> - # # Deploy parameters. # # Must be specified in case of deploy message.
69
+ # call_set: CallSet<Optional> - # # Function call parameters. # # Must be specified in case of non-deploy message.
70
+ # In case of deploy message it is optional and contains parametersof the functions that will to be called upon deploy transaction.
71
+ # value: String - # # Value in nanotokens to be sent with message.
72
+ # bounce: Boolean<Optional> - # # Flag of bounceable message. # # Default is true.
73
+ # enable_ihr: Boolean<Optional> - # # Enable Instant Hypercube Routing for the message. # # Default is false.
74
+ # RESPONSE: ResultOfEncodeInternalMessage
75
+ # message: String - # # Message BOC encoded with `base64`.
76
+ # address: String - # # Destination address.
77
+ # message_id: String - # # Message id.
26
78
  def encode_internal_message(payload, &block)
27
79
  core.requestLibrary(context: context.id, method_name: full_method_name(MODULE, __method__.to_s), payload: payload, &block)
28
80
  end
29
81
 
82
+ # INPUT: ParamsOfAttachSignature
83
+ # abi: Value - # # Contract ABI
84
+ # public_key: String - # # Public key encoded in `hex`.
85
+ # message: String - # # Unsigned message BOC encoded in `base64`.
86
+ # signature: String - # # Signature encoded in `hex`.
87
+ # RESPONSE: ResultOfAttachSignature
88
+ # message: String - # # Signed message BOC
89
+ # message_id: String - # # Message ID
30
90
  def attach_signature(payload, &block)
31
91
  core.requestLibrary(context: context.id, method_name: full_method_name(MODULE, __method__.to_s), payload: payload, &block)
32
92
  end
33
93
 
94
+ # INPUT: ParamsOfDecodeMessage
95
+ # abi: Value - # # contract ABI
96
+ # message: String - # # Message BOC
97
+ # RESPONSE: DecodedMessageBody
98
+ # body_type: MessageBodyType - # # Type of the message body content.
99
+ # name: String - # # Function or event name.
100
+ # value: Value<Optional> - # # Parameters or result value.
101
+ # header: FunctionHeader<Optional> - # # Function header.
34
102
  def decode_message(payload, &block)
35
103
  core.requestLibrary(context: context.id, method_name: full_method_name(MODULE, __method__.to_s), payload: payload, &block)
36
104
  end
37
105
 
106
+ # INPUT: ParamsOfDecodeMessageBody
107
+ # abi: Value - # # Contract ABI used to decode.
108
+ # body: String - # # Message body BOC encoded in `base64`.
109
+ # is_internal: Boolean - # # True if the body belongs to the internal message.
110
+ # RESPONSE: DecodedMessageBody
111
+ # body_type: MessageBodyType - # # Type of the message body content.
112
+ # name: String - # # Function or event name.
113
+ # value: Value<Optional> - # # Parameters or result value.
114
+ # header: FunctionHeader<Optional> - # # Function header.
38
115
  def decode_message_body(payload, &block)
39
116
  core.requestLibrary(context: context.id, method_name: full_method_name(MODULE, __method__.to_s), payload: payload, &block)
40
117
  end
41
118
 
119
+ # INPUT: ParamsOfEncodeAccount
120
+ # state_init: StateInitSource - # # Source of the account state init.
121
+ # balance: BigInt<Optional> - # # Initial balance.
122
+ # last_trans_lt: BigInt<Optional> - # # Initial value for the `last_trans_lt`.
123
+ # last_paid: Number<Optional> - # # Initial value for the `last_paid`.
124
+ # boc_cache: BocCacheType<Optional> - # # Cache type to put the result. # # The BOC itself returned if no cache type provided
125
+ # RESPONSE: ResultOfEncodeAccount
126
+ # account: String - # # Account BOC encoded in `base64`.
127
+ # id: String - # # Account ID encoded in `hex`.
42
128
  def encode_account(payload, &block)
43
129
  core.requestLibrary(context: context.id, method_name: full_method_name(MODULE, __method__.to_s), payload: payload, &block)
44
130
  end
131
+
45
132
  end
46
133
  end
47
134
 
48
-
49
-
50
-
51
-
52
-