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.
- checksums.yaml +4 -4
- data/lib/mixin_bot/api/address.rb +21 -0
- data/lib/mixin_bot/api/app.rb +5 -11
- data/lib/mixin_bot/api/asset.rb +9 -16
- data/lib/mixin_bot/api/attachment.rb +27 -22
- data/lib/mixin_bot/api/auth.rb +34 -56
- data/lib/mixin_bot/api/blaze.rb +4 -3
- data/lib/mixin_bot/api/conversation.rb +29 -49
- data/lib/mixin_bot/api/encrypted_message.rb +19 -19
- data/lib/mixin_bot/api/inscription.rb +71 -0
- data/lib/mixin_bot/api/legacy_collectible.rb +140 -0
- data/lib/mixin_bot/api/legacy_multisig.rb +87 -0
- data/lib/mixin_bot/api/legacy_output.rb +50 -0
- data/lib/mixin_bot/api/legacy_payment.rb +31 -0
- data/lib/mixin_bot/api/legacy_snapshot.rb +39 -0
- data/lib/mixin_bot/api/legacy_transaction.rb +173 -0
- data/lib/mixin_bot/api/legacy_transfer.rb +42 -0
- data/lib/mixin_bot/api/me.rb +13 -17
- data/lib/mixin_bot/api/message.rb +13 -10
- data/lib/mixin_bot/api/multisig.rb +17 -222
- data/lib/mixin_bot/api/output.rb +48 -0
- data/lib/mixin_bot/api/payment.rb +9 -20
- data/lib/mixin_bot/api/pin.rb +57 -65
- data/lib/mixin_bot/api/rpc.rb +12 -14
- data/lib/mixin_bot/api/snapshot.rb +15 -29
- data/lib/mixin_bot/api/tip.rb +43 -0
- data/lib/mixin_bot/api/transaction.rb +295 -60
- data/lib/mixin_bot/api/transfer.rb +69 -31
- data/lib/mixin_bot/api/user.rb +88 -53
- data/lib/mixin_bot/api/withdraw.rb +52 -53
- data/lib/mixin_bot/api.rb +81 -46
- data/lib/mixin_bot/cli/api.rb +149 -5
- data/lib/mixin_bot/cli/utils.rb +14 -4
- data/lib/mixin_bot/cli.rb +13 -10
- data/lib/mixin_bot/client.rb +74 -127
- data/lib/mixin_bot/configuration.rb +98 -0
- data/lib/mixin_bot/nfo.rb +174 -0
- data/lib/mixin_bot/transaction.rb +524 -0
- data/lib/mixin_bot/utils/address.rb +121 -0
- data/lib/mixin_bot/utils/crypto.rb +218 -0
- data/lib/mixin_bot/utils/decoder.rb +56 -0
- data/lib/mixin_bot/utils/encoder.rb +63 -0
- data/lib/mixin_bot/utils.rb +8 -109
- data/lib/mixin_bot/uuid.rb +41 -0
- data/lib/mixin_bot/version.rb +1 -1
- data/lib/mixin_bot.rb +39 -14
- data/lib/mvm/bridge.rb +2 -19
- data/lib/mvm/client.rb +11 -33
- data/lib/mvm/nft.rb +4 -4
- data/lib/mvm/registry.rb +9 -9
- data/lib/mvm/scan.rb +3 -5
- data/lib/mvm.rb +5 -6
- metadata +77 -103
- data/lib/mixin_bot/api/collectible.rb +0 -138
- data/lib/mixin_bot/utils/nfo.rb +0 -176
- data/lib/mixin_bot/utils/transaction.rb +0 -478
- data/lib/mixin_bot/utils/uuid.rb +0 -43
data/lib/mixin_bot/utils/nfo.rb
DELETED
@@ -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
|
data/lib/mixin_bot/utils/uuid.rb
DELETED
@@ -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
|