Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions Cargo.lock

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

6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,10 @@ anchor-lang = { version = "^0", features = ["init-if-needed"] }
anchor-cli = { version = "^0" }
anchor-client = { version = "^0", features = ["async"] }
anchor-syn = { version = "^0" }
anchor-lang-idl = { version = "^0" }
solana-program = { version = "^2" }
anchor-lang-idl = { version = "^0" }
solana-program = "^2"
solana-client = "^2"
solana-system-interface = "^1"
Comment on lines +45 to +48
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

Workspace deps updated for Solana v2 — check Anchor version compatibility

Looks good. Ensure Anchor crates resolve to ≥0.30 (preferably ≥0.32) to match Solana v2 across the workspace.

Quick check for Anchor versions declared:

If needed, pin Anchor to 0.32.x in workspace.dependencies to avoid accidental downgrade.


🏁 Script executed:

#!/bin/bash
rg -nP --glob '**/Cargo.toml' 'anchor-(lang|cli|client|syn|lang-idl)\s*=' -C1

Length of output: 1050


Pin Anchor workspace dependencies to ^0.32
In top-level Cargo.toml (lines 42–46), anchor-* crates use version = "^0" (resolves to <0.1.0), blocking Anchor v0.30+. Update them to version = "^0.32" (or >=0.30,<1.0.0) to ensure compatibility with Solana v2.

🤖 Prompt for AI Agents
In Cargo.toml around lines 46 to 49, the anchor-* workspace dependencies are
specified as version = "^0" which resolves to <0.1.0 and blocks Anchor v0.30+;
update those anchor-related entries to a pinned Anchor 0.32-compatible range
(e.g. version = "^0.32" or ">=0.30,<1.0.0") so the workspace uses Anchor v0.30+
compatible releases with Solana v2.

zeroize = "^1.7"
mpl-token-metadata = { version = "^5" }
solana-security-txt = "^1"
Expand Down
4 changes: 3 additions & 1 deletion crates/bolt-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ dev = []
[dependencies]
anchor-cli = { workspace = true }
anchor-client = { workspace = true }
solana-client = { workspace = true }
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

Solana v2 dependencies added — verify workspace alignment

The additions look correct for Anchor ≥0.30. Please verify no crates still pin Solana v1 to avoid resolver conflicts.

Run to spot mismatched Solana versions in Cargo.toml files:

Also applies to: 34-35


🏁 Script executed:

#!/bin/bash
# List any Solana crates pinned to 1.x (should be none)
rg -nP -C1 --glob '**/Cargo.toml' '\bsolana-(program|client|system-interface)\b.*["'\'']?1\.' || true
# Show all declared Solana crate versions for quick visual check
rg -nP --glob '**/Cargo.toml' 'solana-(program|client|system-interface)\s*=' -C1

Length of output: 550


solana-system-interface version mismatch — bump to v2

Root Cargo.toml still pins solana-system-interface = "^1" while solana-program and solana-client use v2. Update solana-system-interface to ^2 in Cargo.toml so workspace crates align.

🤖 Prompt for AI Agents
In crates/bolt-cli/Cargo.toml around line 22, the workspace root pins
solana-system-interface = "^1" while solana-program and solana-client require
v2; update the solana-system-interface entry to use "^2" so all workspace crates
depend on the same major version and then run cargo update / cargo check to
verify dependency resolution.

