solana-ruby-kit 7.1.1.2 → 8.3.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 (74) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +106 -12
  3. data/lib/solana/ruby/kit/accounts/maybe_account.rb +1 -1
  4. data/lib/solana/ruby/kit/addresses/address.rb +1 -1
  5. data/lib/solana/ruby/kit/addresses/curve.rb +1 -1
  6. data/lib/solana/ruby/kit/addresses/program_derived_address.rb +1 -1
  7. data/lib/solana/ruby/kit/addresses/public_key.rb +1 -1
  8. data/lib/solana/ruby/kit/codecs/codec.rb +95 -1
  9. data/lib/solana/ruby/kit/codecs/data_structures.rb +51 -8
  10. data/lib/solana/ruby/kit/codecs/numbers.rb +49 -50
  11. data/lib/solana/ruby/kit/codecs/strings.rb +132 -6
  12. data/lib/solana/ruby/kit/encoding/base58.rb +1 -1
  13. data/lib/solana/ruby/kit/errors.rb +12 -0
  14. data/lib/solana/ruby/kit/fast_stable_stringify.rb +1 -1
  15. data/lib/solana/ruby/kit/functional.rb +1 -1
  16. data/lib/solana/ruby/kit/instruction_plans/instruction_plan.rb +1 -1
  17. data/lib/solana/ruby/kit/instruction_plans/max_instructions.rb +1 -1
  18. data/lib/solana/ruby/kit/instruction_plans/transaction_plan.rb +1 -1
  19. data/lib/solana/ruby/kit/instruction_plans/transaction_plan_executor.rb +107 -2
  20. data/lib/solana/ruby/kit/instruction_plans/transaction_plan_result.rb +1 -1
  21. data/lib/solana/ruby/kit/instruction_plans/transaction_planner.rb +2 -2
  22. data/lib/solana/ruby/kit/instructions/accounts.rb +1 -1
  23. data/lib/solana/ruby/kit/instructions/instruction.rb +1 -1
  24. data/lib/solana/ruby/kit/instructions/roles.rb +1 -1
  25. data/lib/solana/ruby/kit/keys/key_pair.rb +1 -1
  26. data/lib/solana/ruby/kit/keys/private_key.rb +1 -1
  27. data/lib/solana/ruby/kit/keys/public_key.rb +1 -1
  28. data/lib/solana/ruby/kit/keys/signatures.rb +1 -1
  29. data/lib/solana/ruby/kit/offchain_messages/codec.rb +1 -1
  30. data/lib/solana/ruby/kit/offchain_messages/message_v1.rb +1 -1
  31. data/lib/solana/ruby/kit/options/option.rb +1 -1
  32. data/lib/solana/ruby/kit/plugin_core.rb +1 -1
  33. data/lib/solana/ruby/kit/programs/associated_token_account.rb +1 -1
  34. data/lib/solana/ruby/kit/programs/stake_program.rb +1 -1
  35. data/lib/solana/ruby/kit/programs/system_program.rb +1 -1
  36. data/lib/solana/ruby/kit/programs.rb +1 -1
  37. data/lib/solana/ruby/kit/promises.rb +1 -1
  38. data/lib/solana/ruby/kit/resource_limit_estimation.rb +1 -1
  39. data/lib/solana/ruby/kit/rpc/api/get_ag_genesis_cert.rb +72 -0
  40. data/lib/solana/ruby/kit/rpc/client.rb +2 -0
  41. data/lib/solana/ruby/kit/rpc_parsed_types/address_lookup_table.rb +1 -1
  42. data/lib/solana/ruby/kit/rpc_parsed_types/nonce_account.rb +1 -1
  43. data/lib/solana/ruby/kit/rpc_parsed_types/stake_account.rb +1 -1
  44. data/lib/solana/ruby/kit/rpc_parsed_types/token_account.rb +1 -1
  45. data/lib/solana/ruby/kit/rpc_parsed_types/vote_account.rb +1 -1
  46. data/lib/solana/ruby/kit/rpc_types/cluster_url.rb +1 -1
  47. data/lib/solana/ruby/kit/rpc_types/commitment.rb +1 -1
  48. data/lib/solana/ruby/kit/rpc_types/lamports.rb +1 -1
  49. data/lib/solana/ruby/kit/rpc_types/sol.rb +1 -1
  50. data/lib/solana/ruby/kit/signers/keypair_signer.rb +1 -1
  51. data/lib/solana/ruby/kit/subscribable/async_iterable.rb +1 -1
  52. data/lib/solana/ruby/kit/subscribable/bridge_store_to_async_iterable.rb +1 -1
  53. data/lib/solana/ruby/kit/subscribable/reactive_action_store.rb +1 -1
  54. data/lib/solana/ruby/kit/subscribable/reactive_stream_store.rb +1 -1
  55. data/lib/solana/ruby/kit/sysvars/clock.rb +1 -1
  56. data/lib/solana/ruby/kit/sysvars/epoch_schedule.rb +1 -1
  57. data/lib/solana/ruby/kit/sysvars/last_restart_slot.rb +1 -1
  58. data/lib/solana/ruby/kit/sysvars/rent.rb +1 -1
  59. data/lib/solana/ruby/kit/sysvars.rb +1 -1
  60. data/lib/solana/ruby/kit/transaction_confirmation.rb +1 -1
  61. data/lib/solana/ruby/kit/transaction_introspection/compiled_transaction_message.rb +1 -1
  62. data/lib/solana/ruby/kit/transaction_introspection/decode_rpc_transaction.rb +1 -1
  63. data/lib/solana/ruby/kit/transaction_introspection/get_inner_instructions.rb +1 -1
  64. data/lib/solana/ruby/kit/transaction_introspection/get_instructions.rb +1 -1
  65. data/lib/solana/ruby/kit/transaction_introspection/walk_instructions.rb +1 -1
  66. data/lib/solana/ruby/kit/transaction_messages/compute_budget.rb +3 -1
  67. data/lib/solana/ruby/kit/transaction_messages/resource_limit_validation.rb +70 -0
  68. data/lib/solana/ruby/kit/transaction_messages/transaction_message.rb +1 -1
  69. data/lib/solana/ruby/kit/transaction_messages.rb +1 -0
  70. data/lib/solana/ruby/kit/transactions/compiler.rb +2 -2
  71. data/lib/solana/ruby/kit/transactions/transaction.rb +30 -10
  72. data/lib/solana/ruby/kit/version.rb +1 -1
  73. data/lib/solana/ruby/kit/wallet_standard.rb +3 -3
  74. metadata +3 -1
