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
@@ -0,0 +1,218 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MixinBot
4
+ module Utils
5
+ module Crypto
6
+ def access_token(method, uri, body = '', **kwargs)
7
+ sig = Digest::SHA256.hexdigest(method + uri + body.to_s)
8
+ iat = Time.now.utc.to_i
9
+ exp = (Time.now.utc + (kwargs[:exp_in] || 600)).to_i
10
+ scp = kwargs[:scp] || 'FULL'
11
+ jti = SecureRandom.uuid
12
+ uid = kwargs[:app_id] || MixinBot.config.app_id
13
+ sid = kwargs[:session_id] || MixinBot.config.session_id
14
+ private_key = kwargs[:private_key] || MixinBot.config.session_private_key
15
+
16
+ payload = {
17
+ uid:,
18
+ sid:,
19
+ iat:,
20
+ exp:,
21
+ jti:,
22
+ sig:,
23
+ scp:
24
+ }
25
+
26
+ if private_key.blank?
27
+ raise ConfigurationNotValidError, 'private_key is required'
28
+ elsif private_key.size == 64
29
+ jwk = JOSE::JWK.from_okp [:Ed25519, private_key]
30
+ jws = JOSE::JWS.from({ 'alg' => 'EdDSA' })
31
+ else
32
+ jwk = JOSE::JWK.from_pem private_key
33
+ jws = JOSE::JWS.from({ 'alg' => 'RS512' })
34
+ end
35
+
36
+ jwt = JOSE::JWT.from payload
37
+ JOSE::JWT.sign(jwk, jws, jwt).compact
38
+ end
39
+
40
+ def generate_ed25519_key
41
+ ed25519_key = JOSE::JWA::Ed25519.keypair
42
+ {
43
+ private_key: Base64.urlsafe_encode64(ed25519_key[1], padding: false),
44
+ public_key: Base64.urlsafe_encode64(ed25519_key[0], padding: false)
45
+ }
46
+ end
47
+
48
+ def generate_rsa_key
49
+ rsa_key = OpenSSL::PKey::RSA.new 1024
50
+ {
51
+ private_key: rsa_key.to_pem,
52
+ public_key: rsa_key.public_key.to_pem
53
+ }
54
+ end
55
+
56
+ def shared_public_key(key)
57
+ (JOSE::JWA::Edwards25519Point.stdbase * scalar_from_bytes(key[...64]).x.to_i).encode
58
+ end
59
+
60
+ def scalar_from_bytes(raw)
61
+ JOSE::JWA::FieldElement.new(
62
+ # https://github.com/potatosalad/ruby-jose/blob/e1be589b889f1e59ac233a5d19a3fa13f1e4b8a0/lib/jose/jwa/x25519.rb#L122C14-L122C48
63
+ OpenSSL::BN.new(raw.reverse, 2),
64
+ JOSE::JWA::Edwards25519Point::L
65
+ )
66
+ end
67
+
68
+ def sign(msg, key:)
69
+ msg = Digest::Blake3.digest msg
70
+
71
+ pub = shared_public_key key
72
+
73
+ y_scalar = scalar_from_bytes key
74
+
75
+ key_digest = Digest::SHA512.digest key
76
+ msg_digest = Digest::SHA512.digest(key_digest[-32...] + msg)
77
+
78
+ z_scalar = scalar_from_bytes msg_digest[...64]
79
+
80
+ r_point = JOSE::JWA::Edwards25519Point.stdbase * z_scalar.x.to_i
81
+
82
+ hram_digest = Digest::SHA512.digest(r_point.encode + pub + msg)
83
+
84
+ x_scalar = scalar_from_bytes hram_digest[...64]
85
+
86
+ s_scalar = (x_scalar * y_scalar) + z_scalar
87
+
88
+ r_point.encode + s_scalar.to_bytes(36)
89
+ end
90
+
91
+ def generate_unique_uuid(uuid1, uuid2)
92
+ md5 = Digest::MD5.new
93
+ md5 << [uuid1, uuid2].min
94
+ md5 << [uuid1, uuid2].max
95
+ digest = md5.digest
96
+ digest6 = ((digest[6].ord & 0x0f) | 0x30).chr
97
+ digest8 = ((digest[8].ord & 0x3f) | 0x80).chr
98
+ cipher = digest[0...6] + digest6 + digest[7] + digest8 + digest[9..]
99
+
100
+ MixinBot::UUID.new(raw: cipher).unpacked
101
+ end
102
+
103
+ def unique_uuid(*uuids)
104
+ uuids = uuids.flatten.compact
105
+ uuids.sort
106
+ r = uuids.first
107
+ uuids.each_with_index do |uuid, i|
108
+ r = generate_unique_uuid(r, uuid) if i.positive?
109
+ end
110
+
111
+ r
112
+ end
113
+
114
+ def generate_trace_from_hash(hash, output_index = 0)
115
+ md5 = Digest::MD5.new
116
+ md5 << hash
117
+ md5 << [output_index].pack('c*') if output_index.positive? && output_index < 256
118
+ digest = md5.digest
119
+ digest[6] = ((digest[6].ord & 0x0f) | 0x30).chr
120
+ digest[8] = ((digest[8].ord & 0x3f) | 0x80).chr
121
+
122
+ MixinBot::UUID.new(raw: digest).unpacked
123
+ end
124
+
125
+ # decrypt the encrpted pin, just for test
126
+ def decrypt_pin(msg, shared_key:)
127
+ msg = Base64.urlsafe_decode64 msg
128
+ iv = msg[0..15]
129
+ cipher = msg[16..47]
130
+ alg = 'AES-256-CBC'
131
+ decode_cipher = OpenSSL::Cipher.new(alg)
132
+ decode_cipher.decrypt
133
+ decode_cipher.iv = iv
134
+ decode_cipher.key = shared_key
135
+ decode_cipher.update(cipher)
136
+ end
137
+
138
+ # 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.
139
+ def encrypt_pin(pin, **kwargs)
140
+ pin = MixinBot.utils.decode_key pin
141
+
142
+ shared_key = kwargs[:shared_key]
143
+ raise ArgumentError, 'shared_key is required' if shared_key.blank?
144
+
145
+ iterator ||= kwargs[:iterator] || Time.now.utc.to_i
146
+ tszero = iterator % 0x100
147
+ tsone = (iterator % 0x10000) >> 8
148
+ tstwo = (iterator % 0x1000000) >> 16
149
+ tsthree = (iterator % 0x100000000) >> 24
150
+ tsstring = "#{tszero.chr}#{tsone.chr}#{tstwo.chr}#{tsthree.chr}\u0000\u0000\u0000\u0000"
151
+ encrypt_content = pin + tsstring + tsstring
152
+ pad_count = 16 - (encrypt_content.length % 16)
153
+ padded_content =
154
+ if pad_count.positive?
155
+ encrypt_content + (pad_count.chr * pad_count)
156
+ else
157
+ encrypt_content
158
+ end
159
+
160
+ alg = 'AES-256-CBC'
161
+ aes = OpenSSL::Cipher.new(alg)
162
+ iv = OpenSSL::Cipher.new(alg).random_iv
163
+ aes.encrypt
164
+ aes.key = shared_key
165
+ aes.iv = iv
166
+ cipher = aes.update(padded_content)
167
+ msg = iv + cipher
168
+ Base64.urlsafe_encode64 msg, padding: false
169
+ end
170
+
171
+ def tip_public_key(key, counter: 0)
172
+ raise ArgumentError, 'invalid key' if key.size < 32
173
+
174
+ (key[0...32].bytes + MixinBot::Utils.encode_uint64(counter + 1)).pack('c*').unpack1('H*')
175
+ end
176
+
177
+ def hash_scalar(pkey, output_index)
178
+ tmp = [output_index].pack('Q<').reverse
179
+
180
+ hash1 = Digest::Blake3.digest(pkey + tmp)
181
+ hash2 = Digest::Blake3.digest hash1
182
+
183
+ hash3 = Digest::Blake3.digest(hash1 + hash2)
184
+ hash4 = Digest::Blake3.digest hash3
185
+
186
+ hash3 + hash4
187
+ end
188
+
189
+ def multiply_keys(public_key:, private_key:)
190
+ public_point = JOSE::JWA::Edwards25519Point.stdbase.decode public_key
191
+ private_scalar = scalar_from_bytes private_key
192
+ (public_point * private_scalar.x.to_i).encode
193
+ end
194
+
195
+ def derive_ghost_public_key(private_key, view_key, spend_key, index)
196
+ mult_value = multiply_keys(public_key: view_key, private_key:)
197
+
198
+ x = hash_scalar mult_value, index
199
+
200
+ p1 = JOSE::JWA::Edwards25519Point.stdbase.decode spend_key
201
+ p2 = JOSE::JWA::Edwards25519Point.stdbase * scalar_from_bytes(x).x.to_i
202
+
203
+ (p1 + p2).encode
204
+ end
205
+
206
+ def derive_ghost_private_key(public_key, view_key, spend_key, index)
207
+ mult_value = multiply_keys(public_key:, private_key: view_key)
208
+
209
+ x = hash_scalar mult_value, index
210
+
211
+ x_scalar = scalar_from_bytes x
212
+ y_scalar = scalar_from_bytes spend_key
213
+
214
+ (x_scalar + y_scalar).to_bytes(36)
215
+ end
216
+ end
217
+ end
218
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MixinBot
4
+ module Utils
5
+ module Decoder
6
+ def decode_key(key)
7
+ return if key.blank?
8
+
9
+ if key.match?(/\A[\h]{64,}\z/i)
10
+ [key].pack('H*')
11
+ elsif key.match?(/^-----BEGIN RSA PRIVATE KEY-----/)
12
+ key.gsub('\\r\\n', "\n").gsub("\r\n", "\n")
13
+ elsif key.match?(/\d{6}/) || (key.size % 32).zero?
14
+ key
15
+ else
16
+ Base64.urlsafe_decode64 key
17
+ end
18
+ end
19
+
20
+ def decode_raw_transaction(hex)
21
+ MixinBot::Transaction.new(hex:).decode.to_h
22
+ end
23
+
24
+ def decode_uint16(bytes)
25
+ raise ArgumentError, "only support bytes #{bytes}" unless bytes.is_a?(Array)
26
+
27
+ bytes.reverse.pack('C*').unpack1('S*')
28
+ end
29
+
30
+ def decode_uint32(bytes)
31
+ raise ArgumentError, "only support bytes #{bytes}" unless bytes.is_a?(Array)
32
+
33
+ bytes.reverse.pack('C*').unpack1('L*')
34
+ end
35
+
36
+ def decode_uint64(bytes)
37
+ raise ArgumentError, "only support bytes #{bytes}" unless bytes.is_a?(Array)
38
+
39
+ bytes.reverse.pack('C*').unpack1('Q*')
40
+ end
41
+
42
+ def decode_int(bytes)
43
+ int = 0
44
+ bytes.each do |byte|
45
+ int = (int * (2**8)) + byte
46
+ end
47
+
48
+ int
49
+ end
50
+
51
+ def hex_to_uuid(hex)
52
+ MixinBot::UUID.new(hex:).unpacked
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MixinBot
4
+ module Utils
5
+ module Encoder
6
+ def encode_raw_transaction(txn)
7
+ if txn.is_a? String
8
+ begin
9
+ txn = JSON.parse txn
10
+ rescue JSON::ParserError
11
+ txn
12
+ end
13
+ end
14
+
15
+ raise ArgumentError, "#{txn} is not a valid json" unless txn.is_a? Hash
16
+
17
+ txn = txn.with_indifferent_access
18
+
19
+ MixinBot::Transaction.new(**txn).encode.hex
20
+ end
21
+
22
+ def encode_uint16(int)
23
+ raise ArgumentError, "only support int #{int}" unless int.is_a?(Integer)
24
+
25
+ [int].pack('S*').bytes.reverse
26
+ end
27
+
28
+ def encode_uint32(int)
29
+ raise ArgumentError, "only support int #{int}" unless int.is_a?(Integer)
30
+
31
+ [int].pack('L*').bytes.reverse
32
+ end
33
+
34
+ def encode_uint64(int)
35
+ raise ArgumentError, "only support int #{int}" unless int.is_a?(Integer)
36
+
37
+ [int].pack('Q*').bytes.reverse
38
+ end
39
+
40
+ def encode_int(int)
41
+ raise ArgumentError, 'not integer' unless int.is_a?(Integer)
42
+
43
+ bytes = []
44
+ loop do
45
+ break if int.zero?
46
+
47
+ bytes.push int & 255
48
+ int = (int / (2**8)) | 0
49
+ end
50
+
51
+ bytes.reverse
52
+ end
53
+
54
+ def nft_memo(collection, token, extra)
55
+ MixinBot::Nfo.new(
56
+ collection:,
57
+ token:,
58
+ extra:
59
+ ).mint_memo
60
+ end
61
+ end
62
+ end
63
+ end
@@ -1,116 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative './utils/nfo'
4
- require_relative './utils/uuid'
5
- require_relative './utils/transaction'
3
+ require_relative 'utils/address'
4
+ require_relative 'utils/crypto'
5
+ require_relative 'utils/decoder'
6
+ require_relative 'utils/encoder'
6
7
 
