mixin_bot 0.3.9 → 0.5.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d714edf6aef84c707774d04abf1b8016041d09160f82864966e2b09bf6845870
4
- data.tar.gz: 7816eaf72dd92c841ed78e9bc315a562feb12b34d50f7c87c35a3c34d7fe1176
3
+ metadata.gz: c746194faff682c2e72eac0cd3673986c9ecf02fd4bbbc7a07afc114f9594646
4
+ data.tar.gz: e33d157e155c857cfe2eff5c78150ac2e1c10f1b48f9925474d0cd09f5664581
5
5
  SHA512:
6
- metadata.gz: 846f28a71824b964b68664538e2960f991dabf3ebbcf3f162cacc2ef4fd88713351d2949f639108d125cfd65dc33aebb9f6c4bfdc07d2fcf07f72d01a96c10b2
7
- data.tar.gz: fc2939f80ba895921d45d5d29866d50696dab737b19f5234d1223d6f3cd5867879606ec3978ee502ae7532275cbd6172a6a780771c3d68965fa82f5e2ae446f7
6
+ metadata.gz: 6b73cf7f7a56f9b982de773c5b4158ff00a72e09938d6b06398b0595eea9a58095874eddfe26f9407e4c2e887e8b9f05ee3a33b7222fe71efe6b592c21be41c8
7
+ data.tar.gz: 372982bdcd9d1bb1ba5be676d0f195e2eaa9a4a7205b50736b589da0890d41f78db6ce153f9bd11a2b84cc545c456388ed584c19762f8e8a1a13e362e86e04a0
data/lib/mixin_bot.rb CHANGED
@@ -11,6 +11,7 @@ require 'msgpack'
11
11
  require 'open3'
12
12
  require 'openssl'
13
13
  require 'rbnacl'
14
+ require 'sha3'
14
15
 
15
16
  require_relative './mixin_bot/api'
16
17
  require_relative './mixin_bot/cli'
data/lib/mixin_bot/api.rb CHANGED
@@ -13,6 +13,7 @@ require_relative './api/multisig'
13
13
  require_relative './api/payment'
14
14
  require_relative './api/pin'
15
15
  require_relative './api/snapshot'
16
+ require_relative './api/transaction'
16
17
  require_relative './api/transfer'
17
18
  require_relative './api/user'
18
19
  require_relative './api/withdraw'
@@ -43,7 +44,7 @@ module MixinBot
43
44
  end
44
45
 
45
46
  # Use a mixin software to implement transaction build
46
- def build_transaction(json)
47
+ def sign_raw_transaction(json)
47
48
  ensure_mixin_command_exist
48
49
  command = format("mixin signrawtransaction --raw '%<arg>s'", arg: json)
49
50
 
@@ -65,6 +66,7 @@ module MixinBot
65
66
  include MixinBot::API::Payment
66
67
  include MixinBot::API::Pin
67
68
  include MixinBot::API::Snapshot
69
+ include MixinBot::API::Transaction
68
70
  include MixinBot::API::Transfer
69
71
  include MixinBot::API::User
70
72
  include MixinBot::API::Withdraw
@@ -28,26 +28,28 @@ module MixinBot
28
28
  # "signed_tx":""
29
29
  # }
30
30
  # ]}
31
- def multisigs(limit: 100, offset: nil, access_token: nil)
32
- path = format('/multisigs?limit=%<limit>s&offset=%<offset>s', limit: limit, offset: offset)
31
+ def outputs(**kwargs)
32
+ limit = kwargs[:limit] || 100
33
+ offset = kwargs[:offset] || ''
34
+ state = kwargs[:state] || ''
35
+ members = kwargs[:members] || []
36
+ threshold = kwargs[:threshold] || ''
37
+ access_token = kwargs[:access_token]
38
+ members = SHA3::Digest::SHA256.hexdigest(members&.sort&.join)
39
+
40
+ path = format(
41
+ '/multisigs/outputs?limit=%<limit>s&offset=%<offset>s&state=%<state>s&members=%<members>s&threshold=%<threshold>s',
42
+ limit: limit,
43
+ offset: offset,
44
+ state: state,
45
+ members: members,
46
+ threshold: threshold
47
+ )
33
48
  access_token ||= access_token('GET', path, '')
34
49
  authorization = format('Bearer %<access_token>s', access_token: access_token)
35
50
  client.get(path, headers: { 'Authorization': authorization })
36
51
  end