@@ -0,0 +1,72 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'has_transport'
5
+
6
+ module Solana::Ruby::Kit
7
+ module Rpc
8
+ module Api
9
+ # The block an Alpenglow genesis certificate certifies.
10
+ AgGenesisCertBlock = T.let(
11
+ Struct.new(
12
+ :block_id, # Array<Integer> — block id of the certified block, as a 32-byte array
13
+ :slot, # Integer — slot of the certified block
14
+ keyword_init: true
15
+ ),
16
+ T.untyped
17
+ )
18
+
19
+ # The aggregate signature over an Alpenglow genesis certificate.
20
+ AgGenesisCertSignature = T.let(
21
+ Struct.new(
22
+ :bitmap, # Array<Integer> — ranks of the validators in the aggregate signature
23
+ :signature, # Array<Integer> — the 192-byte aggregate BLS signature
24
+ keyword_init: true
25
+ ),
26
+ T.untyped
27
+ )
28
+
29
+ # The Alpenglow genesis certificate, as gossiped between validators.
30
+ # Mirrors the `WireBlockCertMessage` type in the Agave validator.
31
+ AgGenesisCert = T.let(
32
+ Struct.new(
33
+ :block, # AgGenesisCertBlock
34
+ :signature, # AgGenesisCertSignature
35
+ keyword_init: true
36
+ ),
37
+ T.untyped
38
+ )
39
+
40
+ # Returns the Alpenglow genesis certificate — the certificate over the block at which the
41
+ # Alpenglow consensus protocol was activated — or nil if the node does not have one.
42
+ # Mirrors TypeScript's GetAgGenesisCertApi.getAgGenesisCert.
43
+ # @see https://solana.com/docs/rpc/http/getaggenesiscert
44
+ module GetAgGenesisCert
45
+ extend T::Sig
46
+ extend T::Helpers
47
+
48
+ requires_ancestor { HasTransport }
49
+
50
+ sig { returns(T.untyped) }
51
+ def get_ag_genesis_cert
52
+ raw = transport.request('getAgGenesisCert', [])
53
+ return nil if raw.nil?
54
+
55
+ block = raw['block'] || {}
56
+ signature = raw['signature'] || {}
57
+
58
+ AgGenesisCert.new(
59
+ block: AgGenesisCertBlock.new(
60
+ block_id: Kernel.Array(block['blockId']).map { |b| Kernel.Integer(b) },
61
+ slot: Kernel.Integer(block['slot'])
62
+ ),
63
+ signature: AgGenesisCertSignature.new(
64
+ bitmap: Kernel.Array(signature['bitmap']).map { |b| Kernel.Integer(b) },
65
+ signature: Kernel.Array(signature['signature']).map { |b| Kernel.Integer(b) }
66
+ )
67
+ )
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -7,6 +7,7 @@ require_relative 'api/get_slot'
7
7
  require_relative 'api/get_balance'
