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
@@ -10,10 +10,10 @@ module MixinBot
10
10
 
11
11
  def acknowledge_message_receipt(message_id)
12
12
  params = {
13
- message_id: message_id,
13
+ message_id:,
14
14
  status: 'READ'
15
15
  }
16
- write_ws_message(action: 'ACKNOWLEDGE_MESSAGE_RECEIPT', params: params)
16
+ write_ws_message(action: 'ACKNOWLEDGE_MESSAGE_RECEIPT', params:)
17
17
  end
18
18
 
19
19
  def plain_text(options)
@@ -72,7 +72,7 @@ module MixinBot
72
72
  options.merge!(
73
73
  category: 'MESSAGE_RECALL',
74
74
  data: {
75
- message_id: message_id
75
+ message_id:
76
76
  }
77
77
  )
78
78
  base_message_params(options)
@@ -90,11 +90,11 @@ module MixinBot
90
90
  quote_message_id: options[:quote_message_id],
91
91
  message_id: options[:message_id] || SecureRandom.uuid,
92
92
  data: Base64.encode64(data)
93
- }
93
+ }.compact
94
94
  end
95
95
 
96
96
  # read the gzipped message form websocket
97
- def read_ws_message(data)
97
+ def ws_message(data)
98
98
  io = StringIO.new(data.pack('c*'), 'rb')
99
99
  gzip = Zlib::GzipReader.new io
100
100
  msg = gzip.read
@@ -107,8 +107,8 @@ module MixinBot
107
107
  def write_ws_message(params:, action: 'CREATE_MESSAGE')
108
108
  msg = {
109
109
  id: SecureRandom.uuid,
110
- action: action,
111
- params: params
110
+ action:,
111
+ params:
112
112
  }.to_json
113
113
 
114
114
  io = StringIO.new 'wb'
@@ -158,9 +158,12 @@ module MixinBot
158
158
  # http post request
159
159
  def send_message(payload)
160
160
  path = '/messages'
161
- access_token ||= access_token('POST', path, payload.to_json)
162
- authorization = format('Bearer %<access_token>s', access_token: access_token)
163
- client.post(path, headers: { 'Authorization': authorization }, json: payload)
161
+
162
+ if payload.is_a? Hash
163
+ client.post path, **payload
164
+ elsif payload.is_a? Array
165
+ client.post path, *payload
166
+ end
164
167
  end
165
168
  end
166
169
  end
@@ -3,241 +3,36 @@
3
3
  module MixinBot
4
4
  class API
5
5
  module Multisig
6
- def outputs(**kwargs)
7
- limit = kwargs[:limit] || 100
8
- offset = kwargs[:offset] || ''
9
- state = kwargs[:state] || ''
10
- members = kwargs[:members] || []
11
- threshold = kwargs[:threshold] || ''
12
- access_token = kwargs[:access_token]
13
- members = SHA3::Digest::SHA256.hexdigest(members&.sort&.join)
6
+ def create_safe_multisig_request(request_id, raw, access_token: nil)
7
+ path = '/safe/multisigs'
8
+ payload = [{
9
+ request_id:,
10
+ raw:
11
+ }]
14
12
 
15
- path = format(
16
- '/multisigs/outputs?limit=%<limit>s&offset=%<offset>s&state=%<state>s&members=%<members>s&threshold=%<threshold>s',
17
- limit: limit,
18
- offset: offset,
19
- state: state,
20
- members: members,
21
- threshold: threshold
22
- )
23
- access_token ||= access_token('GET', path, '')
24
- authorization = format('Bearer %<access_token>s', access_token: access_token)
25
- client.get(path, headers: { 'Authorization': authorization })
13
+ client.post path, *payload, access_token:
26
14
  end
27
- alias multisigs outputs
28
- alias multisig_outputs outputs
29
15
 