7
8
  module MixinBot
8
9
  module Utils
9
- class << self
10
- MAGIC = [0x77, 0x77].freeze
11
- TX_VERSION = 2
12
- MAX_ENCODE_INT = 0xFFFF
13
- NULL_BYTES = [0x00, 0x00].freeze
14
- AGGREGATED_SIGNATURE_PREFIX = 0xFF01
15
- AGGREGATED_SIGNATURE_ORDINAY_MASK = [0x00].freeze
16
- AGGREGATED_SIGNATURE_SPARSE_MASK = [0x01].freeze
17
-
18
- def generate_unique_uuid(uuid_1, uuid_2)
19
- md5 = Digest::MD5.new
20
- md5 << [uuid_1, uuid_2].min
21
- md5 << [uuid_1, uuid_2].max
22
- digest = md5.digest
23
- digest6 = (digest[6].ord & 0x0f | 0x30).chr
24
- digest8 = (digest[8].ord & 0x3f | 0x80).chr
25
- cipher = digest[0...6] + digest6 + digest[7] + digest8 + digest[9..]
26
-
27
- UUID.new(raw: cipher).unpacked
28
- end
29
-
30
- def unique_uuid(*uuids)
31
- uuids.sort
32
- r = uuids.first
33
- uuids.each_with_index do |uuid, i|
34
- r = MixinBot::Utils.generate_unique_uuid(r, uuid) if i.positive?
35
- end
36
-
37
- r
38
- end
39
-
40
- def generate_trace_from_hash(hash, output_index = 0)
41
- md5 = Digest::MD5.new
42
- md5 << hash
43
- md5 << [output_index].pack('c*') if output_index.positive? && output_index < 256
44
- digest = md5.digest
45
- digest[6] = ((digest[6].ord & 0x0f) | 0x30).chr
46
- digest[8] = ((digest[8].ord & 0x3f) | 0x80).chr
47
-
48
- UUID.new(raw: digest).unpacked
49
- end
50
-
51
- def hex_to_uuid(hex)
52
- UUID.new(hex: hex).unpacked
53
- end
54
-
55
- def sign_raw_transaction(tx)
56
- tx = JSON.parse tx if tx.is_a? String
57
- raise ArgumentError, "#{tx} is not a valid json" unless tx.is_a? Hash
58
-
59
- tx = tx.with_indifferent_access
60
-
61
- Transaction.new(
62
- asset: tx[:asset],
63
- inputs: tx[:inputs],
64
- outputs: tx[:outputs],
65
- extra: tx[:extra]
66
- ).encode.hex
67
- end
68
-
69
- def decode_raw_transaction(hex)
70
- Transaction.new(hex: hex).decode.to_h
71
- end
72
-
73
- def nft_memo(collection, token, extra)
74
- MixinBot::Utils::Nfo.new(
75
- collection: collection,
76
- token: token,
77
- extra: extra
78
- ).mint_memo
79
- end
80
-
81
- def encode_int(int)
82
- raise ArgumentError, "only support int #{int}" unless int.is_a?(Integer)
83
- raise ArgumentError, "int #{int} is larger than MAX_ENCODE_INT #{MAX_ENCODE_INT}" if int > MAX_ENCODE_INT
84
-
85
- [int].pack('S*').bytes.reverse
86
- end
87
-
88
- def encode_unit_64(int)
89
- [int].pack('Q*').bytes.reverse
90
- end
91
-
92
- def bytes_of(int)
93
- raise ArgumentError, 'not integer' unless int.is_a?(Integer)
94
-
95
- bytes = []
96
- loop do
97
- break if int === 0
98
-
99
- bytes.push int & 255
100
- int = int / (2**8) | 0
101
- end
102
-
103
- bytes.reverse
104
- end
105
-
106
- def bytes_to_int(bytes)
107
- int = 0
108
- bytes.each do |byte|
109
- int = int * (2**8) + byte
110
- end
111
-
112
- int
113
- end
114
- end
10
+ extend MixinBot::Utils::Address
11
+ extend MixinBot::Utils::Crypto
12
+ extend MixinBot::Utils::Decoder
13
+ extend MixinBot::Utils::Encoder
115
14
  end