8
8
  require_relative 'api/get_latest_blockhash'
9
9
  require_relative 'api/get_account_info'
10
+ require_relative 'api/get_ag_genesis_cert'
10
11
  require_relative 'api/get_block_height'
11
12
  require_relative 'api/get_signature_statuses'
12
13
  require_relative 'api/send_transaction'
@@ -51,6 +52,7 @@ module Solana::Ruby::Kit
51
52
  include Api::GetBalance
52
53
  include Api::GetLatestBlockhash
53
54
  include Api::GetAccountInfo
55
+ include Api::GetAgGenesisCert
54
56
  include Api::GetBlockHeight
55
57
  include Api::GetSignatureStatuses
56
58
  include Api::SendTransaction
@@ -14,7 +14,7 @@ module Solana::Ruby::Kit
14
14
  T.untyped
15
15
  )
16
16
 
17
- module_function
17
+ extend self
18
18
 
19
19
  sig { params(raw: T::Hash[String, T.untyped]).returns(T.untyped) }
20
20
  def parse_address_lookup_table(raw)
@@ -14,7 +14,7 @@ module Solana::Ruby::Kit
14
14
  T.untyped
15
15
  )
16
16
 
17
- module_function
17
+ extend self
18
18
 
19
19
  sig { params(raw: T::Hash[String, T.untyped]).returns(T.untyped) }
20
20
  def parse_nonce_account(raw)
@@ -20,7 +20,7 @@ module Solana::Ruby::Kit
20
20
  T.untyped
21
21
  )
22
22
 
23
- module_function
23
+ extend self
24
24
 
25
25
  sig { params(raw: T::Hash[String, T.untyped]).returns(T.untyped) }
26
26
  def parse_stake_account(raw)
@@ -22,7 +22,7 @@ module Solana::Ruby::Kit
22
22
  T.untyped
23
23
  )
24
24
 
25
- module_function
25
+ extend self
26
26
 
27
27
  sig { params(raw: T::Hash[String, T.untyped]).returns(T.untyped) }
28
28
  def parse_token_account(raw)
@@ -15,7 +15,7 @@ module Solana::Ruby::Kit
15
15
  T.untyped
16
16
  )
17
17
 
18
- module_function
18
+ extend self
19
19
 
20
20
  sig { params(raw: T::Hash[String, T.untyped]).returns(T.untyped) }
21
21
  def parse_vote_account(raw)
@@ -24,7 +24,7 @@ module Solana::Ruby::Kit
24
24
  def to_s = @url
25
25
  end
26
26
 
27
- module_function
27
+ extend self
28
28
 
29
29
  # Wraps a URL string and tags it as mainnet.
30
30
  # Mirrors `mainnet(url)`.
@@ -22,7 +22,7 @@ module Solana::Ruby::Kit
22
22
  T::Array[Symbol]
23
23
  )
24
24
 
25
- module_function
25
+ extend self
26
26
 
27
27
  # Returns a numeric score for a commitment level (higher = more confirmed).
28
28
  # Mirrors `getCommitmentScore()`.
@@ -15,7 +15,7 @@ module Solana::Ruby::Kit
15
15
 
16
16
  LAMPORTS_U64_MAX = T.let(T.unsafe(2**64 - 1), Integer)
17
17
 
18
- module_function
18
+ extend self
19
19
 
20
20
  # Returns true if the integer is a valid u64 lamport value.
21
21
  # Mirrors `isLamports()`.
@@ -55,7 +55,7 @@ module Solana::Ruby::Kit
55
55
  SOL_SCALE = T.let(1_000_000_000, Integer)
56
56
  SOL_RAW_MAX = T.let(Kernel.Integer(2**64 - 1), Integer)
57
57
 
58
- module_function
58
+ extend self
59
59
 
60
60
  # Parses a decimal string and returns a Sol value.