30
- def create_output(receivers:, index:, hint: nil, access_token: nil)
31
- path = '/outputs'
32
- payload = {
33
- receivers: receivers,
34
- index: index,
35
- hint: hint
36
- }
37
- access_token ||= access_token('POST', path, payload.to_json)
38
- authorization = format('Bearer %<access_token>s', access_token: access_token)
39
- client.post(path, headers: { 'Authorization': authorization }, json: payload)
40
- end
41
-
42
- MULTISIG_REQUEST_ACTIONS = %i[sign unlock].freeze
43
- def create_multisig_request(action, raw, access_token: nil)
44
- raise ArgumentError, "request action is limited in #{MULTISIG_REQUEST_ACTIONS.join(', ')}" unless MULTISIG_REQUEST_ACTIONS.include? action.to_sym
45
-
46
- path = '/multisigs/requests'
47
- payload = {
48
- action: action,
49
- raw: raw
50
- }
51
- access_token ||= access_token('POST', path, payload.to_json)
52
- authorization = format('Bearer %<access_token>s', access_token: access_token)
53
- client.post(path, headers: { 'Authorization': authorization }, json: payload)
54
- end
55
-
56
- # transfer from the multisig address
57
- def create_sign_multisig_request(raw, access_token: nil)
58
- create_multisig_request 'sign', raw, access_token: access_token
59
- end
60
-
61
- # transfer from the multisig address
62
- # create a request for unlock a multi-sign
63
- def create_unlock_multisig_request(raw, access_token: nil)
64
- create_multisig_request 'unlock', raw, access_token: access_token
65
- end
66
-
67
- def sign_multisig_request(request_id, pin)
68
- path = format('/multisigs/requests/%<request_id>s/sign', request_id: request_id)
69
- payload = {
70
- pin: encrypt_pin(pin)
71
- }
72
- access_token ||= access_token('POST', path, payload.to_json)
73
- authorization = format('Bearer %<access_token>s', access_token: access_token)
74
- client.post(path, headers: { 'Authorization': authorization }, json: payload)
75
- end
76
-
77
- def unlock_multisig_request(request_id, pin)
78
- path = format('/multisigs/requests/%<request_id>s/unlock', request_id: request_id)
79
- payload = {
80
- pin: encrypt_pin(pin)
81
- }
82
- access_token ||= access_token('POST', path, payload.to_json)
83
- authorization = format('Bearer %<access_token>s', access_token: access_token)
84
- client.post(path, headers: { 'Authorization': authorization }, json: payload)
85
- end
86
-
87
- def cancel_multisig_request(request_id, pin)
88
- path = format('/multisigs/requests/%<request_id>s/cancel', request_id: request_id)
89
- payload = {
90
- pin: encrypt_pin(pin)
91
- }
92
- access_token ||= access_token('POST', path, payload.to_json)
93
- authorization = format('Bearer %<access_token>s', access_token: access_token)
94
- client.post(path, headers: { 'Authorization': authorization }, json: payload)
95
- end
16
+ def sign_safe_multisig_request(request_id, raw, access_token: nil)
17
+ path = format('/safe/multisigs/%<request_id>s/sign', request_id:)
96
18
 
97
- # pay to the multisig address
98
- # used for create multisig payment code_id
99
- def create_payment(**kwargs)
100
- path = '/payments'
101
19
  payload = {
102
- asset_id: kwargs[:asset_id],
103
- amount: format('%.8f', kwargs[:amount].to_d.to_r),
104
- trace_id: kwargs[:trace_id] || SecureRandom.uuid,
105
- memo: kwargs[:memo],
106
- opponent_multisig: {
107
- receivers: kwargs[:receivers],
108
- threshold: kwargs[:threshold]
109
- }
20
+ raw:
110
21
  }
111
- access_token = kwargs[:access_token]
112
- access_token ||= access_token('POST', path, payload.to_json)
113
- authorization = format('Bearer %<access_token>s', access_token: access_token)
114
- client.post(path, headers: { 'Authorization': authorization }, json: payload)
115
- end
116
- alias create_multisig_payment create_payment
117
22
 
