mixin_bot 1.4.0 → 2.0.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 (94) hide show
  1. checksums.yaml +4 -4
  2. data/AGENTS.md +75 -0
  3. data/API_COVERAGE.md +143 -0
  4. data/CHANGELOG.md +112 -0
  5. data/README.md +375 -0
  6. data/docs/agent/cli.md +149 -0
  7. data/docs/agent/cookbook.md +152 -0
  8. data/examples/blaze.rb +43 -0
  9. data/examples/config.yml.example +21 -0
  10. data/lib/mixin_bot/address.rb +43 -3
  11. data/lib/mixin_bot/api/app.rb +7 -0
  12. data/lib/mixin_bot/api/asset.rb +114 -3
  13. data/lib/mixin_bot/api/auth.rb +19 -10
  14. data/lib/mixin_bot/api/blaze.rb +81 -0
  15. data/lib/mixin_bot/api/chain.rb +94 -0
  16. data/lib/mixin_bot/api/code.rb +16 -0
  17. data/lib/mixin_bot/api/computer_api.rb +60 -0
  18. data/lib/mixin_bot/api/conversation.rb +7 -1
  19. data/lib/mixin_bot/api/deposit.rb +12 -0
  20. data/lib/mixin_bot/api/encrypted_message.rb +1 -1
  21. data/lib/mixin_bot/api/fiat.rb +12 -0
  22. data/lib/mixin_bot/api/inscription.rb +2 -2
  23. data/lib/mixin_bot/api/legacy_collectible.rb +26 -27
  24. data/lib/mixin_bot/api/legacy_multisig.rb +20 -21
  25. data/lib/mixin_bot/api/legacy_output.rb +10 -3
  26. data/lib/mixin_bot/api/legacy_payment.rb +2 -0
  27. data/lib/mixin_bot/api/legacy_snapshot.rb +16 -0
  28. data/lib/mixin_bot/api/legacy_transaction.rb +28 -13
  29. data/lib/mixin_bot/api/legacy_transfer.rb +11 -8
  30. data/lib/mixin_bot/api/legacy_user.rb +51 -0
  31. data/lib/mixin_bot/api/me.rb +99 -3
  32. data/lib/mixin_bot/api/message.rb +18 -27
  33. data/lib/mixin_bot/api/multisig.rb +19 -0
  34. data/lib/mixin_bot/api/network.rb +17 -0
  35. data/lib/mixin_bot/api/network_asset.rb +27 -0
  36. data/lib/mixin_bot/api/output.rb +1 -1
  37. data/lib/mixin_bot/api/pin.rb +16 -3
  38. data/lib/mixin_bot/api/pin_payload.rb +26 -0
  39. data/lib/mixin_bot/api/session.rb +14 -0
  40. data/lib/mixin_bot/api/snapshot.rb +6 -0
  41. data/lib/mixin_bot/api/tip.rb +74 -1
  42. data/lib/mixin_bot/api/transaction.rb +106 -17
  43. data/lib/mixin_bot/api/transfer.rb +141 -14
  44. data/lib/mixin_bot/api/turn.rb +12 -0
  45. data/lib/mixin_bot/api/user.rb +148 -45
  46. data/lib/mixin_bot/api/withdraw.rb +24 -23
  47. data/lib/mixin_bot/api.rb +248 -3
  48. data/lib/mixin_bot/bot_auth.rb +71 -0
  49. data/lib/mixin_bot/cli/api.rb +224 -143
  50. data/lib/mixin_bot/cli/base.rb +77 -0
  51. data/lib/mixin_bot/cli/call.rb +71 -0
  52. data/lib/mixin_bot/cli/errors.rb +56 -0
  53. data/lib/mixin_bot/cli/node.rb +9 -2
  54. data/lib/mixin_bot/cli/output.rb +196 -0
  55. data/lib/mixin_bot/cli/schema.rb +274 -0
  56. data/lib/mixin_bot/cli/schema_command.rb +21 -0
  57. data/lib/mixin_bot/cli/utils.rb +114 -18
  58. data/lib/mixin_bot/cli.rb +124 -48
  59. data/lib/mixin_bot/client/error_mapper.rb +40 -0
  60. data/lib/mixin_bot/client.rb +94 -64
  61. data/lib/mixin_bot/computer.rb +132 -0
  62. data/lib/mixin_bot/configuration.rb +108 -1
  63. data/lib/mixin_bot/errors.rb +102 -0
  64. data/lib/mixin_bot/models/address.rb +11 -0
  65. data/lib/mixin_bot/models/api_envelope.rb +67 -0
  66. data/lib/mixin_bot/models/asset.rb +11 -0
  67. data/lib/mixin_bot/models/ghost_keys.rb +14 -0
  68. data/lib/mixin_bot/models/output.rb +11 -0
  69. data/lib/mixin_bot/models/safe_multisig_request.rb +11 -0
  70. data/lib/mixin_bot/models/sequencer_transaction_request.rb +11 -0
  71. data/lib/mixin_bot/models/user.rb +11 -0
  72. data/lib/mixin_bot/models.rb +10 -0
  73. data/lib/mixin_bot/monitor.rb +77 -0
  74. data/lib/mixin_bot/transaction/buffer.rb +34 -0
  75. data/lib/mixin_bot/transaction/decoder.rb +227 -0
  76. data/lib/mixin_bot/transaction/encoder.rb +255 -0
  77. data/lib/mixin_bot/transaction.rb +6 -475
  78. data/lib/mixin_bot/url_scheme.rb +63 -0
  79. data/lib/mixin_bot/utils/address.rb +17 -80
  80. data/lib/mixin_bot/utils/crypto.rb +173 -1
  81. data/lib/mixin_bot/utils/decoder.rb +1 -1
  82. data/lib/mixin_bot/utils/encoder.rb +13 -0
  83. data/lib/mixin_bot/utils.rb +45 -0
  84. data/lib/mixin_bot/uuid.rb +78 -1
  85. data/lib/mixin_bot/version.rb +11 -1
  86. data/lib/mixin_bot.rb +172 -18
  87. data/lib/mvm/bridge.rb +46 -0
  88. data/lib/mvm/client.rb +60 -0
  89. data/lib/mvm/nft.rb +4 -2
  90. data/lib/mvm/registry.rb +2 -1
  91. data/lib/mvm.rb +93 -0
  92. data/lib/tasks/api_coverage.rake +20 -0
  93. data/llms.txt +29 -0
  94. metadata +77 -9