61
61
  # Raises FIXED_POINTS__STRICT_MODE_PRECISION_LOSS if the string has more
@@ -59,7 +59,7 @@ module Solana::Ruby::Kit
59
59
  end
60
60
  end
61
61
 
62
- module_function
62
+ extend self
63
63
 
64
64
  # Creates a KeyPairSigner from an existing Keys::KeyPair.
65
65
  # Mirrors `createSignerFromKeyPair(keyPair)`.
@@ -20,7 +20,7 @@ module Solana::Ruby::Kit
20
20
  # Sentinel value pushed into the queue when the stream is done.
21
21
  DONE = T.let(Object.new.freeze, Object)
22
22
 
23
- module_function
23
+ extend self
24
24
 
25
25
  # @param publisher [DataPublisher]
26
26
  # @param data_channel channel name for data messages
@@ -8,7 +8,7 @@ module Solana::Ruby::Kit
8
8
  module Subscribable
9
9
  extend T::Sig
10
10
 
11
- module_function
11
+ extend self
12
12
 
13
13
  # Adapts a ReactiveStreamStore into an Enumerator, so a *push*-based
14
14
  # reactive store can be driven by *pull*-based code that consumes it with
@@ -191,7 +191,7 @@ module Solana::Ruby::Kit
191
191
  end
192
192
  end
193
193
 
194
- module_function
194
+ extend self
195
195
 
196
196
  # Wraps a callable in a ReactiveActionStore.
197
197
  # fn receives the arguments passed to dispatch/dispatch_async.
@@ -199,7 +199,7 @@ module Solana::Ruby::Kit
199
199
  end
200
200
  end
201
201
 
202
- module_function
202
+ extend self
203
203
 
204
204
  # Creates a ReactiveStreamStore backed by a ready-made DataPublisher.
205
205
  # retry() is not supported — see create_reactive_store_from_data_publisher_factory.
@@ -17,7 +17,7 @@ module Solana::Ruby::Kit
17
17
 
18
18
  CLOCK_SIZE = T.let(40, Integer)
19
19
 
20
- module_function
20
+ extend self
21
21
 
22
22
  sig { params(rpc: Rpc::Client).returns(SysvarClock) }
23
23
  def fetch_sysvar_clock(rpc)
@@ -14,7 +14,7 @@ module Solana::Ruby::Kit
14
14
  const :first_normal_slot, Integer
15
15
  end
16
16
 
17
- module_function
17
+ extend self
18
18
 
19
19
  sig { params(rpc: Rpc::Client).returns(SysvarEpochSchedule) }
20
20
  def fetch_sysvar_epoch_schedule(rpc)
@@ -8,7 +8,7 @@ module Solana::Ruby::Kit
8
8
  const :last_restart_slot, Integer
9
9
  end
10
10
 
11
- module_function
11
+ extend self
12
12
 
13
13
  sig { params(rpc: Rpc::Client).returns(SysvarLastRestartSlot) }
14
14
  def fetch_sysvar_last_restart_slot(rpc)
@@ -11,7 +11,7 @@ module Solana::Ruby::Kit
11
11
  const :burn_percent, Integer
12
12
  end
13
13
 
14
- module_function
14
+ extend self
15
15
 
16
16
  sig { params(rpc: Rpc::Client).returns(SysvarRent) }
17
17
  def fetch_sysvar_rent(rpc)
@@ -11,7 +11,7 @@ module Solana::Ruby::Kit
11
11
  module Sysvars
12
12
  extend T::Sig
13
13
 
14
- module_function
14
+ extend self
15
15
 
16
16
  # Decode base64 account data from an RpcContextualValue returned by
17
17
  # get_account_info(encoding: 'base64').
@@ -10,7 +10,7 @@ module Solana::Ruby::Kit
10
10
  module TransactionConfirmation
11
11
  extend T::Sig
12
12
 
13
- module_function
13
+ extend self
14
14
 
15
15
  # Poll getSignatureStatuses until +signature+ reaches +commitment+ or
16
16
  # the blockheight/timeout deadline is exceeded.
@@ -39,7 +39,7 @@ module Solana::Ruby::Kit
39
39
  const :lifetime_token, String # base58-encoded blockhash or nonce value
40
40
  end
41
41
 
42
- module_function
42
+ extend self
43
43
 
44
44
  # Decodes legacy or v0 compiled transaction message bytes (the
45
45
  # `message_bytes` of a `Transactions::Transaction`) into a
