Skip to content

feat: add the create_fund instruction#7

Open
0xgleb wants to merge 4 commits into
masterfrom
feat/create-fund-instruction
Open

feat: add the create_fund instruction#7
0xgleb wants to merge 4 commits into
masterfrom
feat/create-fund-instruction

Conversation

@0xgleb

@0xgleb 0xgleb commented Jun 6, 2026

Copy link
Copy Markdown
Member

🦋 GitButler workspace — open PRs in data-cartel/fund


Motivation

The fund program needs its first real instruction — creating a fund — as the
foundation that deposits, withdrawals, and NAV accounting build on. This is
split out of the oversized create-fund PR (#3) so the on-chain logic can be
reviewed on its own, and it folds in the CodeRabbit feedback from #3 plus a
multi-model review pass.

Solution

  • create_fund instruction: initializes the Fund PDA (seeds
    [b"fund", manager, name], canonical bump cached on-chain), an SPL vault
    token account, and a shares mint — both with authority = Fund and the token
    program pinned via Program<Token>.
  • Fund / CreateFundParams state. build_fund constructs the state as a
    struct literal (a missing field is a compile error) and the handler applies
    it with set_inner.
  • Parameter validation: management and performance fees must be <= 10_000
    bps, and name must be non-empty and canonically zero-padded so two
    encodings can't render as the same name.
  • litesvm integration tests at programs/fund/tests/test_create_fund.rs (per
    the repo's test architecture): full happy path asserting Fund/vault/shares
    mint state and that stored bumps re-derive the canonical PDAs, plus
    rejection paths (over-cap fees, non-canonical and empty names, duplicate
    creation / re-init).
  • The program ID moves to 8FUTArRdDgGDTYbnBMrzB7mBTwLrYpJDTzWY4d62GpCD to
    match the deploy keypair (anchor keys sync); AGENTS.md is updated to
    document it.

Closes #17

Summary by CodeRabbit

  • New Features

    • Fund creation instruction now available with built-in validation for fee parameters and fund name canonicality, ensuring proper fund initialization with defined constraints.
  • Configuration

    • Program identifier updated to latest deployment address.
  • Documentation

    • Program documentation updated with current configuration guidance.
  • Tests

    • New integration test suite validates fund creation, fee boundary conditions, and name validation across comprehensive scenarios.

@0xgleb 0xgleb self-assigned this Jun 6, 2026
@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@0xgleb, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 28 minutes and 23 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5eb0ac10-d3a5-4b1e-8818-5ec84c646e45

📥 Commits

Reviewing files that changed from the base of the PR and between 77b32d1 and b8e6057.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (12)
  • AGENTS.md
  • Anchor.toml
  • programs/fund/Cargo.toml
  • programs/fund/SPEC.md
  • programs/fund/src/error.rs
  • programs/fund/src/instructions.rs
  • programs/fund/src/instructions/create_fund.rs
  • programs/fund/src/instructions/initialize.rs
  • programs/fund/src/lib.rs
  • programs/fund/src/state.rs
  • programs/fund/tests/test_create_fund.rs
  • programs/fund/tests/test_initialize.rs

Walkthrough

Replaces the scaffold initialize instruction with a fully functional create_fund instruction. Introduces CreateFundParams and Fund on-chain structs, a FundError enum, PDA initialization for a fund account, vault token account, and shares mint. Adds fee and name canonicality validation, plus unit, property-based, and LiteSVM integration tests. Updates the program ID and removes the old initialize code.

Changes

create_fund instruction

Layer / File(s) Summary
State structs, error enum, and dependency config
programs/fund/src/state.rs, programs/fund/src/error.rs, programs/fund/Cargo.toml
CreateFundParams and Fund on-chain structs are defined. ErrorCode is replaced by FundError with FeeTooHigh and NonCanonicalName variants. anchor-spl = "0.31" and proptest = "1" are added to dependencies, and idl-build is extended to include anchor-spl/idl-build.
create_fund accounts context, handler, and validation
programs/fund/src/instructions/create_fund.rs
CreateFund Anchor accounts context is defined with PDA seed and init constraints for fund, vault, and shares_mint. The handler validates params via validate_params (fee bounds, non-empty canonical name) then constructs and stores a Fund state via build_fund. is_canonically_padded enforces zero-padding canonicality.
Program entrypoint wiring and ID update
programs/fund/src/lib.rs, programs/fund/src/instructions.rs, Anchor.toml
declare_id and Anchor.toml programs.localnet.fund are updated to the new program address. The state module is publicly re-exported. The initialize entrypoint and module are replaced by create_fund. initialize.rs is deleted.
Unit, property-based, and integration tests
programs/fund/src/instructions/create_fund.rs, programs/fund/tests/test_create_fund.rs
Unit tests verify build_fund field/bump mapping and validate_params accept/reject for fee bounds and name canonicality. Proptest suites cover field preservation, excessive fee rejection, and is_canonically_padded consistency. LiteSVM integration tests assert happy-path Fund state and PDA bumps, and rejection for duplicate creation, boundary/out-of-range fees, non-canonical names, and all-zero names. test_initialize.rs is deleted.
AGENTS.md documentation updates
AGENTS.md
Documented program ID, anchor keys sync instructions, single-test command selector, and test architecture example are updated to reflect the new program ID and create_fund test.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the primary change: adding the create_fund instruction as the main feature of this PR.
Linked Issues check ✅ Passed The PR fully implements the create_fund instruction with Fund PDA initialization, vault account, shares mint, parameter validation, and integration tests—directly addressing issue #17.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the create_fund instruction and its supporting infrastructure; no unrelated changes detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/create-fund-instruction

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@0xgleb

0xgleb commented Jun 18, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@0xgleb 0xgleb force-pushed the feat/create-fund-instruction branch from 1c435c6 to 77b32d1 Compare June 18, 2026 23:10

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@programs/fund/src/instructions/create_fund.rs`:
- Around line 73-89: The validate_params function currently returns generic
error variants that don't distinguish between different validation failures,
making it hard for clients to provide specific feedback. Replace the shared
FundError::FeeTooHigh variant with field-specific error types for
management_fee_bps and performance_fee_bps validations (line 75 and line 79
checks), and similarly replace the generic FundError::NonCanonicalName with
separate error variants for the empty name check (line 83) and the canonical
padding check (line 87). This requires defining new error variants in the
FundError enum to handle each validation failure independently.

In `@programs/fund/tests/test_create_fund.rs`:
- Around line 138-155: The test functions
create_fund_rejects_a_non_canonical_name and
create_fund_rejects_an_all_zero_name currently only verify that the result is an
error. Add explicit assertions after each is_err() check to verify that the fund
account, vault account, and shares account were not created (i.e., they should
not exist in the state). This validates that when name validation fails, the
transaction is properly rolled back atomically and no accounts are left behind.
- Around line 96-111: The assertion in the duplicate create_fund test is too
permissive and accepts any instruction error, potentially missing unrelated
regressions. Instead of only checking that the second send_create_fund call
returns an InstructionError, retrieve and store the fund account state
immediately after the first successful create_fund call, then after the failed
second attempt, retrieve the fund account state again and assert that the bytes
are identical to verify the account state was not modified. This makes the test
specific to the invariant that fund account initialization is protected.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5bc58f5e-435e-4110-a806-0d035648b2d4

📥 Commits

Reviewing files that changed from the base of the PR and between 502aaea and 77b32d1.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (11)
  • AGENTS.md
  • Anchor.toml
  • programs/fund/Cargo.toml
  • programs/fund/src/error.rs
  • programs/fund/src/instructions.rs
  • programs/fund/src/instructions/create_fund.rs
  • programs/fund/src/instructions/initialize.rs
  • programs/fund/src/lib.rs
  • programs/fund/src/state.rs
  • programs/fund/tests/test_create_fund.rs
  • programs/fund/tests/test_initialize.rs
💤 Files with no reviewable changes (2)
  • programs/fund/src/instructions/initialize.rs
  • programs/fund/tests/test_initialize.rs
📜 Review details
🧰 Additional context used
📓 Path-based instructions (9)
programs/**/src/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

programs/**/src/**/*.rs: Walk every new or modified #[derive(Accounts)] struct through the checklist in @docs/sealevel-attacks.md, confirming each Solana/Anchor attack class is handled (signer, owner, account matching, arbitrary CPI, PDA seeds and canonical bump, duplicate-mutable, init re-entry).
Treat the security checklist at the bottom of @docs/sealevel-attacks.md as a hard gate — each #[derive(Accounts)] struct should be walked through it explicitly before merging.

Files:

  • programs/fund/src/instructions.rs
  • programs/fund/src/error.rs
  • programs/fund/src/lib.rs
  • programs/fund/src/state.rs
  • programs/fund/src/instructions/create_fund.rs
programs/fund/src/instructions.rs

📄 CodeRabbit inference engine (AGENTS.md)

Add pub mod <name>; pub use <name>::*; to instructions.rs for each new instruction.

Files:

  • programs/fund/src/instructions.rs
{programs/fund/src/lib.rs,Anchor.toml,target/deploy/fund-keypair.json}

📄 CodeRabbit inference engine (AGENTS.md)

Program ID 8FUTArRdDgGDTYbnBMrzB7mBTwLrYpJDTzWY4d62GpCD must be declared in programs/fund/src/lib.rs, Anchor.toml's [programs.localnet], and match target/deploy/fund-keypair.json — keep all three in sync via anchor keys sync.

Files:

  • Anchor.toml
  • programs/fund/src/lib.rs
Anchor.toml

📄 CodeRabbit inference engine (AGENTS.md)

Anchor toolchain must use package_manager = "bun" (not yarn/npm) in Anchor.toml.

Files:

  • Anchor.toml
*

⚙️ CodeRabbit configuration file

Focus on providing constructive criticism. Whenever you see a suboptimal approach, suggest more idiomatic or robust alternative(s). Flag potential footguns. Suggest FP alternatives to mutable/imperative code. Point out architectural flaws like leaky abstractions, tight coupling, wrong level of abstraction, poor type modeling, over-abstraction, unclear domain boundaries. Code should generally be organized based on business concerns rather than technical aspects - suggest improvements if you find violations. Point out gaps in test coverage but suggest tests that are not too coupled to the implementation and actually test domain invariants and business logic.

Files:

  • Anchor.toml
  • AGENTS.md
programs/fund/src/lib.rs

📄 CodeRabbit inference engine (AGENTS.md)

Add a thin wrapper inside #[program] mod fund in lib.rs that calls <name>::handler(ctx, ...) for each new instruction.

Files:

  • programs/fund/src/lib.rs
programs/fund/tests/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

programs/fund/tests/**/*.rs: Write integration tests using litesvm directly from Rust integration tests under programs/fund/tests/ that include the compiled BPF binary via include_bytes!, load it with LiteSVM::new(), and construct Instruction using Anchor-generated types.
Use litesvm directly from Rust integration tests under programs/fund/tests/ instead of anchor test.

Files:

  • programs/fund/tests/test_create_fund.rs
**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

Document everything in tracked markdown files (this file, programs/fund/README.md, programs/fund/SPEC.md, ADRs under adrs/, or a dedicated doc). Agent memory, scratchpads, or .tmp/ files do not count as documentation.

Files:

  • AGENTS.md

⚙️ CodeRabbit configuration file

Focus on the contents of the docs and not on cosmetic things like markdown formatting. We use markdown files for various docs including but not limited to the north star system specification, SPEC.md, the plan for how to get there, ROADMAP.md, guidelines for AI contributors, AGENTS.md, project overview and instructions for human contributors, README.md. Think about the target audience of a document when deciding what comment to leave. For specifications and designs, suggest potential product, architectural, and UI/UX improvements. For plans, suggest changes that would make things more parallelizable and deliverable-focused. For instructions, suggest better rules and guidelines and point out missing instructions. In all cases, flag needless bloat, prefer clear concise writing, and consider the structure of the document and order of the sections

Files:

  • AGENTS.md
programs/fund/src/instructions/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

When adding a new instruction, create programs/fund/src/instructions/<name>.rs with #[derive(Accounts)] pub struct <Name> and pub fn handler(...).

Files:

  • programs/fund/src/instructions/create_fund.rs
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: data-cartel/fund

Timestamp: 2026-06-18T23:11:32.200Z
Learning: `anchor build` must run before `cargo test` because integration tests use `include_bytes!` to pull the compiled BPF binary at compile time.
Learnt from: CR
Repo: data-cartel/fund

Timestamp: 2026-06-18T23:11:32.200Z
Learning: Run `anchor build` first, then `cargo test --workspace` to ensure tests exercise a fresh binary and report accurate results.
Learnt from: CR
Repo: data-cartel/fund

Timestamp: 2026-06-18T23:11:32.200Z
Learning: Use lowercase commit messages with conventional prefixes (`feat:`, `fix:`, `docs:`, `chore:`, `refactor:`, `test:`) and explain why in the body.
Learnt from: CR
Repo: data-cartel/fund

Timestamp: 2026-06-18T23:11:32.200Z
Learning: Never add 'Generated with ...' or co-author trailers to commit messages.
Learnt from: CR
Repo: data-cartel/fund

Timestamp: 2026-06-18T23:11:32.200Z
Learning: Use GitButler CLI (`but`) for all version-control write operations (commits, branches, push).
Learnt from: CR
Repo: data-cartel/fund

Timestamp: 2026-06-18T23:11:32.200Z
Learning: Use branch names with format `<type>/<kebab-description>` and always pass an explicit name to `but branch new`.
Learnt from: CR
Repo: data-cartel/fund

Timestamp: 2026-06-18T23:11:32.200Z
Learning: Always succumb to whatever Solana tooling wants — match its version pins, directory layout, env-var conventions, and config defaults rather than fighting them.
Learnt from: CR
Repo: data-cartel/fund

Timestamp: 2026-06-18T23:11:32.200Z
Learning: Anchor-based Solana program named `fund` uses a single on-chain program with a Cargo workspace and TypeScript app/migrations side managed via bun.
🔇 Additional comments (7)
AGENTS.md (1)

75-75: LGTM!

Also applies to: 91-91, 125-125

programs/fund/src/state.rs (1)

1-34: LGTM!

programs/fund/Cargo.toml (1)

17-30: LGTM!

programs/fund/src/lib.rs (1)

10-20: LGTM!

programs/fund/src/instructions.rs (1)

1-3: LGTM!

programs/fund/tests/test_create_fund.rs (1)

1-89: LGTM!

Also applies to: 114-135, 157-249

Anchor.toml (1)

9-9: ✓ Hard-gate Anchor config constraints confirmed: toolchain.package_manager = "bun" is set, and the Program ID 8FUTArRdDgGDTYbnBMrzB7mBTwLrYpJDTzWY4d62GpCD matches between Anchor.toml and programs/fund/src/lib.rs. The keypair sync should be verified locally via anchor keys sync to ensure the generated target/deploy/fund-keypair.json is current.

Comment thread programs/fund/src/instructions/create_fund.rs
Comment thread programs/fund/tests/test_create_fund.rs
Comment thread programs/fund/tests/test_create_fund.rs
0xgleb added a commit that referenced this pull request Jun 27, 2026
Address the CodeRabbit review on #7:

- Split the shared `FeeTooHigh` and `NonCanonicalName` variants into
  field-specific `ManagementFeeTooHigh`, `PerformanceFeeTooHigh`, and
  `EmptyName`, so a client (and telemetry) can tell which input was rejected.
  Validation logic is unchanged; only the error codes get more specific.
- Harden the duplicate-create test to assert the pre-existing fund stays
  byte-identical after the rejected re-init, not merely that it errors.
- Assert fund/vault/shares accounts are absent after every rejected create
  (non-canonical name, all-zero name, and the excessive fee), proving the
  atomic rollback rather than only checking `is_err`.
@0xgleb 0xgleb requested a review from levsgit June 27, 2026 20:10
0xgleb added 4 commits June 27, 2026 18:20
Address the CodeRabbit review on #7:

- Split the shared `FeeTooHigh` and `NonCanonicalName` variants into
  field-specific `ManagementFeeTooHigh`, `PerformanceFeeTooHigh`, and
  `EmptyName`, so a client (and telemetry) can tell which input was rejected.
  Validation logic is unchanged; only the error codes get more specific.
- Harden the duplicate-create test to assert the pre-existing fund stays
  byte-identical after the rejected re-init, not merely that it errors.
- Assert fund/vault/shares accounts are absent after every rejected create
  (non-canonical name, all-zero name, and the excessive fee), proving the
  atomic rollback rather than only checking `is_err`.
The error split (ManagementFeeTooHigh / PerformanceFeeTooHigh / EmptyName /
NonCanonicalName) updated the code but left SPEC.md describing the old collapsed
FeeTooHigh and the shared NonCanonicalName. Rewrite create_fund's error
conditions to match, so CodeRabbit's field-specific-errors point holds in the
spec too, not only the implementation, and spec-code parity is preserved.
@0xgleb 0xgleb force-pushed the feat/create-fund-instruction branch from 31c3c65 to b8e6057 Compare June 27, 2026 21:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

the program has no instruction to create a fund

1 participant