118
- def verify_multisig(code_id, access_token: nil)
119
- path = format('/codes/%<code_id>s', code_id: code_id)
120
- access_token ||= access_token('GET', path, '')
121
- authorization = format('Bearer %<access_token>s', access_token: access_token)
122
- client.get(path, headers: { 'Authorization': authorization })
23
+ client.post path, **payload, access_token:
123
24
  end
124
25
 
125
- def build_threshold_script(threshold)
126
- s = threshold.to_s(16)
127
- s = s.length == 1 ? "0#{s}" : s
128
- raise 'NVALID THRESHOLD' if s.length > 2
26
+ def unlock_safe_multisig_request(request_id, access_token: nil)
27
+ path = format('/safe/multisigs/%<request_id>s/unlock', request_id:)
129
28
 
130
- "fffe#{s}"
29
+ client.post path, access_token:
131
30
  end
132
31
 
133
- # kwargs:
134
- # {
135
- # senders: [ uuid ],
136
- # senders_threshold: integer,
137
- # receivers: [ uuid ],
138
- # receivers_threshold: integer,
139
- # asset_id: uuid,
140
- # amount: string / float,
141
- # memo: string,
142
- # }
143
- RAW_TRANSACTION_ARGUMENTS = %i[utxos senders senders_threshold receivers receivers_threshold amount].freeze
144
- def build_raw_transaction(**kwargs)
145
- raise ArgumentError, "#{RAW_TRANSACTION_ARGUMENTS.join(', ')} are needed for build raw transaction" unless RAW_TRANSACTION_ARGUMENTS.all? { |param| kwargs.keys.include? param }
146
-
147
- senders = kwargs[:senders]
148
- senders_threshold = kwargs[:senders_threshold]
149
- receivers = kwargs[:receivers]
150
- receivers_threshold = kwargs[:receivers_threshold]
151
- amount = kwargs[:amount]
152
- asset_id = kwargs[:asset_id]
153
- asset_mixin_id = kwargs[:asset_mixin_id]
154
- utxos = kwargs[:utxos]
155
- memo = kwargs[:memo]
156
- extra = kwargs[:extra]
157
- access_token = kwargs[:access_token]
158
- outputs = kwargs[:outputs] || []
159
- hint = kwargs[:hint]
160
-
161
- raise 'access_token required!' if access_token.nil? && !senders.include?(client_id)
162
-
163
- amount = amount.to_d.round(8)
164
- input_amount = utxos.map(
165
- &lambda { |utxo|
166
- utxo['amount'].to_d
167
- }
168
- ).sum
169
-
170
- if input_amount < amount
171
- raise format(
172
- 'not enough amount! %<input_amount>s < %<amount>s',
173
- input_amount: input_amount,
174
- amount: amount
175
- )
176
- end
177
-
178
- inputs = utxos.map(
179
- &lambda { |utx|
180
- {
181
- 'hash' => utx['transaction_hash'],
182
- 'index' => utx['output_index']
183
- }
184
- }
185
- )
186
-
187
- if outputs.empty?
188
- receivers_threshold = 1 if receivers.size == 1
189
- output0 = build_output(
190
- receivers: receivers,
191
- index: 0,
192
- amount: amount,
193
- threshold: receivers_threshold,
194
- hint: hint
195
- )
196
- outputs.push output0
197
-
198
- if input_amount > amount
199
- output1 = build_output(
200
- receivers: senders,
201
- index: 1,
202
- amount: input_amount - amount,
203
- threshold: senders_threshold,
204
- hint: hint
205
- )
206
- outputs.push output1
207
- end
208
- end
209
-
210
- extra ||= Digest.hexencode(memo.to_s.slice(0, 140))
211
- asset = asset_mixin_id || SHA3::Digest::SHA256.hexdigest(asset_id)
212
- tx = {
213
- version: 2,
214
- asset: asset,
215
- inputs: inputs,
216
- outputs: outputs,
217
- extra: extra
218
- }
219
-
220
- tx.to_json
221
- end
222
-
223
- def build_output(receivers:, index:, amount:, threshold:, hint: nil)
224
- _output = create_output receivers: receivers, index: index, hint: hint
225
- {
226
- amount: format('%.8f', amount.to_d.to_r),
227
- script: build_threshold_script(threshold),
228
- mask: _output['mask'],
229
- keys: _output['keys']
230
- }
231
- end
232
-
233
- def str_to_bin(str)
234
- return if str.nil?
235
-
236
- str.scan(/../).map(&:hex).pack('c*')
237
- end
32
+ def safe_multisig_request(request_id, access_token: nil)
33
+ path = format('/safe/multisigs/%<request_id>s', request_id:)
238
34
 