@@ -31,7 +31,7 @@ module Solana::Ruby::Kit
31
31
  const :transaction, T.nilable(Transactions::Transaction)
32
32
  end
33
33
 
34
- module_function
34
+ extend self
35
35
 
36
36
  # Decodes a confirmed-transaction RPC response (any of `encoding: 'base64'`,
37
37
  # `'base58'`, or `'json'`) into a CompiledTransactionMessage plus, for
@@ -10,7 +10,7 @@ module Solana::Ruby::Kit
10
10
  module TransactionIntrospection
11
11
  extend T::Sig
12
12
 
13
- module_function
13
+ extend self
14
14
 
15
15
  # Returns the inner instructions in a transaction `meta` as
16
16
  # TracedInstructions.
@@ -11,7 +11,7 @@ module Solana::Ruby::Kit
11
11
  module TransactionIntrospection
12
12
  extend T::Sig
13
13
 
14
- module_function
14
+ extend self
15
15
 
16
16
  # Builds the full ordered list of AccountMetas for a compiled transaction
17
17
  # message.
@@ -11,7 +11,7 @@ module Solana::Ruby::Kit
11
11
  module TransactionIntrospection
12
12
  extend T::Sig
13
13
 
14
- module_function
14
+ extend self
15
15
 
16
16
  # Returns every instruction in a confirmed transaction as
17
17
  # TracedInstructions, in the order an explorer displays them: each outer
@@ -4,6 +4,7 @@
4
4
  require_relative '../addresses/address'
5
5
  require_relative '../instructions/instruction'
6
6
  require_relative 'transaction_message'
7
+ require_relative 'resource_limit_validation'
7
8
 
8
9
  module Solana::Ruby::Kit
9
10
  module TransactionMessages
@@ -22,7 +23,7 @@ module Solana::Ruby::Kit
22
23
  SET_COMPUTE_UNIT_LIMIT_DISCRIMINATOR = T.let(2, Integer)
23
24
  SET_LOADED_ACCOUNTS_DATA_SIZE_LIMIT_DISCRIMINATOR = T.let(4, Integer)
24
25
 
25
- module_function
26
+ extend self
26
27
 
27
28
  # ---------------------------------------------------------------------------
28
29
  # SetComputeUnitLimit instruction helpers
@@ -63,6 +64,7 @@ module Solana::Ruby::Kit
63
64
  # SetComputeUnitLimit instruction. Mirrors `setTransactionMessageComputeUnitLimit`.
64
65
  sig { params(limit: Integer, message: TransactionMessage).returns(TransactionMessage) }
65
66
  def set_transaction_message_compute_unit_limit(limit, message)
67
+ assert_is_valid_compute_unit_limit(limit)
66
68
  existing_idx = message.instructions.index { |i| set_compute_unit_limit_instruction?(i) }
67
69
  new_ix = get_set_compute_unit_limit_instruction(limit)
68
70
 