anchor-syn = { workspace = true }
anchor-lang-idl = { workspace = true, features = ["build"] }
anyhow = { workspace = true }
Expand All @@ -30,4 +31,5 @@ world = { workspace = true }
which = { workspace = true }
tokio = { workspace = true }
sysinfo = { workspace = true }
bytemuck_derive = { workspace = true }
bytemuck_derive = { workspace = true }
solana-system-interface = { workspace = true }
4 changes: 2 additions & 2 deletions crates/bolt-cli/src/instructions.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use anchor_cli::config::{Config, ConfigOverride};
use anchor_client::solana_client::rpc_config::RpcSendTransactionConfig;
use anchor_client::solana_sdk::commitment_config::CommitmentConfig;
use anchor_client::solana_sdk::pubkey::Pubkey;
use anchor_client::solana_sdk::signature::{read_keypair_file, Keypair};
use anchor_client::solana_sdk::signer::Signer;
use anchor_client::solana_sdk::system_program;
use anchor_client::Client;
use anyhow::{anyhow, Result};
use solana_client::rpc_config::RpcSendTransactionConfig;
use solana_system_interface::program as system_program;
use std::rc::Rc;
use world::{accounts, instruction, Registry, World, ID};

Expand Down
123 changes: 51 additions & 72 deletions crates/bolt-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ pub async fn entry(opts: Opts) -> Result<()> {
anchor_cli::Command::Init {
name,
javascript,
solidity,
no_install,
no_git,
template,
Expand All @@ -133,7 +132,6 @@ pub async fn entry(opts: Opts) -> Result<()> {
&opts.cfg_override,
name,
javascript,
solidity,
no_install,
no_git,
template,
Expand Down Expand Up @@ -214,7 +212,6 @@ fn init(
cfg_override: &ConfigOverride,
name: String,
javascript: bool,
solidity: bool,
no_install: bool,
no_git: bool,
template: anchor_cli::rust_template::ProgramTemplate,
Expand Down Expand Up @@ -289,33 +286,31 @@ fn init(
idl: None,
},
);
if !solidity {
let component_id = anchor_cli::rust_template::get_or_create_program_id(component_name);
let system_id = anchor_cli::rust_template::get_or_create_program_id(system_name);
localnet.insert(
component_name.to_owned(),
ProgramDeployment {
address: component_id,
path: None,
idl: None,
},
);
localnet.insert(
system_name.to_owned(),
ProgramDeployment {
address: system_id,
path: None,
idl: None,
},
);
cfg.workspace.members.push("programs/*".to_owned());
cfg.workspace
.members
.push("programs-ecs/components/*".to_owned());
cfg.workspace
.members
.push("programs-ecs/systems/*".to_owned());
}
let component_id = anchor_cli::rust_template::get_or_create_program_id(component_name);
let system_id = anchor_cli::rust_template::get_or_create_program_id(system_name);
localnet.insert(
component_name.to_owned(),
ProgramDeployment {
address: component_id,
path: None,
idl: None,
},
);
localnet.insert(
system_name.to_owned(),
ProgramDeployment {
address: system_id,
path: None,
idl: None,
},
);
cfg.workspace.members.push("programs/*".to_owned());
cfg.workspace
.members
.push("programs-ecs/components/*".to_owned());
cfg.workspace
.members
.push("programs-ecs/systems/*".to_owned());

// Setup the test validator to clone Bolt programs from devnet
let validator = Validator {
Expand Down Expand Up @@ -359,7 +354,7 @@ fn init(
// Remove the default programs if `--force` is passed
if force {
let programs_path = std::env::current_dir()?
.join(if solidity { "solidity" } else { "programs" })
.join("programs")
.join(&project_name);
fs::create_dir_all(&programs_path)?;
fs::remove_dir_all(&programs_path)?;
Expand All @@ -371,32 +366,28 @@ fn init(
}

// Build the program.
if solidity {
anchor_cli::solidity_template::create_program(&project_name)?;
} else {
create_system(system_name)?;
create_component(component_name)?;
rust_template::create_program(&project_name, template)?;

// Add the component as a dependency to the system
std::process::Command::new("cargo")
.arg("add")
.arg("--package")
.arg(system_name)
.arg("--path")
.arg(format!("programs-ecs/components/{}", component_name))
.arg("--features")
.arg("cpi")
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.spawn()
.map_err(|e| {
anyhow::format_err!(
"error adding component as dependency to the system: {}",
e.to_string()
)
})?;
}
create_system(system_name)?;
create_component(component_name)?;
rust_template::create_program(&project_name, template)?;

Comment on lines 368 to +372
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

Blocking: external command uses spawn() without waiting — results are nondeterministic

The cargo add command is started but not awaited, so dependency injection may silently fail or race with subsequent steps.

-    std::process::Command::new("cargo")
+    let status = std::process::Command::new("cargo")
         .arg("add")
         .arg("--package")
         .arg(system_name)
         .arg("--path")
         .arg(format!("programs-ecs/components/{}", component_name))
         .arg("--features")
         .arg("cpi")
         .stdout(std::process::Stdio::null())
         .stderr(std::process::Stdio::null())
-        .spawn()
-        .map_err(|e| {
-            anyhow::format_err!(
-                "error adding component as dependency to the system: {}",
-                e.to_string()
-            )
-        })?;
+        .status()
+        .map_err(|e| anyhow::format_err!("failed to run cargo add: {}", e))?;
+    if !status.success() {
+        return Err(anyhow::format_err!(
+            "cargo add failed when adding component '{}' as dependency to system '{}'",
+            component_name,
+            system_name
+        ));
+    }

Also apply the same fix to other Command::spawn() usages that must complete before proceeding (e.g., add_types_crate_dependency, and optionally the solana program dump step if the generated artifact is required immediately).

Also applies to: 373-390

🤖 Prompt for AI Agents
crates/bolt-cli/src/lib.rs around lines 368-372 (and also apply to 373-390):
external commands are launched with Command::spawn() and not awaited, causing
race conditions; change these to use Command::status() or Command::output() (or
call child.wait() / child.wait_with_output()) and check the exit status/error,
so the code blocks until the external process completes; apply the same change
in add_types_crate_dependency and any solana program dump invocation that must
finish before subsequent steps, and propagate or return errors when the child
process exits with a non-zero status.

// Add the component as a dependency to the system
std::process::Command::new("cargo")
.arg("add")
.arg("--package")
.arg(system_name)
.arg("--path")
.arg(format!("programs-ecs/components/{}", component_name))
.arg("--features")
.arg("cpi")
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.spawn()
.map_err(|e| {
anyhow::format_err!(
"error adding component as dependency to the system: {}",
e.to_string()
)
})?;

// Build the test suite.
fs::create_dir_all("tests/fixtures")?;
Expand Down Expand Up @@ -429,18 +420,10 @@ fn init(

if jest {
let mut test = File::create(format!("tests/{}.test.js", &project_name))?;
if solidity {
test.write_all(anchor_cli::solidity_template::jest(&project_name).as_bytes())?;
} else {
test.write_all(templates::workspace::jest(&project_name).as_bytes())?;
}
test.write_all(templates::workspace::jest(&project_name).as_bytes())?;
} else {
let mut test = File::create(format!("tests/{}.js", &project_name))?;
if solidity {
test.write_all(anchor_cli::solidity_template::mocha(&project_name).as_bytes())?;
} else {
test.write_all(templates::workspace::mocha(&project_name).as_bytes())?;
}
test.write_all(templates::workspace::mocha(&project_name).as_bytes())?;
}

let mut deploy = File::create("migrations/deploy.js")?;
Expand All @@ -458,11 +441,7 @@ fn init(
deploy.write_all(anchor_cli::rust_template::ts_deploy_script().as_bytes())?;

let mut mocha = File::create(format!("tests/{}.ts", &project_name))?;
if solidity {
mocha.write_all(anchor_cli::solidity_template::ts_mocha(&project_name).as_bytes())?;
} else {
mocha.write_all(templates::workspace::ts_mocha(&project_name).as_bytes())?;
}
mocha.write_all(templates::workspace::ts_mocha(&project_name).as_bytes())?;
}

if !no_install {
Expand Down
Loading