solace-squads-smart-accounts 0.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 (65) hide show
  1. checksums.yaml +7 -0
  2. data/lib/solace/squads_smart_accounts/codecs_extensions.rb +259 -0
  3. data/lib/solace/squads_smart_accounts/composers/activate_proposal_composer.rb +69 -0
  4. data/lib/solace/squads_smart_accounts/composers/add_signer_as_authority_composer.rb +94 -0
  5. data/lib/solace/squads_smart_accounts/composers/add_spending_limit_as_authority_composer.rb +170 -0
  6. data/lib/solace/squads_smart_accounts/composers/approve_proposal_composer.rb +80 -0
  7. data/lib/solace/squads_smart_accounts/composers/cancel_proposal_composer.rb +86 -0
  8. data/lib/solace/squads_smart_accounts/composers/change_threshold_as_authority_composer.rb +94 -0
  9. data/lib/solace/squads_smart_accounts/composers/close_settings_transaction_composer.rb +98 -0
  10. data/lib/solace/squads_smart_accounts/composers/close_transaction_composer.rb +97 -0
  11. data/lib/solace/squads_smart_accounts/composers/create_proposal_composer.rb +104 -0
  12. data/lib/solace/squads_smart_accounts/composers/create_settings_transaction_composer.rb +105 -0
  13. data/lib/solace/squads_smart_accounts/composers/create_smart_account_composer.rb +142 -0
  14. data/lib/solace/squads_smart_accounts/composers/create_transaction_composer.rb +154 -0
  15. data/lib/solace/squads_smart_accounts/composers/execute_settings_transaction_composer.rb +112 -0
  16. data/lib/solace/squads_smart_accounts/composers/execute_settings_transaction_sync_composer.rb +114 -0
  17. data/lib/solace/squads_smart_accounts/composers/execute_transaction_composer.rb +122 -0
  18. data/lib/solace/squads_smart_accounts/composers/execute_transaction_sync_composer.rb +157 -0
  19. data/lib/solace/squads_smart_accounts/composers/reject_proposal_composer.rb +80 -0
  20. data/lib/solace/squads_smart_accounts/composers/remove_signer_as_authority_composer.rb +94 -0
  21. data/lib/solace/squads_smart_accounts/composers/remove_spending_limit_as_authority_composer.rb +88 -0
  22. data/lib/solace/squads_smart_accounts/composers/set_new_settings_authority_as_authority_composer.rb +100 -0
  23. data/lib/solace/squads_smart_accounts/composers/set_time_lock_as_authority_composer.rb +94 -0
  24. data/lib/solace/squads_smart_accounts/composers/use_spending_limit_composer.rb +203 -0
  25. data/lib/solace/squads_smart_accounts/constants.rb +27 -0
  26. data/lib/solace/squads_smart_accounts/idl/squads_smart_account_program.json +3966 -0
  27. data/lib/solace/squads_smart_accounts/instructions/activate_proposal_instruction.rb +60 -0
  28. data/lib/solace/squads_smart_accounts/instructions/add_signer_as_authority_instruction.rb +69 -0
  29. data/lib/solace/squads_smart_accounts/instructions/add_spending_limit_as_authority_instruction.rb +112 -0
  30. data/lib/solace/squads_smart_accounts/instructions/approve_proposal_instruction.rb +66 -0
  31. data/lib/solace/squads_smart_accounts/instructions/cancel_proposal_instruction.rb +67 -0
  32. data/lib/solace/squads_smart_accounts/instructions/change_threshold_as_authority_instruction.rb +66 -0
  33. data/lib/solace/squads_smart_accounts/instructions/close_settings_transaction_instruction.rb +71 -0
  34. data/lib/solace/squads_smart_accounts/instructions/close_transaction_instruction.rb +72 -0
  35. data/lib/solace/squads_smart_accounts/instructions/create_proposal_instruction.rb +78 -0
  36. data/lib/solace/squads_smart_accounts/instructions/create_settings_transaction_instruction.rb +78 -0
  37. data/lib/solace/squads_smart_accounts/instructions/create_smart_account_instruction.rb +96 -0
  38. data/lib/solace/squads_smart_accounts/instructions/create_transaction_instruction.rb +95 -0
  39. data/lib/solace/squads_smart_accounts/instructions/execute_settings_transaction_instruction.rb +79 -0
  40. data/lib/solace/squads_smart_accounts/instructions/execute_settings_transaction_sync_instruction.rb +78 -0
  41. data/lib/solace/squads_smart_accounts/instructions/execute_transaction_instruction.rb +71 -0
  42. data/lib/solace/squads_smart_accounts/instructions/execute_transaction_sync_instruction.rb +80 -0
  43. data/lib/solace/squads_smart_accounts/instructions/reject_proposal_instruction.rb +66 -0
  44. data/lib/solace/squads_smart_accounts/instructions/remove_signer_as_authority_instruction.rb +66 -0
  45. data/lib/solace/squads_smart_accounts/instructions/remove_spending_limit_as_authority_instruction.rb +62 -0
  46. data/lib/solace/squads_smart_accounts/instructions/set_new_settings_authority_as_authority_instruction.rb +66 -0
  47. data/lib/solace/squads_smart_accounts/instructions/set_time_lock_as_authority_instruction.rb +66 -0
  48. data/lib/solace/squads_smart_accounts/instructions/use_spending_limit_instruction.rb +96 -0
  49. data/lib/solace/squads_smart_accounts/programs/squads_smart_account.rb +1841 -0
  50. data/lib/solace/squads_smart_accounts/types/period.rb +24 -0
  51. data/lib/solace/squads_smart_accounts/types/permissions.rb +43 -0
  52. data/lib/solace/squads_smart_accounts/types/program_config.rb +36 -0
  53. data/lib/solace/squads_smart_accounts/types/proposal.rb +91 -0
  54. data/lib/solace/squads_smart_accounts/types/settings.rb +50 -0
  55. data/lib/solace/squads_smart_accounts/types/settings_action.rb +109 -0
  56. data/lib/solace/squads_smart_accounts/types/settings_transaction.rb +40 -0
  57. data/lib/solace/squads_smart_accounts/types/smart_account_identity.rb +20 -0
  58. data/lib/solace/squads_smart_accounts/types/smart_account_signer.rb +26 -0
  59. data/lib/solace/squads_smart_accounts/types/spending_limit.rb +52 -0
  60. data/lib/solace/squads_smart_accounts/types/transaction.rb +115 -0
  61. data/lib/solace/squads_smart_accounts/types/transaction_message.rb +41 -0
  62. data/lib/solace/squads_smart_accounts/vault_index.rb +113 -0
  63. data/lib/solace/squads_smart_accounts/version.rb +7 -0
  64. data/lib/solace/squads_smart_accounts.rb +29 -0
  65. metadata +210 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 02a25a8f810ed514e72c62cf865dd3ea92a4edb614260fc5fbc110f913d79b6e
