Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
3d2c3ac
WIP
0xRigel-squads Jul 9, 2025
2c35e0c
feat: core logic
0xRigel-squads Jul 23, 2025
cc45378
feat: resource limit refactoring
0xRigel-squads Jul 24, 2025
dd841b9
fixes
0xRigel-squads Jul 27, 2025
baaf4b0
tests & refactoring
0xRigel-squads Jul 28, 2025
966e3f4
remove: dead code
0xRigel-squads Jul 28, 2025
f475ba3
merge: async transaction logging
0xRigel-squads Jul 28, 2025
38af553
feat: policy logging
0xRigel-squads Jul 29, 2025
875d3bb
cleanup
0xRigel-squads Jul 29, 2025
8d17f16
remove: .yarn cache
0xRigel-squads Jul 29, 2025
49f7268
chore: minor cleanup:
0xRigel-squads Jul 29, 2025
84f37e6
feat: policy update events
0xRigel-squads Jul 30, 2025
46ca8b0
cleanup
0xRigel-squads Jul 30, 2025
72a6f6e
add: sanity sizing to program interaction policy
0xRigel-squads Jul 30, 2025
cadfb48
fix: sync program interaction policy ix evaluation
0xRigel-squads Sep 3, 2025
798794f
fix: policy activation timestamp check
0xRigel-squads Sep 3, 2025
7f3c52c
fix: spending limit policy destination check
0xRigel-squads Sep 3, 2025
b297788
fix: policy creation signer seeds
0xRigel-squads Sep 3, 2025
a203163
fix: source token account info validation
0xRigel-squads Sep 3, 2025
949b45e
fix: policy timelock invariant
0xRigel-squads Sep 8, 2025
7149ae2
fix: spending limit policy source-destination inequality
0xRigel-squads Sep 8, 2025
95692e5
fix: settings change realloc
0xRigel-squads Sep 8, 2025
c77e92c
feat: discriminator based log event protection
0xRigel-squads Sep 8, 2025
b9979a4
chore: fmt
0xRigel-squads Sep 8, 2025
a99ca0c
fix: policy seed unique string seed & suggestions
0xRigel-squads Sep 8, 2025
1fb5a1d
fix: settings change policy settings authority
0xRigel-squads Sep 8, 2025
8de9d1b
fix: missing policy seed adjustment
0xRigel-squads Sep 16, 2025
04cd19f
fix: tests
0xRigel-squads Sep 16, 2025
74d2415
Merge pull request #15 from Squads-Protocol/fix/policy-remediation
0xRigel-squads Sep 18, 2025
ac23d6d
WIP
0xRigel-squads Sep 23, 2025
215856d
WIP
0xRigel-squads Sep 29, 2025
921febe
feat: hook implementation
0xRigel-squads Oct 27, 2025
f311b7a
fix: M-01 SpendingLimitPolicy
0xRigel-squads Oct 27, 2025
6d17d1e
fix: M-03 Spending limits
0xRigel-squads Oct 27, 2025
65e301e
fix: L-01
0xRigel-squads Oct 27, 2025
74e41ec
fix: L-04
0xRigel-squads Oct 27, 2025
24b0b20
fix: I-08
0xRigel-squads Oct 27, 2025
f589dc8
fix: I-09
0xRigel-squads Oct 27, 2025
295187a
fix: I-11
0xRigel-squads Oct 27, 2025
4ab8ecf
feat: hooks in sync execution
0xRigel-squads Nov 3, 2025
32e38d5
L-04 adjustment
0xRigel-squads Nov 3, 2025
ee05fbb
chore: add tests
0xRigel-squads Nov 3, 2025
595d5a5
Merge branch 'policies' into feat/policy-hooks
0xRigel-squads Nov 3, 2025
380a444
feat(program): deduplicate code
0xRigel-squads Nov 4, 2025
ae46e55
add: tests
0xRigel-squads Nov 4, 2025
e7cf2f6
add: sdk utils
0xRigel-squads Nov 4, 2025
1d1032c
fix & dedup: account constraint evaluation
0xRigel-squads Nov 5, 2025
7d3d45c
fix: size calulations
0xRigel-squads Nov 15, 2025
f2df7ea
Merge pull request #18 from Squads-Protocol/feat/hook-improvment
0xRigel-squads Nov 17, 2025
6a6c7e2
Merge pull request #17 from Squads-Protocol/feat/policy-hooks
0xRigel-squads Nov 17, 2025
69deafb
Merge pull request #16 from Squads-Protocol/audit/certora-remediations
0xRigel-squads Nov 17, 2025
b12937d
feat: new program interaction policy creation format
0xLeo-sqds Nov 26, 2025
6a66c2f
feat: add builtin programs
0xLeo-sqds Nov 26, 2025
7139abf
feat: improved builtins and added index to spendingLimits
0xLeo-sqds Nov 26, 2025
7ecb5d0
Changed Indexed to Compiled
0xLeo-sqds Nov 26, 2025
2dee83a
Use SmallVec in the Compiled version
0xLeo-sqds Nov 26, 2025
0def404
Added some unit test for all new helpers
0xLeo-sqds Nov 27, 2025
6cf4ca5
added a cleanup function for SmallVec and added tests
0xLeo-sqds Nov 27, 2025
cfd49f0
Changed naming of the struct
0xLeo-sqds Nov 27, 2025
fd7fe27
Fixed some nits
0xLeo-sqds Dec 9, 2025
cd3ce98
Nits
0xLeo-sqds Dec 9, 2025
ee728b5
Merge pull request #21 from Squads-Protocol/create-program-interactio…
0xLeo-sqds Dec 17, 2025
a5d3bb3
Feat: general cleanup
0xLeo-sqds Jan 14, 2026
bba31a1
Merge pull request #24 from Squads-Protocol/cleanup/general-cleanup
0xRigel-squads Jan 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,8 @@ node_modules
test-ledger
.yarn-error

