Review Dojo code for best practices, common mistakes, security issues, and optimization opportunities. Use when auditing models, systems, tests, or preparing for deployment.
Reviews Dojo code for best practices, security issues, and gas optimization. Use when auditing models, systems, or tests before deployment.
/plugin marketplace add dojoengine/book/plugin install book@dojoengineThis skill is limited to using the following tools:
Review your Dojo code for best practices, potential issues, security concerns, and optimization opportunities.
Analyzes your code for:
Interactive mode:
"Review my Dojo project"
I'll ask about:
Direct mode:
"Review the combat system for security issues"
"Check if my models follow ECS patterns"
Checks:
Common issues:
// ❌ Missing required traits
#[dojo::model]
struct Position { ... }
// ✅ Proper traits
#[derive(Copy, Drop, Serde)]
#[dojo::model]
struct Position { ... }
// ❌ Keys after data fields
struct Example {
data: u32,
#[key]
id: u32, // Must come first!
}
// ✅ Keys first
struct Example {
#[key]
id: u32,
data: u32,
}
Checks:
Common issues:
// ❌ No authorization check
fn admin_function(ref self: ContractState) {
// Anyone can call!
}
// ✅ Authorization check
fn admin_function(ref self: ContractState) {
let world = self.world_default();
world.assert_owner(get_caller_address());
}
// ❌ No input validation
fn set_health(ref self: ContractState, health: u8) {
// Could be zero or invalid!
}
// ✅ Input validation
fn set_health(ref self: ContractState, health: u8) {
assert(health > 0 && health <= 100, 'invalid health');
}
Checks:
Common vulnerabilities:
// ❌ Integer underflow
health.current -= damage; // Could underflow!
// ✅ Safe subtraction
health.current = if health.current > damage {
health.current - damage
} else {
0
};
// ❌ Missing permission check
fn transfer_ownership(ref self: ContractState, new_owner: ContractAddress) {
// Anyone can call!
}
// ✅ Permission check
fn transfer_ownership(ref self: ContractState, new_owner: ContractAddress) {
let world = self.world_default();
world.assert_owner(get_caller_address());
}
Checks:
Optimization opportunities:
// ❌ Multiple reads
let pos: Position = world.read_model(player);
let x = pos.x;
let pos2: Position = world.read_model(player); // Duplicate read!
let y = pos2.y;
// ✅ Single read
let pos: Position = world.read_model(player);
let x = pos.x;
let y = pos.y;
// ❌ Oversized types
struct Position {
#[key]
player: ContractAddress,
x: u128, // Overkill for coordinates!
y: u128,
}
// ✅ Appropriate types
struct Position {
#[key]
player: ContractAddress,
x: u32, // Sufficient for most games
y: u32,
}
Checks:
Coverage gaps:
// Missing tests:
- ✗ No test for boundary values (max health, zero health)
- ✗ No test for unauthorized access
- ✗ No test for invalid inputs
- ✗ No integration test for full workflow
// Add:
#[test]
fn test_health_bounds() { ... }
#[test]
#[should_panic]
fn test_unauthorized_attack() { ... }
#[test]
fn test_spawn_move_attack_flow() { ... }
// ❌ Everything in one model
#[dojo::model]
struct Player {
#[key] player: ContractAddress,
x: u32, y: u32, // Position
health: u8, mana: u8, // Stats
gold: u32, items: u8, // Inventory
level: u8, xp: u32, // Progress
}
// ✅ Separate concerns
Position { player, x, y }
Stats { player, health, mana }
Inventory { player, gold, items }
Progress { player, level, xp }
// ❌ No checks
fn set_admin(ref self: ContractState, new_admin: ContractAddress) {
// Anyone can become admin!
}
// ✅ Check permissions
fn set_admin(ref self: ContractState, new_admin: ContractAddress) {
let world = self.world_default();
world.assert_owner(get_caller_address());
}
// ❌ Reading same model multiple times
let pos = world.read_model(player);
let health = world.read_model(player);
let mana = world.read_model(player);
// ✅ Read once if possible, or use separate models
let stats = world.read_model(player); // Single read
After code review:
dojo-test skill to ensure tests passdojo-deploy skill when readyThis skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.