Skip to content

Conversation

@notdanilo
Copy link
Contributor

@notdanilo notdanilo commented Nov 4, 2025

Status Type ⚠️ Core Change Issue
Ready Refactor Yes None

Problem

New version of Bolt introduces a breaking change, we want to keep a program that is retro-compatible while introducing a new one with the breaking changes.

Solution

New program with the new features

Summary by CodeRabbit

  • New Features

    • Added bundle support combining components and systems into unified programs.
    • Added CLI command to create new bundles.
    • Introduced new Component and System classes in TypeScript and C# clients.
    • Updated instruction APIs with new discriminator-based methods and improved type handling.
  • Chores

    • Updated world program identifier.
    • Reorganized workspace members and dependencies.

@coderabbitai
Copy link

coderabbitai bot commented Nov 4, 2025

Walkthrough

This pull request refactors the Bolt framework's architecture by consolidating attribute macros into a unified bolt-attribute crate, removing standalone bolt-component and bolt-system programs, and introducing a new bundle concept for combining components and systems. It adds ECS support classes (Component, System, Identifier) to TypeScript and C# clients, updates the World program with discriminator-based CPI calls, and extends CLI tooling and test infrastructure for bundle support. World program ID has been updated across configurations.

Changes

Cohort / File(s) Summary
CI/CD Workflows
.github/workflows/publish-bolt-crates.yml, publish-bolt-sdk.yml, run-tests.yml
Added deployment keypair provisioning for example_bundle; restructured crate publish list (removed bolt-component, bolt-system, bolt-delegate, bolt-program; added bolt-attribute-bolt-bundle)
Configuration & Manifests
Anchor.toml, Cargo.toml, crates/bolt-lang/Cargo.toml, crates/programs/world/Cargo.toml
Updated workspace members and dependencies; reorganized localnet programs; changed devnet world ID; replaced bolt-component/bolt-system with bundle-related entries; added const-crypto and sha2 dependencies
Attribute Macro Consolidation
crates/bolt-lang/attribute/Cargo.toml, crates/bolt-lang/attribute/bolt-program/src/lib.rs (deleted), crates/bolt-lang/attribute/component/src/lib.rs, crates/bolt-lang/attribute/delegate/src/lib.rs (deleted), crates/bolt-lang/attribute/bundle/Cargo.toml
Consolidated attribute macro logic into unified bolt-attribute crate; renamed bolt-attribute-bolt-delegate to bolt-attribute-bolt-bundle; removed standalone bolt-program and delegate macros; delegated component processing to central processor
Attribute Macro Implementations
crates/bolt-lang/attribute/src/lib.rs, crates/bolt-lang/attribute/src/component/mod.rs, crates/bolt-lang/attribute/src/system/mod.rs, crates/bolt-lang/attribute/src/bundle/mod.rs, crates/bolt-lang/attribute/src/delegate/mod.rs
Added modular attribute processing for component, system, bundle, and delegate with code generation helpers and module transformation logic
Component Deserialization & System Input
crates/bolt-lang/attribute/component-deserialize/src/lib.rs, crates/bolt-lang/attribute/system-input/src/lib.rs
Introduced SHA-256 based discriminator generation for components; updated system input to use Signer<'info> and relocated NumberOfComponents trait to bolt-lang
Utility Attributes
crates/bolt-lang/attribute/extra-accounts/src/lib.rs
Dynamically generated trait names and struct generation; added heck dependency for case conversion
Bundle CLI & Templates
crates/bolt-cli/src/bundle.rs, crates/bolt-cli/src/lib.rs, crates/bolt-cli/src/rust_template.rs, crates/bolt-cli/src/templates/bundle/lib.rs.template, crates/bolt-cli/src/templates/bundle/mod.rs, crates/bolt-cli/src/templates/mod.rs, crates/bolt-cli/src/templates/workspace/workspace.toml.template
Added Bundle command and bundle creation templates; registered new bundle workflow in CLI dispatcher
Core Bolt Lang
crates/bolt-lang/src/lib.rs, crates/bolt-lang/src/cpi/mod.rs, crates/bolt-lang/src/errors.rs, crates/bolt-lang/src/instructions/mod.rs, crates/bolt-lang/src/instructions/initialize.rs, crates/bolt-lang/src/instructions/destroy.rs, crates/bolt-lang/src/instructions/update.rs
Added new CPI validation, instruction lifecycle functions (initialize, destroy, update), NumberOfComponents trait, and BoltMetadata helpers; added AccountMismatch and ComponentNotDelegateable error variants
Removed Programs
crates/programs/bolt-component/*, crates/programs/bolt-system/*
Deleted standalone component and system program implementations; moved functionality into bundle and core instruction modules
World Program Refactoring
crates/programs/world/src/lib.rs, crates/programs/world/src/utils.rs, crates/programs/world/Cargo.toml
Refactored CPI invocations from CpiContext-based to explicit Solana SDK calls; introduced discriminator-based routing; added utils module with discriminator_for function; updated program ID
TypeScript Client - ECS Classes
clients/typescript/src/ecs/identifier.ts, clients/typescript/src/ecs/component.ts, clients/typescript/src/ecs/system.ts, clients/typescript/src/ecs/index.ts
Added Identifier, Component, and System classes with method discriminator, PDA, and conversion support
TypeScript Client - Core
clients/typescript/src/index.ts, clients/typescript/.solitarc.js, clients/typescript/idl/world.json
Exported Component and System; added GetDiscriminator utility; updated world program ID
TypeScript Client - Transactions
clients/typescript/src/delegation/delegate.ts, clients/typescript/src/world/transactions.ts
Updated signatures to accept Component/System objects; refactored initialization, destruction, and apply flows to use discriminators; added component/system resolution via factory methods
TypeScript Client - Tests & Framework
clients/typescript/test/framework.ts, clients/typescript/test/intermediate-level/acceleration.ts, clients/typescript/test/intermediate-level/ecs.ts
Added ExampleBundle program support; added bundle-related PDA fields; extended test coverage for bundled components and systems
C# Client - ECS Classes
clients/csharp/Solana.Unity.Bolt/ECS/Identifier.cs, clients/csharp/Solana.Unity.Bolt/ECS/Component.cs, clients/csharp/Solana.Unity.Bolt/ECS/System.cs
Introduced Identifier, Component, and System classes with method discriminator and conversion support
C# Client - World Program
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt.cs, clients/csharp/Solana.Unity.Bolt/WorldProgram/Generated.cs, clients/csharp/Solana.Unity.Bolt/WorldProgram/World.cs
Added GetDiscriminator utility; introduced ApplyWithDiscriminator and ApplyWithSessionAndDiscriminator methods; added CpiAuthAddress field; updated world program ID
C# Client - Component Operations
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/ApplySystem.cs, clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/InitializeComponent.cs, clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/DestroyComponent.cs, clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/DelegateComponent.cs
Added Component-aware overloads for initialize, destroy, delegate, and apply operations with discriminator-based routing
C# Client - Tests & Framework
clients/csharp/Solana.Unity.Bolt.Test/Framework.cs, clients/csharp/Solana.Unity.Bolt.Test/AccelerationTest.cs, clients/csharp/Solana.Unity.Bolt.Test/ECSTest.cs
Added ExampleBundle program support; extended test methods for bundled component initialization and bundled system application
Example Bundle
examples/bundle/Cargo.toml, examples/bundle/src/lib.rs
Added new example bundle module with Position and Velocity components and movement/stop systems
Test & Build Scripts
scripts/test-publish.sh, tests/test-validator.sh, docs/REPORT.md, crates/bolt-lang/utils/src/lib.rs
Updated publish script to reflect new crate structure; updated validator test with new world program ID; updated performance report data; minor utility change for bolt_metadata field ordering

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant BundleProgram as Bundle Program<br/>(example_bundle)
    participant WorldProgram as World Program
    participant Sysvar as Instruction Sysvar

    rect rgb(200, 220, 255)
    Note over Client,WorldProgram: Old Flow: CpiContext-based
    Client->>WorldProgram: InitializeComponent<br/>(via CpiContext)
    WorldProgram->>BundleProgram: CPI (auto-generated context)
    end

    rect rgb(220, 240, 220)
    Note over Client,WorldProgram: New Flow: Discriminator-based
    Client->>WorldProgram: InitializeComponent<br/>(with discriminator)
    WorldProgram->>Sysvar: Verify caller via<br/>instruction sysvar
    Sysvar-->>WorldProgram: Instruction validated
    WorldProgram->>BundleProgram: CPI (explicit instruction<br/>+ accounts + discriminator)
    BundleProgram-->>WorldProgram: Component initialized
    end

    rect rgb(240, 240, 220)
    Note over Client,WorldProgram: Bundle Apply Flow
    Client->>WorldProgram: ApplySystem<br/>(system_id, entities, args)
    WorldProgram->>BundleProgram: Execute system<br/>(bolt_execute)
    BundleProgram-->>WorldProgram: Execution result
    WorldProgram->>BundleProgram: Update component<br/>(update with discriminator)
    BundleProgram-->>WorldProgram: Component updated
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Areas requiring extra attention:

  • Attribute macro refactoring (crates/bolt-lang/attribute/src/*): Complex procedural macro logic with interconnected code generation for components, systems, bundles, and delegates. Requires understanding of token stream processing and trait implementations.
  • World program CPI changes (crates/programs/world/src/lib.rs): Significant architectural shift from auto-generated CpiContext patterns to explicit Solana SDK invocations with discriminator routing. High logic density requiring careful verification of account ordering and discriminator computation.
  • Component/System/Identifier classes (across TypeScript and C# clients): Parallel implementations in multiple languages with new factory methods and PDA derivation logic; ensure consistency across bindings.
  • Removed programs (crates/programs/bolt-component/ and crates/programs/bolt-system/): Verify that all functionality previously in these programs is correctly migrated to the new instruction module and bundle system.
  • Discriminator computation (SHA-256 based): Verify discriminator generation is consistent across Rust, TypeScript, and C# implementations, especially in const/compile-time evaluations.

Possibly related PRs

  • bolt#213: Changes CPI authentication by replacing cpi_auth/World PDA usage with instruction sysvar validation (InstructionSysvarAccount) and adjusts generated account field handling—directly related to the instruction sysvar check pattern introduced here.

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title '🔐 New address' is vague and does not clearly convey the main purpose of this substantial refactoring PR. Use a more descriptive title that captures the primary change, such as 'Refactor: Update World program ID and introduce bundle architecture' or 'Add new World program with bundle support and deprecate legacy components'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The PR description follows the template structure with Status, Type, Core Change fields filled in and includes Problem/Solution sections explaining the refactoring rationale.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/new-address

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 and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 20

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/DestroyComponent.cs (1)

50-65: Add discriminator handling to match InitializeComponent pattern and TS behavior.

The implementation references DestroyComponentWithDiscriminator in its XML comment ("Mirrors TS: discriminator derived from component name if provided") but calls the non-discriminator variant instead. Unlike InitializeComponent, which retrieves the discriminator via component.GetMethodDiscriminator("initialize"), validates it, and calls WorldProgram.InitializeComponentWithDiscriminator, the DestroyComponent overload skips this entirely.

The TypeScript implementation uses destroyComponentWithDiscriminator with a discriminator, but the C# variant lacks this critical step. Either the generated DestroyComponentWithDiscriminator method needs to be created, or the implementation must be updated to:

  1. Retrieve: var discriminator = component.GetMethodDiscriminator("destroy");
  2. Validate: if (discriminator is null || discriminator.Length != 8) throw...
  3. Call: WorldProgram.DestroyComponentWithDiscriminator(destroyComponent, discriminator);
crates/programs/world/src/lib.rs (1)

461-591: Add the target program account to update/system CPIs

apply_impl, apply_with_session_impl, and system_execute all call invoke without the callee program AccountInfo. As soon as you hit these paths on-chain the CPI aborts. Append the program handle alongside the existing account infos—for example:

-        invoke(
-            &ix,
-            &[
-                component.clone(),
-                ctx.accounts.authority.to_account_info(),
-                ctx.accounts.instruction_sysvar_account.to_account_info(),
-            ],
-        )?;
+        invoke(
+            &ix,
+            &[
+                component.clone(),
+                ctx.accounts.authority.to_account_info(),
+                ctx.accounts.instruction_sysvar_account.to_account_info(),
+                program.clone(),
+            ],
+        )?;

and in apply_with_session_impl add program.clone(), while in system_execute push bolt_system.to_account_info() to account_infos before invoking. Without these additions, none of the new CPI flows can succeed.

crates/bolt-lang/attribute/extra-accounts/src/lib.rs (1)

8-34: Update documentation to reflect the new required attribute parameter.

The macro now requires a key = "TypePath" attribute argument (lines 27-34), but the example in the documentation (lines 14-24) shows #[extra_accounts] without any parameters. Update the example to demonstrate the new syntax, e.g., #[extra_accounts(components = "YourComponentsType")].

clients/typescript/src/world/transactions.ts (1)

359-384: Restore legacy component flow when metadata is missing

Component.from simply wraps the supplied id, so every existing caller that still passes a bare PublicKey (the pattern we document today) ends up with component.name === undefined. The new implementation still calls getMethodDiscriminator("destroy")/("initialize") regardless, and that helper throws when the name is absent. In practice this means both DestroyComponent and InitializeComponent now crash before issuing any Anchor instruction, breaking the backward compatibility this PR is supposed to preserve.

Please gate the discriminator path on component.name and retain the legacy instruction flow when the name/discriminator isn’t available (i.e. the exact logic we had before this change). Without that fallback, upgrading the SDK bricks every existing project that still uses the legacy world program.

Also applies to: 416-434

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 37cfe30 and 4fc6848.

⛔ Files ignored due to path filters (16)
  • Cargo.lock is excluded by !**/*.lock
  • clients/typescript/src/generated/accounts/Entity.ts is excluded by !**/generated/**
  • clients/typescript/src/generated/accounts/Registry.ts is excluded by !**/generated/**
  • clients/typescript/src/generated/accounts/World.ts is excluded by !**/generated/**
  • clients/typescript/src/generated/idl/world.json is excluded by !**/generated/**
  • clients/typescript/src/generated/index.ts is excluded by !**/generated/**
  • clients/typescript/src/generated/instructions/addEntity.ts is excluded by !**/generated/**
  • clients/typescript/src/generated/instructions/apply.ts is excluded by !**/generated/**
  • clients/typescript/src/generated/instructions/apply2.ts is excluded by !**/generated/**
  • clients/typescript/src/generated/instructions/apply3.ts is excluded by !**/generated/**
  • clients/typescript/src/generated/instructions/apply4.ts is excluded by !**/generated/**
  • clients/typescript/src/generated/instructions/apply5.ts is excluded by !**/generated/**
  • clients/typescript/src/generated/instructions/initializeComponent.ts is excluded by !**/generated/**
  • clients/typescript/src/generated/instructions/initializeNewWorld.ts is excluded by !**/generated/**
  • clients/typescript/src/generated/instructions/initializeRegistry.ts is excluded by !**/generated/**
  • clients/typescript/src/generated/types/world.ts is excluded by !**/generated/**
📒 Files selected for processing (82)
  • .github/workflows/publish-bolt-crates.yml (2 hunks)
  • .github/workflows/publish-bolt-sdk.yml (1 hunks)
  • .github/workflows/run-tests.yml (1 hunks)
  • Anchor.toml (2 hunks)
  • Cargo.toml (3 hunks)
  • clients/csharp/Solana.Unity.Bolt.Test/AccelerationTest.cs (2 hunks)
  • clients/csharp/Solana.Unity.Bolt.Test/ECSTest.cs (5 hunks)
  • clients/csharp/Solana.Unity.Bolt.Test/Framework.cs (2 hunks)
  • clients/csharp/Solana.Unity.Bolt/ECS/Component.cs (1 hunks)
  • clients/csharp/Solana.Unity.Bolt/ECS/Identifier.cs (1 hunks)
  • clients/csharp/Solana.Unity.Bolt/ECS/System.cs (1 hunks)
  • clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt.cs (2 hunks)
  • clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/ApplySystem.cs (2 hunks)
  • clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/DelegateComponent.cs (1 hunks)
  • clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/DestroyComponent.cs (1 hunks)
  • clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/InitializeComponent.cs (2 hunks)
  • clients/csharp/Solana.Unity.Bolt/WorldProgram/Generated.cs (1 hunks)
  • clients/csharp/Solana.Unity.Bolt/WorldProgram/World.cs (3 hunks)
  • clients/typescript/.solitarc.js (1 hunks)
  • clients/typescript/idl/world.json (1 hunks)
  • clients/typescript/src/delegation/delegate.ts (3 hunks)
  • clients/typescript/src/ecs/component.ts (1 hunks)
  • clients/typescript/src/ecs/identifier.ts (1 hunks)
  • clients/typescript/src/ecs/index.ts (1 hunks)
  • clients/typescript/src/ecs/system.ts (1 hunks)
  • clients/typescript/src/index.ts (2 hunks)
  • clients/typescript/src/world/transactions.ts (9 hunks)
  • clients/typescript/test/framework.ts (3 hunks)
  • clients/typescript/test/intermediate-level/acceleration.ts (3 hunks)
  • clients/typescript/test/intermediate-level/ecs.ts (4 hunks)
  • crates/bolt-cli/src/bundle.rs (1 hunks)
  • crates/bolt-cli/src/lib.rs (5 hunks)
  • crates/bolt-cli/src/rust_template.rs (3 hunks)
  • crates/bolt-cli/src/templates/bundle/lib.rs.template (1 hunks)
  • crates/bolt-cli/src/templates/bundle/mod.rs (1 hunks)
  • crates/bolt-cli/src/templates/mod.rs (1 hunks)
  • crates/bolt-cli/src/templates/workspace/workspace.toml.template (1 hunks)
  • crates/bolt-lang/Cargo.toml (1 hunks)
  • crates/bolt-lang/attribute/Cargo.toml (1 hunks)
  • crates/bolt-lang/attribute/bolt-program/src/lib.rs (0 hunks)
  • crates/bolt-lang/attribute/bundle/Cargo.toml (2 hunks)
  • crates/bolt-lang/attribute/bundle/src/lib.rs (1 hunks)
  • crates/bolt-lang/attribute/component-deserialize/Cargo.toml (1 hunks)
  • crates/bolt-lang/attribute/component-deserialize/src/lib.rs (3 hunks)
  • crates/bolt-lang/attribute/component/Cargo.toml (1 hunks)
  • crates/bolt-lang/attribute/component/src/lib.rs (1 hunks)
  • crates/bolt-lang/attribute/delegate/src/lib.rs (0 hunks)
  • crates/bolt-lang/attribute/extra-accounts/Cargo.toml (1 hunks)
  • crates/bolt-lang/attribute/extra-accounts/src/lib.rs (4 hunks)
  • crates/bolt-lang/attribute/src/bundle/mod.rs (1 hunks)
  • crates/bolt-lang/attribute/src/common/mod.rs (1 hunks)
  • crates/bolt-lang/attribute/src/component/attributes.rs (1 hunks)
  • crates/bolt-lang/attribute/src/component/generate/mod.rs (1 hunks)
  • crates/bolt-lang/attribute/src/component/generate/program.rs (1 hunks)
  • crates/bolt-lang/attribute/src/component/mod.rs (1 hunks)
  • crates/bolt-lang/attribute/src/delegate/mod.rs (1 hunks)
  • crates/bolt-lang/attribute/src/lib.rs (1 hunks)
  • crates/bolt-lang/attribute/src/system/mod.rs (1 hunks)
  • crates/bolt-lang/attribute/system-input/src/lib.rs (2 hunks)
  • crates/bolt-lang/attribute/system/Cargo.toml (1 hunks)
  • crates/bolt-lang/attribute/system/src/lib.rs (1 hunks)
  • crates/bolt-lang/src/cpi/mod.rs (1 hunks)
  • crates/bolt-lang/src/errors.rs (1 hunks)
  • crates/bolt-lang/src/instructions/destroy.rs (1 hunks)
  • crates/bolt-lang/src/instructions/initialize.rs (1 hunks)
  • crates/bolt-lang/src/instructions/mod.rs (1 hunks)
  • crates/bolt-lang/src/instructions/update.rs (1 hunks)
  • crates/bolt-lang/src/lib.rs (3 hunks)
  • crates/bolt-lang/utils/src/lib.rs (2 hunks)
  • crates/programs/bolt-component/Cargo.toml (0 hunks)
  • crates/programs/bolt-component/src/lib.rs (0 hunks)
  • crates/programs/bolt-system/Cargo.toml (0 hunks)
  • crates/programs/bolt-system/Xargo.toml (0 hunks)
  • crates/programs/bolt-system/src/lib.rs (0 hunks)
  • crates/programs/world/Cargo.toml (1 hunks)
  • crates/programs/world/src/lib.rs (5 hunks)
  • crates/programs/world/src/utils.rs (1 hunks)
  • docs/REPORT.md (1 hunks)
  • examples/bundle/Cargo.toml (1 hunks)
  • examples/bundle/src/lib.rs (1 hunks)
  • scripts/test-publish.sh (1 hunks)
  • tests/test-validator.sh (1 hunks)
💤 Files with no reviewable changes (7)
  • crates/programs/bolt-system/Xargo.toml
  • crates/programs/bolt-system/src/lib.rs
  • crates/bolt-lang/attribute/bolt-program/src/lib.rs
  • crates/programs/bolt-component/src/lib.rs
  • crates/programs/bolt-system/Cargo.toml
  • crates/programs/bolt-component/Cargo.toml
  • crates/bolt-lang/attribute/delegate/src/lib.rs
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: notdanilo
Repo: magicblock-labs/bolt PR: 207
File: crates/bolt-lang/attribute/src/component/attributes.rs:35-56
Timestamp: 2025-10-15T16:28:50.695Z
Learning: In the Bolt Lang attribute system (crates/bolt-lang/attribute), component_id in the #[component] attribute is optional and can be empty by design. When not provided, it defaults to an empty string in the Attributes struct, with the code generator providing fallback logic (e.g., using the type name) at a later stage rather than during attribute parsing.
📚 Learning: 2025-10-15T16:28:50.695Z
Learnt from: notdanilo
Repo: magicblock-labs/bolt PR: 207
File: crates/bolt-lang/attribute/src/component/attributes.rs:35-56
Timestamp: 2025-10-15T16:28:50.695Z
Learning: In the Bolt Lang attribute system (crates/bolt-lang/attribute), component_id in the #[component] attribute is optional and can be empty by design. When not provided, it defaults to an empty string in the Attributes struct, with the code generator providing fallback logic (e.g., using the type name) at a later stage rather than during attribute parsing.

Applied to files:

  • crates/bolt-lang/attribute/bundle/src/lib.rs
  • crates/bolt-lang/attribute/component-deserialize/src/lib.rs
  • crates/bolt-lang/attribute/component/src/lib.rs
  • crates/bolt-lang/attribute/src/component/generate/program.rs
  • crates/bolt-lang/attribute/Cargo.toml
  • crates/bolt-lang/attribute/system-input/src/lib.rs
  • crates/bolt-lang/attribute/src/component/attributes.rs
  • crates/bolt-lang/attribute/src/lib.rs
  • clients/csharp/Solana.Unity.Bolt/ECS/Component.cs
  • crates/bolt-lang/attribute/src/component/generate/mod.rs
  • crates/bolt-cli/src/templates/bundle/lib.rs.template
  • crates/bolt-lang/src/lib.rs
  • crates/bolt-lang/attribute/system/src/lib.rs
  • crates/bolt-lang/attribute/component/Cargo.toml
  • Cargo.toml
  • crates/bolt-lang/Cargo.toml
  • crates/bolt-lang/attribute/system/Cargo.toml
  • crates/bolt-lang/attribute/bundle/Cargo.toml
  • crates/bolt-lang/attribute/src/component/mod.rs
  • examples/bundle/src/lib.rs
  • crates/bolt-lang/attribute/component-deserialize/Cargo.toml
📚 Learning: 2025-10-15T15:51:36.753Z
Learnt from: notdanilo
Repo: magicblock-labs/bolt PR: 207
File: crates/programs/world/src/lib.rs:519-519
Timestamp: 2025-10-15T15:51:36.753Z
Learning: In the Bolt codebase, discriminator parameters should remain as `Vec<u8>` rather than `[u8; 8]` because the client code generation tooling (TypeScript/C#) cannot generate code from fixed-size array types.

Applied to files:

  • crates/programs/world/src/utils.rs
  • clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt.cs
  • crates/bolt-lang/attribute/component-deserialize/src/lib.rs
  • crates/bolt-lang/src/lib.rs
🧬 Code graph analysis (46)
crates/bolt-cli/src/templates/mod.rs (1)
crates/bolt-lang/attribute/bundle/src/lib.rs (1)
  • bundle (9-11)
clients/csharp/Solana.Unity.Bolt.Test/Framework.cs (1)
clients/csharp/Solana.Unity.Bolt/WorldProgram/World.cs (14)
  • PublicKey (36-46)
  • PublicKey (48-55)
  • PublicKey (57-66)
  • PublicKey (68-77)
  • PublicKey (79-91)
  • PublicKey (93-96)
  • PublicKey (98-105)
  • PublicKey (106-111)
  • PublicKey (113-119)
  • PublicKey (121-132)
  • PublicKey (136-143)
  • PublicKey (145-152)
  • PublicKey (188-191)
  • PublicKey (192-200)
crates/bolt-lang/attribute/bundle/src/lib.rs (3)
crates/bolt-lang/attribute/src/system/mod.rs (1)
  • process (37-84)
crates/bolt-lang/attribute/src/bundle/mod.rs (1)
  • process (10-80)
crates/bolt-lang/attribute/src/component/mod.rs (1)
  • process (13-31)
crates/bolt-lang/attribute/src/bundle/mod.rs (6)
crates/bolt-lang/attribute/src/common/mod.rs (1)
  • generate_program (5-14)
crates/bolt-lang/attribute/src/system/mod.rs (1)
  • transform_module_for_bundle (86-195)
crates/bolt-lang/attribute/src/component/generate/program.rs (3)
  • generate_update (191-248)
  • generate_instructions (13-23)
  • remove_component_attributes (9-11)
crates/bolt-lang/attribute/src/component/attributes.rs (3)
  • from (14-20)
  • from (24-32)
  • from (36-56)
crates/bolt-lang/attribute/src/component/generate/mod.rs (2)
  • generate_implementation (17-24)
  • enrich_type (9-15)
crates/bolt-lang/attribute/src/delegate/mod.rs (1)
  • inject_delegate_items (6-36)
clients/csharp/Solana.Unity.Bolt/ECS/Identifier.cs (6)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/ApplySystem.cs (5)
  • Solana (14-25)
  • Solana (27-38)
  • Solana (40-50)
  • Solana (58-140)
  • World (10-167)
clients/typescript/src/index.ts (2)
  • Program (18-18)
  • GetDiscriminator (26-28)
clients/typescript/src/ecs/identifier.ts (1)
  • Identifier (4-18)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/DestroyComponent.cs (1)
  • World (10-66)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/InitializeComponent.cs (1)
  • World (11-74)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt.cs (2)
  • World (13-41)
  • GetDiscriminator (30-40)
crates/bolt-cli/src/bundle.rs (2)
crates/bolt-cli/src/rust_template.rs (1)
  • create_bundle (32-45)
crates/bolt-cli/src/workspace.rs (1)
  • with_workspace (9-24)
clients/typescript/test/intermediate-level/acceleration.ts (3)
clients/typescript/src/world/transactions.ts (1)
  • InitializeComponent (397-442)
clients/typescript/src/ecs/component.ts (1)
  • Component (5-27)
clients/typescript/src/delegation/delegate.ts (1)
  • DelegateComponent (154-199)
clients/csharp/Solana.Unity.Bolt.Test/AccelerationTest.cs (3)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/ApplySystem.cs (4)
  • World (10-167)
  • EntityType (143-166)
  • EntityType (148-154)
  • EntityType (156-165)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt.cs (2)
  • World (13-41)
  • SerializeArgs (25-28)
clients/csharp/Solana.Unity.Bolt/WorldProgram/World.cs (16)
  • EntityType (164-170)
  • EntityType (172-181)
  • PublicKey (36-46)
  • PublicKey (48-55)
  • PublicKey (57-66)
  • PublicKey (68-77)
  • PublicKey (79-91)
  • PublicKey (93-96)
  • PublicKey (98-105)
  • PublicKey (106-111)
  • PublicKey (113-119)
  • PublicKey (121-132)
  • PublicKey (136-143)
  • PublicKey (145-152)
  • PublicKey (188-191)
  • PublicKey (192-200)
clients/typescript/src/ecs/system.ts (1)
clients/typescript/src/ecs/identifier.ts (1)
  • Identifier (4-18)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt.cs (3)
clients/typescript/src/index.ts (2)
  • System (20-20)
  • GetDiscriminator (26-28)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/ApplySystem.cs (1)
  • World (10-167)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/InitializeComponent.cs (1)
  • World (11-74)
crates/bolt-lang/src/instructions/initialize.rs (1)
crates/bolt-lang/src/cpi/mod.rs (1)
  • check (7-19)
crates/bolt-lang/src/instructions/update.rs (1)
crates/bolt-lang/src/cpi/mod.rs (1)
  • check (7-19)
crates/bolt-lang/src/cpi/mod.rs (2)
clients/typescript/test/low-level/permissioning/world.ts (1)
  • world (4-234)
clients/typescript/src/generated/types/world.ts (1)
  • World (7-610)
crates/bolt-lang/attribute/component/src/lib.rs (1)
crates/bolt-lang/attribute/src/component/mod.rs (1)
  • process (13-31)
crates/bolt-lang/attribute/src/component/generate/program.rs (4)
crates/bolt-lang/src/lib.rs (3)
  • seed (61-61)
  • size (62-62)
  • try_from_account_info (89-97)
crates/bolt-lang/src/instructions/destroy.rs (1)
  • destroy (5-39)
crates/bolt-lang/src/instructions/initialize.rs (1)
  • initialize (4-14)
crates/bolt-lang/src/instructions/update.rs (2)
  • update (6-31)
  • update_with_session (33-78)
clients/typescript/src/ecs/component.ts (2)
clients/typescript/src/index.ts (2)
  • Component (20-20)
  • FindComponentPda (109-122)
clients/typescript/src/ecs/identifier.ts (1)
  • Identifier (4-18)
clients/typescript/test/intermediate-level/ecs.ts (3)
clients/typescript/src/world/transactions.ts (2)
  • InitializeComponent (397-442)
  • ApplySystem (581-612)
clients/typescript/src/ecs/component.ts (1)
  • Component (5-27)
clients/typescript/src/ecs/system.ts (1)
  • System (4-12)
crates/bolt-lang/src/instructions/destroy.rs (1)
crates/bolt-lang/src/cpi/mod.rs (1)
  • check (7-19)
clients/typescript/test/framework.ts (2)
clients/csharp/Solana.Unity.Bolt.Test/Framework.cs (2)
  • Framework (32-146)
  • Framework (64-76)
clients/typescript/src/generated/accounts/World.ts (1)
  • World (30-170)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/DelegateComponent.cs (4)
clients/typescript/src/delegation/delegate.ts (1)
  • DelegateComponent (154-199)
clients/csharp/Solana.Unity.Bolt/WorldProgram/World.cs (15)
  • PublicKey (36-46)
  • PublicKey (48-55)
  • PublicKey (57-66)
  • PublicKey (68-77)
  • PublicKey (79-91)
  • PublicKey (93-96)
  • PublicKey (98-105)
  • PublicKey (106-111)
  • PublicKey (113-119)
  • PublicKey (121-132)
  • PublicKey (136-143)
  • PublicKey (145-152)
  • PublicKey (188-191)
  • PublicKey (192-200)
  • WorldProgram (17-308)
clients/typescript/src/index.ts (1)
  • FindComponentPda (109-122)
clients/csharp/Solana.Unity.Bolt/ECS/Component.cs (4)
  • Component (9-34)
  • Component (15-15)
  • Component (20-25)
  • Seeds (30-33)
crates/bolt-lang/attribute/src/system/mod.rs (3)
crates/bolt-lang/attribute/system-input/src/lib.rs (2)
  • syn (43-43)
  • system_input (20-133)
crates/bolt-lang/attribute/src/bundle/mod.rs (1)
  • process (10-80)
crates/bolt-lang/src/lib.rs (1)
  • parse_args (50-55)
crates/bolt-lang/attribute/src/component/attributes.rs (1)
crates/bolt-lang/attribute/component-id/src/lib.rs (1)
  • component_id (9-15)
crates/bolt-lang/attribute/src/lib.rs (3)
crates/bolt-lang/attribute/bundle/src/lib.rs (1)
  • bundle (9-11)
crates/bolt-lang/attribute/component/src/lib.rs (1)
  • component (17-19)
crates/bolt-lang/attribute/system/src/lib.rs (1)
  • system (4-6)
clients/csharp/Solana.Unity.Bolt/ECS/System.cs (3)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/ApplySystem.cs (4)
  • Solana (14-25)
  • Solana (27-38)
  • Solana (40-50)
  • Solana (58-140)
clients/typescript/src/ecs/system.ts (1)
  • System (4-12)
clients/csharp/Solana.Unity.Bolt/ECS/Identifier.cs (2)
  • Identifier (8-38)
  • Identifier (24-27)
clients/typescript/src/ecs/identifier.ts (2)
clients/typescript/src/index.ts (1)
  • GetDiscriminator (26-28)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt.cs (1)
  • GetDiscriminator (30-40)
clients/csharp/Solana.Unity.Bolt/ECS/Component.cs (4)
clients/typescript/src/ecs/component.ts (1)
  • Component (5-27)
clients/csharp/Solana.Unity.Bolt/ECS/Identifier.cs (2)
  • Identifier (8-38)
  • Identifier (24-27)
clients/csharp/Solana.Unity.Bolt/WorldProgram/World.cs (14)
  • PublicKey (36-46)
  • PublicKey (48-55)
  • PublicKey (57-66)
  • PublicKey (68-77)
  • PublicKey (79-91)
  • PublicKey (93-96)
  • PublicKey (98-105)
  • PublicKey (106-111)
  • PublicKey (113-119)
  • PublicKey (121-132)
  • PublicKey (136-143)
  • PublicKey (145-152)
  • PublicKey (188-191)
  • PublicKey (192-200)
clients/csharp/Solana.Unity.Bolt/ECS/System.cs (3)
  • System (9-26)
  • System (15-15)
  • System (20-25)
crates/bolt-lang/attribute/src/component/generate/mod.rs (2)
crates/bolt-lang/utils/src/lib.rs (1)
  • add_bolt_metadata (4-22)
crates/bolt-lang/src/lib.rs (2)
  • seed (61-61)
  • size (62-62)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/ApplySystem.cs (6)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Generated.cs (17)
  • Solana (386-400)
  • Solana (402-429)
  • Solana (431-447)
  • Solana (449-465)
  • Solana (467-479)
  • Solana (481-493)
  • Solana (495-507)
  • Solana (509-526)
  • Solana (528-540)
  • Solana (542-554)
  • Solana (556-570)
  • Solana (572-584)
  • WorldProgram (383-585)
  • ApplyWithSessionAccounts (284-294)
  • World (75-122)
  • World (90-121)
  • ApplyAccounts (274-282)
clients/csharp/Solana.Unity.Bolt/WorldProgram/World.cs (19)
  • Solana (24-28)
  • Solana (30-34)
  • Solana (254-279)
  • Solana (281-307)
  • PublicKey (36-46)
  • PublicKey (48-55)
  • PublicKey (57-66)
  • PublicKey (68-77)
  • PublicKey (79-91)
  • PublicKey (93-96)
  • PublicKey (98-105)
  • PublicKey (106-111)
  • PublicKey (113-119)
  • PublicKey (121-132)
  • PublicKey (136-143)
  • PublicKey (145-152)
  • PublicKey (188-191)
  • PublicKey (192-200)
  • WorldProgram (17-308)
clients/csharp/Solana.Unity.Bolt/ECS/System.cs (3)
  • System (9-26)
  • System (15-15)
  • System (20-25)
clients/csharp/Solana.Unity.Bolt/ECS/Component.cs (4)
  • Component (9-34)
  • Component (15-15)
  • Component (20-25)
  • Seeds (30-33)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/InitializeComponent.cs (1)
  • World (11-74)
clients/csharp/Solana.Unity.Bolt/ECS/Identifier.cs (1)
  • GetMethodDiscriminator (33-37)
crates/bolt-lang/src/instructions/mod.rs (3)
crates/bolt-lang/src/instructions/destroy.rs (1)
  • destroy (5-39)
crates/bolt-lang/src/instructions/initialize.rs (1)
  • initialize (4-14)
crates/bolt-lang/src/instructions/update.rs (1)
  • update (6-31)
crates/bolt-lang/attribute/src/delegate/mod.rs (2)
crates/bolt-lang/src/lib.rs (2)
  • seed (61-61)
  • discriminator_from_account_info (99-104)
crates/bolt-lang/attribute/src/component/generate/program.rs (2)
  • vec (36-41)
  • vec (236-244)
crates/bolt-lang/src/lib.rs (2)
crates/bolt-lang/attribute/arguments/src/lib.rs (1)
  • arguments (6-14)
crates/bolt-lang/attribute/bundle/src/lib.rs (1)
  • bundle (9-11)
clients/typescript/src/world/transactions.ts (3)
clients/typescript/src/index.ts (5)
  • Component (20-20)
  • Program (18-18)
  • FindComponentProgramDataPda (97-106)
  • System (20-20)
  • SerializeArgs (129-138)
clients/typescript/src/ecs/component.ts (2)
  • Component (5-27)
  • pda (16-22)
clients/typescript/src/ecs/system.ts (1)
  • System (4-12)
clients/csharp/Solana.Unity.Bolt.Test/ECSTest.cs (5)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/InitializeComponent.cs (6)
  • Task (17-20)
  • Task (22-25)
  • Task (27-30)
  • Task (32-45)
  • Task (56-73)
  • World (11-74)
clients/csharp/Solana.Unity.Bolt.Test/Framework.cs (7)
  • Task (78-88)
  • Task (90-125)
  • Task (127-130)
  • Task (132-140)
  • Task (142-145)
  • Framework (32-146)
  • Framework (64-76)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/ApplySystem.cs (4)
  • World (10-167)
  • EntityType (143-166)
  • EntityType (148-154)
  • EntityType (156-165)
clients/csharp/Solana.Unity.Bolt/ECS/Component.cs (3)
  • Component (9-34)
  • Component (15-15)
  • Component (20-25)
clients/csharp/Solana.Unity.Bolt.Test/Position.cs (3)
  • Position (56-90)
  • Position (69-89)
  • Deserialize (150-157)
crates/bolt-lang/attribute/system/src/lib.rs (1)
crates/bolt-lang/attribute/src/system/mod.rs (1)
  • process (37-84)
clients/typescript/src/delegation/delegate.ts (1)
clients/typescript/src/ecs/component.ts (1)
  • Component (5-27)
clients/csharp/Solana.Unity.Bolt/WorldProgram/World.cs (3)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Generated.cs (16)
  • Solana (386-400)
  • Solana (402-429)
  • Solana (431-447)
  • Solana (449-465)
  • Solana (467-479)
  • Solana (481-493)
  • Solana (495-507)
  • Solana (509-526)
  • Solana (528-540)
  • Solana (542-554)
  • Solana (556-570)
  • Solana (572-584)
  • ApplyAccounts (274-282)
  • World (75-122)
  • World (90-121)
  • ApplyWithSessionAccounts (284-294)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/ApplySystem.cs (5)
  • Solana (14-25)
  • Solana (27-38)
  • Solana (40-50)
  • Solana (58-140)
  • World (10-167)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt.cs (1)
  • World (13-41)
crates/bolt-lang/attribute/extra-accounts/src/lib.rs (1)
crates/bolt-lang/attribute/system-input/src/lib.rs (1)
  • syn (43-43)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/InitializeComponent.cs (6)
clients/csharp/Solana.Unity.Bolt/WorldProgram/World.cs (15)
  • PublicKey (36-46)
  • PublicKey (48-55)
  • PublicKey (57-66)
  • PublicKey (68-77)
  • PublicKey (79-91)
  • PublicKey (93-96)
  • PublicKey (98-105)
  • PublicKey (106-111)
  • PublicKey (113-119)
  • PublicKey (121-132)
  • PublicKey (136-143)
  • PublicKey (145-152)
  • PublicKey (188-191)
  • PublicKey (192-200)
  • WorldProgram (17-308)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Generated.cs (4)
  • WorldProgram (383-585)
  • InitializeComponentAccounts (325-339)
  • Entity (27-49)
  • Entity (34-48)
clients/typescript/src/world/transactions.ts (1)
  • InitializeComponent (397-442)
clients/typescript/src/ecs/component.ts (1)
  • Component (5-27)
clients/csharp/Solana.Unity.Bolt/ECS/Component.cs (4)
  • Component (9-34)
  • Component (15-15)
  • Component (20-25)
  • Seeds (30-33)
clients/csharp/Solana.Unity.Bolt/ECS/Identifier.cs (1)
  • GetMethodDiscriminator (33-37)
crates/bolt-cli/src/lib.rs (1)
crates/bolt-cli/src/bundle.rs (1)
  • new_bundle (7-42)
crates/programs/world/src/lib.rs (3)
crates/programs/world/src/utils.rs (1)
  • discriminator_for (19-36)
clients/typescript/src/world/transactions.ts (2)
  • InitializeComponent (397-442)
  • DestroyComponent (343-385)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/ApplySystem.cs (1)
  • World (10-167)
clients/typescript/src/index.ts (2)
clients/csharp/Solana.Unity.Bolt/WorldProgram/World.cs (14)
  • PublicKey (36-46)
  • PublicKey (48-55)
  • PublicKey (57-66)
  • PublicKey (68-77)
  • PublicKey (79-91)
  • PublicKey (93-96)
  • PublicKey (98-105)
  • PublicKey (106-111)
  • PublicKey (113-119)
  • PublicKey (121-132)
  • PublicKey (136-143)
  • PublicKey (145-152)
  • PublicKey (188-191)
  • PublicKey (192-200)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt.cs (1)
  • GetDiscriminator (30-40)
crates/bolt-lang/attribute/src/component/mod.rs (5)
crates/bolt-lang/attribute/src/common/mod.rs (1)
  • generate_program (5-14)
crates/bolt-lang/attribute/src/delegate/mod.rs (2)
  • inject_delegate_items (6-36)
  • vec (22-32)
crates/bolt-lang/attribute/src/component/attributes.rs (3)
  • from (14-20)
  • from (24-32)
  • from (36-56)
crates/bolt-lang/attribute/src/component/generate/mod.rs (2)
  • generate_implementation (17-24)
  • enrich_type (9-15)
crates/bolt-lang/attribute/src/component/generate/program.rs (4)
  • generate_instructions (13-23)
  • vec (36-41)
  • vec (236-244)
  • generate_update (191-248)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/DestroyComponent.cs (5)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Generated.cs (13)
  • WorldProgram (383-585)
  • Task (148-157)
  • Task (159-168)
  • Task (170-179)
  • Task (181-188)
  • Task (190-197)
  • Task (199-206)
  • Task (208-218)
  • Task (220-230)
  • Task (232-242)
  • DestroyComponentAccounts (307-323)
  • Entity (27-49)
  • Entity (34-48)
clients/csharp/Solana.Unity.Bolt/WorldProgram/World.cs (15)
  • WorldProgram (17-308)
  • PublicKey (36-46)
  • PublicKey (48-55)
  • PublicKey (57-66)
  • PublicKey (68-77)
  • PublicKey (79-91)
  • PublicKey (93-96)
  • PublicKey (98-105)
  • PublicKey (106-111)
  • PublicKey (113-119)
  • PublicKey (121-132)
  • PublicKey (136-143)
  • PublicKey (145-152)
  • PublicKey (188-191)
  • PublicKey (192-200)
clients/typescript/src/world/transactions.ts (1)
  • DestroyComponent (343-385)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/InitializeComponent.cs (5)
  • Task (17-20)
  • Task (22-25)
  • Task (27-30)
  • Task (32-45)
  • Task (56-73)
clients/csharp/Solana.Unity.Bolt/ECS/Component.cs (4)
  • Component (9-34)
  • Component (15-15)
  • Component (20-25)
  • Seeds (30-33)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Generated.cs (3)
clients/csharp/Solana.Unity.Bolt/WorldProgram/World.cs (19)
  • Solana (24-28)
  • Solana (30-34)
  • Solana (254-279)
  • Solana (281-307)
  • PublicKey (36-46)
  • PublicKey (48-55)
  • PublicKey (57-66)
  • PublicKey (68-77)
  • PublicKey (79-91)
  • PublicKey (93-96)
  • PublicKey (98-105)
  • PublicKey (106-111)
  • PublicKey (113-119)
  • PublicKey (121-132)
  • PublicKey (136-143)
  • PublicKey (145-152)
  • PublicKey (188-191)
  • PublicKey (192-200)
  • WorldProgram (17-308)
clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/InitializeComponent.cs (6)
  • World (11-74)
  • Task (17-20)
  • Task (22-25)
  • Task (27-30)
  • Task (32-45)
  • Task (56-73)
clients/typescript/src/generated/accounts/World.ts (1)
  • World (30-170)
crates/bolt-cli/src/rust_template.rs (2)
crates/bolt-cli/src/templates/bundle/mod.rs (1)
  • create_bundle_template (5-16)
crates/bolt-cli/src/templates/workspace/mod.rs (3)
  • workspace_manifest (4-6)
  • cargo_toml_with_serde (47-55)
  • xargo_toml (57-59)
examples/bundle/src/lib.rs (4)
crates/bolt-lang/attribute/bundle/src/lib.rs (1)
  • bundle (9-11)
crates/bolt-lang/attribute/component/src/lib.rs (1)
  • component (17-19)
crates/bolt-lang/attribute/system/src/lib.rs (1)
  • system (4-6)
crates/bolt-lang/attribute/system-input/src/lib.rs (1)
  • system_input (20-133)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: lint (yarn)
  • GitHub Check: lint (clippy)
  • GitHub Check: test
🔇 Additional comments (65)
crates/bolt-cli/src/templates/workspace/workspace.toml.template (1)

2-7: Workspace member patterns reference non-existent directories—clarification needed.

The template syntax is valid, but verification reveals that the referenced directories don't exist in the repository:

  • programs/ — not found
  • programs-ecs/bundles/ — not found
  • programs-ecs/ — not found

The glob patterns are syntactically correct for Cargo, but currently unmatched. Clarify whether:

  1. This is intentional setup for future bundle/program implementations (acceptable for forward-looking template), or
  2. These patterns should be added only when actual crates are created, or
  3. The patterns are erroneous and should be removed
crates/bolt-lang/attribute/extra-accounts/Cargo.toml (1)

17-18: LGTM: Dependency additions align with attribute macro requirements.

The addition of heck (typically used for case conversions) and explicit declaration of proc-macro2 are appropriate for procedural macro crates. Both correctly reference workspace versions.

clients/typescript/idl/world.json (1)

203-203: LGTM: IDL metadata address updated consistently.

The metadata address field has been updated to match the new World program ID. This is consistent with the program ID change in .solitarc.js.

scripts/test-publish.sh (1)

17-17: LGTM: bolt-attribute-bolt-bundle added to publish list.

The new bundle attribute crate has been correctly added to the workspace publish command, aligning with the broader reorganization mentioned in the PR summary.

crates/bolt-lang/attribute/component-deserialize/Cargo.toml (1)

19-19: LGTM: sha2 dependency supports discriminator generation.

The sha2 dependency addition aligns with the PR's introduction of SHA-256 based discriminators for components. This is the standard crate for SHA-2 hashing in Rust.

crates/programs/world/Cargo.toml (1)

30-30: LGTM: const-crypto dependency added for compile-time cryptographic operations.

The addition of const-crypto likely supports compile-time discriminator or hash computations, aligning with the architectural changes in this PR.

tests/test-validator.sh (1)

10-10: LGTM: Test validator configuration updated with new World program ID.

The --bpf-program argument has been updated to match the new World program ID, maintaining consistency with the changes in .solitarc.js and world.json.

clients/typescript/.solitarc.js (1)

10-10: Program ID migration verified—all references successfully updated.

The old World program ID (WorLD15A7CrDwLcLy4fRqtaTb9fbd8o8iqiEMUDse2n) has been completely removed from the codebase. The new program ID (wor1DcaDr8AeBdaf5bqeBQUY9My2sgZwtanRcaALE9L) is correctly set across all locations: configuration files, Rust program declaration, generated TypeScript bindings, test scripts, and CLI templates. The breaking change has been applied consistently.

.github/workflows/publish-bolt-sdk.yml (1)

147-147: Ensure EXAMPLE_BUNDLE secret is configured in GitHub repository settings.

The workflow references the EXAMPLE_BUNDLE secret alongside other deployment key secrets (WORLD, BOLT_COMPONENT, BOLT_SYSTEM, COMPONENT_POSITION, COMPONENT_VELOCITY, SYSTEM_APPLY_VELOCITY, SYSTEM_FLY, SYSTEM_SIMPLE_MOVEMENT). This follows the established pattern across all three workflows (run-tests.yml, publish-bolt-crates.yml, publish-bolt-sdk.yml). Verify that this secret has been added to the repository's GitHub Actions secrets settings before merging.

crates/bolt-cli/src/templates/mod.rs (1)

1-1: LGTM! Clean module declaration.

The new bundle submodule is properly exposed, aligning with the PR's bundle-based architecture changes.

docs/REPORT.md (1)

7-8: LGTM! Updated benchmark data.

The CU (Compute Unit) values have been updated to reflect the new bundle-based architecture's performance characteristics. The chart structure remains consistent.

.github/workflows/publish-bolt-crates.yml (1)

184-184: LGTM! Publishing list updated correctly.

The addition of bolt-attribute-bolt-bundle aligns with the PR's consolidation of attribute macros into the unified bolt-attribute crate.

.github/workflows/run-tests.yml (1)

92-92: LGTM! Test workflow updated consistently.

The example bundle keypair provisioning aligns with the changes in the publish workflow, ensuring consistent deployment key handling across workflows.

crates/bolt-cli/src/lib.rs (5)

4-4: LGTM! New module declaration.

The bundle module is properly integrated into the CLI structure.


14-14: LGTM! Import added correctly.

The new_bundle function import follows the same pattern as the existing new_component and new_system imports.


44-45: LGTM! Command variant added with clear documentation.

The Bundle command variant is properly documented and follows the existing CLI command pattern.


76-79: LGTM! Command struct follows existing pattern.

The BundleCommand struct is consistent with ComponentCommand and SystemCommand structures.


198-198: LGTM! Command wiring is correct.

The Bundle command is properly dispatched to the new_bundle function, following the same pattern as Component and System commands.

crates/programs/world/src/utils.rs (1)

1-18: Excellent documentation of collision risk.

The documentation clearly explains the 8-byte discriminator collision probability and its practical acceptability. This transparency is valuable for maintainers.

crates/bolt-lang/attribute/bundle/src/lib.rs (2)

3-7: Excellent macro documentation.

The documentation clearly explains that the #[bundle] macro combines a #[component] and #[system] into a unified Anchor #[program] module, making the behavior transparent to users.


8-11: LGTM! Clean macro delegation pattern.

The procedural macro correctly delegates to bolt_attribute::bundle::process, following the established pattern used by other attribute macros in the codebase (component, system).

clients/csharp/Solana.Unity.Bolt/WorldProgram/Generated.cs (2)

1-1: LGTM! Appropriate pragma for generated code.

The #pragma warning disable CS1591 is appropriate for generated code where XML documentation comments may not be present.


385-385: Breaking change properly coordinated across all clients.

Verification confirms the World program ID update is consistently applied across all language clients. The old ID (WorLD15A7CrDwLcLy4fRqtaTb9fbd8o8iqiEMUDse2n) is completely removed, and the new ID (wor1DcaDr8AeBdaf5bqeBQUY9My2sgZwtanRcaALE9L) is present in Rust, TypeScript, C#, and configuration files without gaps or inconsistencies. The C# file at line 385 correctly reflects this change.

clients/csharp/Solana.Unity.Bolt/ECS/System.cs (2)

1-15: LGTM!

The class structure properly mirrors the TypeScript implementation and correctly extends Identifier. The constructor appropriately delegates to the base class.


20-25: LGTM!

The static factory method correctly implements polymorphic input handling, matching the TypeScript implementation. The use of global::System.ArgumentException properly avoids naming conflicts with the Bolt.System class.

crates/bolt-cli/src/bundle.rs (1)

34-37: LGTM!

The config serialization and file writing logic is correct. The success message clearly indicates completion.

Anchor.toml (3)

10-28: LGTM! Architectural refactoring reflected correctly.

The removal of standalone bolt-component and bolt-system programs and the addition of example-bundle and related systems align with the PR's objective to introduce bundle-based architecture. The configuration changes are consistent with the broader refactoring.


37-38: LGTM! Workspace members updated.

The workspace members have been appropriately updated to reflect the architectural changes, removing standalone component/system entries and adding bundle-related examples. The reorganization is consistent with the PR's objectives.


8-8: Verification confirmed: World program ID updated consistently across codebase.

The new program ID wor1DcaDr8AeBdaf5bqeBQUY9My2sgZwtanRcaALE9L is properly referenced throughout the codebase, including in Anchor.toml, Rust program declarations, TypeScript and C# generated clients, test scripts, and IDL files. The old program ID has been completely removed with no remaining references. Deployment coordination is complete.

crates/bolt-lang/attribute/component/src/lib.rs (1)

1-19: LGTM! Clean delegation refactoring.

The refactoring successfully delegates component attribute processing to the centralized bolt_attribute::component::process function, eliminating local macro expansion logic while preserving the public API. This aligns with the broader architectural shift toward consolidated attribute processing.

crates/bolt-lang/attribute/component-deserialize/src/lib.rs (2)

42-44: LGTM! Proper discriminator generation.

The discriminator generation correctly uses SHA-256 hashing with the Anchor-standard "account:{name}" format, replacing the placeholder discriminator. This ensures unique and collision-resistant discriminators for component types.


76-78: LGTM! Discriminator correctly applied.

The Discriminator trait implementation now uses the computed discriminator instead of a hardcoded placeholder. The quote macro expansion correctly converts the Vec<u8> into individual byte literals.

crates/bolt-lang/attribute/system/src/lib.rs (1)

1-6: LGTM! Consistent delegation refactoring.

The refactoring mirrors the component attribute changes, successfully delegating system attribute processing to the centralized bolt_attribute::system::process function. The parameter rename from _attr to attr is appropriate since the attribute tokens are now consumed by the delegated processor.

examples/bundle/Cargo.toml (1)

1-25: LGTM! Standard bundle manifest setup.

The Cargo manifest follows Solana program conventions with appropriate crate types, features, and workspace dependencies.

crates/bolt-lang/attribute/component/Cargo.toml (1)

14-15: LGTM! Clean dependency consolidation.

Replacing multiple explicit dependencies with a single workspace dependency simplifies maintenance and aligns with the PR's attribute crate consolidation.

clients/typescript/src/index.ts (2)

26-28: LGTM! Discriminator computation matches Anchor convention.

The GetDiscriminator function correctly implements the Anchor discriminator pattern (first 8 bytes of SHA256 hash) and aligns with the C# implementation added in this PR.


20-20: LGTM! Public API expansion for ECS support.

Re-exporting Component and System makes them available to consumers as part of the bundle/ECS feature set introduced in this PR.

crates/bolt-lang/src/errors.rs (1)

11-16: LGTM! Clear error variants for validation checks.

The new error codes provide specific feedback for account validation and delegateability checks, supporting the expanded CPI validation introduced in this PR.

clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt.cs (2)

30-40: LGTM! Discriminator computation consistent across languages.

The GetDiscriminator implementation correctly matches the Anchor pattern and aligns with the TypeScript version. Proper use of using statement ensures SHA256 disposal.


27-27: LGTM! Explicit encoding improves clarity.

Using Encoding.UTF8.GetBytes makes the encoding explicit and consistent with the GetDiscriminator implementation.

crates/bolt-lang/utils/src/lib.rs (1)

5-19: Review field order change for serialization compatibility.

The change from push() to insert(0, ...) is a valid concern. Structs decorated with #[component_deserialize] derive AnchorDeserialize and AnchorSerialize, which serialize in field declaration order. Moving bolt_metadata from the end to the beginning changes the byte layout of serialized accounts.

If existing components with bolt_metadata at the end have already been deployed and serialized on-chain, deserializing them with the field at the beginning will cause all fields to misalign during deserialization, resulting in data corruption or deserialization failures.

Verification needed:

  • Is this a new feature or a reordering of an existing field?
  • Are there any existing serialized component instances that would be affected?
  • If this is a breaking change to existing data, migration or versioning logic should be implemented.
clients/csharp/Solana.Unity.Bolt.Test/Framework.cs (1)

59-75: Code is correct as-is.

The verification confirms that BundlePositionEntity1Pda and BundleVelocityEntity1Pda are properly initialized before use. Both properties are assigned in test setup (ECSTest.cs lines 100 and 117) before being accessed (lines 103, 120, 214, 236). The bundle test infrastructure additions are sound.

crates/bolt-lang/Cargo.toml (1)

19-19: LGTM! Consolidation of attribute dependencies.

The introduction of bolt-attribute-bolt-bundle to replace the previous bolt-attribute-bolt-program and bolt-attribute-bolt-delegate dependencies aligns with the PR's bundle-based refactoring approach.

crates/bolt-lang/attribute/src/lib.rs (1)

1-7: LGTM! Clean proc macro crate structure.

The file properly sets up the procedural macro infrastructure with appropriate module visibility. The public exports (bundle, component, delegate, system) and private common module align well with the attribute consolidation architecture.

crates/bolt-cli/src/rust_template.rs (2)

31-45: LGTM! Consistent bundle creation pattern.

The create_bundle function follows the established pattern used by create_component and create_system, appropriately using cargo_toml_with_serde to include serde support and placing bundles under programs-ecs/bundles.


90-90: World program ID update is consistently applied across the codebase.

Verification confirms the old program ID has been completely removed and the new ID (wor1DcaDr8AeBdaf5bqeBQUY9My2sgZwtanRcaALE9L) is consistently present in all required locations: Anchor configuration, Rust program declaration, all TypeScript client files (instructions, accounts, IDL), C# client, test setup, and the specified template file.

Cargo.toml (2)

22-23: LGTM! New attribute dependencies for bundle support.

The addition of bolt-attribute and bolt-attribute-bolt-bundle workspace dependencies properly supports the new unified attribute architecture.


64-65: LGTM! Cryptographic dependencies for discriminator computation.

The addition of const-crypto and sha2 dependencies appropriately supports the discriminator generation functionality introduced in this PR (e.g., for GetDiscriminator methods in the client libraries).

clients/csharp/Solana.Unity.Bolt/ECS/Identifier.cs (1)

1-39: LGTM! Well-structured ECS identifier abstraction.

The Identifier class correctly mirrors the TypeScript implementation, with proper discriminator generation logic that matches the format "global:" + (name? name + "_" : "") + method. The delegation to World.GetDiscriminator for SHA256 computation ensures consistency across language bindings.

clients/typescript/test/intermediate-level/acceleration.ts (2)

47-71: LGTM! Comprehensive test for bundled component initialization.

The test properly validates bundled component creation using the new Component class with both program ID and name parameters. The position coordinate assertions (x=0, y=0, z=0) appropriately verify initial state.


93-114: LGTM! Delegation test mirrors existing pattern.

The bundled component delegation test follows the established pattern from the non-bundled test above it, appropriately verifying that the delegated component's owner is updated to the delegation program.

crates/bolt-cli/src/templates/bundle/mod.rs (1)

5-16: LGTM! Standard template generation implementation.

The create_bundle_template function follows the established pattern used by component and system templates, properly using anchor_cli::rust_template::get_or_create_program_id and formatting the template with derived identifiers.

clients/typescript/src/delegation/delegate.ts (1)

167-181: LGTM! Enhanced flexibility with backward compatibility.

The parameter type change from PublicKey to PublicKey | Component and the use of Component.from() provide a more flexible API while maintaining backward compatibility. The component.pda() method properly encapsulates PDA derivation logic for both standalone and bundled components.

examples/bundle/src/lib.rs (4)

8-14: LGTM!

The Position component is correctly configured with the delegate attribute and Default derive. The default values (0, 0, 0) align with test expectations.


34-51: LGTM!

The movement system correctly increments the position by the velocity values. The logic is straightforward and matches the expected behavior verified in tests.


53-66: LGTM!

The stop system correctly resets velocity to zero. The system input appropriately includes only the velocity component since position is not needed.


23-32: No issues found—bolt_metadata field is correctly injected by the macro.

The #[component] macro (via add_bolt_metadata() in crates/bolt-lang/utils/src/lib.rs) automatically injects the bolt_metadata field into the struct during macro expansion. This happens before the Default impl is compiled, so the field is available when the impl references it. The pattern is intentional and consistent across the codebase—other code (e.g., in program.rs) also accesses bolt_metadata on component instances, confirming this is the designed behavior.

crates/bolt-lang/attribute/src/component/attributes.rs (1)

1-101: LGTM!

The attribute parsing logic is well-structured and handles various meta attribute forms (Path, List, NameValue) defensively. The use of unwrap/expect in macro code is acceptable since syntax errors should fail at compile time. The component_id defaulting to an empty string aligns with the design noted in learnings.

Based on learnings

clients/csharp/Solana.Unity.Bolt.Test/ECSTest.cs (4)

94-109: LGTM!

The test correctly initializes a bundled position component and verifies the default values (0, 0, 0) match the Position struct's Default implementation.


158-177: LGTM!

The refactor to use Bolt.World.ApplySystem with the bundled API is cleaner, and the corrected assertion (Y=1 on line 175) properly reflects the "Up" movement incrementing the Y coordinate.


199-220: LGTM!

The bundled movement system test correctly verifies that position is incremented by velocity (0+1, 0+2, 0+3 → 1, 2, 3), and properly supplies both required components (position and velocity) to the system.


222-245: LGTM!

The bundled stop system test correctly verifies that velocity is zeroed out, and appropriately supplies only the velocity component since the stop system doesn't require position.

crates/bolt-lang/attribute/extra-accounts/src/lib.rs (1)

78-99: LGTM!

The refactor to dynamic trait naming and explicit type parameter improves type safety. The change from Self::NUMBER_OF_COMPONENTS to <#type_path as bolt_lang::NumberOfComponents>::NUMBER_OF_COMPONENTS (line 90) correctly references the component count from the specified type, ensuring proper indexing into remaining_accounts.

crates/bolt-lang/attribute/src/delegate/mod.rs (2)

49-84: LGTM!

The delegate function correctly matches component discriminators and builds PDA seeds from the component's seed, name, and entity key. The error handling for non-delegateable components is appropriate.


153-192: LGTM!

The undelegate function correctly calls the Bolt Lang undelegation helper with the appropriate accounts. The generated structs have proper Anchor account constraints.

echo ${{ secrets.SYSTEM_FLY }} > target/deploy/system_fly-keypair.json
echo ${{ secrets.SYSTEM_SIMPLE_MOVEMENT }} > target/deploy/system_simple_movement-keypair.json
echo ${{ secrets.EXAMPLE_BUNDLE }} > target/deploy/example_bundle-keypair.json
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify the new deployment secret is configured.

Ensure the EXAMPLE_BUNDLE secret is properly configured in the repository settings to avoid deployment failures.


🏁 Script executed:

#!/bin/bash
# Check if the secret reference is used consistently across all workflow files
rg -n "EXAMPLE_BUNDLE" .github/workflows/

Length of output: 390



---

🏁 Script executed:

```shell
#!/bin/bash
# Check if EXAMPLE_BUNDLE secret is configured in the repository
gh secret list --repo "$GITHUB_REPOSITORY" 2>/dev/null | grep -i "EXAMPLE_BUNDLE" || echo "Secret not found in list"

Length of output: 24


Configure the EXAMPLE_BUNDLE secret in repository settings before deployment.

The secret is referenced in three workflow files (run-tests.yml:92, publish-bolt-sdk.yml:147, publish-bolt-crates.yml:142) but is not configured in repository settings. Add this secret to avoid runtime deployment failures.

Comment on lines 111 to 129
public static async Task InitializeBundledVelocityOnEntity1(Framework framework) {
var initializeComponent = await Bolt.World.InitializeComponent(
framework.Wallet.Account.PublicKey,
framework.Entity1Pda,
new Bolt.Component(framework.ExampleBundleProgramId, "velocity")
);
framework.BundleVelocityEntity1Pda = initializeComponent.Pda;
await framework.SendAndConfirmInstruction(initializeComponent.Instruction);

var accountInfo = await framework.GetAccountInfo(framework.BundleVelocityEntity1Pda);
var data = Convert.FromBase64String(accountInfo.Data[0]);
int offset = 8; // skip discriminator
long x = BitConverter.ToInt64(data, offset); offset += 8;
long y = BitConverter.ToInt64(data, offset); offset += 8;
long z = BitConverter.ToInt64(data, offset); offset += 8;
Debug.Assert(1 == x, "X is not equal to 1");
Debug.Assert(2 == y, "Y is not equal to 2");
Debug.Assert(3 == z, "Z is not equal to 3");
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider consistent deserialization approach.

This test manually deserializes velocity data (lines 122-125) with explicit byte offset handling, while InitializeBundledPositionOnEntity1 (line 105) uses Position.Deserialize. If a Velocity.Deserialize method exists or could be generated, using it would improve consistency and reduce manual offset calculations. If the bundle program's velocity doesn't have a generated deserializer, consider documenting why manual deserialization is necessary here.

🤖 Prompt for AI Agents
In clients/csharp/Solana.Unity.Bolt.Test/ECSTest.cs around lines 111 to 129 the
test manually parses velocity fields by byte offsets instead of using a
deserializer; replace the manual offset/BitConverter logic with a call to
Velocity.Deserialize (or the generated deserializer for the bundle velocity
type) and assert on the deserialized X/Y/Z properties, ensuring discriminator
handling is done by the deserializer; if no deserializer exists,
generate/implement Velocity.Deserialize in the bundle types (or add a brief
comment explaining why manual deserialization is required) and keep the
assertions identical.

Comment on lines 30 to 33
public string Seeds(string seed = null)
{
return (seed ?? "") + (Name ?? "");
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix seed concatenation order to match on-chain PDA derivation.

Seeds() currently returns (seed ?? "") + (Name ?? ""), which is reversed compared with the TypeScript implementation ((name ?? "") + (seed ?? "")). When both a component name and an additional seed are supplied (e.g., bundle component with an extra user seed), the C# client derives a different PDA than the TypeScript client and the on-chain program, causing instructions to fail. Mirror the TS ordering so the name prefix always precedes the optional seed.

-            return (seed ?? "") + (Name ?? "");
+            return (Name ?? "") + (seed ?? "");
🤖 Prompt for AI Agents
In clients/csharp/Solana.Unity.Bolt/ECS/Component.cs around lines 30 to 33, the
Seeds method concatenates the optional seed before the component name causing
PDAs to be derived in the wrong order; change the concatenation so the component
name prefix comes first by returning (Name ?? "") + (seed ?? "") instead of
(seed ?? "") + (Name ?? "") so the C# client matches the TypeScript/on-chain PDA
derivation.

Comment on lines 36 to 56
var data = Concat(discriminator, commitFrequencyBytes, validatorNoneTag);

TransactionInstruction instruction = new TransactionInstruction() {
ProgramId = componentId,
Keys = new List<AccountMeta>() {
AccountMeta.ReadOnly(payer, true),
AccountMeta.ReadOnly(entity, false),
AccountMeta.Writable(account, false),
AccountMeta.ReadOnly(componentId, false),
AccountMeta.Writable(bufferPda, false),
AccountMeta.Writable(delegationRecord, false),
AccountMeta.Writable(delegationMetadata, false),
AccountMeta.ReadOnly(WorldProgram.DelegationProgram, false),
AccountMeta.ReadOnly(SystemProgram.ProgramIdKey, false),
},
Data = data,
};
return new DelegateComponentInstruction() {
Pda = account,
Instruction = instruction,
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix delegate instruction payload serialization.

The delegate Beet layout still ends with pdaSeeds: Vec<Bytes>, but we only write the discriminator, the commitFrequencyMs u32 and the COption tag. On chain the decoder immediately tries to pull the vector length, hits EOF, and returns InvalidInstructionData, so both overloads fail as soon as the world program inspects the payload (bundle seeds never arrive). Please emit the Vec encoding (length + element length/value) using the same seed/component.Seeds(seed) you rely on locally, and make sure every little‑endian field stays little‑endian regardless of host endianness.

@@
-			uint commitFrequencyMs = 0;
-			byte[] commitFrequencyBytes = BitConverter.GetBytes(commitFrequencyMs); // little-endian on most platforms
-			byte[] validatorNoneTag = new byte[] { 0 }; // COption None
-
-			var data = Concat(discriminator, commitFrequencyBytes, validatorNoneTag);
+			uint commitFrequencyMs = 0;
+			byte[] commitFrequencyBytes = BitConverter.GetBytes(commitFrequencyMs);
+			if (!BitConverter.IsLittleEndian)
+			{
+				Array.Reverse(commitFrequencyBytes);
+			}
+			byte[] validatorNoneTag = new byte[] { 0 }; // COption None
+
+			byte[] data;
+			if (string.IsNullOrEmpty(seed))
+			{
+				data = Concat(discriminator, commitFrequencyBytes, validatorNoneTag, new byte[4]);
+			}
+			else
+			{
+				var seedsVecLength = BitConverter.GetBytes(1u);
+				var seedBytes = Encoding.UTF8.GetBytes(seed);
+				var seedLength = BitConverter.GetBytes((uint)seedBytes.Length);
+				if (!BitConverter.IsLittleEndian)
+				{
+					Array.Reverse(seedsVecLength);
+					Array.Reverse(seedLength);
+				}
+				data = Concat(
+					discriminator,
+					commitFrequencyBytes,
+					validatorNoneTag,
+					seedsVecLength,
+					seedLength,
+					seedBytes
+				);
+			}
@@
-			var account = WorldProgram.FindComponentPda(component.Program, entity, component.Seeds(seed));
+			var componentSeed = component.Seeds(seed) ?? string.Empty;
+			var account = WorldProgram.FindComponentPda(component.Program, entity, componentSeed);
@@
-			uint commitFrequencyMs = 0;
-			byte[] commitFrequencyBytes = BitConverter.GetBytes(commitFrequencyMs);
-			byte[] validatorNoneTag = new byte[] { 0 };
-
-			var data = Concat(discriminator, commitFrequencyBytes, validatorNoneTag);
+			uint commitFrequencyMs = 0;
+			byte[] commitFrequencyBytes = BitConverter.GetBytes(commitFrequencyMs);
+			if (!BitConverter.IsLittleEndian)
+			{
+				Array.Reverse(commitFrequencyBytes);
+			}
+			byte[] validatorNoneTag = new byte[] { 0 };
+
+			byte[] data;
+			if (string.IsNullOrEmpty(componentSeed))
+			{
+				data = Concat(discriminator, commitFrequencyBytes, validatorNoneTag, new byte[4]);
+			}
+			else
+			{
+				var seedsVecLength = BitConverter.GetBytes(1u);
+				var seedBytes = Encoding.UTF8.GetBytes(componentSeed);
+				var seedLength = BitConverter.GetBytes((uint)seedBytes.Length);
+				if (!BitConverter.IsLittleEndian)
+				{
+					Array.Reverse(seedsVecLength);
+					Array.Reverse(seedLength);
+				}
+				data = Concat(
+					discriminator,
+					commitFrequencyBytes,
+					validatorNoneTag,
+					seedsVecLength,
+					seedLength,
+					seedBytes
+				);
+			}

Also applies to: 64-95

🤖 Prompt for AI Agents
In clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/DelegateComponent.cs
around lines 36 to 56 (and similarly lines 64-95), the serialized instruction
Data only contains the discriminator, commitFrequencyBytes and the COption tag
but omits the Vec<Bytes> pdaSeeds payload and may use host endianness; update
the serialization to append the Vec encoding: write the vector length (as
little-endian uint32 or the Beet/BEET-expected integer size), then for each seed
use the same seed/component.Seeds(seed) routine to write element length + bytes,
and ensure all integer fields (commitFrequencyMs, lengths, tags) are serialized
in little-endian explicitly so the on-chain decoder can read the vector and all
fields correctly.

Comment on lines 56 to 73
public static async Task<InitializeComponentInstruction> InitializeComponent(PublicKey payer, PublicKey entity, Component component, string seed = "", PublicKey authority = null) {
if (component is null) throw new ArgumentNullException(nameof(component));
var discriminator = component.GetMethodDiscriminator("initialize");
if (discriminator is null || discriminator.Length != 8) throw new ArgumentException("Invalid discriminator", nameof(component));
var componentPda = WorldProgram.FindComponentPda(component.Program, entity, component.Seeds(seed));
var initializeComponent = new InitializeComponentAccounts() {
Payer = payer,
Entity = entity,
Data = componentPda,
ComponentProgram = component.Program,
Authority = authority ?? new PublicKey(WorldProgram.ID),
};
var instruction = WorldProgram.InitializeComponentWithDiscriminator(initializeComponent, discriminator);
return new InitializeComponentInstruction() {
Pda = componentPda,
Instruction = instruction
};
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

LGTM! Consider simplifying discriminator validation.

The new overload correctly implements discriminator-based initialization for bundled components, mirroring the TypeScript implementation. The validation and PDA derivation logic are sound.

However, consider whether the discriminator validation at lines 58-59 is necessary. Based on the Identifier.GetMethodDiscriminator implementation, it should always return a valid 8-byte array. If this is guaranteed by design, the validation could be simplified or removed.

🤖 Prompt for AI Agents
In clients/csharp/Solana.Unity.Bolt/WorldProgram/Bolt/InitializeComponent.cs
around lines 56 to 73, the explicit null/length validation for the discriminator
is redundant because Identifier.GetMethodDiscriminator always returns a valid
8-byte array; remove the two-line check (or replace it with a non-throwing
debug/assert) so the method relies on the guaranteed contract instead of
throwing ArgumentException—if you prefer a safety net, change the check to a
Debug.Assert(discriminator != null && discriminator.Length == 8) so it only runs
in debug builds and does not affect runtime behavior.

Comment on lines 7 to 19
pub fn check(instruction_sysvar_account: &AccountInfo<'_>) -> Result<()> {
let instruction = anchor_lang::solana_program::sysvar::instructions::get_instruction_relative(
0,
&instruction_sysvar_account.to_account_info(),
)
.map_err(|_| BoltError::InvalidCaller)?;
require_eq!(
instruction.program_id,
World::id(),
BoltError::InvalidCaller
);
Ok(())
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: CPI validation checks wrong instruction index.

The function uses get_instruction_relative(0, ...) which retrieves the current instruction, not the calling instruction. This means:

  • When called directly (not via CPI), it checks if the direct call is from World → passes if called as World instruction
  • When called via CPI from World, it checks if the CPI target instruction is from World → fails incorrectly

To validate that a function is called via CPI from World, you need to check the previous instruction (the caller):

-    let instruction = anchor_lang::solana_program::sysvar::instructions::get_instruction_relative(
-        0,
-        &instruction_sysvar_account.to_account_info(),
-    )
+    let instruction = anchor_lang::solana_program::sysvar::instructions::get_instruction_relative(
+        -1,
+        &instruction_sysvar_account.to_account_info(),
+    )
     .map_err(|_| BoltError::InvalidCaller)?;

With index -1, the function checks the calling instruction, ensuring that component/system methods can only be invoked via CPI from the World program.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub fn check(instruction_sysvar_account: &AccountInfo<'_>) -> Result<()> {
let instruction = anchor_lang::solana_program::sysvar::instructions::get_instruction_relative(
0,
&instruction_sysvar_account.to_account_info(),
)
.map_err(|_| BoltError::InvalidCaller)?;
require_eq!(
instruction.program_id,
World::id(),
BoltError::InvalidCaller
);
Ok(())
}
pub fn check(instruction_sysvar_account: &AccountInfo<'_>) -> Result<()> {
let instruction = anchor_lang::solana_program::sysvar::instructions::get_instruction_relative(
-1,
&instruction_sysvar_account.to_account_info(),
)
.map_err(|_| BoltError::InvalidCaller)?;
require_eq!(
instruction.program_id,
World::id(),
BoltError::InvalidCaller
);
Ok(())
}
🤖 Prompt for AI Agents
In crates/bolt-lang/src/cpi/mod.rs around lines 7 to 19, the CPI validation is
using get_instruction_relative(0, ...) which inspects the current instruction
instead of the caller; change the index to -1 so it inspects the previous
(calling) instruction, keep the same error mapping to BoltError::InvalidCaller,
and leave the require_eq check against World::id() intact so the function
enforces that it was invoked via CPI from the World program.

Comment on lines 22 to 33
let program_account_data = component_program_data.try_borrow_data()?;
let upgrade_authority = if let crate::prelude::solana_program::bpf_loader_upgradeable::UpgradeableLoaderState::ProgramData {
upgrade_authority_address,
..
} =
crate::prelude::bincode::deserialize(&program_account_data).map_err(|_| BoltError::InvalidAuthority)?
{
Ok(upgrade_authority_address)
} else {
Err(anchor_lang::error::Error::from(BoltError::InvalidAuthority))
}?.ok_or(BoltError::InvalidAuthority)?;

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Use the loader’s deserializer so trailing program bytes don’t break us.

component_program_data for an upgradeable program stores the serialized UpgradeableLoaderState::ProgramData header followed by the program bytes. bincode::deserialize(&program_account_data) insists on consuming the entire slice and returns TrailingData, so we always fall back to InvalidAuthority. Switch to UpgradeableLoaderState::deserialize(&mut &[u8]), which consumes just the header and tolerates the trailing payload.

-    let program_account_data = component_program_data.try_borrow_data()?;
-    let upgrade_authority = if let crate::prelude::solana_program::bpf_loader_upgradeable::UpgradeableLoaderState::ProgramData {
-        upgrade_authority_address,
-        ..
-    } =
-        crate::prelude::bincode::deserialize(&program_account_data).map_err(|_| BoltError::InvalidAuthority)?
-    {
-        Ok(upgrade_authority_address)
-    } else {
-        Err(anchor_lang::error::Error::from(BoltError::InvalidAuthority))
-    }?.ok_or(BoltError::InvalidAuthority)?;
+    let program_account_data = component_program_data.try_borrow_data()?;
+    let mut cursor: &[u8] = &program_account_data;
+    let upgrade_authority = if let crate::prelude::solana_program::bpf_loader_upgradeable::UpgradeableLoaderState::ProgramData {
+        upgrade_authority_address,
+        ..
+    } =
+        crate::prelude::solana_program::bpf_loader_upgradeable::UpgradeableLoaderState::deserialize(&mut cursor)
+            .map_err(|_| BoltError::InvalidAuthority)?
+    {
+        Ok(upgrade_authority_address)
+    } else {
+        Err(anchor_lang::error::Error::from(BoltError::InvalidAuthority))
+    }?.ok_or(BoltError::InvalidAuthority)?;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let program_account_data = component_program_data.try_borrow_data()?;
let upgrade_authority = if let crate::prelude::solana_program::bpf_loader_upgradeable::UpgradeableLoaderState::ProgramData {
upgrade_authority_address,
..
} =
crate::prelude::bincode::deserialize(&program_account_data).map_err(|_| BoltError::InvalidAuthority)?
{
Ok(upgrade_authority_address)
} else {
Err(anchor_lang::error::Error::from(BoltError::InvalidAuthority))
}?.ok_or(BoltError::InvalidAuthority)?;
let program_account_data = component_program_data.try_borrow_data()?;
let mut cursor: &[u8] = &program_account_data;
let upgrade_authority = if let crate::prelude::solana_program::bpf_loader_upgradeable::UpgradeableLoaderState::ProgramData {
upgrade_authority_address,
..
} =
crate::prelude::solana_program::bpf_loader_upgradeable::UpgradeableLoaderState::deserialize(&mut cursor)
.map_err(|_| BoltError::InvalidAuthority)?
{
Ok(upgrade_authority_address)
} else {
Err(anchor_lang::error::Error::from(BoltError::InvalidAuthority))
}?.ok_or(BoltError::InvalidAuthority)?;
🤖 Prompt for AI Agents
In crates/bolt-lang/src/instructions/destroy.rs around lines 22 to 33, the code
uses bincode::deserialize(&program_account_data) which fails because the
upgradeable program account contains header plus trailing program bytes; replace
the bincode call with the loader's deserializer by calling
UpgradeableLoaderState::deserialize on a &mut &[u8] that points to
program_account_data so only the header is consumed and trailing bytes are
ignored, then extract upgrade_authority_address as before and propagate errors
to BoltError::InvalidAuthority if deserialization or option unwrapping fails.

Comment on lines 41 to 62
if component_authority == world::id_const() {
require!(
Clock::get()?.unix_timestamp < session_token.valid_until,
crate::session_keys::SessionError::InvalidToken
);
} else {
let validity_ctx = crate::session_keys::ValidityChecker {
session_token: session_token.clone(),
session_signer: authority.clone(),
authority: component_authority,
target_program: world::id_const(),
};
require!(
session_token.validate(validity_ctx)?,
crate::session_keys::SessionError::InvalidToken
);
require_eq!(
component_authority,
session_token.authority,
crate::session_keys::SessionError::InvalidToken
);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Session token is never validated when the world owns the component

In the component_authority == world::id_const() branch we only check valid_until and skip SessionToken::validate, so any signer can reuse any still‑valid session token minted by the world and mutate this component. We still need to bind the provided signer and token together, just like in the non‑world branch.

Please invoke session_token.validate (with the same ValidityChecker context) and enforce the signer/authority checks for the world-owned path before proceeding. Doing so restores the intended authorization semantics.

Consider applying this diff:

-    if component_authority == world::id_const() {
-        require!(
-            Clock::get()?.unix_timestamp < session_token.valid_until,
-            crate::session_keys::SessionError::InvalidToken
-        );
-    } else {
-        let validity_ctx = crate::session_keys::ValidityChecker {
-            session_token: session_token.clone(),
-            session_signer: authority.clone(),
-            authority: component_authority,
-            target_program: world::id_const(),
-        };
-        require!(
-            session_token.validate(validity_ctx)?,
-            crate::session_keys::SessionError::InvalidToken
-        );
-        require_eq!(
-            component_authority,
-            session_token.authority,
-            crate::session_keys::SessionError::InvalidToken
-        );
-    }
+    let validity_ctx = crate::session_keys::ValidityChecker {
+        session_token: session_token.clone(),
+        session_signer: authority.clone(),
+        authority: component_authority,
+        target_program: world::id_const(),
+    };
+    require!(
+        session_token.validate(validity_ctx)?,
+        crate::session_keys::SessionError::InvalidToken
+    );
+
+    if component_authority == world::id_const() {
+        require!(
+            Clock::get()?.unix_timestamp < session_token.valid_until,
+            crate::session_keys::SessionError::InvalidToken
+        );
+    } else {
+        require_eq!(
+            component_authority,
+            session_token.authority,
+            crate::session_keys::SessionError::InvalidToken
+        );
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if component_authority == world::id_const() {
require!(
Clock::get()?.unix_timestamp < session_token.valid_until,
crate::session_keys::SessionError::InvalidToken
);
} else {
let validity_ctx = crate::session_keys::ValidityChecker {
session_token: session_token.clone(),
session_signer: authority.clone(),
authority: component_authority,
target_program: world::id_const(),
};
require!(
session_token.validate(validity_ctx)?,
crate::session_keys::SessionError::InvalidToken
);
require_eq!(
component_authority,
session_token.authority,
crate::session_keys::SessionError::InvalidToken
);
}
let validity_ctx = crate::session_keys::ValidityChecker {
session_token: session_token.clone(),
session_signer: authority.clone(),
authority: component_authority,
target_program: world::id_const(),
};
require!(
session_token.validate(validity_ctx)?,
crate::session_keys::SessionError::InvalidToken
);
if component_authority == world::id_const() {
require!(
Clock::get()?.unix_timestamp < session_token.valid_until,
crate::session_keys::SessionError::InvalidToken
);
} else {
require_eq!(
component_authority,
session_token.authority,
crate::session_keys::SessionError::InvalidToken
);
}
🤖 Prompt for AI Agents
In crates/bolt-lang/src/instructions/update.rs around lines 41 to 62, the branch
for component_authority == world::id_const() only checks unix_timestamp and
skips SessionToken::validate, allowing any signer to reuse a still-valid
world‑minted token; fix by constructing the same
crate::session_keys::ValidityChecker (session_token.clone(), session_signer:
authority.clone(), authority: component_authority, target_program:
world::id_const()), call session_token.validate(validity_ctx)? and require its
result (crate::session_keys::SessionError::InvalidToken), and then
require_eq!(component_authority, session_token.authority,
crate::session_keys::SessionError::InvalidToken) so the provided signer and
token are bound before proceeding (you may keep the existing unix_timestamp
check in addition if desired).

Comment on lines 304 to 315
// CPI: invoke the instruction
invoke(
&ix,
&[
ctx.accounts.payer.to_account_info(),
ctx.accounts.data.to_account_info(),
ctx.accounts.entity.to_account_info(),
ctx.accounts.authority.to_account_info(),
ctx.accounts.instruction_sysvar_account.to_account_info(),
ctx.accounts.system_program.to_account_info(),
],
)?;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Include the invoked program account in every CPI

Each manual invoke must receive the callee’s program AccountInfo. Here we omit ctx.accounts.component_program, so the runtime will fail the CPI (ProgramError::NotEnoughAccountKeys). The same issue repeats in destroy_component_with_discriminator, apply_impl, apply_with_session_impl, and system_execute.

         invoke(
             &ix,
             &[
                 ctx.accounts.payer.to_account_info(),
                 ctx.accounts.data.to_account_info(),
                 ctx.accounts.entity.to_account_info(),
                 ctx.accounts.authority.to_account_info(),
                 ctx.accounts.instruction_sysvar_account.to_account_info(),
                 ctx.accounts.system_program.to_account_info(),
+                ctx.accounts.component_program.to_account_info(),
             ],
         )?;

Please append the corresponding program account for every CPI site (component destroy/update, session update, and the system execute path).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// CPI: invoke the instruction
invoke(
&ix,
&[
ctx.accounts.payer.to_account_info(),
ctx.accounts.data.to_account_info(),
ctx.accounts.entity.to_account_info(),
ctx.accounts.authority.to_account_info(),
ctx.accounts.instruction_sysvar_account.to_account_info(),
ctx.accounts.system_program.to_account_info(),
],
)?;
// CPI: invoke the instruction
invoke(
&ix,
&[
ctx.accounts.payer.to_account_info(),
ctx.accounts.data.to_account_info(),
ctx.accounts.entity.to_account_info(),
ctx.accounts.authority.to_account_info(),
ctx.accounts.instruction_sysvar_account.to_account_info(),
ctx.accounts.system_program.to_account_info(),
ctx.accounts.component_program.to_account_info(),
],
)?;
🤖 Prompt for AI Agents
In crates/programs/world/src/lib.rs around lines 304 to 315, the CPI invoke call
omits the callee program AccountInfo which causes
ProgramError::NotEnoughAccountKeys; for this and the other CPI sites
(destroy_component_with_discriminator, apply_impl, apply_with_session_impl, and
system_execute) update each invoke call to include the program account (e.g.
ctx.accounts.component_program.to_account_info()) as the last entry in the
accounts slice so the runtime receives the callee program AccountInfo for every
CPI.

Comment on lines 19 to 36
pub const fn discriminator_for(name: &str) -> [u8; 8] {
let mut discriminator = [0u8; 8];

let hash = const_crypto::sha2::Sha256::new()
.update(name.as_bytes())
.finalize();

let hash_bytes = hash.as_slice();

// Manual loop required for const fn compatibility
let mut i = 0;
while i < 8 {
discriminator[i] = hash_bytes[i];
i += 1;
}

discriminator
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

🧩 Analysis chain

LGTM! Solid implementation with const fn compatibility.

The discriminator computation is correctly implemented with:

  • Proper use of const_crypto::sha2::Sha256 for compile-time evaluation
  • Manual loop to maintain const fn compatibility
  • Correct 8-byte extraction from the hash

Based on learnings, discriminator parameters should remain as Vec<u8> in client-facing APIs, but this internal utility returning [u8; 8] is appropriate for const evaluation.

Consider adding unit tests to verify the discriminator computation:


🏁 Script executed:

#!/bin/bash
# Check if tests exist for the discriminator_for function
rg -n "discriminator_for" --type rust -A5 -B5 | rg -i "test|#\[cfg\(test\)\]"

Length of output: 0


🏁 Script executed:

#!/bin/bash
# More comprehensive search: look for all occurrences of discriminator_for in rust files
echo "=== All references to discriminator_for ==="
rg -n "discriminator_for" --type rust

echo ""
echo "=== Check for test modules in utils.rs ==="
fd utils.rs --type rust | xargs rg -n "#\[cfg\(test\)\]|mod tests" -A 20

echo ""
echo "=== Look for test files that might contain discriminator tests ==="
fd "test.*\.rs|.*_test\.rs" --type rust | head -20

Length of output: 1291


🏁 Script executed:

#!/bin/bash
# Corrected search for test modules
echo "=== Search for test modules in utils.rs ==="
cat crates/programs/world/src/utils.rs | grep -n "mod tests\|#\[cfg(test)\]" -A 10

echo ""
echo "=== Check entire utils.rs structure ==="
cat crates/programs/world/src/utils.rs

echo ""
echo "=== Search for test files in crates/programs/world ==="
find crates/programs/world -name "*test*" -o -name "*tests*" 2>/dev/null

echo ""
echo "=== Check for mod tests anywhere in world crate ==="
rg "#\[cfg\(test\)\]|mod tests" crates/programs/world/

Length of output: 1236


Solid implementation with proper const fn compatibility.

The discriminator computation is correctly implemented with:

  • Proper use of const_crypto::sha2::Sha256 for compile-time evaluation
  • Manual loop to maintain const fn compatibility
  • Correct 8-byte extraction from the hash
  • Appropriate [u8; 8] return type for internal const contexts (aligned with the learning that client-facing APIs should use Vec<u8>)

No unit tests currently exist for this function. Consider adding tests to verify the discriminator computation produces consistent results and correctly handles edge cases.

@notdanilo notdanilo changed the base branch from main to feature/bundle November 5, 2025 15:41
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.

2 participants