# Yarn - ignore entire yarn directories
.yarn/

lib
.crates
1 change: 1 addition & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
4 changes: 4 additions & 0 deletions Anchor.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,9 @@ url = "https://api.devnet.solana.com"
address = "8UuqDAqe9UQx9e9Sjj4Gs3msrWGfzb4CJHGK3U3tcCEX"
filename = "tests/fixtures/pre-rent-collector/multisig-account.json"

[[test.genesis]]
address = "noopb9bkMVfRPU8AsbpTUg8AQkHtKwMYZiFUjNRtMmV"
program = "tests/fixtures/noop.so"

[scripts]
test = "npx mocha --node-option require=ts-node/register --extension ts -t 1000000 tests/index.ts"
14 changes: 7 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

502 changes: 447 additions & 55 deletions README.md

Large diffs are not rendered by default.

63 changes: 32 additions & 31 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,33 +1,34 @@
{
"private": true,
"workspaces": [
"sdk/*"
],
"scripts": {
"build": "turbo run build",
"test:detached": "turbo run build && anchor test --detach -- --features=testing && echo \"\n⚠️ Don't forget to recompile the .so file before deployment\n\"",
"test": "turbo run build && anchor test -- --features=testing && echo \"\n⚠️ Don't forget to recompile the .so file before deployment\n\"",
"pretest": "mkdir -p target/deploy && cp ./test-program-keypair.json ./target/deploy/squads_smart_account_program-keypair.json",
"ts": "turbo run ts && yarn tsc --noEmit"
},
"devDependencies": {
"@solana/spl-memo": "^0.2.3",
"@solana/spl-token": "*",
"@types/bn.js": "5.1.0",
"@types/mocha": "10.0.1",
"@types/node-fetch": "2.6.2",
"mocha": "10.2.0",
"prettier": "2.6.2",
"ts-node": "10.9.1",
"turbo": "1.6.3",
"typescript": "*"
},
"resolutions": {
"@solana/web3.js": "1.70.3",
"@solana/spl-token": "0.3.6",
"typescript": "4.9.4"
},
"dependencies": {
"@solana/web3.js": "^1.95.5"
}
"private": true,
"workspaces": [
"sdk/*"
],
"scripts": {
"build": "turbo run build",
"test:detached": "turbo run build && anchor test --detach -- --features=testing && echo \"\n⚠️ Don't forget to recompile the .so file before deployment\n\"",
"test:detached:nb": "anchor test --detach -- --features=testing && echo \"\n⚠️ Don't forget to recompile the .so file before deployment\n\"",
"test": "turbo run build && anchor test -- --features=testing && echo \"\n⚠️ Don't forget to recompile the .so file before deployment\n\"",
"pretest": "mkdir -p target/deploy && cp ./test-program-keypair.json ./target/deploy/squads_smart_account_program-keypair.json",
"ts": "turbo run ts && yarn tsc --noEmit"
},
"devDependencies": {
"@solana/spl-memo": "^0.2.3",
"@solana/spl-token": "*",
"@types/mocha": "10.0.1",
"@types/node-fetch": "2.6.2",
"mocha": "10.2.0",
"prettier": "2.6.2",
"ts-node": "10.9.1",
"turbo": "1.6.3",
"typescript": "*"
},
"resolutions": {
"@solana/web3.js": "1.70.3",
"@solana/spl-token": "0.3.6",
"typescript": "4.9.4"
},
"dependencies": {
"@solana/web3.js": "^1.95.5"
},
"packageManager": "yarn@1.22.22"
}
1 change: 1 addition & 0 deletions programs/squads_smart_account_program/src/allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,5 +129,6 @@ unsafe impl std::alloc::GlobalAlloc for BumpAllocator {

// Only use the allocator if we're not in a no-entrypoint context
#[cfg(not(feature = "no-entrypoint"))]
#[cfg(not(test))]
#[global_allocator]
static A: BumpAllocator = BumpAllocator;
184 changes: 182 additions & 2 deletions programs/squads_smart_account_program/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@ pub enum SmartAccountError {
SpendingLimitExceeded,
#[msg("Decimals don't match the mint")]
DecimalsMismatch,
#[msg("Spending limit is expired")]
SpendingLimitExpired,
#[msg("Signer has unknown permission")]
UnknownPermission,
#[msg("Account is protected, it cannot be passed into a CPI as writable")]
Expand Down Expand Up @@ -110,4 +108,186 @@ pub enum SmartAccountError {
TimeLockNotZero,
#[msg("Feature not implemented")]
NotImplemented,
#[msg("Invalid cadence configuration")]
SpendingLimitInvalidCadenceConfiguration,
#[msg("Invalid data constraint")]
InvalidDataConstraint,


#[msg("Invalid payload")]
InvalidPayload,
#[msg("Protected instruction")]
ProtectedInstruction,
#[msg("Placeholder error")]
PlaceholderError,

// ===============================================
// Overall Policy Errors
// ===============================================
#[msg("Invalid policy payload")]
InvalidPolicyPayload,
#[msg("Invalid empty policy")]
InvalidEmptyPolicy,
#[msg("Transaction is for another policy")]
TransactionForAnotherPolicy,

// ===============================================
// Program Interaction Policy Errors
// ===============================================
#[msg("Program interaction sync payload not allowed with async transaction")]
ProgramInteractionAsyncPayloadNotAllowedWithSyncTransaction,
#[msg("Program interaction sync payload not allowed with sync transaction")]
ProgramInteractionSyncPayloadNotAllowedWithAsyncTransaction,
#[msg("Program interaction data constraint failed: instruction data too short")]
ProgramInteractionDataTooShort,
#[msg("Program interaction data constraint failed: invalid numeric value")]
ProgramInteractionInvalidNumericValue,
#[msg("Program interaction data constraint failed: invalid byte sequence")]
ProgramInteractionInvalidByteSequence,
#[msg("Program interaction data constraint failed: unsupported operator for byte slice")]
ProgramInteractionUnsupportedSliceOperator,
#[msg("Program interaction constraint failed: instruction data parsing error")]
ProgramInteractionDataParsingError,
#[msg("Program interaction constraint failed: program ID mismatch")]
ProgramInteractionProgramIdMismatch,
#[msg("Program interaction constraint violation: account constraint")]
ProgramInteractionAccountConstraintViolated,
#[msg("Program interaction constraint violation: instruction constraint index out of bounds")]
ProgramInteractionConstraintIndexOutOfBounds,
#[msg("Program interaction constraint violation: instruction count mismatch")]
ProgramInteractionInstructionCountMismatch,
#[msg("Program interaction constraint violation: insufficient remaining lamport allowance")]
ProgramInteractionInsufficientLamportAllowance,
#[msg("Program interaction constraint violation: insufficient remaining token allowance")]
ProgramInteractionInsufficientTokenAllowance,
#[msg("Program interaction constraint violation: modified illegal balance")]
ProgramInteractionModifiedIllegalBalance,
#[msg("Program interaction constraint violation: illegal token account modification")]
ProgramInteractionIllegalTokenAccountModification,
#[msg("Program interaction invariant violation: duplicate spending limit for the same mint")]
ProgramInteractionDuplicateSpendingLimit,
#[msg("Program interaction constraint violation: too many instruction constraints. Max is 20")]
ProgramInteractionTooManyInstructionConstraints,
#[msg("Program interaction constraint violation: too many spending limits. Max is 10")]
ProgramInteractionTooManySpendingLimits,
#[msg("Program interaction constraint violation: invalid pubkey table index")]
ProgramInteractionInvalidPubkeyTableIndex,
#[msg("Program interaction constraint violation: too many unique pubkeys. Max is 240 (indices 240-255 reserved for builtin programs)")]
ProgramInteractionTooManyUniquePubkeys,
#[msg("Program interaction hook violation: template hook error")]
ProgramInteractionTemplateHookError,
#[msg("Program interaction hook violation: hook authority cannot be part of hook accounts")]
ProgramInteractionHookAuthorityCannotBePartOfHookAccounts,

// ===============================================
// Spending Limit Policy Errors
// ===============================================
#[msg("Spending limit is not active")]
SpendingLimitNotActive,
#[msg("Spending limit is expired")]
SpendingLimitExpired,
#[msg("Spending limit policy invariant violation: usage state cannot be Some() if accumulate_unused is true")]
SpendingLimitPolicyInvariantAccumulateUnused,
#[msg("Amount violates exact quantity constraint")]
SpendingLimitViolatesExactQuantityConstraint,
#[msg("Amount violates max per use constraint")]
SpendingLimitViolatesMaxPerUseConstraint,
#[msg("Spending limit is insufficient")]
SpendingLimitInsufficientRemainingAmount,
#[msg("Spending limit invariant violation: max per period must be non-zero")]
SpendingLimitInvariantMaxPerPeriodZero,
#[msg("Spending limit invariant violation: start time must be positive")]
SpendingLimitInvariantStartTimePositive,
#[msg("Spending limit invariant violation: expiration must be greater than start")]
SpendingLimitInvariantExpirationSmallerThanStart,
#[msg("Spending limit invariant violation: overflow enabled must have expiration")]
SpendingLimitInvariantOverflowEnabledMustHaveExpiration,
#[msg("Spending limit invariant violation: one time period cannot have overflow enabled")]
SpendingLimitInvariantOneTimePeriodCannotHaveOverflowEnabled,
#[msg("Spending limit invariant violation: remaining amount must be less than max amount")]
SpendingLimitInvariantOverflowRemainingAmountGreaterThanMaxAmount,
#[msg("Spending limit invariant violation: remaining amount must be less than or equal to max per period")]
SpendingLimitInvariantRemainingAmountGreaterThanMaxPerPeriod,
#[msg("Spending limit invariant violation: exact quantity must have max per use non-zero")]
SpendingLimitInvariantExactQuantityMaxPerUseZero,
#[msg("Spending limit invariant violation: max per use must be less than or equal to max per period")]
SpendingLimitInvariantMaxPerUseGreaterThanMaxPerPeriod,
#[msg("Spending limit invariant violation: custom period must be positive")]
SpendingLimitInvariantCustomPeriodNegative,
#[msg("Spending limit policy invariant violation: cannot have duplicate destinations for the same mint")]
SpendingLimitPolicyInvariantDuplicateDestinations,
#[msg("Spending limit invariant violation: last reset must be between start and expiration")]
SpendingLimitInvariantLastResetOutOfBounds,
#[msg("Spending limit invariant violation: last reset must be greater than start")]
SpendingLimitInvariantLastResetSmallerThanStart,

// ===============================================
// Internal Fund Transfer Policy Errors
// ===============================================
#[msg("Internal fund transfer policy invariant violation: source account index is not allowed")]
InternalFundTransferPolicyInvariantSourceAccountIndexNotAllowed,
#[msg("Internal fund transfer policy invariant violation: destination account index is not allowed")]
InternalFundTransferPolicyInvariantDestinationAccountIndexNotAllowed,
#[msg("Internal fund transfer policy invariant violation: source and destination cannot be the same")]
InternalFundTransferPolicyInvariantSourceAndDestinationCannotBeTheSame,
#[msg("Internal fund transfer policy invariant violation: mint is not allowed")]
InternalFundTransferPolicyInvariantMintNotAllowed,
#[msg("Internal fund transfer policy invariant violation: amount must be greater than 0")]
InternalFundTransferPolicyInvariantAmountZero,
#[msg("Internal fund transfer policy invariant violation: cannot have duplicate mints")]
InternalFundTransferPolicyInvariantDuplicateMints,

// ===============================================
// Consensus Account Errors
// ===============================================
#[msg("Consensus account is not a settings")]
ConsensusAccountNotSettings,
#[msg("Consensus account is not a policy")]
ConsensusAccountNotPolicy,

// ===============================================
// Settings Change Policy Errors
// ===============================================
#[msg("Settings change policy invariant violation: actions must be non-zero")]
SettingsChangePolicyActionsMustBeNonZero,
#[msg("Settings change policy violation: submitted settings account must match policy settings key")]
SettingsChangeInvalidSettingsKey,
#[msg("Settings change policy violation: submitted settings account must be writable")]
SettingsChangeInvalidSettingsAccount,
#[msg("Settings change policy violation: rent payer must be writable and signer")]
SettingsChangeInvalidRentPayer,
#[msg("Settings change policy violation: system program must be the system program")]
SettingsChangeInvalidSystemProgram,
#[msg("Settings change policy violation: signer does not match allowed signer")]
SettingsChangeAddSignerViolation,
#[msg("Settings change policy violation: signer permissions does not match allowed signer permissions")]
SettingsChangeAddSignerPermissionsViolation,
#[msg("Settings change policy violation: signer removal does not mach allowed signer removal")]
SettingsChangeRemoveSignerViolation,
#[msg("Settings change policy violation: time lock does not match allowed time lock")]
SettingsChangeChangeTimelockViolation,
#[msg("Settings change policy violation: action does not match allowed action")]
SettingsChangeActionMismatch,
#[msg("Settings change policy invariant violation: cannot have duplicate actions")]
SettingsChangePolicyInvariantDuplicateActions,
#[msg("Settings change policy invariant violation: action indices must match actions length")]
SettingsChangePolicyInvariantActionIndicesActionsLengthMismatch,
#[msg("Settings change policy invariant violation: action index out of bounds")]
SettingsChangePolicyInvariantActionIndexOutOfBounds,

// ===============================================
// Policy Expiration Errors
// ===============================================
#[msg("Policy is not active yet")]
PolicyNotActiveYet,
#[msg("Policy invariant violation: invalid policy expiration")]
PolicyInvariantInvalidExpiration,
#[msg("Policy expiration violation: submitted settings key does not match policy settings key")]
PolicyExpirationViolationPolicySettingsKeyMismatch,
#[msg("Policy expiration violation: state expiration requires the settings to be submitted")]
PolicyExpirationViolationSettingsAccountNotPresent,
#[msg("Policy expiration violation: state hash has expired")]
PolicyExpirationViolationHashExpired,
#[msg("Policy expiration violation: timestamp has expired")]
PolicyExpirationViolationTimestampExpired,
}
Loading