37
-
38
- def all_multisigs(utxos: [], offset: nil, access_token: nil)
39
- res = multisigs(limit: 100, offset: offset, access_token: access_token)
40
-
41
- return [] if res['data'].nil?
42
-
43
- utxos += res['data']
44
-
45
- if res['data'].length < 100
46
- utxos
47
- else
48
- all_multisigs(utxos: utxos, offset: utxos[-1]['created_at'], access_token: access_token)
49
- end
50
- end
52
+ alias multisigs outputs
51
53
 
52
54
  def create_output(receivers:, index:, access_token: nil)
53
55
  path = '/outputs'
@@ -64,7 +66,7 @@ module MixinBot
64
66
  # create a request for multi sign
65
67
  # for now, raw(RAW-TRANSACTION-HEX) can only be generated by Mixin SDK of Golang or Javascript
66
68
  def create_sign_multisig_request(raw, access_token: nil)
67
- path = '/multisigs'
69
+ path = '/multisigs/requests'
68
70
  payload = {
69
71
  action: 'sign',
70
72
  raw: raw
@@ -77,7 +79,7 @@ module MixinBot
77
79
  # transfer from the multisig address
78
80
  # create a request for unlock a multi-sign
79
81
  def create_unlock_multisig_request(raw, access_token: nil)
80
- path = '/multisigs'
82
+ path = '/multisigs/requests'
81
83
  payload = {
82
84
  action: 'unlock',
83
85
  raw: raw
@@ -88,7 +90,7 @@ module MixinBot
88
90
  end
89
91
 
90
92
  def sign_multisig_request(request_id, pin)
91
- path = format('/multisigs/%<request_id>s/sign', request_id: request_id)
93
+ path = format('/multisigs/requests/%<request_id>s/sign', request_id: request_id)
92
94
  payload = {
93
95
  pin: encrypt_pin(pin)
94
96
  }
@@ -98,7 +100,7 @@ module MixinBot
98
100
  end
99
101
 
100
102
  def unlock_multisig_request(request_id, pin)
101
- path = format('/multisigs/%<request_id>s/unlock', request_id: request_id)
103
+ path = format('/multisigs/requests/%<request_id>s/unlock', request_id: request_id)
102
104
  payload = {
103
105
  pin: encrypt_pin(pin)
104
106
  }
@@ -108,7 +110,7 @@ module MixinBot
108
110
  end
109
111
 
110
112
  def cancel_multisig_request(request_id, pin)
111
- path = format('/multisigs/%<request_id>s/cancel', request_id: request_id)
113
+ path = format('/multisigs/requests/%<request_id>s/cancel', request_id: request_id)
112
114
  payload = {
113
115
  pin: encrypt_pin(pin)
114
116
  }
@@ -165,76 +167,42 @@ module MixinBot
165
167
  "fffe#{s}"
166
168
  end
167
169
 
168
- # filter utxo by members, asset_id and threshold
169
- def filter_utxos(**kwargs)
170
- utxos = all_multisigs(access_token: kwargs[:access_token])
171
-
172
- unless kwargs[:members].nil?
173
- utxos = utxos.filter(
174
- &lambda { |utxo|
175
- utxo['members'].sort == kwargs[:members].sort
176
- }
177
- )
178
- end
179
-
180
- unless kwargs[:asset_id].nil?
181
- utxos = utxos.filter(
182
- &lambda { |utxo|
183
- utxo['asset_id'] == kwargs[:asset_id]
184
- }
185
- )
186
- end
187
-
188
- unless kwargs[:threshold].nil?
189
- utxos = utxos.filter(
190
- &lambda { |utxo|
191
- utxo['threshold'] == kwargs[:threshold]
192
- }
193
- )
194
- end
195
-
196
- unless kwargs[:state].nil?
197
- utxos = utxos.filter(
198
- &lambda { |utxo|
199
- utxo['state'] == kwargs[:state]
200
- }
201
- )
202
- end
203
-
204
- utxos
205
- end
206
-
207
170
  # kwargs:
208
171
  # {
209
172
  # senders: [ uuid ],
210
173
  # receivers: [ uuid ],
211
174
  # threshold: integer,
212
175
  # asset_id: uuid,
213
- # asset_mixin_id: string,
214
176
  # amount: string / float,
215
177
  # memo: string,
216
178
  # }
217
- def build_raw_transaction(kwargs)
179
+ RAW_TRANSACTION_ARGUMENTS = %i[senders receivers amount threshold asset_id].freeze
180
+ def build_raw_transaction(**kwargs)
181
+ raise ArgumentError, "#{RAW_TRANSACTION_ARGUMENTS.join(', ')} are needed for build raw transaction" unless RAW_TRANSACTION_ARGUMENTS.all? { |param| kwargs.keys.include? param }
182
+
218
183
  senders = kwargs[:senders]
219
184
  receivers = kwargs[:receivers]
220
- asset_id = kwargs[:asset_id]
221
- asset_mixin_id = kwargs[:asset_mixin_id]
222
185
  amount = kwargs[:amount]
223
- memo = kwargs[:memo]
224
186
  threshold = kwargs[:threshold]
225
- access_token = kwargs[:access_token]
187
+ asset_id = kwargs[:asset_id]
226
188
  utxos = kwargs[:utxos]
189
+ memo = kwargs[:memo]
190
+ access_token = kwargs[:access_token]
227
191
 
228
192
  raise 'access_token required!' if access_token.nil? && !senders.include?(client_id)
229
193
 
230
- # default to use all unspent utxo
231
- utxos ||= filter_utxos(
194
+ # default to use all(first 100) unspent utxo
195
+ utxos ||= multisigs(
232
196
  members: senders,
233
- asset_id: asset_id,
234
197
  threshold: threshold,
235
198
  state: 'unspent',
236
199
  access_token: access_token
200
+ )['data'].filter(
201
+ &lambda { |utxo|
202
+ utxo['asset_id'] == kwargs[:asset_id]
203
+ }
237
204
  )
205
+
238
206
  amount = amount.to_f.round(8)
239
207
  input_amount = utxos.map(
240
208
  &lambda { |utxo|
@@ -281,13 +249,13 @@ module MixinBot
281
249
  extra = Digest.hexencode memo.to_s.slice(0, 140)
282
250
  tx = {
283
251
  version: 1,
284
- asset: asset_mixin_id,
252
+ asset: SHA3::Digest::SHA256.hexdigest(asset_id),
285
253
  inputs: inputs,
286
254
  outputs: outputs,
287
255
  extra: extra
288
256
  }
289
257
 
290
- build_transaction tx.to_json
258
+ tx.to_json
291
259
  end
292
260
 
293
261
  def str_to_bin(str)
@@ -3,7 +3,7 @@
3
3
  module MixinBot
4
4
  class API
5
5
  module Snapshot
6
- def network_snapshots(options = {})
6
+ def network_snapshots(**options)
7
7
  path = format(
8
8
  '/network/snapshots?limit=%<limit>s&offset=%<offset>s&asset=%<asset>s&order=%<order>s',
9
9
  limit: options[:limit],
@@ -18,12 +18,13 @@ module MixinBot
18
18
  end
19
19
  alias read_network_snapshots network_snapshots
20
20
 
21
- def snapshots(options = {})
21
+ def snapshots(**options)
22
22
  path = format(
23
- '/snapshots?limit=%<limit>s&offset=%<offset>s&asset=%<asset>s',
23
+ '/snapshots?limit=%<limit>s&offset=%<offset>s&asset=%<asset>s&opponent=%<opponent>s',
24
24
  limit: options[:limit],
25
25
  offset: options[:offset],
26
- asset: options[:asset]
26
+ asset: options[:asset],
27
+ opponent: options[:opponent]
27
28
  )
28
29
 
29
30
  access_token = options[:access_token] || access_token('GET', path)
@@ -32,7 +33,7 @@ module MixinBot
32
33
  end
33
34
  alias read_snapshots snapshots
34
35
 
35
- def network_snapshot(snapshot_id, options = {})
36
+ def network_snapshot(snapshot_id, **options)
36
37
  path = format('/network/snapshots/%<snapshot_id>s', snapshot_id: snapshot_id)
37
38
 
38
39
  access_token = options[:access_token] || access_token('GET', path)
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MixinBot
4
+ class API
5
+ module Transaction
6
+ MULTISIG_TRANSACTION_ARGUMENTS = %i[asset_id receivers threshold amount].freeze
7
+ def create_multisig_transaction(pin, options = {})
8
+ raise ArgumentError, "#{MULTISIG_TRANSACTION_ARGUMENTS.join(', ')} are needed for create multisig transaction" unless MULTISIG_TRANSACTION_ARGUMENTS.all? { |param| options.keys.include? param }
9
+
10
+ asset_id = options[:asset_id]
11
+ receivers = options[:receivers]
12
+ threshold = options[:threshold]
13
+ amount = options[:amount].to_f
14
+ memo = options[:memo]
15
+ trace_id = options[:trace_id] || SecureRandom.uuid
16
+ encrypted_pin = options[:encrypted_pin] || encrypt_pin(pin)
17
+
18
+ path = '/transactions'
19
+ payload = {
20
+ asset_id: asset_id,
21
+ opponent_multisig: {
22
+ receivers: receivers,
23
+ threshold: threshold
24
+ },
25
+ pin: encrypted_pin,
26
+ amount: format('%.8f', amount),
27
+ trace_id: trace_id,
28
+ memo: memo
29
+ }
30
+
31
+ access_token = options[:access_token]
32
+ access_token ||= access_token('POST', path, payload.to_json)
33
+ authorization = format('Bearer %<access_token>s', access_token: access_token)
34
+ client.post(path, headers: { 'Authorization': authorization }, json: payload)
35
+ end
36
+
37
+ MAINNET_TRANSACTION_ARGUMENTS = %i[asset_id opponent_key amount].freeze
38
+ def create_mainnet_transaction(pin, options = {})
39
+ raise ArgumentError, "#{MAINNET_TRANSACTION_ARGUMENTS.join(', ')} are needed for create main net transactions" unless MAINNET_TRANSACTION_ARGUMENTS.all? { |param| options.keys.include? param }
40
+
41
+ asset_id = options[:asset_id]
42
+ opponent_key = options[:opponent_key]
43
+ amount = options[:amount].to_f
44
+ memo = options[:memo]
45
+ trace_id = options[:trace_id] || SecureRandom.uuid
46
+ encrypted_pin = options[:encrypted_pin] || encrypt_pin(pin)
47
+
48
+ path = '/transactions'
49
+ payload = {
50
+ asset_id: asset_id,
51
+ opponent_key: opponent_key,
52
+ pin: encrypted_pin,
53
+ amount: format('%.8f', amount),
54
+ trace_id: trace_id,
55
+ memo: memo
56
+ }
57
+
58
+ access_token = options[:access_token]
59
+ access_token ||= access_token('POST', path, payload.to_json)
60
+ authorization = format('Bearer %<access_token>s', access_token: access_token)
61
+ client.post(path, headers: { 'Authorization': authorization }, json: payload)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -9,7 +9,7 @@ module MixinBot
9
9
 
10
10
  asset_id = options[:asset_id]
11
11
  opponent_id = options[:opponent_id]
12
- amount = options[:amount]
12
+ amount = options[:amount].to_f
13
13
  memo = options[:memo]
14
14
  trace_id = options[:trace_id] || SecureRandom.uuid
15
15
  encrypted_pin = options[:encrypted_pin] || encrypt_pin(pin)
@@ -19,7 +19,7 @@ module MixinBot
19
19
  asset_id: asset_id,
20
20
  opponent_id: opponent_id,
21
21
  pin: encrypted_pin,
22
- amount: amount.to_s,
22
+ amount: format('%.8f', amount),
23
23
  trace_id: trace_id,
24
24
  memo: memo
25
25
  }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MixinBot
4
- VERSION = '0.3.9'
4
+ VERSION = '0.5.1'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mixin_bot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.9
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - an-lee
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-22 00:00:00.000000000 Z
11
+ date: 2021-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: awesome_print
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
124
  version: '7.1'
125
+ - !ruby/object:Gem::Dependency
126
+ name: sha3
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '1.0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '1.0'
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: thor
127
141
  requirement: !ruby/object:Gem::Requirement
@@ -244,6 +258,7 @@ files:
244
258
  - lib/mixin_bot/api/payment.rb
245
259
  - lib/mixin_bot/api/pin.rb
246
260
  - lib/mixin_bot/api/snapshot.rb
261
+ - lib/mixin_bot/api/transaction.rb
247
262
  - lib/mixin_bot/api/transfer.rb
248
263
  - lib/mixin_bot/api/user.rb
249
264
  - lib/mixin_bot/api/withdraw.rb
@@ -272,7 +287,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
272
287
  - !ruby/object:Gem::Version
273
288
  version: '0'
274
289
  requirements: []
275
- rubygems_version: 3.0.3
290
+ rubygems_version: 3.0.3.1
276
291
  signing_key:
277
292
  specification_version: 4
278
293
  summary: An API wrapper for Mixin Nexwork