mixin_bot 0.12.1 → 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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/lib/mixin_bot/api/address.rb +21 -0
  3. data/lib/mixin_bot/api/app.rb +5 -11
  4. data/lib/mixin_bot/api/asset.rb +9 -16
  5. data/lib/mixin_bot/api/attachment.rb +27 -22
  6. data/lib/mixin_bot/api/auth.rb +34 -56
  7. data/lib/mixin_bot/api/blaze.rb +4 -3
  8. data/lib/mixin_bot/api/conversation.rb +29 -49
  9. data/lib/mixin_bot/api/encrypted_message.rb +19 -19
  10. data/lib/mixin_bot/api/inscription.rb +71 -0
  11. data/lib/mixin_bot/api/legacy_collectible.rb +140 -0
  12. data/lib/mixin_bot/api/legacy_multisig.rb +87 -0
  13. data/lib/mixin_bot/api/legacy_output.rb +50 -0
  14. data/lib/mixin_bot/api/legacy_payment.rb +31 -0
  15. data/lib/mixin_bot/api/legacy_snapshot.rb +39 -0
  16. data/lib/mixin_bot/api/legacy_transaction.rb +173 -0
  17. data/lib/mixin_bot/api/legacy_transfer.rb +42 -0
  18. data/lib/mixin_bot/api/me.rb +13 -17
  19. data/lib/mixin_bot/api/message.rb +13 -10
  20. data/lib/mixin_bot/api/multisig.rb +17 -222
  21. data/lib/mixin_bot/api/output.rb +48 -0
  22. data/lib/mixin_bot/api/payment.rb +9 -20
  23. data/lib/mixin_bot/api/pin.rb +57 -65
  24. data/lib/mixin_bot/api/rpc.rb +12 -14
  25. data/lib/mixin_bot/api/snapshot.rb +15 -29
  26. data/lib/mixin_bot/api/tip.rb +43 -0
  27. data/lib/mixin_bot/api/transaction.rb +295 -60
  28. data/lib/mixin_bot/api/transfer.rb +69 -31
  29. data/lib/mixin_bot/api/user.rb +88 -53
  30. data/lib/mixin_bot/api/withdraw.rb +52 -53
  31. data/lib/mixin_bot/api.rb +81 -46
  32. data/lib/mixin_bot/cli/api.rb +149 -5
  33. data/lib/mixin_bot/cli/utils.rb +14 -4
  34. data/lib/mixin_bot/cli.rb +13 -10
  35. data/lib/mixin_bot/client.rb +74 -127
  36. data/lib/mixin_bot/configuration.rb +98 -0
  37. data/lib/mixin_bot/nfo.rb +174 -0
  38. data/lib/mixin_bot/transaction.rb +524 -0
  39. data/lib/mixin_bot/utils/address.rb +121 -0
  40. data/lib/mixin_bot/utils/crypto.rb +218 -0
  41. data/lib/mixin_bot/utils/decoder.rb +56 -0
  42. data/lib/mixin_bot/utils/encoder.rb +63 -0
  43. data/lib/mixin_bot/utils.rb +8 -109
  44. data/lib/mixin_bot/uuid.rb +41 -0
  45. data/lib/mixin_bot/version.rb +1 -1
  46. data/lib/mixin_bot.rb +39 -14
  47. data/lib/mvm/bridge.rb +2 -19
  48. data/lib/mvm/client.rb +11 -33
  49. data/lib/mvm/nft.rb +4 -4
  50. data/lib/mvm/registry.rb +9 -9
  51. data/lib/mvm/scan.rb +3 -5
  52. data/lib/mvm.rb +5 -6
  53. metadata +77 -103
  54. data/lib/mixin_bot/api/collectible.rb +0 -138
  55. data/lib/mixin_bot/utils/nfo.rb +0 -176
  56. data/lib/mixin_bot/utils/transaction.rb +0 -478
  57. data/lib/mixin_bot/utils/uuid.rb +0 -43