@@ -2,7 +2,65 @@
2
2
 
3
3
  module MixinBot
4
4
  module Utils
5
+ ##
6
+ # Cryptographic utility methods for Mixin Network operations.
7
+ #
8
+ # This module provides essential cryptographic functions including:
9
+ # - JWT token generation for API authentication
10
+ # - Ed25519 and RSA key generation
11
+ # - PIN encryption/decryption
12
+ # - Transaction signing
13
+ # - UUID generation and derivation
14
+ # - Ghost key derivation for Safe API
15
+ #
16
+ # == Key Types
17
+ #
18
+ # Mixin Network uses several types of cryptographic keys:
19
+ #
20
+ # [Session Key] Ed25519 or RSA key for API authentication
21
+ # [Spend Key] Ed25519 key for signing transactions (Safe API)
22
+ # [View Key] Ed25519 key for viewing transactions
23
+ # [PIN Key] For legacy PIN operations
24
+ #
25
+ # == Signature Algorithm
26
+ #
27
+ # Safe API uses Ed25519 with Blake3 hashing for transaction signing.
28
+ # This provides quantum-resistant security with compact signatures.
29
+ #
5
30
  module Crypto
31
+ ##
32
+ # Generates a JWT access token for API authentication.
33
+ #
34
+ # Creates a signed JWT token containing request details and credentials.
35
+ # The token is used in the Authorization header for API requests.
36
+ #
37
+ # Token payload includes:
38
+ # - uid: user/bot ID
39
+ # - sid: session ID
40
+ # - iat: issued at timestamp
41
+ # - exp: expiration timestamp
42
+ # - jti: unique token ID
43
+ # - sig: SHA-256 hash of request (method + uri + body)
44
+ # - scp: scope (usually 'FULL')
45
+ #
46
+ # @param method [String] HTTP method (GET, POST, etc.)
47
+ # @param uri [String] request URI path
48
+ # @param body [String] request body (empty for GET)
49
+ # @param kwargs [Hash] additional options
50
+ # @option kwargs [Integer] :exp_in (600) token lifetime in seconds
51
+ # @option kwargs [String] :scp ('FULL') token scope
52
+ # @option kwargs [String] :app_id bot application ID
53
+ # @option kwargs [String] :session_id session ID
54
+ # @option kwargs [String] :private_key session private key
55
+ #
56
+ # @return [String] JWT token
57
+ #
58
+ # @raise [ConfigurationNotValidError] if private_key is missing
59
+ #
60
+ # @example
61
+ # token = MixinBot.utils.access_token('GET', '/me', '')
62
+ # # Use in request: Authorization: Bearer #{token}
63
+ #
6
64
  def access_token(method, uri, body = '', **kwargs)