116
15
  end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MixinBot
4
+ class UUID
5
+ attr_accessor :hex, :raw
6
+
7
+ def initialize(**args)
8
+ @hex = args[:hex]
9
+ @raw = args[:raw]
10
+
11
+ raise MixinBot::InvalidUuidFormatError if raw.present? && raw.size != 16
12
+ raise MixinBot::InvalidUuidFormatError if hex.present? && hex.gsub('-', '').size != 32
13
+ end
14
+
15
+ def packed
16
+ if raw.present?
17
+ raw
18
+ elsif hex.present?
19
+ [hex.gsub('-', '')].pack('H*')
20
+ end
21
+ end
22
+
23
+ def unpacked
24
+ _hex =
25
+ if hex.present?
26
+ hex.gsub('-', '')
27
+ elsif raw.present?
28
+ _hex = raw.unpack1('H*')
29
+ end
30
+
31
+ format(
32
+ '%<first>s-%<second>s-%<third>s-%<forth>s-%<fifth>s',
33
+ first: _hex[0..7],
34
+ second: _hex[8..11],
35
+ third: _hex[12..15],
36
+ forth: _hex[16..19],
37
+ fifth: _hex[20..]
38
+ )
39
+ end
40
+ end
41
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MixinBot
4
- VERSION = '0.12.1'
4
+ VERSION = '1.1.0'
5
5
  end