@@ -1,176 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module MixinBot
4
- module Utils
5
- class Nfo
6
- NFT_MEMO_PREFIX = 'NFO'
7
- NFT_MEMO_VERSION = 0x00
8
- NFT_MEMO_DEFAULT_CHAIN = '43d61dcd-e413-450d-80b8-101d5e903357'
9
- NFT_MEMO_DEFAULT_CLASS = '3c8c161a18ae2c8b14fda1216fff7da88c419b5d'
10
- NULL_UUID = '00000000-0000-0000-0000-000000000000'
11
-
12
- attr_reader :prefix, :version, :raw
13
- attr_accessor :mask, :chain, :nm_class, :collection, :token, :extra, :memo, :hex
14
-
15
- def initialize(**kwargs)
16
- @prefix = NFT_MEMO_PREFIX
17
- @version = NFT_MEMO_VERSION
18
- @mask = kwargs[:mask] || 0
19
- @chain = kwargs[:chain] || NFT_MEMO_DEFAULT_CHAIN
20
- @nm_class = kwargs[:nm_class] || NFT_MEMO_DEFAULT_CLASS
21
- @collection = kwargs[:collection] || NULL_UUID
22
- @token = kwargs[:token].presence&.to_i
23
- @extra = kwargs[:extra]
24
- @memo = kwargs[:memo]
25
- @hex = kwargs[:hex]
26
- end
27
-
28
- def mint_memo
29
- raise MixinBot::InvalidNfoFormatError, 'token is required' if token.blank?
30
- raise MixinBot::InvalidNfoFormatError, 'extra must be 256-bit string' if extra.blank? || extra.size != 64
31
-
32
- @collection = NULL_UUID if collection.blank?
33
- @chain = NFT_MEMO_DEFAULT_CHAIN
34
- @nm_class = NFT_MEMO_DEFAULT_CLASS
35
- mark 0
36
- encode
37
-
38
- memo
39
- end
40
-
41
- def unique_token_id
42
- bytes = []
43
- bytes += MixinBot::Utils::UUID.new(hex: chain).packed.bytes
44
- bytes += [nm_class].pack('H*').bytes
45
- bytes += MixinBot::Utils::UUID.new(hex: collection).packed.bytes
46
- bytes += MixinBot::Utils.bytes_of token
47
-
48
- md5 = Digest::MD5.new
49
- md5.update bytes.pack('c*')
50
- digest = [md5.hexdigest].pack('H*').bytes
51
-
52
- digest[6] = (digest[6] & 0x0f) | 0x30
53
- digest[8] = (digest[8] & 0x3f) | 0x80
54
-
55
- hex = digest.pack('c*').unpack1('H*')
56
-
57
- MixinBot::Utils::UUID.new(hex: hex).unpacked
58
- end
59
-
60
- def mark(*indexes)
61
- indexes.map do |index|
62
- raise ArgumentError, "invalid NFO memo index #{index}" if index >= 64 || index.negative?
63
-
64
- @mask = mask ^ (1 << index)
65
- end
66
- end
67
-
68
- def encode
69
- bytes = []
70
-
71
- bytes += prefix.bytes
72
- bytes += [version]
73
-
74
- if mask != 0
75
- bytes += [1]
76
- bytes += MixinBot::Utils.encode_unit_64 mask
77
- bytes += MixinBot::Utils::UUID.new(hex: chain).packed.bytes
78
-
79
- class_bytes = [nm_class].pack('H*').bytes
80
- bytes += MixinBot::Utils.bytes_of class_bytes.size
81
- bytes += class_bytes
82
-
83
- collection_bytes = collection.split('-').pack('H* H* H* H* H*').bytes
84
- bytes += MixinBot::Utils.bytes_of collection_bytes.size
85
- bytes += collection_bytes
86
-
87
- # token_bytes = memo[:token].split('-').pack('H* H* H* H* H*').bytes
88
- token_bytes = MixinBot::Utils.bytes_of token
89
- bytes += MixinBot::Utils.bytes_of token_bytes.size
90
- bytes += token_bytes
91
- else
92
- bytes += [0]
93
- end
94
-
95
- extra_bytes = [extra].pack('H*').bytes
96
- bytes += MixinBot::Utils.bytes_of extra_bytes.size
97
- bytes += extra_bytes
98
-
99
- @raw = bytes.pack('C*')
100
- @hex = raw.unpack1('H*')
101
- @memo = Base64.urlsafe_encode64 raw, padding: false
102
-
103
- self
104
- end
105
-
106
- def decode
107
- @raw =
108
- if memo.present?
109
- Base64.urlsafe_decode64 memo
110
- elsif hex.present?
111
- [hex].pack('H*')
112
- else
113
- raise InvalidNfoFormatError, 'memo or hex is required'
114
- end
115
-
116
- @hex = raw.unpack1('H*') if hex.blank?
117
- @memo = Base64.urlsafe_encode64 raw, padding: false if memo.blank?
118
-
119
- decode_bytes
120
- self
121
- end
122
-
123
- def decode_bytes
124
- bytes = raw.bytes
125
-
126
- _prefix = bytes.shift(3).pack('C*')
127
- raise MixinBot::InvalidNfoFormatError, "NFO prefix #{_prefix}" if _prefix != prefix
128
-
129
- _version = bytes.shift
130
- raise MixinBot::InvalidNfoFormatError, "NFO version #{prefix}" if _version != version
131
-
132
- hint = bytes.shift
133
- if hint == 1
134
- @mask = bytes.shift(8).reverse.pack('C*').unpack1('Q*')
135
-
136
- @chain = MixinBot::Utils::UUID.new(hex: bytes.shift(16).pack('C*').unpack1('H*')).unpacked
137
-
138
- class_length = bytes.shift
139
- @nm_class = bytes.shift(class_length).pack('C*').unpack1('H*')
140
-
141
- collection_length = bytes.shift
142
- @collection = MixinBot::Utils::UUID.new(hex: bytes.shift(collection_length).pack('C*').unpack1('H*')).unpacked
143
-
144
- token_length = bytes.shift
145
- @token = MixinBot::Utils.bytes_to_int bytes.shift(token_length)
146
- end
147
-
148
- extra_length = bytes.shift
149
- @extra = bytes.shift(extra_length).pack('C*').unpack1('H*')
150
-
151
- self
152
- end
153
-
154
- def to_h
155
- hash = {
156
- prefix: prefix,
157
- version: version,
158
- mask: mask,
159
- chain: chain,
160
- class: nm_class,
161
- collection: collection,
162
- token: token,
163
- extra: extra,
164
- memo: memo,
165
- hex: hex
166
- }
167
-
168
- hash.each do |key, value|
169
- hash.delete key if value.blank?
170
- end
171
-
172
- hash
173
- end
174
- end
175
- end
176
- end
@@ -1,478 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module MixinBot
4
- module Utils
5
- class Transaction
6
- DEAULT_VERSION = 2
7
- MAGIC = [0x77, 0x77]
8
- TX_VERSION = 2
9
- MAX_ENCODE_INT = 0xFFFF
10
- NULL_BYTES = [0x00, 0x00]
11
- AGGREGATED_SIGNATURE_PREFIX = 0xFF01
12
- AGGREGATED_SIGNATURE_ORDINAY_MASK = [0x00]
13
- AGGREGATED_SIGNATURE_SPARSE_MASK = [0x01]
14
-
15
- attr_accessor :version, :asset, :inputs, :outputs, :extra, :signatures, :aggregated, :hex, :hash
16
-
17
- def initialize(**kwargs)
18
- @version = kwargs[:version] || DEAULT_VERSION
19
- @asset = kwargs[:asset]
20
- @inputs = kwargs[:inputs]
21
- @outputs = kwargs[:outputs]
22
- @extra = kwargs[:extra]
23
- @hex = kwargs[:hex]
24
- @signatures = kwargs[:signatures]
25
- @aggregated = kwargs[:aggregated]
26
- end
27
-
28
- def encode
29
- raise InvalidTransactionFormatError, 'asset is required' if asset.blank?
30
- raise InvalidTransactionFormatError, 'inputs is required' if inputs.blank?
31
- raise InvalidTransactionFormatError, 'outputs is required' if outputs.blank?
32
-
33
- bytes = []
34
-
35
- # magic number
36
- bytes += MAGIC
37
-
38
- # version
39
- bytes += [0, version]
40
-
41
- # asset
42
- bytes += [asset].pack('H*').bytes
43
-
44
- # inputs
45
- bytes += encode_inputs
46
-
47
- # output
48
- bytes += encode_outputs
49
-
50
- # extra
51
- extra_bytes = [extra].pack('H*').bytes
52
- bytes += MixinBot::Utils.encode_int extra_bytes.size
53
- bytes += extra_bytes
54
-
55
- # aggregated
56
- if aggregated.nil?
57
- # signatures
58
- bytes += encode_signatures
59
- else
60
- bytes += encode_aggregated_signature
61
- end
62
-
63
- @hash = SHA3::Digest::SHA256.hexdigest bytes.pack('C*')
64
- @hex = bytes.pack('C*').unpack1('H*')
65
-
66
- self
67
- end
68
-
69
- def decode
70
- @bytes = [hex].pack('H*').bytes
71
- @hash = SHA3::Digest::SHA256.hexdigest @bytes.pack('C*')
72
-
73
- magic = @bytes.shift(2)
74
- raise ArgumentError, 'Not valid raw' unless magic == MAGIC
75
-
76
- version = @bytes.shift(2)
77
- @version = MixinBot::Utils.bytes_to_int version
78
-
79
- asset = @bytes.shift(32)
80
- @asset = asset.pack('C*').unpack1('H*')
81
-
82
- # read inputs
83
- decode_inputs
84
-
85
- # read outputs
86
- decode_outputs
87
-
88
- extra_size = @bytes.shift(2).reverse.pack('C*').unpack1('S*')
89
- @extra = @bytes.shift(extra_size).pack('C*').unpack1('H*')
90
-
91
- num = @bytes.shift(2).reverse.pack('C*').unpack1('S*')
92
- if num == MAX_ENCODE_INT
93
- # aggregated
94
- @aggregated = {}
95
-
96
- raise ArgumentError, 'invalid aggregated' unless @bytes.shift(2).reverse.pack('C*').unpack1('S*') == AGGREGATED_SIGNATURE_PREFIX
97
-
98
- @aggregated['signature'] = @bytes.shift(64).pack('C*').unpack1('H*')
99
-
100
- byte = @bytes.shift
101
- case byte
102
- when AGGREGATED_SIGNATURE_ORDINAY_MASK.first
103
- @aggregated['signers'] = []
104
- masks_size = @bytes.shift(2).reverse.pack('C*').unpack1('S*')
105
- masks = @bytes.shift(masks_size)
106
- masks = [masks] unless masks.is_a? Array
107
-
108
- masks.each_with_index do |mask, i|
109
- 8.times do |j|
110
- k = 1 << j
111
- aggregated['signers'].push(i * 8 + j) if mask & k == k
112
- end
113
- end
114
- when AGGREGATED_SIGNATURE_SPARSE_MASK.first
115
- signers_size = @bytes.shift(2).reverse.pack('C*').unpack1('S*')
116
- return if signers_size == 0
117
-
118
- aggregated['signers'] = []
119
- signers_size.times do
120
- aggregated['signers'].push @bytes.shift(2).reverse.pack('C*').unpack1('S*')
121
- end
122
- end
123
- else
124
- if !@bytes.empty? && @bytes[...2] != NULL_BYTES
125
- signatures_size = @bytes.shift(2).reverse.pack('C*').unpack1('S*')
126
- @signatures = @bytes.shift(signatures_size).pack('C*').unpack1('H*')
127
- end
128
- end
129
-
130
- self
131
- end
132
-
133
- def to_h
134
- {
135
- version: version,
136
- asset: asset,
137
- inputs: inputs,
138
- outputs: outputs,
139
- extra: extra,
140
- signatures: signatures,
141
- aggregated: aggregated,
142
- hash: hash
143
- }.compact
144
- end
145
-
146
- private
147
-
148
- def encode_inputs
149
- bytes = []
150
-
151
- bytes += MixinBot::Utils.encode_int(inputs.size)
152
-
153
- inputs.each do |input|
154
- bytes += [input['hash']].pack('H*').bytes
155
- bytes += MixinBot::Utils.encode_int(input['index'])
156
-
157
- # genesis
158
- genesis = input['genesis'] || ''
159
- if genesis.empty?
160
- bytes += NULL_BYTES
161
- else
162
- genesis_bytes = [genesis].pack('H*').bytes
163
- bytes += MixinBot::Utils.encode_int genesis_bytes.size
164
- bytes += genesis_bytes
165
- end
166
-
167
- # deposit
168
- deposit = input['deposit']
169
- if deposit.nil?
170
- bytes += NULL_BYTES
171
- else
172
- bytes += MAGIC
173
- bytes += [deposit['chain']].pack('H*').bytes
174
-
175
- asset_bytes = [deposit['asset']].pack('H*')
176
- bytes += MixinBot::Utils.encode_int asset_bytes.size
177
- bytes += asset_bytes
178
-
179
- transaction_bytes = [deposit['transaction']].pack('H*')
180
- bytes += MixinBot::Utils.encode_int transaction_bytes.size
181
- bytes += transaction_bytes
182
-
183
- bytes += MixinBot::Utils.encode_unit_64 deposit['index']
184
-
185
- amount_bytes = MixinBot::Utils.bytes_of deposit['amount']
186
- bytes += MixinBot::Utils.encode_int amount_bytes.size
187
- bytes += amount_bytes
188
- end
189
-
190
- # mint
191
- mint = input['mint']
192
- if mint.nil?
193
- bytes += NULL_BYTES
194
- else
195
- bytes += MAGIC
196
-
197
- # group
198
- group = mint['group'] || ''
199
- if group.empty?
200
- bytes += MixinBot::Utils.encode_int NULL_BYTES
201
- else
202
- group_bytes = [group].pack('H*')
203
- bytes += MixinBot::Utils.encode_int group_bytes.size
204
- bytes += group_bytes
205
- end
206
-
207
- bytes += MixinBot::Utils.encode_unit_64 mint['batch']
208
-
209
- amount_bytes = MixinBot::Utils.bytes_of mint['amount']
210
- bytes += MixinBot::Utils.encode_int amount_bytes.size
211
- bytes += amount_bytes
212
- end
213
- end
214
-
215
- bytes
216
- end
217
-
218
- def encode_outputs
219
- bytes = []
220
-
221
- bytes += MixinBot::Utils.encode_int outputs.size
222
-
223
- outputs.each do |output|
224
- type = output['type'] || 0
225
- bytes += [0x00, type]
226
-
227
- # amount
228
- amount_bytes = MixinBot::Utils.bytes_of (output['amount'].to_d * 1e8).round
229
- bytes += MixinBot::Utils.encode_int amount_bytes.size
230
- bytes += amount_bytes
231
-
232
- # keys
233
- bytes += MixinBot::Utils.encode_int output['keys'].size
234
- output['keys'].each do |key|
235
- bytes += [key].pack('H*').bytes
236
- end
237
-
238
- # mask
239
- bytes += [output['mask']].pack('H*').bytes
240
-
241
- # script
242
- script_bytes = [output['script']].pack('H*').bytes
243
- bytes += MixinBot::Utils.encode_int script_bytes.size
244
- bytes += script_bytes
245
-
246
- # withdrawal
247
- withdrawal = output['withdrawal']
248
- if withdrawal.nil?
249
- bytes += NULL_BYTES
250
- else
251
- bytes += MAGIC
252
-
253
- # chain
254
- bytes += [withdrawal['chain']].pack('H*').bytes
255
-
256
- # asset
257
- @asset_bytes = [withdrawal['asset']].pack('H*')
258
- bytes += MixinBot::Utils.encode_int asset_bytes.size
259
- bytes += asset_bytes
260
-
261
- # address
262
- address = withdrawal['address'] || ''
263
- if address.empty?
264
- bytes += NULL_BYTES
265
- else
266
- address_bytes = [address].pack('H*').bytes
267
- bytes += MixinBot::Utils.encode_int address.size
268
- bytes += address_bytes
269
- end
270
-
271
- # tag
272
- tag = withdrawal['tag'] || ''
273
- if tag.empty?
274
- bytes += NULL_BYTES
275
- else
276
- address_bytes = [tag].pack('H*').bytes
277
- bytes += MixinBot::Utils.encode_int tag.size
278
- bytes += address_bytes
279
- end
280
- end
281
- end
282
-
283
- bytes
284
- end
285
-
286
- def encode_aggregated_signature
287
- bytes = []
288
-
289
- bytes += MixinBot::Utils.encode_int MAX_ENCODE_INT
290
- bytes += MixinBot::Utils.encode_int AGGREGATED_SIGNATURE_PREFIX
291
- bytes += [aggregated['signature']].pack('H*').bytes
292
-
293
- signers = aggregated['signers']
294
- if signers.size == 0
295
- bytes += AGGREGATED_SIGNATURE_ORDINAY_MASK
296
- bytes += NULL_BYTES
297
- else
298
- signers.each do |sig, i|
299
- raise ArgumentError, 'signers not sorted' if i > 0 && sig <= signers[i - 1]
300
- raise ArgumentError, 'signers not sorted' if sig > MAX_ENCODE_INT
301
- end
302
-
303
- max = signers.last
304
- if (((max / 8 | 0) + 1 | 0) > aggregated['signature'].size * 2)
305
- bytes += AGGREGATED_SIGNATURE_SPARSE_MASK
306
- bytes += MixinBot::Utils.encode_int aggregated['signers'].size
307
- signers.map(&->(signer) { bytes += MixinBot::Utils.encode_int(signer) })
308
- end
309
-
310
- masks_bytes = Array.new(max / 8 + 1, 0)
311
- signers.each do |signer|
312
- masks[signer/8] = masks[signer/8] ^ (1 << (signer % 8))
313
- end
314
- bytes += AGGREGATED_SIGNATURE_ORDINAY_MASK
315
- bytes += MixinBot::Utils.encode_int masks_bytes.size
316
- bytes += masks_bytes
317
- end
318
-
319
- bytes
320
- end
321
-
322
- def encode_signatures
323
- bytes = []
324
-
325
- sl =
326
- if signatures.is_a? Hash
327
- signatures.keys.size
328
- else
329
- 0
330
- end
331
-
332
- raise ArgumentError, 'signatures overflow' if sl == MAX_ENCODE_INT
333
- bytes += MixinBot::Utils.encode_int sl
334
-
335
- if sl > 0
336
- bytes += MixinBot::Utils.encode_int signatures.keys.size
337
- signatures.keys.sort.each do |key|
338
- bytes += MixinBot::Utils.encode_int key
339
- bytes += [signatures[key]].pack('H*').bytes
340
- end
341
- end
342
-
343
- bytes
344
- end
345
-
346
- def decode_inputs
347
- inputs_size = @bytes.shift(2).reverse.pack('C*').unpack1('S*')
348
- @inputs = []
349
- inputs_size.times do
350
- input = {}
351
- hash = @bytes.shift(32)
352
- input['hash'] = hash.pack('C*').unpack1('H*')
353
-
354
- index = @bytes.shift(2)
355
- input['index'] = index.reverse.pack('C*').unpack1('S*')
356
-
357
- if @bytes[...2] != NULL_BYTES
358
- genesis_size = @bytes.shift(2).reverse.pack('C*').unpack1('S*')
359
- genesis = @bytes.shift(genesis_size)
360
- input['genesis'] = genesis.pack('C*').unpack1('H*')
361
- else
362
- @bytes.shift 2
363
- end
364
-
365
- if @bytes[...2] != NULL_BYTES
366
- magic = @bytes.shift(2)
367
- raise ArgumentError, 'Not valid input' unless magic == MAGIC
368
-
369
- deposit = {}
370
- deposit['chain'] = @bytes.shift(32).pack('C*').unpack1('H*')
371
-
372
- asset_size = @bytes.shift(2).reverse.pack('C*').unpack1('S*')
373
- deposit['asset'] = @bytes.shift(asset_size).unpack1('H*')
374
-
375
- transaction_size = @bytes.shift(2).reverse.pack('C*').unpack1('S*')
376
- deposit['transaction'] = @bytes.shift(transaction_size).unpack1('H*')
377
-
378
- deposit['index'] = @bytes.shift(8).reverse.pack('C*').unpack1('Q*')
379
-
380
- amount_size = @bytes.shift(2).reverse.pack('C*').unpack1('S*')
381
- deposit['amount'] = MixinBot::Utils.bytes_to_int @bytes.shift(amount_size)
382
-
383
- input['deposit'] = deposit
384
- else
385
- @bytes.shift 2
386
- end
387
-
388
- if @bytes[...2] != NULL_BYTES
389
- magic = @bytes.shift(2)
390
- raise ArgumentError, 'Not valid input' unless magic == MAGIC
391
-
392
- mint = {}
393
- if bytes[...2] != NULL_BYTES
394
- group_size = @bytes.shift(2).reverse.pack('C*').unpack1('S*')
395
- mint['group'] = @bytes.shift(group_size).unpack1('H*')
396
- else
397
- @bytes.shift 2
398
- end
399
-
400
- mint['batch'] = @bytes.shift(8).reverse.pack('C*').unpack1('Q*')
401
- _amount_size = @bytes.shift(2).reverse.pack('C*').unpack1('S*')
402
- mint['amount'] = MixinBot::Utils.bytes_to_int bytes.shift(_amount_size)
403
-
404
- input['mint'] = mint
405
- else
406
- @bytes.shift 2
407
- end
408
-
409
- @inputs.push input
410
- end
411
-
412
- self
413
- end
414
-
415
- def decode_outputs
416
- outputs_size = @bytes.shift(2).reverse.pack('C*').unpack1('S*')
417
- @outputs = []
418
- outputs_size.times do
419
- output = {}
420
-
421
- @bytes.shift
422
- type = @bytes.shift
423
- output['type'] = type
424
-
425
- amount_size = @bytes.shift(2).reverse.pack('C*').unpack1('S*')
426
- output['amount'] = format('%.8f', MixinBot::Utils.bytes_to_int(@bytes.shift(amount_size)).to_f / 1e8)
427
-
428
- output['keys'] = []
429
- keys_size = @bytes.shift(2).reverse.pack('C*').unpack1('S*')
430
- keys_size.times do
431
- output['keys'].push @bytes.shift(32).pack('C*').unpack1('H*')
432
- end
433
-
434
- output['mask'] = @bytes.shift(32).pack('C*').unpack1('H*')
435
-
436
- script_size = @bytes.shift(2).reverse.pack('C*').unpack1('S*')
437
- output['script'] = @bytes.shift(script_size).pack('C*').unpack1('H*')
438
-
439
- if @bytes[...2] != NULL_BYTES
440
- magic = @bytes.shift(2)
441
- raise ArgumentError, 'Not valid output' unless magic == MAGIC
442
-
443
- withdraw = {}
444
-
445
- output['chain'] = @bytes.shift(32).pack('C*').unpack1('H*')
446
-
447
- asset_size = @bytes.shift(2).reverse.pack('C*').unpack1('S*')
448
- output['asset'] = @bytes.shift(asset_size).unpack1('H*')
449
-
450
- if @bytes[...2] != NULL_BYTES
451
- address = {}
452
-
453
- adderss_size = @bytes.shift(2).reverse.pack('C*').unpack1('S*')
454
- output['adderss'] = @bytes.shift(adderss_size).pack('C*').unpack1('H*')
455
- else
456
- @bytes.shift 2
457
- end
458
-
459
- if @bytes[...2] != NULL_BYTES
460
- tag = {}
461
-
462
- tag_size = @bytes.shift(2).reverse.pack('C*').unpack1('S*')
463
- output['tag'] = @bytes.shift(tag_size).pack('C*').unpack1('H*')
464
- else
465
- @bytes.shift 2
466
- end
467
- else
468
- @bytes.shift 2
469
- end
470
-
471
- @outputs.push output
472
- end
473
-
474
- self
475
- end
476
- end
477
- end
478
- end
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module MixinBot
4
- module Utils
5
- class UUID
6
- attr_accessor :hex, :raw
7
-
8
- def initialize(**args)
9
- @hex = args[:hex]
10
- @raw = args[:raw]
11
-
12
- raise MixinBot::InvalidUuidFormatError if raw.present? && raw.size != 16
13
- raise MixinBot::InvalidUuidFormatError if hex.present? && hex.gsub('-', '').size != 32
14
- end
15
-
16
- def packed
17
- if raw.present?
18
- raw
19
- elsif hex.present?
20
- [hex.gsub('-', '')].pack('H*')
21
- end
22
- end
23
-
24
- def unpacked
25
- _hex =
26
- if hex.present?
27
- hex.gsub('-', '')
28
- elsif raw.present?
29
- _hex = raw.unpack1('H*')
30
- end
31
-
32
- format(
33
- '%<first>s-%<second>s-%<third>s-%<forth>s-%<fifth>s',
34
- first: _hex[0..7],
35
- second: _hex[8..11],
36
- third: _hex[12..15],
37
- forth: _hex[16..19],
38
- fifth: _hex[20..]
39
- )
40
- end
41
- end
42
- end
43
- end