@@ -0,0 +1,70 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../errors'
5
+
6
+ module Solana::Ruby::Kit
7
+ # NOTE: `MAX_COMPUTE_UNIT_LIMIT` lives in `compute_budget.rb`, which requires this file, so it
8
+ # is referenced from a method body rather than at load time to keep the two files acyclic.
9
+ module TransactionMessages
10
+ # The smallest heap frame size that a transaction may request (32 KiB).
11
+ MIN_HEAP_SIZE = T.let(32 * 1024, Integer)
12
+
13
+ # The largest heap frame size that a transaction may request (256 KiB).
14
+ MAX_HEAP_SIZE = T.let(256 * 1024, Integer)
15
+
16
+ # A requested heap frame size must be a whole number of KiB.
17
+ HEAP_SIZE_MULTIPLE_OF = T.let(1024, Integer)
18
+
19
+ extend self
20
+
21
+ # Raises if the given compute unit limit is one the runtime will not honor as written.
22
+ #
23
+ # A transaction may request at most MAX_COMPUTE_UNIT_LIMIT compute units. Requesting more
24
+ # does not fail the transaction; the runtime clamps the request down to that maximum, so
25
+ # the budget the transaction runs with is silently not the one that was asked for. Values
26
+ # that are not integers are a separate hazard, since they cannot be encoded as a `u32` and
27
+ # are not clamped. Failing here surfaces both at the point the value is set.
28
+ #
29
+ # Mirrors `assertIsValidComputeUnitLimit` from @solana/transaction-messages.
30
+ sig { params(compute_unit_limit: T.untyped).void }
31
+ def assert_is_valid_compute_unit_limit(compute_unit_limit)
32
+ return if compute_unit_limit.is_a?(Integer) &&
33
+ compute_unit_limit >= 0 &&
34
+ compute_unit_limit <= MAX_COMPUTE_UNIT_LIMIT
35
+
36
+ Kernel.raise SolanaError.new(
37
+ SolanaError::TRANSACTION__COMPUTE_UNIT_LIMIT_OUT_OF_RANGE,
38
+ { compute_unit_limit: compute_unit_limit, max_compute_unit_limit: MAX_COMPUTE_UNIT_LIMIT }
39
+ )
40
+ end
41
+
42
+ # Raises if the given heap frame size is one the runtime will not accept.
43
+ #
44
+ # The requested heap size must be a multiple of HEAP_SIZE_MULTIPLE_OF bytes and lie between
45
+ # MIN_HEAP_SIZE and MAX_HEAP_SIZE inclusive. This mirrors the transaction sanitization check
46
+ # performed by the runtime.
47
+ #
48
+ # Mirrors `assertIsValidHeapSize` from @solana/transaction-messages. Ruby has no heap-size
49
+ # setter of its own — the `RequestHeapFrame` instruction and the version 1 transaction config
50
+ # are both untranslated — so this is offered as a standalone check for callers building that
51
+ # instruction themselves.
52
+ sig { params(heap_size: T.untyped).void }
53
+ def assert_is_valid_heap_size(heap_size)
54
+ return if heap_size.is_a?(Integer) &&
55
+ heap_size >= MIN_HEAP_SIZE &&
56
+ heap_size <= MAX_HEAP_SIZE &&
57
+ (heap_size % HEAP_SIZE_MULTIPLE_OF).zero?
58
+
59
+ Kernel.raise SolanaError.new(
60
+ SolanaError::TRANSACTION__INVALID_HEAP_SIZE,
61
+ {
62
+ heap_size: heap_size,
63
+ max_heap_size: MAX_HEAP_SIZE,
64
+ min_heap_size: MIN_HEAP_SIZE,
65
+ multiple_of: HEAP_SIZE_MULTIPLE_OF
66
+ }
67
+ )
68
+ end
69
+ end
70
+ end
@@ -57,7 +57,7 @@ module Solana::Ruby::Kit
57
57
  const :address_table_lookups, T.nilable(T::Hash[String, T::Array[Integer]])
58
58
  end
59
59
 
60
- module_function
60
+ extend self
61
61
 
62
62
  # Creates an empty transaction message at the given version.
63
63
  # Mirrors `createTransactionMessage({ version })`.
@@ -3,4 +3,5 @@
3
3
 
4
4
  # Transaction message construction utilities — mirrors @solana/transaction-messages.
5
5
  require_relative 'transaction_messages/transaction_message'
6
+ require_relative 'transaction_messages/resource_limit_validation'
6
7
  require_relative 'transaction_messages/compute_budget'
@@ -12,7 +12,7 @@ module Solana::Ruby::Kit
12
12
  # Maximum wire-encoded transaction size in bytes (Solana protocol limit).
13
13
  TRANSACTION_SIZE_LIMIT = T.let(1232, Integer)
14
14
 
15
- module_function
15
+ extend self
16
16
 
17
17
  # Returns the compiled byte-size of a transaction message.
18
18
  # Mirrors `getTransactionMessageSize()` from @solana/transactions.
@@ -174,7 +174,7 @@ module Solana::Ruby::Kit
174
174
  # [message bytes]
175
175
  #
176
176
  # The result is a binary String; base64-encode it before sending via HTTP.
177
- sig { params(transaction: Transaction).returns(String) }
177
+ sig { params(transaction: AnyTransaction).returns(String) }
178
178
  def wire_encode_transaction(transaction)
179
179
  sigs = transaction.signatures
180
180
  header = encode_compact_u16(sigs.size)
@@ -34,12 +34,32 @@ module Solana::Ruby::Kit
34
34
  const :signatures, T::Hash[String, T.nilable(String)]
35
35
  end
36
36
 