239
- def generate_trace_from_hash(hash, output_index = 0)
240
- MixinBot::Utils.generate_trace_from_hash hash, output_index
35
+ client.get path, access_token:
241
36
  end
242
37
  end
243
38
  end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MixinBot
4
+ class API
5
+ module Output
6
+ def build_threshold_script(threshold)
7
+ s = threshold.to_s(16)
8
+ s = "0#{s}" if s.length == 1
9
+ raise 'NVALID THRESHOLD' if s.length > 2
10
+
11
+ "fffe#{s}"
12
+ end
13
+
14
+ def safe_outputs(**kwargs)
15
+ asset = kwargs[:asset] || kwargs[:asset_id]
16
+ limit = kwargs[:limit] || 500
17
+ offset = kwargs[:offset] || ''
18
+ state = kwargs[:state] || ''
19
+ access_token = kwargs[:access_token]
20
+ order = kwargs[:order] || 'ASC'
21
+ members = kwargs[:members].presence || [config.app_id]
22
+ threshold = kwargs[:threshold] || members.length
23
+
24
+ members_hash = SHA3::Digest::SHA256.hexdigest(members&.sort&.join)
25
+
26
+ path = '/safe/outputs'
27
+ params = {
28
+ asset:,
29
+ limit:,
30
+ offset:,
31
+ state:,
32
+ members: members_hash,
33
+ threshold:,
34
+ order:
35
+ }.compact
36
+
37
+ client.get path, **params, access_token:
38
+ end
39
+ alias outputs safe_outputs
40
+
41
+ def safe_output(id, access_token: nil)
42
+ path = format('/safe/outputs/%<id>s', id:)
43
+ client.get path, access_token:
44
+ end
45
+ alias output safe_output
46
+ end
47
+ end
48
+ end
@@ -3,28 +3,17 @@
3
3
  module MixinBot
4
4
  class API
5
5
  module Payment
6
- def pay_url(options)
7
- format(
8
- 'https://mixin.one/pay?recipient=%<recipient_id>s&asset=%<asset>s&amount=%<amount>s&trace=%<trace>s&memo=%<memo>s',
9
- recipient_id: options[:recipient_id],
10
- asset: options[:asset_id],
11
- amount: options[:amount].to_s,
12
- trace: options[:trace],
13
- memo: options[:memo]
14
- )
15
- end
6
+ def safe_pay_url(**kwargs)
7
+ members = kwargs[:members]
8
+ threshold = kwargs[:threshold]
9
+ asset_id = kwargs[:asset_id]
10
+ amount = kwargs[:amount]
11
+ memo = kwargs[:memo] || ''
12
+ trace_id = kwargs[:trace_id] || SecureRandom.uuid
16
13
 
17
- # https://developers.mixin.one/api/alpha-mixin-network/verify-payment/
18
- def verify_payment(options)
19
- path = 'payments'
20
- payload = {
21
- asset_id: options[:asset_id],
22
- opponent_id: options[:opponent_id],
23
- amount: options[:amount].to_s,
24
- trace_id: options[:trace]
25
- }
14
+ mix_address = MixinBot.utils.build_mix_address(members, threshold)
26
15
 