data/lib/mixin_bot.rb CHANGED
@@ -3,12 +3,16 @@
3
3
  # third-party dependencies
4
4
  require 'English'
5
5
  require 'active_support/all'
6
+ require 'base58'
6
7
  require 'base64'
7
8
  require 'bigdecimal'
8
9
  require 'bigdecimal/util'
9
10
  require 'digest'
11
+ require 'digest/blake3'
10
12
  require 'faye/websocket'
11
- require 'http'
13
+ require 'faraday'
14
+ require 'faraday/multipart'
15
+ require 'faraday/retry'
12
16
  require 'jose'
13
17
  require 'msgpack'
14
18
  require 'open3'
@@ -16,19 +20,38 @@ require 'openssl'
16
20
  require 'rbnacl'
17
21
  require 'sha3'
18
22
 
19
- require_relative './mixin_bot/api'
20
- require_relative './mixin_bot/cli'
21
- require_relative './mixin_bot/utils'
22
- require_relative './mixin_bot/version'
23
- require_relative './mvm'
23
+ require_relative 'mixin_bot/api'
24
+ require_relative 'mixin_bot/cli'
25
+ require_relative 'mixin_bot/utils'
26
+ require_relative 'mixin_bot/nfo'
27
+ require_relative 'mixin_bot/uuid'
28
+ require_relative 'mixin_bot/transaction'
29
+ require_relative 'mixin_bot/version'
30
+ require_relative 'mvm'
24
31
 