4
+ data.tar.gz: 898e4feceedc71e37de62c3dcd02ef19cc79fbed1d6a982a6b3c294ddc58e11a
5
+ SHA512:
6
+ metadata.gz: 15b4b488be4b53df4c2d61729c58fdae258478d24b59bd5b35f361b6087b9bcb2fdc4b204f3d796bcd21b833e0f76d476df7bdacd2f084b7fd3643ce5f0e421f
7
+ data.tar.gz: 746d685aba1a248a94f947910350396ce64b1dbf84ba9b86d50d29ab84a7ea597f65286003a0becf963630af77167e2fd5f37a1b530154503553cc5189708c21
@@ -0,0 +1,259 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solace
4
+ module Utils
5
+ # Extensions to Solace::Utils::Codecs for Anchor programs and Borsh types not
6
+ # covered by the base gem. Candidates for upstreaming to solace when the need
7
+ # is confirmed across other extension gems.
8
+ module Codecs
9
+ extend self
10
+
11
+ # Encodes a SmallVec<u8, u8>: u8 length prefix + raw bytes.
12
+ #
13
+ # @param bytes [Array<Integer>] The raw bytes (max 255).
14
+ # @return [Array<Integer>]
15
+ def encode_smallvec_u8_bytes(bytes)
16
+ [bytes.length] + bytes
17
+ end
18
+
19
+ # Encodes a u16 as 2 little-endian bytes.
20
+ #
21
+ # @param u16 [Integer] Value in range 0..65535.
22
+ # @return [String] 2-byte little-endian binary string.
23
+ def encode_le_u16(u16)
24
+ [u16].pack('S<')
25
+ end
26
+
27
+ # Encodes a SmallVec<u16, u8>: u16 LE length prefix + raw bytes.
28
+ #
29
+ # @param bytes [Array<Integer>] The raw bytes (max 65535).
30
+ # @return [Array<Integer>]
31
+ def encode_smallvec_u16_bytes(bytes)
32
+ encode_le_u16(bytes.length).bytes + bytes
33
+ end
34
+
35
+ # Encodes a u32 as 4 little-endian bytes.
36
+ #
37
+ # @param u32 [Integer] Value in range 0..4294967295.
38
+ # @return [String] 4-byte little-endian binary string.
39
+ def encode_le_u32(u32)
40
+ [u32].pack('L<')
41
+ end
42
+
43
+ # Encodes an i64 as 8 little-endian bytes (two's complement).
44
+ #
45
+ # @param i64 [Integer] Value in range -2**63..2**63-1.
46
+ # @return [String] 8-byte little-endian binary string.
47
+ def encode_le_i64(i64)
48
+ [i64].pack('q<')
49
+ end
50
+
51
+ # Encodes a Borsh bool as a single byte: false → 0, true → 1.
52
+ #
53
+ # @param bool [Boolean] The value to encode.
54
+ # @return [Array<Integer>] A single-element byte array.
55
+ def encode_bool(bool)
56
+ [bool ? 1 : 0]
57
+ end
58
+
59
+ # Encodes a u128 as 16 little-endian bytes (two u64 words, low word first).
60
+ #
61
+ # @param u128 [Integer] Value in range 0..2**128-1.
62
+ # @return [String] 16-byte little-endian binary string.
63
+ def encode_le_u128(u128)
64
+ [u128 & 0xFFFFFFFFFFFFFFFF, u128 >> 64].pack('Q<Q<')
65
+ end
66
+
67
+ # Encodes a Borsh bytes field: u32 LE length prefix + raw bytes.
68
+ #
69
+ # @param bytes [Array<Integer>] The raw bytes.
70
+ # @return [Array<Integer>]
71
+ def encode_bytes(bytes)
72
+ encode_le_u32(bytes.length).bytes + bytes
73
+ end
74
+
75
+ # Encodes an Option<String> in Borsh format.
76
+ # None → [0], Some(str) → [1] + u32 length + UTF-8 bytes.
77
+ #
78
+ # @param str [String, nil]
79
+ # @return [Array<Integer>]
80
+ def encode_option_string(str)
81
+ return [0] if str.nil?
82
+
83
+ bytes = str.encode('UTF-8').bytes
84
+ [1] + encode_le_u32(bytes.length).bytes + bytes
85
+ end
86
+
87
+ # Encodes a public key as 32 bytes. Accepts any representation that
88
+ # resolves to a base58 string via #to_s (String, Keypair, PublicKey).
89
+ #
90
+ # @param pubkey [#to_s] The public key in any representation.
91
+ # @return [Array<Integer>] 32 bytes.
92
+ def encode_pubkey(pubkey)
93
+ Solace::Utils::Codecs.base58_to_bytes(pubkey.to_s)
94
+ end
95
+
96
+ # Encodes an Option<publicKey> in Borsh format.
97
+ # None → [0], Some(key) → [1] + 32 bytes.
98
+ #
99
+ # @param pubkey [String, nil] Base58 public key or nil.
100
+ # @return [Array<Integer>]
101
+ def encode_option_pubkey(pubkey)
102
+ return [0] if pubkey.nil?
103
+
104
+ [1] + encode_pubkey(pubkey)
105
+ end
106
+
107
+ # Encodes a Vec<publicKey> in Borsh format.
108
+ # u32 LE count prefix followed by each 32-byte pubkey.
109
+ #
110
+ # @param pubkeys [Array<#to_s>] The public keys in any representation.
111
+ # @return [Array<Integer>]
112
+ def encode_vec_pubkeys(pubkeys)
113
+ encode_le_u32(pubkeys.length).bytes +
114
+ pubkeys.flat_map { |pubkey| encode_pubkey(pubkey) }
115
+ end
116
+
117
+ # Encodes a SmallVec<u8, Pubkey>: u8 count prefix followed by each 32-byte
118
+ # pubkey. Used by the transaction message header's account_keys (distinct
119
+ # from encode_vec_pubkeys, which uses a u32 count).
120
+ #
121
+ # @param pubkeys [Array<#to_s>] The public keys in any representation (max 255).
122
+ # @return [Array<Integer>]
123
+ def encode_smallvec_u8_pubkeys(pubkeys)
124
+ [pubkeys.length] + pubkeys.flat_map { |pubkey| encode_pubkey(pubkey) }
125
+ end
126
+
127
+ # Encodes a Vec<SmartAccountSigner> in Borsh format.
128
+ # u32 length prefix followed by each signer's 32-byte pubkey + 1-byte permission mask.
129
+ #
130
+ # @param signers [Array<SquadsSmartAccounts::SmartAccountSigner>]
131
+ # @return [Array<Integer>]
132
+ def encode_smart_account_signers(signers)
133
+ encode_le_u32(signers.length).bytes +
134
+ signers.flat_map do |signer|
135
+ encode_pubkey(signer.pubkey) + [signer.permission]
136
+ end
137
+ end
138
+
139
+ # Encodes a Vec<SettingsAction> in Borsh format.
140
+ # u32 LE count prefix followed by each action's variant index + field bytes.
141
+ #
142
+ # @param actions [Array<SquadsSmartAccounts::SettingsAction>]
143
+ # @return [Array<Integer>]
144
+ def encode_settings_actions(actions)
145
+ encode_le_u32(actions.length).bytes + actions.flat_map(&:serialize)
146
+ end
147
+
148
+ # Encodes a SmallVec<u8, CompiledInstruction> — the wire format the Squads
149
+ # program expects for synchronously executed inner instructions.
150
+ #
151
+ # NOTE: this intentionally does NOT reuse Solace's InstructionSerializer.
152
+ # That serializer produces the Solana transaction wire format, which uses
153
+ # compact-u16 (varint) length prefixes for the vec count, account indexes,
154
+ # and data. The Squads SmallVec format uses fixed-width prefixes instead:
155
+ # u8 for the vec count, u8 for the account indexes length, and u16 LE for
156
+ # the data length. The two encodings coincide for lengths < 128 (compact-u16
157
+ # encodes those as a single byte) but diverge beyond that, so reusing the
158
+ # Solana format would corrupt larger instructions silently.
159
+ #
160
+ # Each instruction is a {Solace::Instruction} whose program_index and
161
+ # accounts are indexes into the full remaining-accounts list (signers included).
162
+ # Layout per instruction: u8 program_id_index + SmallVec<u8,u8> account
163
+ # indexes + SmallVec<u16,u8> data.
164
+ #
165
+ # @param instructions [Array<Solace::Instruction>]
166
+ # @return [Array<Integer>]
167
+ def encode_compiled_instructions(instructions)
168
+ [instructions.length] +
169
+ instructions.flat_map do |ix|
170
+ [ix.program_index] +
171
+ encode_smallvec_u8_bytes(ix.accounts) +
172
+ encode_smallvec_u16_bytes(ix.data)
173
+ end
174
+ end
175
+
176
+ # Decodes an i64 from 8 little-endian bytes (two's complement).
177
+ #
178
+ # @param stream [IO, StringIO] The stream to read from.
179
+ # @return [Integer] Value in range -2**63..2**63-1.
180
+ def decode_le_i64(stream)
181
+ stream.read(8).unpack1('q<')
182
+ end
183
+
184
+ # Decodes a Vec<publicKey> in Borsh format.
185
+ #
186
+ # @param stream [IO, StringIO] The stream to read from.
187
+ # @return [Array<String>] Base58 public keys.
188
+ def decode_vec_pubkeys(stream)
189
+ Array.new(decode_le_u32(stream)) { decode_pubkey(stream) }
190
+ end
191
+
192
+ # Decodes a u8 from 1 byte.
193
+ #
194
+ # @param stream [IO, StringIO] The stream to read from.
195
+ # @return [Integer] Value in range 0..255.
196
+ def decode_u8(stream)
197
+ stream.read(1).unpack1('C')
198
+ end
199
+
200
+ # Decodes a u16 from 2 little-endian bytes.
201
+ #
202
+ # @param stream [IO, StringIO] The stream to read from.
203
+ # @return [Integer] Value in range 0..65535.
204
+ def decode_le_u16(stream)
205
+ stream.read(2).unpack1('S<')
206
+ end
207
+
208
+ # Decodes a u32 from 4 little-endian bytes.
209
+ #
210
+ # @param stream [IO, StringIO] The stream to read from.
211
+ # @return [Integer] Value in range 0..4294967295.
212
+ def decode_le_u32(stream)
213
+ stream.read(4).unpack1('L<')
214
+ end
215
+
216
+ # Decodes a u128 from 16 little-endian bytes (two u64 words, low word first).
217
+ #
218
+ # @param stream [IO, StringIO] The stream to read from.
219
+ # @return [Integer] Value in range 0..2**128-1.
220
+ def decode_le_u128(stream)
221
+ lo, hi = stream.read(16).unpack('Q<Q<')
222
+ lo + (hi << 64)
223
+ end
224
+
225
+ # Decodes a public key from 32 bytes.
226
+ #
227
+ # @param stream [IO, StringIO] The stream to read from.
228
+ # @return [String] Base58 public key.
229
+ def decode_pubkey(stream)
230
+ Solace::Utils::Codecs.bytes_to_base58(stream.read(32).bytes)
231
+ end
232
+
233
+ # Decodes an Option<publicKey> in Borsh format.
234
+ # None → nil, Some(key) → base58 pubkey.
235
+ #
236
+ # @param stream [IO, StringIO] The stream to read from.
237
+ # @return [String, nil] Base58 public key or nil.
238
+ def decode_option_pubkey(stream)
239
+ return nil if decode_u8(stream).zero?
240
+
241
+ decode_pubkey(stream)
242
+ end
243
+
244
+ # Decodes a Vec<SmartAccountSigner> in Borsh format.
245
+ # u32 length prefix followed by each signer's 32-byte pubkey + 1-byte permission mask.
246
+ #
247
+ # @param stream [IO, StringIO] The stream to read from.
248
+ # @return [Array<SquadsSmartAccounts::SmartAccountSigner>]
249
+ def decode_smart_account_signers(stream)
250
+ Array.new(decode_le_u32(stream)) do
251
+ SquadsSmartAccounts::SmartAccountSigner.new(
252
+ pubkey: decode_pubkey(stream),
253
+ permission: decode_u8(stream)
254
+ )
255
+ end
256
+ end
257
+ end
258
+ end
259
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solace
4
+ module Composers
5
+ # Composes an `activateProposal` instruction for the Squads Smart Account program.
6
+ #
7
+ # Moves a Draft proposal to Active. The signer must be a smart-account member
8
+ # with the Initiate permission. Only needed for proposals created as drafts.
9
+ #
10
+ # Required params:
11
+ # :settings [#to_s] Base58 address of the settings account.
12
+ # :signer [#to_s, Keypair] The activating signer (must sign).
13
+ # :proposal [#to_s] The Proposal PDA to activate.
14
+ class SquadsSmartAccountsActivateProposalComposer < Base
15
+ # Extracts the settings address from the params
16
+ #
17
+ # @return [String] The settings address
18
+ def settings
19
+ params[:settings].to_s
20
+ end
21
+
22
+ # Extracts the activating signer address from the params
23
+ #
24
+ # @return [String] The signer address
25
+ def signer
26
+ params[:signer].to_s
27
+ end
28
+
29
+ # Extracts the proposal PDA address from the params
30
+ #
31
+ # @return [String] The proposal address
32
+ def proposal
33
+ params[:proposal].to_s
34
+ end
35
+
36
+ # Returns the Squads Smart Account program id from the constants
37
+ #
38
+ # @return [String] The Squads Smart Account program id
39
+ def program_id
40
+ SquadsSmartAccounts::PROGRAM_ID
41
+ end
42
+
43
+ # Declares all accounts required by this instruction. The Squads program
44
+ # is registered so it appears in the message account keys (it is the
45
+ # invoked program), but — unlike the other proposal instructions — it is
46
+ # NOT included in this instruction's account-metas list (no trailing
47
+ # program account).
48
+ def setup_accounts
49
+ account_context.add_readonly_nonsigner(settings)
50
+ account_context.add_writable_signer(signer)
51
+ account_context.add_writable_nonsigner(proposal)
52
+ account_context.add_readonly_nonsigner(program_id)
53
+ end
54
+
55
+ # Builds the instruction with resolved account indices.
56
+ #
57
+ # @param context [Solace::Utils::AccountContext] Merged context from TransactionComposer.
58
+ # @return [Solace::Instruction]
59
+ def build_instruction(context)
60
+ SquadsSmartAccounts::Instructions::ActivateProposalInstruction.build(
61
+ settings_index: context.index_of(settings),
62
+ signer_index: context.index_of(signer),
63
+ proposal_index: context.index_of(proposal),
64
+ program_index: context.index_of(program_id)
65
+ )
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solace
4
+ module Composers
5
+ # Composes an `addSignerAsAuthority` instruction for the Squads Smart Account program.
6
+ #
7
+ # Adds a new signer to a controlled smart account. Only the account's
8
+ # settings authority may do this — single signature, no consensus.
9
+ #
10
+ # Required params:
11
+ # :settings [String] Base58 address of the settings account.
12
+ # :settings_authority [#to_s, Keypair] The account's settings authority (must sign).
13
+ # :rent_payer [#to_s, Keypair] Pays for settings account reallocation (must sign).
14
+ # :new_signer [SquadsSmartAccounts::SmartAccountSigner] The signer to add.
15
+ #
16
+ # Optional params:
17
+ # :memo [String] Indexing memo (default: nil).
18
+ class SquadsSmartAccountsAddSignerAsAuthorityComposer < Base
19
+ # Extracts the settings address from the params
20
+ #
21
+ # @return [String] The settings address
22
+ def settings
23
+ params[:settings].to_s
24
+ end
25
+
26
+ # Extracts the settings authority address from the params
27
+ #
28
+ # @return [String] The settings authority address
29
+ def settings_authority
30
+ params[:settings_authority].to_s
31
+ end
32
+
33
+ # Extracts the rent payer address from the params
34
+ #
35
+ # @return [String] The rent payer address
36
+ def rent_payer
37
+ params[:rent_payer].to_s
38
+ end
39
+
40
+ # Extracts the new signer from the params
41
+ #
42
+ # @return [SquadsSmartAccounts::SmartAccountSigner] The signer to add
43
+ def new_signer
44
+ params[:new_signer]
45
+ end
46
+
47
+ # Extracts the memo from the params
48
+ #
49
+ # @return [String, nil] The memo
50
+ def memo
51
+ params[:memo]
52
+ end
53
+
54
+ # Returns the Squads Smart Account program id from the constants
55
+ #
56
+ # @return [String] The Squads Smart Account program id
57
+ def program_id
58
+ SquadsSmartAccounts::PROGRAM_ID
59
+ end
60
+
61
+ # Returns the system program id from the constants
62
+ #
63
+ # @return [String] The system program id
64
+ def system_program
65
+ Solace::Constants::SYSTEM_PROGRAM_ID
66
+ end
67
+
68
+ # Declares all accounts required by this instruction.
69
+ def setup_accounts
70
+ account_context.add_writable_nonsigner(settings)
71
+ account_context.add_readonly_signer(settings_authority)
72
+ account_context.add_writable_signer(rent_payer)
73
+ account_context.add_readonly_nonsigner(system_program)
74
+ account_context.add_readonly_nonsigner(program_id)
75
+ end
76
+
77
+ # Builds the instruction with resolved account indices.
78
+ #
79
+ # @param context [Solace::Utils::AccountContext] Merged context from TransactionComposer.
80
+ # @return [Solace::Instruction]
81
+ def build_instruction(context)
82
+ SquadsSmartAccounts::Instructions::AddSignerAsAuthorityInstruction.build(
83
+ new_signer:,
84
+ memo:,
85
+ settings_index: context.index_of(settings),
86
+ settings_authority_index: context.index_of(settings_authority),
87
+ rent_payer_index: context.index_of(rent_payer),
88
+ system_program_index: context.index_of(system_program),
89
+ program_index: context.index_of(program_id)
90
+ )
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,170 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solace
4
+ module Composers
5
+ # Composes an `addSpendingLimitAsAuthority` instruction for the Squads
6
+ # Smart Account program.
7
+ #
8
+ # Creates a SpendingLimit PDA granting designated signers a pre-authorized
9
+ # allowance from a vault. Only the account's settings authority may do
10
+ # this — single signature, no consensus.
11
+ #
12
+ # Required params:
13
+ # :settings [#to_s] Base58 address of the settings account.
14
+ # :settings_authority [#to_s, Keypair] The account's settings authority (must sign).
15
+ # :spending_limit [#to_s] The SpendingLimit PDA to create — derive via
16
+ # Programs::SquadsSmartAccount.get_spending_limit_address.
17
+ # :rent_payer [#to_s, Keypair] Funds the new account's rent (must sign).
18
+ # :seed [#to_s] The pubkey the spending_limit PDA was derived with.
19
+ # :amount [Integer] Amount spendable per period (mint decimals).
20
+ # :period [Integer] Period enum value (reset cadence).
21
+ # :signers [Array<#to_s>] Pubkeys allowed to use the limit.
22
+ #
23
+ # Optional params:
24
+ # :account_index [Integer] Vault index the limit spends from (default: 0).
25
+ # :mint [#to_s] Token mint (default: DEFAULT_PUBKEY = SOL).
26
+ # :destinations [Array<#to_s>] Allowed destinations; empty = any (default: []).
27
+ # :expiration [Integer] Unix expiration timestamp (default: I64_MAX = never).
28
+ # :memo [String] Indexing memo (default: nil).
29
+ class SquadsSmartAccountsAddSpendingLimitAsAuthorityComposer < Base
30
+ # Extracts the settings address from the params
31
+ #
32
+ # @return [String] The settings address
33
+ def settings
34
+ params[:settings].to_s
35
+ end
36
+
37
+ # Extracts the settings authority address from the params
38
+ #
39
+ # @return [String] The settings authority address
40
+ def settings_authority
41
+ params[:settings_authority].to_s
42
+ end
43
+
44
+ # Extracts the spending limit PDA address from the params
45
+ #
46
+ # @return [String] The spending limit address
47
+ def spending_limit
48
+ params[:spending_limit].to_s
49
+ end
50
+
51
+ # Extracts the rent payer address from the params
52
+ #
53
+ # @return [String] The rent payer address
54
+ def rent_payer
55
+ params[:rent_payer].to_s
56
+ end
57
+
58
+ # Extracts the PDA seed pubkey from the params
59
+ #
60
+ # @return [String] The seed pubkey
61
+ def seed
62
+ params[:seed].to_s
63
+ end
64
+
65
+ # Extracts the vault index from the params
66
+ #
67
+ # @return [Integer] The vault index (defaults to 0)
68
+ def account_index
69
+ params[:account_index] || 0
70
+ end
71
+
72
+ # Extracts the mint from the params
73
+ #
74
+ # @return [String] The mint address (defaults to DEFAULT_PUBKEY = SOL)
75
+ def mint
76
+ (params[:mint] || SquadsSmartAccounts::DEFAULT_PUBKEY).to_s
77
+ end
78
+
79
+ # Extracts the per-period amount from the params
80
+ #
81
+ # @return [Integer] The amount spendable per period
82
+ def amount
83
+ params[:amount]
84
+ end
85
+
86
+ # Extracts the reset period from the params
87
+ #
88
+ # @return [Integer] The Period enum value
89
+ def period
90
+ params[:period]
91
+ end
92
+
93
+ # Extracts the allowed signer pubkeys from the params
94
+ #
95
+ # @return [Array<String>] The allowed signer addresses
96
+ def signers
97
+ params[:signers].map(&:to_s)
98
+ end
99
+
100
+ # Extracts the allowed destinations from the params
101
+ #
102
+ # @return [Array<String>] The allowed destination addresses (defaults to [])
103
+ def destinations
104
+ (params[:destinations] || []).map(&:to_s)
105
+ end
106
+
107
+ # Extracts the expiration from the params
108
+ #
109
+ # @return [Integer] Unix expiration timestamp (defaults to I64_MAX = never)
110
+ def expiration
111
+ params[:expiration] || SquadsSmartAccounts::I64_MAX
112
+ end
113
+
114
+ # Extracts the memo from the params
115
+ #
116
+ # @return [String, nil] The memo
117
+ def memo
118
+ params[:memo]
119
+ end
120
+
121
+ # Returns the Squads Smart Account program id from the constants
122
+ #
123
+ # @return [String] The Squads Smart Account program id
124
+ def program_id
125
+ SquadsSmartAccounts::PROGRAM_ID
126
+ end
127
+
128
+ # Returns the system program id from the constants
129
+ #
130
+ # @return [String] The system program id
131
+ def system_program
132
+ Solace::Constants::SYSTEM_PROGRAM_ID
133
+ end
134
+
135
+ # Declares all accounts required by this instruction.
136
+ def setup_accounts
137
+ account_context.add_readonly_nonsigner(settings)
138
+ account_context.add_readonly_signer(settings_authority)
139
+ account_context.add_writable_nonsigner(spending_limit)
140
+ account_context.add_writable_signer(rent_payer)
141
+ account_context.add_readonly_nonsigner(system_program)
142
+ account_context.add_readonly_nonsigner(program_id)
143
+ end
144
+
145
+ # Builds the instruction with resolved account indices.
146
+ #
147
+ # @param context [Solace::Utils::AccountContext] Merged context from TransactionComposer.
148
+ # @return [Solace::Instruction]
149
+ def build_instruction(context)
150
+ SquadsSmartAccounts::Instructions::AddSpendingLimitAsAuthorityInstruction.build(
151
+ seed:,
152
+ account_index:,
153
+ mint:,
154
+ amount:,
155
+ period:,
156
+ signers:,
157
+ destinations:,
158
+ expiration:,
159
+ memo:,
160
+ settings_index: context.index_of(settings),
161
+ settings_authority_index: context.index_of(settings_authority),
162
+ spending_limit_index: context.index_of(spending_limit),
163
+ rent_payer_index: context.index_of(rent_payer),
164
+ system_program_index: context.index_of(system_program),
165
+ program_index: context.index_of(program_id)
166
+ )
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solace
4
+ module Composers
5
+ # Composes an `approveProposal` instruction for the Squads Smart Account program.
6
+ #
7
+ # Casts an approval vote on an active proposal. The signer must be a smart
8
+ # account member with the Vote permission.
9
+ #
10
+ # Required params:
11
+ # :settings [#to_s] Base58 address of the settings account.
12
+ # :signer [#to_s, Keypair] The voting signer (must sign).
13
+ # :proposal [#to_s] The Proposal PDA to vote on.
14
+ #
15
+ # Optional params:
16
+ # :memo [String] Indexing memo (default: nil).
17
+ class SquadsSmartAccountsApproveProposalComposer < Base
18
+ # Extracts the settings address from the params
19
+ #
20
+ # @return [String] The settings address
21
+ def settings
22
+ params[:settings].to_s
23
+ end
24
+
25
+ # Extracts the voting signer address from the params
26
+ #
27
+ # @return [String] The signer address
28
+ def signer
29
+ params[:signer].to_s
30
+ end
31
+
32
+ # Extracts the proposal PDA address from the params
33
+ #
34
+ # @return [String] The proposal address
35
+ def proposal
36
+ params[:proposal].to_s
37
+ end
38
+
39
+ # Extracts the memo from the params
40
+ #
41
+ # @return [String, nil] The memo
42
+ def memo
43
+ params[:memo]
44
+ end
45
+
46
+ # Returns the Squads Smart Account program id from the constants. The
47
+ # systemProgram account is optional and absent for a vote, so this id
48
+ # also fills that slot.
49
+ #
50
+ # @return [String] The Squads Smart Account program id
51
+ def program_id
52
+ SquadsSmartAccounts::PROGRAM_ID
53
+ end
54
+
55
+ # Declares all accounts required by this instruction.
56
+ def setup_accounts
57
+ account_context.add_readonly_nonsigner(settings)
58
+ account_context.add_writable_signer(signer)
59
+ account_context.add_writable_nonsigner(proposal)
60
+ account_context.add_readonly_nonsigner(program_id)
61
+ end
62
+
63
+ # Builds the instruction with resolved account indices. The absent
64
+ # systemProgram slot resolves to the Squads program id index.
65
+ #
66
+ # @param context [Solace::Utils::AccountContext] Merged context from TransactionComposer.
67
+ # @return [Solace::Instruction]
68
+ def build_instruction(context)
69
+ SquadsSmartAccounts::Instructions::ApproveProposalInstruction.build(
70
+ memo:,
71
+ settings_index: context.index_of(settings),
72
+ signer_index: context.index_of(signer),
73
+ proposal_index: context.index_of(proposal),
74
+ system_program_index: context.index_of(program_id),
75
+ program_index: context.index_of(program_id)
76
+ )
77
+ end
78
+ end
79
+ end
80
+ end