27
- client.post(path, json: payload)
16
+ "https://mixin.one/pay/#{mix_address}?amount=#{amount}&asset=#{asset_id}&memo=#{memo}&trace=#{trace_id}"
28
17
  end
29
18
  end
30
19
  end
@@ -4,89 +4,81 @@ module MixinBot
4
4
  class API
5
5
  module Pin
6
6
  # https://developers.mixin.one/api/alpha-mixin-network/verify-pin/
7
- def verify_pin(pin_code)
7
+ def verify_pin(pin = nil)
8
+ pin ||= MixinBot.config.pin
9
+ raise ArgumentError, 'invalid pin' if pin.blank?
10
+
8
11
  path = '/pin/verify'
9
- payload = {
10
- pin: encrypt_pin(pin_code)
11
- }
12
12
 
13
- access_token = access_token('POST', path, payload.to_json)
14
- authorization = format('Bearer %<access_token>s', access_token: access_token)
15
- client.post(path, headers: { 'Authorization': authorization }, json: payload)
13
+ payload =
14
+ if pin.length > 6
15
+ timestamp = (Time.now.utc.to_f * 1e9).to_i
16
+ pin_base64 = encrypt_tip_pin pin, 'TIP:VERIFY:', timestamp.to_s.rjust(32, '0')
17
+
18
+ {
19
+ pin_base64:,
20
+ timestamp:
21
+ }
22
+ else
23
+ {
24
+ pin: MixinBot.utils.encrypt_pin(pin)
25
+ }
26
+ end
27
+
28
+ client.post path, **payload
16
29
  end
17
30
 
18
31
  # https://developers.mixin.one/api/alpha-mixin-network/create-pin/
19
- def update_pin(old_pin:, pin:)
32
+ def update_pin(pin:, old_pin: nil)
33
+ old_pin ||= MixinBot.config.pin
34
+ raise ArgumentError, 'invalid old pin' if old_pin.present? && old_pin.length != 6
35
+
20
36
  path = '/pin/update'
21
37
  encrypted_old_pin = old_pin.nil? ? '' : encrypt_pin(old_pin, iterator: Time.now.utc.to_i)
38
+
22
39
  encrypted_pin = encrypt_pin(pin, iterator: Time.now.utc.to_i + 1)
23
40
  payload = {
24
- old_pin: encrypted_old_pin,
25
- pin: encrypted_pin
41
+ old_pin_base64: encrypted_old_pin,
42
+ pin_base64: encrypted_pin
26
43
  }
27
44
 
28
- access_token = access_token('POST', path, payload.to_json)
29
- authorization = format('Bearer %<access_token>s', access_token: access_token)
30
- client.post(path, headers: { 'Authorization': authorization }, json: payload)
45
+ client.post path, **payload
31
46
  end
32
47
 
33
- # decrypt the encrpted pin, just for test
34
- def decrypt_pin(msg)
35
- msg = Base64.strict_decode64 msg
36
- iv = msg[0..15]
37
- cipher = msg[16..47]
38
- alg = 'AES-256-CBC'
39
- decode_cipher = OpenSSL::Cipher.new(alg)
40
- decode_cipher.decrypt
41
- decode_cipher.iv = iv
42
- decode_cipher.key = _generate_aes_key
43
- decoded = decode_cipher.update(cipher)
44
- decoded[0..5]
48
+ def prepare_tip_key(counter = 0)
49
+ ed25519_key = JOSE::JWA::Ed25519.keypair
50
+
51
+ private_key = ed25519_key[1].unpack1('H*')
52
+ public_key = (ed25519_key[0].bytes + MixinBot::Utils.encode_uint64(counter + 1)).pack('c*').unpack1('H*')
53
+
54
+ {
55
+ private_key:,
56
+ public_key:
57
+ }
45
58
  end
46
59
 