25
32
  module MixinBot
26
- class<< self
27
- attr_accessor :client_id, :client_secret, :session_id, :pin_token, :private_key, :scope, :api_host, :blaze_host
28
- end
33
+ class << self
34
+ def api
35
+ return @api if defined?(@api)
36
+
37
+ @api = MixinBot::API.new
38
+ @api
39
+ end
40
+
41
+ def config
42
+ return @config if defined?(@config)
43
+
44
+ @config = MixinBot::Configuration.new
45
+ @config
46
+ end
47
+
48
+ def configure(&)
49
+ config.instance_exec(&)
50
+ end
29
51
 
30
- def self.api
31
- @api ||= MixinBot::API.new
52
+ def utils
53
+ MixinBot::Utils
54
+ end
32
55
  end
33
56
 
34
57
  class Error < StandardError; end
@@ -37,12 +60,14 @@ module MixinBot
37
60
  class RequestError < Error; end
38
61
  class ResponseError < Error; end
39
62
  class NotFoundError < Error; end
63
+ class UserNotFoundError < Error; end
40
64
  class UnauthorizedError < Error; end
41
65
  class ForbiddenError < Error; end
42
66
  class InsufficientBalanceError < Error; end
43
67
  class InsufficientPoolError < Error; end
44
68
  class PinError < Error; end