7
65
  sig = Digest::SHA256.hexdigest(method + uri + body.to_s)
8
66
  iat = Time.now.utc.to_i
@@ -37,6 +95,19 @@ module MixinBot
37
95
  JOSE::JWT.sign(jwk, jws, jwt).compact
38
96
  end
39
97
 
98
+ ##
99
+ # Generates a new Ed25519 keypair.
100
+ #
101
+ # Ed25519 is the recommended key type for Mixin Network.
102
+ # It provides strong security with compact keys and signatures.
103
+ #
104
+ # @return [Hash] hash containing :private_key and :public_key (Base64-encoded)
105
+ #
106
+ # @example
107
+ # keys = MixinBot.utils.generate_ed25519_key
108
+ # puts "Private: #{keys[:private_key]}"
109
+ # puts "Public: #{keys[:public_key]}"
110
+ #
40
111
  def generate_ed25519_key
41
112
  ed25519_key = JOSE::JWA::Ed25519.keypair
42
113
  {
@@ -45,6 +116,18 @@ module MixinBot
45
116
  }
46
117
  end
47
118
 
119
+ ##
120
+ # Generates a new RSA keypair.
121
+ #
122
+ # RSA keys are supported for backward compatibility but
123
+ # Ed25519 is recommended for new applications.
124
+ #
125
+ # @return [Hash] hash containing :private_key and :public_key (PEM format)
126
+ #
127
+ # @example
128
+ # keys = MixinBot.utils.generate_rsa_key
129
+ # puts keys[:private_key]
130
+ #
48
131
  def generate_rsa_key
49
132
  rsa_key = OpenSSL::PKey::RSA.new 1024
50
133
  {
@@ -53,10 +136,26 @@ module MixinBot
53
136
  }
54
137
  end
55
138
 
139
+ ##
140
+ # Derives a public key from a private key.
141
+ #
142
+ # Used internally for cryptographic operations.
143
+ #
144
+ # @param key [String] the private key (64 bytes)
145
+ # @return [String] the derived public key
146
+ #
56
147
  def shared_public_key(key)
57
148
  (JOSE::JWA::Edwards25519Point.stdbase * scalar_from_bytes(key[...64]).x.to_i).encode
58
149
  end
59
150
 
151
+ ##
152
+ # Converts raw bytes to a scalar for Ed25519 operations.
153
+ #
154
+ # Used internally for cryptographic calculations.
155
+ #
156
+ # @param raw [String] raw bytes
157
+ # @return [JOSE::JWA::FieldElement] the scalar value
158
+ #
60
159
  def scalar_from_bytes(raw)