47
- # https://developers.mixin.one/api/alpha-mixin-network/encrypted-pin/
48
- # use timestamp(timestamp) for iterator as default: must be bigger than the previous, the first time must be greater than 0. After a new session created, it will be reset to 0.
49
- def encrypt_pin(pin_code, iterator: nil)
50
- iterator ||= Time.now.utc.to_i
51
- tszero = iterator % 0x100
52
- tsone = (iterator % 0x10000) >> 8
53
- tstwo = (iterator % 0x1000000) >> 16
54
- tsthree = (iterator % 0x100000000) >> 24
55
- tsstring = "#{tszero.chr}#{tsone.chr}#{tstwo.chr}#{tsthree.chr}\u0000\u0000\u0000\u0000"
56
- encrypt_content = pin_code + tsstring + tsstring
57
- pad_count = 16 - encrypt_content.length % 16
58
- padded_content =
59
- if pad_count.positive?
60
- encrypt_content + pad_count.chr * pad_count
61
- else
62
- encrypt_content
63
- end
60
+ def encrypt_pin(pin, iterator: nil)
61
+ MixinBot.utils.encrypt_pin(pin, iterator:, shared_key: generate_shared_key_with_server)
62
+ end
64
63
 
65
- alg = 'AES-256-CBC'
66
- aes = OpenSSL::Cipher.new(alg)
67
- iv = OpenSSL::Cipher.new(alg).random_iv
68
- aes.encrypt
69
- aes.key = _generate_aes_key
70
- aes.iv = iv
71
- cipher = aes.update(padded_content)
72
- msg = iv + cipher
73
- Base64.strict_encode64 msg
64
+ def decrypt_pin(msg)
65
+ MixinBot.utils.decrypt_pin msg, shared_key: generate_shared_key_with_server
74
66
  end
75
- end
76
67
 
77
- def _generate_aes_key
78
- if pin_token.size == 32
79
- JOSE::JWA::X25519.x25519(
80
- JOSE::JWA::Ed25519.secret_to_curve25519(private_key[0..31]),
81
- pin_token
82
- )
83
- else
84
- JOSE::JWA::PKCS1.rsaes_oaep_decrypt(
85
- 'SHA256',
86
- pin_token,
87
- OpenSSL::PKey::RSA.new(private_key),
88
- session_id
89
- )
68
+ def generate_shared_key_with_server
69
+ if config.server_public_key.size == 32
70
+ JOSE::JWA::X25519.x25519(
71
+ config.session_private_key_curve25519,
72
+ config.server_public_key_curve25519
73
+ )
74
+ else
75
+ JOSE::JWA::PKCS1.rsaes_oaep_decrypt(
76
+ 'SHA256',
77
+ config.server_public_key,
78
+ OpenSSL::PKey::RSA.new(config.session_private_key),
79
+ session_id
80
+ )
81
+ end
90
82
  end
91
83
  end
92
84
  end
@@ -6,42 +6,40 @@ module MixinBot
6
6
  def rpc_proxy(method, params = [], access_token: nil)
7
7
  path = '/external/proxy'
8
8
  payload = {
9
- method: method,
10
- params: params
9
+ method:,
10
+ params:
11
11
  }
12
12
 
13
- access_token ||= access_token('POST', path, payload.to_json)
14
- authorization = format('Bearer %<access_token>s', access_token: access_token)
15
- client.post(path, headers: { 'Authorization': authorization }, json: payload)
13
+ client.post path, **payload, access_token:
16
14
  end
17
15
 
18
16
  # send a signed transaction to main net
19
17
  def send_raw_transaction(raw, access_token: nil)
20
- rpc_proxy('sendrawtransaction', [raw], access_token: access_token)
18
+ rpc_proxy('sendrawtransaction', [raw], access_token:)
21
19
  end
22
20
 
23
21
  def get_transaction(hash, access_token: nil)
24
- rpc_proxy('gettransaction', [hash], access_token: nil)
22
+ rpc_proxy('gettransaction', [hash], access_token:)
25
23
  end
26
24
 
27
25
  def get_utxo(hash, index = 0, access_token: nil)
