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
@@ -10,10 +10,10 @@ module MixinBot
|
|
10
10
|
|
11
11
|
def acknowledge_message_receipt(message_id)
|
12
12
|
params = {
|
13
|
-
message_id
|
13
|
+
message_id:,
|
14
14
|
status: 'READ'
|
15
15
|
}
|
16
|
-
write_ws_message(action: 'ACKNOWLEDGE_MESSAGE_RECEIPT', 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:
|
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
|
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
|
111
|
-
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
|
-
|
162
|
-
|
163
|
-
|
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
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
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
|
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
|
31
|
-
path = '/
|
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
|
-
|
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
|
-
|
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
|
126
|
-
|
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
|
-
|
29
|
+
client.post path, access_token:
|
131
30
|
end
|
132
31
|
|
133
|
-
|
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
|
-
|
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
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/mixin_bot/api/pin.rb
CHANGED
@@ -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(
|
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
|
-
|
14
|
-
|
15
|
-
|
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(
|
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
|
-
|
25
|
-
|
41
|
+
old_pin_base64: encrypted_old_pin,
|
42
|
+
pin_base64: encrypted_pin
|
26
43
|
}
|
27
44
|
|
28
|
-
|
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
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
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
|
-
|
48
|
-
|
49
|
-
|
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
|
-
|
66
|
-
|
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
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
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
|
data/lib/mixin_bot/api/rpc.rb
CHANGED
@@ -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
|
10
|
-
params:
|
9
|
+
method:,
|
10
|
+
params:
|
11
11
|
}
|
12
12
|
|
13
|
-
|
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:
|
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:
|
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:
|
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:
|
30
|
+
rpc_proxy 'getsnapshot', [hash], access_token:
|
33
31
|
end
|
34
32
|
|
35
|
-
def list_snapshots(offset = 0, count = 10, sig
|
36
|
-
rpc_proxy 'listsnapshots', [offset, count, sig,
|
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:
|
38
|
+
rpc_proxy 'listmintworks', [offset], access_token:
|
41
39
|
end
|
42
40
|
|
43
|
-
def list_mint_distributions(offset = 0, count = 10,
|
44
|
-
rpc_proxy 'listmintdistributions', [offset, count,
|
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
|
7
|
-
path =
|
8
|
-
|
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
|
-
|
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
|
38
|
-
path =
|
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
|
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
|