61
160
  JOSE::JWA::FieldElement.new(
62
161
  # https://github.com/potatosalad/ruby-jose/blob/e1be589b889f1e59ac233a5d19a3fa13f1e4b8a0/lib/jose/jwa/x25519.rb#L122C14-L122C48
@@ -100,6 +199,29 @@ module MixinBot
100
199
  MixinBot::UUID.new(raw: cipher).unpacked
101
200
  end
102
201
 
202
+ ##
203
+ # Generates a unique UUID from multiple UUIDs.
204
+ #
205
+ # Creates a deterministic UUID by combining multiple UUIDs.
206
+ # The result is always the same for the same set of input UUIDs,
207
+ # regardless of order (after sorting).
208
+ #
209
+ # This is used for:
210
+ # - Creating conversation IDs
211
+ # - Generating multisig addresses
212
+ # - Creating deterministic identifiers
213
+ #
214
+ # @param uuids [Array<String>] array of UUIDs to combine
215
+ # @return [String] the unique combined UUID
216
+ #
217
+ # @example
218
+ # uuid = MixinBot.utils.unique_uuid(
219
+ # 'user1-uuid',
220
+ # 'user2-uuid',
221
+ # 'user3-uuid'
222
+ # )
223
+ # puts uuid # Always the same for these inputs
224
+ #
103
225
  def unique_uuid(*uuids)
104
226
  uuids = uuids.flatten.compact
105
227
  uuids.sort
@@ -111,6 +233,28 @@ module MixinBot
111
233
  r
112
234
  end
113
235
 
236
+ ##
237
+ # Generates a group conversation ID.
238
+ #
239
+ # Creates a deterministic conversation ID for a group based on:
240
+ # - Owner ID
241
+ # - Group name
242
+ # - Participant IDs
243
+ # - Random ID (optional, for creating different groups with same members)
244
+ #
245
+ # @param user_ids [Array<String>] array of participant user IDs
246
+ # @param name [String] the group name
247
+ # @param owner_id [String] the group owner's user ID
248
+ # @param random_id [String, nil] optional random ID for uniqueness
249
+ # @return [String] the conversation UUID
250
+ #
251
+ # @example
252
+ # conv_id = MixinBot.utils.generate_group_conversation_id(
253
+ # user_ids: ['user1', 'user2', 'user3'],
254
+ # name: 'My Group',
255
+ # owner_id: 'owner-id'
256
+ # )
257
+ #
114
258
  def generate_group_conversation_id(user_ids:, name:, owner_id:, random_id: nil)
115
259
  random_id ||= SecureRandom.uuid
116
260
 
@@ -129,6 +273,33 @@ module MixinBot
129
273
  gid
130
274
  end
131
275
 
276
+ def generate_user_checksum(sessions)
277
+ list = Array(sessions).map do |s|
278
+ s.is_a?(Hash) ? s['session_id'] || s[:session_id] : s.session_id
279
+ end.compact.sort
280
+ return '' if list.empty?
281
+
282
+ Digest::MD5.hexdigest(list.join)
283
+ end
284
+
285
+ def chunked(source, size)
286
+ source.each_slice(size).to_a
287
+ end
288
+
289
+ def make_unique_string_slice(strings)
290
+ strings.uniq
291
+ end
292
+
293
+ def unique_object_id(*args)
294
+ md5 = Digest::MD5.new
295
+ args.flatten.compact.each { |s| md5 << s.to_s }
296
+ digest = md5.digest
297
+ digest = digest.dup
298
+ digest[6] = ((digest[6].ord & 0x0f) | 0x30).chr
299
+ digest[8] = ((digest[8].ord & 0x3f) | 0x80).chr
300
+ MixinBot::UUID.new(raw: digest).unpacked
301
+ end
302
+
132
303
  def generate_trace_from_hash(hash, output_index = 0)
133
304
  md5 = Digest::MD5.new
134
305
  md5 << hash
@@ -153,7 +324,8 @@ module MixinBot
153
324
  decode_cipher.update(cipher)
154
325
  end
155
326
 
156
- # 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.
327
+ # use timestamp(timestamp) for iterator as default: must be bigger than the previous,
328
+ # the first time must be greater than 0. After a new session created, it will be reset to 0.
157
329
  def encrypt_pin(pin, **kwargs)
158
330
  pin = MixinBot.utils.decode_key pin
159
331
 
@@ -6,7 +6,7 @@ module MixinBot
6
6
  def decode_key(key)
7
7
  return if key.blank?
8
8
 
9
- if key.match?(/\A[\h]{64,}\z/i)
9
+ if key.match?(/\A\h{64,}\z/i)
10
10
  [key].pack('H*')
11
11
  elsif key.match?(/^-----BEGIN RSA PRIVATE KEY-----/)
12
12
  key.gsub('\\r\\n', "\n").gsub("\r\n", "\n")
@@ -37,6 +37,19 @@ module MixinBot
37
37
  [int].pack('Q*').bytes.reverse
38
38
  end
39
39
 
40
+ ##
41
+ # Big-endian varint-style encoding for deposit amounts (integer or decimal string).
42
+ #
43
+ def bytes_of(amount)
44
+ int =
45
+ case amount
46
+ when Integer then amount
47
+ when String then Integer(amount, 10)
48
+ else amount.to_i
49
+ end
50
+ encode_int(int)
51
+ end
52
+
40
53
  def encode_int(int)
41
54
  raise ArgumentError, 'not integer' unless int.is_a?(Integer)
42
55
 
@@ -6,6 +6,51 @@ require_relative 'utils/decoder'
6
6
  require_relative 'utils/encoder'
7
7
 
8
8
  module MixinBot
9
+ ##
10
+ # Utility module providing various helper methods for Mixin Network operations.
11
+ #
12
+ # This module aggregates utility methods from several sub-modules:
13
+ #
14
+ # == Sub-modules
15
+ #
16
+ # [MixinBot::Utils::Address] Address-related utilities
17
+ # - Main address handling
18
+ # - Ghost key derivation
19
+ # - Address validation
20
+ #
21
+ # [MixinBot::Utils::Crypto] Cryptographic operations
22
+ # - JWT token generation
23
+ # - Key generation and management
24
+ # - Transaction signing
25
+ # - PIN encryption
26
+ # - UUID generation
27
+ #
28
+ # [MixinBot::Utils::Decoder] Data decoding utilities
29
+ # - Integer decoding
30
+ # - Transaction decoding
31
+ # - Key decoding
32
+ #
33
+ # [MixinBot::Utils::Encoder] Data encoding utilities
34
+ # - Integer encoding
35
+ # - Transaction encoding
36
+ # - Binary packing
37
+ #
38
+ # == Usage
39
+ #
40
+ # Access utilities through the MixinBot.utils shortcut:
41
+ #
42
+ # # Generate a unique UUID
43
+ # uuid = MixinBot.utils.unique_uuid(uuid1, uuid2)
44
+ #
45
+ # # Generate access token
46
+ # token = MixinBot.utils.access_token('GET', '/me', '')
47
+ #
48
+ # # Encode a transaction
49
+ # raw = MixinBot.utils.encode_raw_transaction(txn)
50
+ #
51
+ # # Decode a key
52
+ # key = MixinBot.utils.decode_key(encoded_key)
53
+ #
9
54
  module Utils
10
55
  extend MixinBot::Utils::Address
11
56
  extend MixinBot::Utils::Crypto
@@ -1,9 +1,66 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MixinBot
4
+ ##
5
+ # Utility class for handling Mixin Network UUID format conversions.
6
+ #
7
+ # Mixin Network uses UUIDs extensively for identifying:
8
+ # - Users and bots
9
+ # - Assets
10
+ # - Transactions and traces
11
+ # - Conversations
12
+ #
13
+ # == Format Conversions
14
+ #
15
+ # This class handles conversions between:
16
+ # - Standard UUID format: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" (36 chars)
17
+ # - Packed binary format: 16 bytes
18
+ # - Hex format without dashes: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" (32 chars)
19
+ #
20
+ # == Usage
21
+ #
22
+ # # From hex format to UUID
23
+ # uuid = MixinBot::UUID.new(hex: '965e5c6e434c3fa9b780c50f43cd955c')
24
+ # uuid.unpacked
25
+ # # => "965e5c6e-434c-3fa9-b780-c50f43cd955c"
26
+ #
27
+ # # From UUID to packed binary
28
+ # uuid = MixinBot::UUID.new(hex: '965e5c6e-434c-3fa9-b780-c50f43cd955c')
29
+ # uuid.packed
30
+ # # => "\x96^\\nC<?\xA9\xB7\x80\xC5\x0FC\xCD\x95\\"
31
+ #
32
+ # # From packed binary to UUID
33
+ # uuid = MixinBot::UUID.new(raw: binary_data)
34
+ # uuid.unpacked
35
+ # # => "965e5c6e-434c-3fa9-b780-c50f43cd955c"
36
+ #
4
37
  class UUID
5
- attr_accessor :hex, :raw
38
+ ##
39
+ # @return [String] the UUID in hex format (with or without dashes)
40
+ attr_accessor :hex
6
41
 
42
+ ##
43
+ # @return [String] the UUID in packed binary format (16 bytes)
44
+ attr_accessor :raw
45
+
46
+ ##
47
+ # Initializes a new UUID instance.
48
+ #
49
+ # Provide either :hex or :raw parameter. The other format can be
50
+ # obtained via #packed or #unpacked methods.
51
+ #
52
+ # @param args [Hash] initialization options
53
+ # @option args [String] :hex the UUID in hex format (with or without dashes)
54
+ # @option args [String] :raw the UUID in packed binary format (16 bytes)
55
+ #
56
+ # @raise [MixinBot::InvalidUuidFormatError] if format is invalid
57
+ #
58
+ # @example From hex
59
+ # uuid = MixinBot::UUID.new(hex: '965e5c6e-434c-3fa9-b780-c50f43cd955c')
60
+ #
61
+ # @example From raw binary
62
+ # uuid = MixinBot::UUID.new(raw: binary_string)
63
+ #
7
64
  def initialize(**args)
8
65
  args = args.with_indifferent_access
9
66
 
@@ -14,6 +71,16 @@ module MixinBot
14
71
  raise MixinBot::InvalidUuidFormatError if hex.present? && hex.gsub('-', '').size != 32
15
72
  end
16
73
 
74
+ ##
75
+ # Returns the UUID in packed binary format (16 bytes).
76
+ #
77
+ # @return [String] 16-byte binary string
78
+ #
79
+ # @example
80
+ # uuid = MixinBot::UUID.new(hex: '965e5c6e-434c-3fa9-b780-c50f43cd955c')
81
+ # uuid.packed
82
+ # # => 16-byte binary string
83
+ #
17
84
  def packed
18
85
  if raw.present?
19
86
  raw
@@ -22,6 +89,16 @@ module MixinBot
22
89
  end
23
90
  end
24
91
 
92
+ ##
93
+ # Returns the UUID in standard format with dashes.
94
+ #
95
+ # @return [String] UUID in format "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
96
+ #
97
+ # @example
98
+ # uuid = MixinBot::UUID.new(raw: binary_string)
99
+ # uuid.unpacked
100
+ # # => "965e5c6e-434c-3fa9-b780-c50f43cd955c"
101
+ #
25
102
  def unpacked
26
103
  _hex =
27
104
  if hex.present?
@@ -1,5 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MixinBot
4
- VERSION = '1.4.0'
4
+ ##
5
+ # Current version of the MixinBot gem.
6
+ #
7
+ # Follows Semantic Versioning (SemVer):
8
+ # - MAJOR version for incompatible API changes
9
+ # - MINOR version for backwards-compatible functionality additions
10
+ # - PATCH version for backwards-compatible bug fixes
11
+ #
12
+ # @see https://semver.org/
13
+ #
14
+ VERSION = '2.0.0'
5
15
  end
data/lib/mixin_bot.rb CHANGED
@@ -20,10 +20,16 @@ require 'openssl'
20
20
  require 'rbnacl'
21
21
  require 'sha3'
22
22
 
23
+ require_relative 'mixin_bot/errors'
23
24
  require_relative 'mixin_bot/address'
25
+ require_relative 'mixin_bot/models'
24
26
  require_relative 'mixin_bot/api'
27
+ require_relative 'mixin_bot/bot_auth'
25
28
  require_relative 'mixin_bot/cli'
29
+ require_relative 'mixin_bot/computer'
26
30
  require_relative 'mixin_bot/invoice'
31
+ require_relative 'mixin_bot/monitor'
32
+ require_relative 'mixin_bot/url_scheme'
27
33
  require_relative 'mixin_bot/utils'
28
34
  require_relative 'mixin_bot/nfo'
29
35
  require_relative 'mixin_bot/uuid'
@@ -31,8 +37,134 @@ require_relative 'mixin_bot/transaction'
31
37
  require_relative 'mixin_bot/version'
32
38
  require_relative 'mvm'
33
39
 
40
+ ##
41
+ # = MixinBot
42
+ #
43
+ # MixinBot is a Ruby SDK for interacting with the Mixin Network API.
44
+ #
45
+ # == Overview
46
+ #
47
+ # Mixin Network is a free and lightning fast peer-to-peer transactional network
48
+ # for digital assets. MixinBot provides a comprehensive Ruby interface to interact
49
+ # with the Mixin Network, including asset management, transfers, messaging, and more.
50
+ #
51
+ # == Installation
52
+ #
53
+ # Add this line to your application's Gemfile:
54
+ #
55
+ # gem 'mixin_bot'
56
+ #
57
+ # And then execute:
58
+ #
59
+ # $ bundle install
60
+ #
61
+ # Or install it yourself as:
62
+ #
63
+ # $ gem install mixin_bot
64
+ #
65
+ # == Quick Start
66
+ #
67
+ # === Configuration
68
+ #
69
+ # Configure your Mixin bot credentials:
70
+ #
71
+ # MixinBot.configure do
72
+ # self.app_id = '25696f85-b7b4-4509-8c3f-2684a8fc4a2a'
73
+ # self.client_secret = 'd9dc58107bacde671...'
74
+ # self.session_id = '25696f85-b7b4-4509-8c3f-2684a8fc4a2a'
75
+ # self.server_public_key = 'b0pjBUKI0Vp9K+NspaL....'
76
+ # self.session_private_key = '...'
77
+ # end
78
+ #
79
+ # === Basic Usage
80
+ #
81
+ # Get bot profile:
82
+ #
83
+ # MixinBot.api.me
84
+ # # => { "user_id" => "...", "full_name" => "...", ... }
85
+ #
86
+ # Get bot assets:
87
+ #
88
+ # MixinBot.api.assets
89
+ # # => [{ "asset_id" => "...", "symbol" => "BTC", ... }, ...]
90
+ #
91
+ # Transfer assets:
92
+ #
93
+ # MixinBot.api.create_transfer(
94
+ # '123456', # pin_code
95
+ # asset_id: '965e5c6e-434c-3fa9-b780-c50f43cd955c', # CNB
96
+ # opponent_id: '6ae1c7ae-1df1-498e-8f21-d48cb6d129b5', # receiver
97
+ # amount: 0.00000001,
98
+ # memo: 'test transfer',
99
+ # trace_id: SecureRandom.uuid
100
+ # )
101
+ #
102
+ # === Managing Multiple Bots
103
+ #
104
+ # You can manage multiple bots by creating separate API instances:
105
+ #
106
+ # bot1 = MixinBot::API.new(
107
+ # app_id: '...',
108
+ # session_id: '...',
109
+ # session_private_key: '...',
110
+ # server_public_key: '...'
111
+ # )
112
+ #
113
+ # bot2 = MixinBot::API.new(
114
+ # app_id: '...',
115
+ # session_id: '...',
116
+ # session_private_key: '...',
117
+ # server_public_key: '...'
118
+ # )
119
+ #
120
+ # bot1.me
121
+ # bot2.me
122
+ #
123
+ # == Main Components
124
+ #
125
+ # [MixinBot::API] Main API interface for interacting with Mixin Network
126
+ # [MixinBot::Configuration] Configuration management for bot credentials
127
+ # [MixinBot::Client] HTTP client for making API requests
128
+ # [MixinBot::Utils] Utility methods for cryptography and encoding
129
+ # [MixinBot::Transaction] Transaction encoding and decoding
130
+ # [MixinBot::MixAddress] Address handling for Mixin Network
131
+ # [MixinBot::Invoice] Invoice creation and parsing
132
+ # [MixinBot::Nfo] NFT memo handling
133
+ # [MixinBot::UUID] UUID utilities for Mixin Network
134
+ # [MVM] Mixin Virtual Machine integration
135
+ #
136
+ # == Error Handling
137
+ #
138
+ # MixinBot defines several custom error classes for different scenarios:
139
+ #
140
+ # begin
141
+ # MixinBot.api.create_transfer(...)
142
+ # rescue MixinBot::InsufficientBalanceError => e
143
+ # puts "Insufficient balance: #{e.message}"
144
+ # rescue MixinBot::UnauthorizedError => e
145
+ # puts "Unauthorized: #{e.message}"
146
+ # rescue MixinBot::ResponseError => e
147
+ # puts "API error: #{e.message}"
148
+ # end
149
+ #
150
+ # == Links
151
+ #
152
+ # - {Mixin Network Documentation}[https://developers.mixin.one/docs]
153
+ # - {GitHub Repository}[https://github.com/an-lee/mixin_bot]
154
+ #
34
155
  module MixinBot
35
156
  class << self
157
+ ##
158
+ # Returns the default API instance using the global configuration.
159
+ #
160
+ # This is a singleton instance that will be created on first access.
161
+ # The API instance provides access to all Mixin Network API endpoints.
162
+ #
163
+ # MixinBot.api.me
164
+ # # => { "user_id" => "...", "full_name" => "..." }
165
+ #
166
+ # @return [MixinBot::API] the default API instance
167
+ #
36
168
  def api
37
169
  return @api if defined?(@api)
38
170
 
@@ -40,6 +172,14 @@ module MixinBot
40
172
  @api
41
173
  end
42
174
 
175
+ ##
176
+ # Returns the global configuration instance.
177
+ #
178
+ # The configuration instance stores bot credentials and settings.
179
+ # It will be created on first access with default values.
180
+ #
181
+ # @return [MixinBot::Configuration] the configuration instance
182
+ #
43
183
  def config
44
184
  return @config if defined?(@config)
45
185
 
@@ -47,30 +187,44 @@ module MixinBot
47
187
  @config
48
188
  end
49
189
 
190
+ ##
191
+ # Configures the global MixinBot settings.
192
+ #
193
+ # This method yields the configuration instance to a block where
194
+ # you can set your bot credentials and other settings.
195
+ #
196
+ # MixinBot.configure do
197
+ # self.app_id = '25696f85-b7b4-4509-8c3f-2684a8fc4a2a'
198
+ # self.session_id = '25696f85-b7b4-4509-8c3f-2684a8fc4a2a'
199
+ # self.session_private_key = '...'
200
+ # self.server_public_key = '...'
201
+ # end
202
+ #
203
+ # @yield [Configuration] the configuration instance
204
+ # @return [void]
205
+ #
50
206
  def configure(&)
51
207
  config.instance_exec(&)
52
208
  end
53
209
 
210
+ ##
211
+ # Returns the Utils module for accessing utility methods.
212
+ #
213
+ # MixinBot.utils.unique_uuid(uuid1, uuid2)
214
+ #
215
+ # @return [Module] the Utils module
216
+ #
54
217
  def utils
55
218
  MixinBot::Utils
56
219
  end
57
- end
58
220
 
59
- class Error < StandardError; end
60
- class ArgumentError < StandardError; end
61
- class HttpError < Error; end
62
- class RequestError < Error; end
63
- class ResponseError < Error; end
64
- class NotFoundError < Error; end
65
- class UserNotFoundError < Error; end
66
- class UnauthorizedError < Error; end
67
- class ForbiddenError < Error; end
68
- class InsufficientBalanceError < Error; end
69
- class InsufficientPoolError < Error; end
70
- class PinError < Error; end
71
- class InvalidNfoFormatError < Error; end
72
- class InvalidUuidFormatError < Error; end
73
- class InvalidTransactionFormatError < Error; end
74
- class ConfigurationNotValidError < Error; end
75
- class InvalidInvoiceFormatError < Error; end
221
+ ##
222
+ # ActiveSupport deprecation helper for legacy API surfaces.
223
+ #
224
+ # @return [ActiveSupport::Deprecation]
225
+ #
226
+ def deprecator
227
+ @deprecator ||= ActiveSupport::Deprecation.new('2.0', 'MixinBot')
228
+ end
229
+ end
76
230
  end