45
- class InvalidNfoFormatError < MixinBot::Error; end
46
- class InvalidUuidFormatError < MixinBot::Error; end
47
- class InvalidTransactionFormatError < MixinBot::Error; end
69
+ class InvalidNfoFormatError < Error; end
70
+ class InvalidUuidFormatError < Error; end
71
+ class InvalidTransactionFormatError < Error; end
72
+ class ConfigurationNotValidError < Error; end
48
73
  end
data/lib/mvm/bridge.rb CHANGED
@@ -16,27 +16,10 @@ module MVM
16
16
  path = '/users'
17
17
 
18
18
  payload = {
19
- public_key: public_key
19
+ public_key:
20
20
  }
21
21
 
22
- client.post path, json: payload
23
- end
24
-
25
- def extra(receivers: [], threshold: 1, extra: '')
26
- return if receivers.blank?
27
-
28
- path = '/extra'
29
-
30
- payload = {
31
- receivers: receivers,
32
- threshold: threshold,
33
- extra: extra
34
- }
35
-
36
- client.post path, json: payload
37
- end
38
-
39
- def mirror
22
+ client.post path, **payload
40
23
  end
41
24
  end
42
25
  end
data/lib/mvm/client.rb CHANGED
@@ -8,43 +8,21 @@ module MVM
8
8
 
9
9
  def initialize(host)
10
10
  @host = host
11
- end
12
-
13
- def get(path, options = {})
14
- request(:get, path, options)
15
- end
16
-
17
- def post(path, options = {})
18
- request(:post, path, options)
19
- end
20
-
21
- private
22
-
23
- def request(verb, path, options = {})
24
- uri = uri_for path
25
-
26
- options[:headers] ||= {}
27
- options[:headers]['Content-Type'] ||= 'application/json'
28
-
29
- begin
30
- response = HTTP.timeout(connect: 5, write: 5, read: 5).request(verb, uri, options)
31
- rescue HTTP::Error => e
32
- raise HttpError, e.message
11
+ @conn = Faraday.new(url: "#{SERVER_SCHEME}://#{host}") do |f|
12
+ f.request :json
13
+ f.request :retry
14
+ f.response :raise_error
15
+ f.response :logger
16
+ f.response :json
33
17
  end
18
+ end
34
19
 
35
- raise ResponseError, response.to_s if response.status.server_error?
36
- return response.status.to_s unless response.status.success?
37
-
38
- JSON.parse(response.body.to_s)
20
+ def get(path, **)
21
+ @conn.get(path, **).body
39
22
  end
40
23
 
41
- def uri_for(path)
42
- uri_options = {
43
- scheme: SERVER_SCHEME,
44
- host: host,
45
- path: path
46
- }
47
- Addressable::URI.new(uri_options)
24
+ def post(path, **)
25
+ @conn.post(path, **).body
48
26
  end
49
27
  end
50
28
  end