solace-squads-smart-accounts
A Ruby toolkit for the Squads Smart Account program on Solana
(SMRTzfY6DfH5ik3TKiyLFfXexV8uSG3d2UksSCYdunG) — create multi-signer accounts, run the
full propose → vote → execute governance lifecycle, manage settings and spending limits,
all from idiomatic Ruby. It is an extension gem for solace,
reusing its primitives and adding the Squads-specific instructions, composers, account
types, and a high-level program client.
Squads Smart Account is a distinct program from Squads Multisig. This library targets the Smart Account program only.
📖 Documentation: https://zarpay.github.io/solace-squads-smart-accounts
The gem lives in gem/; the documentation site (VitePress) lives in
site/.
Why a "smart account"?
The naming can be confusing: createSmartAccount does not create an account called
"smart account". It creates a Settings account, and the smart account exists
implicitly.
-
Settings is the control plane. It stores the governance state — signers and their permission masks, threshold, time lock, transaction index. It is the only account the instruction physically creates, because it is the only one that stores data.
-
The smart account is the wallet — the address that holds SOL and tokens. It is a dataless PDA derived from the settings account:
seeds = ["smart_account", settings_address, "smart_account", account_index]It needs no creation instruction: it exists the moment it is funded, and the program signs as it (via CPI) using those seeds.
One settings account governs arbitrarily many smart accounts (account index 0, 1, 2, …)
— same signers and threshold, separate balances. Spending from a smart account goes
through governance: a Transaction account holds the instructions, a Proposal
collects votes per the threshold, and on execution the program signs the instructions as
the smart-account PDA.
Quick start
require 'solace/squads_smart_accounts'
connection = Solace::Connection.new
program = Solace::Programs::SquadsSmartAccount.new(connection:)
creator = Solace::Keypair.generate # a funded keypair
identity = program.next_smart_account
# Create a 1-of-1 smart account.
program.create_smart_account(
payer: creator,
settings_seed: identity.settings_seed,
creator:,
threshold: 1,
signers: [
Solace::SquadsSmartAccounts::SmartAccountSigner.new(
pubkey: creator.address,
permission: Solace::SquadsSmartAccounts::Permissions::ALL
)
]
)
settings = program.get_settings(settings_address: identity.settings_address)
settings.threshold # => 1Spending from the vault then runs through the lifecycle — create_transaction →
create_proposal → approve_proposal → execute_transaction. See the
Quick Start guide
for the full walkthrough, and the docs for a page per operation documented at the
program-method, composer, and instruction level.
Coverage
Covers the flows needed for normal smart-account usage — 22 of the program's 37 instructions. Full matrix: Instruction Coverage.
-
Account creation —
createSmartAccount. -
Async transaction lifecycle —
createTransaction→createProposal→activateProposal→approveProposal/rejectProposal/cancelProposal→executeTransaction→closeTransaction. -
Synchronous execution —
executeTransactionSync(a single transaction, co-signed to threshold, no proposal lifecycle). -
Settings transactions — async (
createSettingsTransaction→ proposal/vote →executeSettingsTransaction→closeSettingsTransaction) and synchronous (executeSettingsTransactionSync); allSettingsActionvariants exceptSetArchivalAuthority. -
Controlled-account authority actions — add/remove signer, change threshold, set time lock, set a new settings authority (the
*AsAuthorityinstructions). - Spending limits — add, use, and remove, across SOL, SPL Token, and Token-2022, in both controlled and autonomous modes.
Limitations
-
Address Lookup Tables (ALTs) are not supported.
createTransactionandexecuteTransactionhandle only "simple" compiled messages — the message'saddress_table_lookupsmust be empty. Pass full 32-byte addresses in the inner instructions. -
Ephemeral signers are not supported (
ephemeral_signersis fixed at 0). - Transaction buffers and batches are not implemented.
-
setArchivalAuthorityAsAuthorityis deliberately skipped — the archival feature is inert in the deployed program. -
Program-config admin instructions and
logEventare out of scope for normal usage.
Development
The gem lives in gem/; run all gem commands from there:
cd gem
bundle install
bundle exec rake # run all tests (boots a fresh solana-test-validator, funds fixtures, stops it after)
bundle exec rubocop # lint
bundle exec rake idl:compare # diff the local Anchor IDL against upstreamTests run against a local solana-test-validator started with a fresh ledger every
run, with the Squads program cloned from mainnet-beta; fixture accounts are funded
automatically at suite start. See gem/CLAUDE.md for architecture and
contribution conventions and gem/INSTRUCTIONS.md for the
per-instruction checklist.
The documentation site is a VitePress app in site/:
cd site
npm install
npm run dev # local preview
npm run build # static buildLicense
Released under the MIT License.