28
- rpc_proxy 'getutxo', [hash, index], access_token: access_token
26
+ rpc_proxy 'getutxo', [hash, index], access_token:
29
27
  end
30
28
 
31
29
  def get_snapshot(hash, access_token: nil)
32
- rpc_proxy 'getsnapshot', [hash], access_token: access_token
30
+ rpc_proxy 'getsnapshot', [hash], access_token:
33
31
  end
34
32
 
35
- def list_snapshots(offset = 0, count = 10, sig = false, tx = false, access_token: nil)
36
- rpc_proxy 'listsnapshots', [offset, count, sig, tx], access_token: access_token
33
+ def list_snapshots(offset = 0, count = 10, sig: false, txn: false, access_token: nil)
34
+ rpc_proxy 'listsnapshots', [offset, count, sig, txn], access_token:
37
35
  end
38
36
 
39
37
  def list_mint_works(offset = 0, access_token: nil)
40
- rpc_proxy 'listmintworks', [offset], access_token: access_token
38
+ rpc_proxy 'listmintworks', [offset], access_token:
41
39
  end
42
40
 
43
- def list_mint_distributions(offset = 0, count = 10, tx = false, access_token: nil)
44
- rpc_proxy 'listmintdistributions', [offset, count, tx], access_token: access_token
41
+ def list_mint_distributions(offset = 0, count = 10, txn: false, access_token: nil)
42
+ rpc_proxy 'listmintdistributions', [offset, count, txn], access_token:
45
43
  end
46
44
  end
47
45
  end
@@ -3,45 +3,31 @@
3
3
  module MixinBot
4
4
  class API
5
5
  module Snapshot
6
- def network_snapshots(**options)
7
- path = format(
8
- '/network/snapshots?limit=%<limit>s&offset=%<offset>s&asset=%<asset>s&order=%<order>s',
9
- limit: options[:limit],
10
- offset: options[:offset],
11
- asset: options[:asset],
12
- order: options[:order]
13
- )
14
-
15
- access_token = options[:access_token] || access_token('GET', path)
16
- authorization = format('Bearer %<access_token>s', access_token: access_token)
17
- client.get(path, headers: { 'Authorization': authorization })
18
- end
19
- alias read_network_snapshots network_snapshots
20
-
21
- def snapshots(**options)
22
- path = format(
23
- '/snapshots?limit=%<limit>s&offset=%<offset>s&asset=%<asset>s&opponent=%<opponent>s&order=%<order>s',
6
+ def safe_snapshots(**options)
7
+ path = '/safe/snapshots'
8
+ params = {
24
9
  limit: options[:limit],
25
10
  offset: options[:offset],
26
11
  asset: options[:asset],
27
12
  opponent: options[:opponent],
13
+ app: options[:app_id],
28
14
  order: options[:order]
29
- )
15
+ }
30
16
 
31
- access_token = options[:access_token] || access_token('GET', path)
32
- authorization = format('Bearer %<access_token>s', access_token: access_token)
33
- client.get(path, headers: { 'Authorization': authorization })
17
+ client.get path, **params
34
18
  end
35
- alias read_snapshots snapshots
36
19
 
37
- def network_snapshot(snapshot_id, **options)
38
- path = format('/network/snapshots/%<snapshot_id>s', snapshot_id: snapshot_id)
20
+ def create_safe_snapshot_notification(**kwargs)
21
+ path = '/safe/snapshots/notifications'
22
+
23
+ payload = {
24
+ transaction_hash: kwargs[:transaction_hash],
25
+ output_index: kwargs[:output_index],
26
+ receiver_id: kwargs[:receiver_id]
27
+ }
39
28
 
40
- access_token = options[:access_token] || access_token('GET', path)
41
- authorization = format('Bearer %<access_token>s', access_token: access_token)
42
- client.get(path, headers: { 'Authorization': authorization })
29
+ client.post path, **payload, access_token: kwargs[:access_token]
43
30
  end
44
- alias read_network_snapshot network_snapshot
45
31
  end
46
32
  end
47
33
  end