37
- module_function
37
+ # Either transaction struct.
38
+ #
39
+ # Because `FullySignedTransaction` is a *parallel* struct rather than a
40
+ # subclass of `Transaction` (T::Struct is final), it is not a subtype of it,
41
+ # and a signature naming only `Transaction` rejects it. That matters for
42
+ # nearly everything below, because `sign_transaction` returns a
43
+ # `FullySignedTransaction` and encoding, inspecting or sending one is the
44
+ # ordinary next step — `wire_encode_transaction(sign_transaction(...))` is
45
+ # the single most common two-call sequence in the whole library.
46
+ #
47
+ # TypeScript has no such problem: `FullySignedTransaction` there is
48
+ # `Transaction & { readonly [brand] }`, an intersection that *is* assignable
49
+ # to `Transaction`. This alias is the Ruby equivalent of that assignability.
50
+ #
51
+ # Use it for any parameter that reads a transaction. Use `Transaction`
52
+ # alone only where the value is specifically an unsigned or partially
53
+ # signed one, and `FullySignedTransaction` alone only as a return type
54
+ # asserting that signing happened.
55
+ AnyTransaction = T.type_alias { T.any(Transaction, FullySignedTransaction) }
56
+
57
+ extend self
38
58
 
39
59
  # Returns the base58-encoded signature that uniquely identifies a transaction.
40
60
  # This is the fee payer's signature (first entry in the signatures map).
41
61
  # Mirrors `getSignatureFromTransaction(transaction)`.
42
- sig { params(transaction: Transaction).returns(Keys::Signature) }
62
+ sig { params(transaction: AnyTransaction).returns(Keys::Signature) }
43
63
  def get_signature_from_transaction(transaction)
44
64
  sig_bytes = transaction.signatures.values.first
45
65
  Kernel.raise SolanaError.new(:SOLANA_ERROR__TRANSACTION__FEE_PAYER_SIGNATURE_MISSING) unless sig_bytes
@@ -49,14 +69,14 @@ module Solana::Ruby::Kit
49
69
 
50
70
  # Returns true if every slot in the signatures map is filled.
51
71
  # Mirrors `isFullySignedTransaction(transaction)`.
52
- sig { params(transaction: Transaction).returns(T::Boolean) }
72
+ sig { params(transaction: AnyTransaction).returns(T::Boolean) }
53
73
  def fully_signed_transaction?(transaction)
54
74
  transaction.signatures.values.all? { |sig| !sig.nil? }
55
75
  end
56
76
 
57
77
  # Raises SolanaError unless every signer slot is filled.
58
78
  # Mirrors `assertIsFullySignedTransaction(transaction)`.
59
- sig { params(transaction: Transaction).void }
79
+ sig { params(transaction: AnyTransaction).void }
60
80
  def assert_fully_signed_transaction!(transaction)
61
81
  missing = transaction.signatures.filter_map { |addr, sig| addr if sig.nil? }
62
82
  return if missing.empty?
@@ -69,14 +89,14 @@ module Solana::Ruby::Kit
69
89
 
70
90
  # Returns true if the wire-encoded transaction fits within TRANSACTION_SIZE_LIMIT.
71
91
  # Mirrors `isTransactionWithinSizeLimit(transaction)`.
72
- sig { params(transaction: Transaction).returns(T::Boolean) }
92
+ sig { params(transaction: AnyTransaction).returns(T::Boolean) }
73
93
  def within_size_limit?(transaction)
74
94
  wire_encode_transaction(transaction).bytesize <= TRANSACTION_SIZE_LIMIT
75
95
  end
76
96
 
77
97
  # Raises SolanaError if the wire-encoded transaction exceeds TRANSACTION_SIZE_LIMIT.
78
98
  # Mirrors `assertIsTransactionWithinSizeLimit(transaction)`.
79
- sig { params(transaction: Transaction).void }
99
+ sig { params(transaction: AnyTransaction).void }
80
100
  def assert_within_size_limit!(transaction)
81
101
  actual = wire_encode_transaction(transaction).bytesize
82
102
  return if actual <= TRANSACTION_SIZE_LIMIT
@@ -90,14 +110,14 @@ module Solana::Ruby::Kit
90
110
  # Returns true if the transaction is both fully signed and within the size limit.
91
111
  # Mirrors `isSendableTransaction(transaction)`.
92
112
  # sendableTransaction = FullySignedTransaction & TransactionWithinSizeLimit
93
- sig { params(transaction: Transaction).returns(T::Boolean) }
113
+ sig { params(transaction: AnyTransaction).returns(T::Boolean) }
94
114
  def sendable_transaction?(transaction)
95
115
  fully_signed_transaction?(transaction) && within_size_limit?(transaction)
96
116
  end
97
117
 
98
118
  # Raises SolanaError unless the transaction is fully signed and within size limit.
99
119
  # Mirrors `assertIsSendableTransaction(transaction)`.
100
- sig { params(transaction: Transaction).void }
120
+ sig { params(transaction: AnyTransaction).void }
101
121
  def assert_sendable_transaction!(transaction)
102
122
  assert_fully_signed_transaction!(transaction)
103
123
  assert_within_size_limit!(transaction)
@@ -112,7 +132,7 @@ module Solana::Ruby::Kit
112
132
  sig do
113
133
  params(
114
134
  signing_keys: T::Array[T.untyped], # Array<RbNaCl::SigningKey>
115
- transaction: Transaction
135
+ transaction: AnyTransaction
116
136
  ).returns(Transaction)
117
137
  end
118
138
  def partially_sign_transaction(signing_keys, transaction)
@@ -155,7 +175,7 @@ module Solana::Ruby::Kit
155
175
  sig do
156
176
  params(
157
177
  signing_keys: T::Array[T.untyped],
158
- transaction: Transaction
178
+ transaction: AnyTransaction
159
179
  ).returns(FullySignedTransaction)
160
180
  end
161
181
  def sign_transaction(signing_keys, transaction)
@@ -4,7 +4,7 @@
4
4
  module Solana
5
5
  module Ruby
6
6
  module Kit
7
- VERSION = '7.1.1.2'
7
+ VERSION = '8.3.0'
8
8
  end
9
9
  end
10
10
  end
@@ -54,7 +54,7 @@ module Solana::Ruby::Kit
54
54
  DISCONNECT = T.let('standard:disconnect', String)
55
55
  EVENTS = T.let('standard:events', String)
56
56
 
57
- module_function
57
+ extend self
58
58
 
59
59
  # ── Wire-format decoder ───────────────────────────────────────────────────
60
60
 
@@ -165,7 +165,7 @@ module Solana::Ruby::Kit
165
165
  # any signature does not verify. Nil (unfilled) slots are skipped silently;
166
166
  # use +Transactions.assert_fully_signed_transaction!+ to enforce that all
167
167
  # required signers have signed.
168
- sig { params(transaction: Transactions::Transaction).void }
168
+ sig { params(transaction: Transactions::AnyTransaction).void }
169
169
  def verify_transaction_signatures!(transaction)
170
170
  transaction.signatures.each do |addr_str, sig_raw|
171
171
  next if sig_raw.nil?
@@ -201,7 +201,7 @@ module Solana::Ruby::Kit
201
201
  # Returns +true+ if +address+ has provided a cryptographically valid
202
202
  # signature for +transaction+; +false+ if the slot is absent, nil, or the
203
203
  # signature does not verify against +transaction.message_bytes+.
204
- sig { params(transaction: Transactions::Transaction, address: Addresses::Address).returns(T::Boolean) }
204
+ sig { params(transaction: Transactions::AnyTransaction, address: Addresses::Address).returns(T::Boolean) }
205
205
  def signed_by?(transaction, address)
206
206
  sig_raw = transaction.signatures[address.value]
207
207
  return false if sig_raw.nil?
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solana-ruby-kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.1.1.2
4
+ version: 8.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Zupan, Idhra Inc.
@@ -262,6 +262,7 @@ files:
262
262
  - lib/solana/ruby/kit/resource_limit_estimation.rb
263
263
  - lib/solana/ruby/kit/rpc.rb
264
264
  - lib/solana/ruby/kit/rpc/api/get_account_info.rb
265
+ - lib/solana/ruby/kit/rpc/api/get_ag_genesis_cert.rb
265
266
  - lib/solana/ruby/kit/rpc/api/get_balance.rb
266
267
  - lib/solana/ruby/kit/rpc/api/get_block_height.rb
267
268
  - lib/solana/ruby/kit/rpc/api/get_block_time.rb
@@ -337,6 +338,7 @@ files:
337
338
  - lib/solana/ruby/kit/transaction_introspection/walk_instructions.rb
338
339
  - lib/solana/ruby/kit/transaction_messages.rb
339
340
  - lib/solana/ruby/kit/transaction_messages/compute_budget.rb
341
+ - lib/solana/ruby/kit/transaction_messages/resource_limit_validation.rb
340
342
  - lib/solana/ruby/kit/transaction_messages/transaction_message.rb
341
343
  - lib/solana/ruby/kit/transactions.rb
342
344
  - lib/solana/ruby/kit/transactions/compiler.rb