Thank you for your interest in contributing to StellarForge! This document provides comprehensive guidelines for contributing to the project. Whether you're fixing bugs, adding features, or improving documentation, we appreciate your effort to make StellarForge better.
- Prerequisites
- Local Development Setup
- Docker Development Setup
- Development Workflow
- Commit Message Format
- Pull Request Process
- Code Style Guidelines
- Running Tests
- Adding a New Language
- SDK Upgrade Process
- Security
- Getting Help
This project uses Husky and lint-staged to enforce code quality automatically. The hooks are installed when you run npm install at the repo root (via the prepare script).
| Git event | Hook | What it does |
|---|---|---|
git commit |
pre-commit |
Runs lint-staged on staged files: ESLint auto-fix → Prettier format. Blocks the commit if lint errors remain after auto-fix. |
git push |
pre-push |
Runs the full frontend test suite (npm test -- --run). Aborts the push if any tests fail. |
lint-staged runs on staged files matching: .js, .jsx, .ts, .tsx, .json, .css, .md
If hooks stop working (e.g. after a fresh clone):
npm installThe prepare script re-initialises Husky automatically.
git commit --no-verify -m "your message"
git push --no-verifyOnly use this when absolutely necessary and document the reason in your commit message.
Before setting up your development environment, ensure you have the following installed:
- Git (v2.0+): Version control
- Node.js (v18+): JavaScript runtime for frontend development
- npm (v9+): Package manager (comes with Node.js)
- Rust (latest stable): For building Soroban smart contracts
- Stellar CLI: For contract deployment and testing (installed via setup script)
node --version # Should be v18 or higher
npm --version # Should be v9 or higher
git --version # Should be v2.0 or higher
rustc --version # Should be latest stable-
Fork the repository on GitHub
-
Clone your fork locally:
git clone https://github.com/YOUR_USERNAME/Stellar-forge.git cd Stellar-forge -
Add upstream remote to keep your fork in sync:
git remote add upstream https://github.com/stellar-forge/Stellar-forge.git git fetch upstream
Install workspace-level dependencies (husky for Git hooks, lint-staged for pre-commit linting):
npm installThis automatically runs the prepare script which sets up Git hooks via husky.
cd frontend
npm install
cd ..Run the setup script to install Rust toolchain, Stellar CLI, and configure the testnet:
./scripts/setup-soroban.shThis script will:
- Install Rust (if not already installed)
- Add the
wasm32-unknown-unknowntarget for Rust - Install Stellar CLI (replaces the older soroban-cli)
- Configure the testnet network with Soroban RPC endpoint
Verify everything is working:
# Check frontend setup
cd frontend
npm run lint
npm run test -- --run
# Check contract setup
cd ../contracts/token-factory
cargo testIf all commands pass, your environment is ready for development.
For a consistent, reproducible development environment, you can use Docker instead of installing dependencies locally.
- Docker (v20.10+): Container runtime
- Docker Compose (v2.0+): Multi-container orchestration
docker --version # Should be v20.10 or higher
docker compose version # Should be v2.0 or highergit clone https://github.com/YOUR_USERNAME/Stellar-forge.git
cd Stellar-forge# Start both frontend and contract builder services
docker compose up -d
# View logs
docker compose logs -f frontend
docker compose logs -f contract-builderThis will:
- Build and start the frontend development server on
http://localhost:5173 - Build the contract builder environment with Rust, Stellar CLI, and all dependencies
- Mount source directories as volumes for hot reloading
# Check frontend is running
curl http://localhost:5173
# Access contract builder for testing
docker compose exec contract-builder bash
# Inside container:
cd token-factory
cargo testThe frontend runs automatically with hot reloading. Make changes to files in frontend/src/ and they'll be reflected immediately at http://localhost:5173.
# View frontend logs
docker compose logs -f frontend
# Restart frontend service
docker compose restart frontendAccess the contract builder environment for Rust development:
# Enter contract builder shell
docker compose exec contract-builder bash
# Inside the container, you can:
cd token-factory
# Run tests
cargo test
# Build contracts
cargo build --target wasm32-unknown-unknown --release
# Run the build script
./build.sh
# Use Stellar CLI
stellar --help# Start services
docker compose up -d
# Stop services
docker compose down
# Rebuild services (after Dockerfile changes)
docker compose build
# View all service status
docker compose ps
# Clean up everything (removes volumes)
docker compose down -v| Aspect | Docker | Local |
|---|---|---|
| Setup Time | Fast (just Docker required) | Longer (multiple tools) |
| Consistency | Identical across machines | May vary by OS/versions |
| Performance | Slight overhead | Native performance |
| Disk Usage | Higher (images + volumes) | Lower |
| Offline Work | Works after initial setup | Requires local installs |
Choose Docker if you:
- Want quick, consistent setup
- Work on multiple machines
- Prefer isolated environments
- Have team members on different OS
Choose local setup if you:
- Need maximum performance
- Already have tools installed
- Prefer native development
- Want to use system-wide tools
# Start development environment
./scripts/docker-dev.sh start
# or
docker compose up -d
# View frontend at http://localhost:5173
# Access contract builder
docker compose exec contract-builder bash
# Run tests
./scripts/docker-dev.sh test
# View logs
./scripts/docker-dev.sh logs
# Stop everything
./scripts/docker-dev.sh stop
# Clean up completely
./scripts/docker-dev.sh cleanAlways create a new branch for your work. Use these prefixes to categorize your changes:
| Prefix | Purpose | Example |
|---|---|---|
feature/ |
New features or enhancements | feature/add-token-burn |
fix/ |
Bug fixes | fix/wallet-connection-timeout |
docs/ |
Documentation updates | docs/update-readme |
refactor/ |
Code refactoring (no behavior change) | refactor/simplify-validation |
test/ |
Test additions or updates | test/add-mint-tests |
chore/ |
Maintenance tasks (deps, config) | chore/update-dependencies |
perf/ |
Performance improvements | perf/optimize-event-queries |
style/ |
Code style/formatting changes | style/fix-linting-errors |
Branch naming rules:
- Use lowercase with hyphens (kebab-case)
- Be descriptive but concise
- Include issue number if applicable:
fix/123-wallet-timeout
Examples:
git checkout -b feature/token-history-pagination
git checkout -b fix/42-ipfs-upload-error
git checkout -b docs/deployment-guide
git checkout -b refactor/stellar-service-cleanup# Make sure you're on main and up to date
git checkout main
git pull origin main
# Create your feature branch
git checkout -b feature/your-feature-name-
Make your changes in the appropriate directory:
- Frontend changes:
frontend/src/ - Smart contract changes:
contracts/token-factory/src/
- Frontend changes:
-
Write tests for new functionality:
- Frontend: Add tests in
frontend/src/test/or co-locate with components - Contracts: Add tests in
contracts/token-factory/src/test.rs
- Frontend: Add tests in
-
Run tests locally before committing:
# Frontend tests cd frontend npm run test -- --run # Contract tests cd ../contracts/token-factory cargo test
-
Run linting to catch style issues:
cd frontend npm run lint -
Commit your changes (pre-commit hooks will run automatically):
git add . git commit -m "feat: add token burn functionality"
This project uses husky and lint-staged to enforce code quality automatically before commits.
When you commit changes, the pre-commit hook automatically:
- Runs ESLint on staged
.tsand.tsxfiles in thefrontend/directory - Auto-fixes fixable linting errors
- Runs TypeScript type checking (
tsc --noEmit) - Blocks the commit if there are linting or TypeScript errors
If hooks aren't working or you need to reinstall them:
npm run prepareTo manually verify what the hooks will do:
cd frontend
npm run lint
tsc --noEmitIn rare cases where you need to bypass hooks:
git commit --no-verify -m "your message"Note: This is strongly discouraged as it may introduce code quality issues. Use only when absolutely necessary and document why.
We follow the Conventional Commits specification for clear, semantic commit messages. This enables automated changelog generation and makes history easier to navigate.
<type>(<scope>): <subject>
<body>
<footer>
Must be one of the following:
- feat: A new feature
- fix: A bug fix
- docs: Documentation only changes
- style: Changes that don't affect code meaning (formatting, missing semicolons, etc.)
- refactor: Code change that neither fixes a bug nor adds a feature
- perf: Code change that improves performance
- test: Adding missing tests or correcting existing tests
- chore: Changes to build process, dependencies, or tooling
Optional but recommended. Specify what part of the codebase is affected:
frontend- Frontend changescontracts- Smart contract changeswallet- Wallet integrationipfs- IPFS/Pinata integrationui- UI componentshooks- React hooksutils- Utility functionsconfig- Configuration files
- Use imperative mood ("add" not "added" or "adds")
- Don't capitalize first letter
- No period (.) at the end
- Limit to 50 characters
Optional but recommended for non-trivial changes:
- Explain what and why, not how
- Wrap at 72 characters
- Separate from subject with a blank line
Optional. Reference issues and breaking changes:
Closes #123- Auto-closes the issueBREAKING CHANGE: description- For breaking changes
# Simple feature
git commit -m "feat(ui): add mainnet confirmation modal"
# Bug fix with body
git commit -m "fix(wallet): resolve connection timeout issue
The wallet connection was timing out after 5 seconds.
Increased timeout to 15 seconds and added retry logic."
# Breaking change
git commit -m "refactor(contracts): update token factory interface
BREAKING CHANGE: The create_token function signature has changed.
Callers must now provide a metadata_uri parameter."
# Closes an issue
git commit -m "feat(ipfs): add metadata pinning
Closes #42"-
Sync with upstream to avoid conflicts:
git fetch upstream git rebase upstream/main
-
Run all tests locally:
cd frontend npm run test -- --run npm run lint cd ../contracts/token-factory cargo test
-
Update documentation if needed (README, code comments, etc.)
-
Push your branch to your fork:
git push origin feature/your-feature-name
-
Open a Pull Request on GitHub with a clear title and description
-
Fill out the PR template with:
- Description: What changes are being made and why
- Type of Change: feat, fix, docs, refactor, etc.
- Related Issues: Use
Closes #XXto auto-close issues - Testing: Describe how you tested the changes
- Screenshots: Include if UI changes are involved
- Checklist: Confirm you've followed guidelines
Follow the same format as commit messages:
feat(scope): brief description
fix(scope): brief description
docs: update contributing guide
- At least one maintainer review is required
- Address feedback promptly
- Push additional commits to the same branch (don't force push)
- Request re-review after making changes
- Maintainers will merge when approved
-
Delete your feature branch locally and remotely:
git branch -d feature/your-feature-name git push origin --delete feature/your-feature-name
-
Sync your fork with upstream:
git fetch upstream git checkout main git merge upstream/main git push origin main
- Use TypeScript for all new files (no
.jsfiles) - Strict mode enabled:
strict: truein tsconfig.json - No unused variables or parameters
- No implicit
anytypes
- Use functional components with hooks (no class components)
- Prefer composition over inheritance
- Keep components focused and single-responsibility
- Use descriptive component names (PascalCase)
// Good
export function TokenForm({ onSubmit }: { onSubmit: (data: TokenData) => void }) {
const [formData, setFormData] = useState<TokenData>(initialState);
return (
<form onSubmit={() => onSubmit(formData)}>
{/* form content */}
</form>
);
}
// Avoid
export function TF(props: any) {
// ...
}- Custom hooks should start with
useprefix - Extract complex logic into custom hooks
- Use proper dependency arrays in
useEffect
// Good
export function useTokenBalance(tokenId: string) {
const [balance, setBalance] = useState<number>(0);
useEffect(() => {
fetchBalance(tokenId).then(setBalance);
}, [tokenId]);
return balance;
}- Use Tailwind CSS utility classes
- Avoid inline styles
- Create reusable component variants using Tailwind
- Use CSS modules only for complex styling
// Good
<button className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">
Submit
</button>
// Avoid
<button style={{ padding: '8px 16px', backgroundColor: 'blue' }}>
Submit
</button>- Use semantic HTML (
<button>,<nav>,<main>, etc.) - Add ARIA labels for interactive elements
- Ensure keyboard navigation works
- Test with screen readers
// Good
<button
aria-label="Close modal"
onClick={onClose}
>
✕
</button>
// Avoid
<div onClick={onClose}>✕</div>- Write tests for utilities and custom hooks
- Test user interactions, not implementation details
- Use React Testing Library for component tests
- Aim for meaningful coverage, not 100%
// Good
test('submits form with valid data', () => {
render(<TokenForm onSubmit={mockSubmit} />);
userEvent.type(screen.getByLabelText('Token Name'), 'MyToken');
userEvent.click(screen.getByRole('button', { name: /submit/i }));
expect(mockSubmit).toHaveBeenCalledWith(expect.objectContaining({ name: 'MyToken' }));
});All Rust code must be formatted with cargo fmt before committing. CI enforces this with cargo fmt -- --check and will fail if any file is not formatted.
# Format all Rust files
cd contracts
cargo fmt
# Verify formatting (what CI runs)
cargo fmt -- --check- Follow Rust naming conventions (snake_case for functions/variables, PascalCase for types)
- Use meaningful variable and function names
- Add doc comments for all public functions
- Handle errors explicitly (no unwrap in production code)
- Add doc comments to all public functions and types
- Include examples in doc comments where helpful
- Document error conditions
/// Creates a new token in the factory.
///
/// # Arguments
///
/// * `name` - The token name
/// * `symbol` - The token symbol
/// * `decimals` - Number of decimal places
///
/// # Returns
///
/// The address of the newly created token
///
/// # Errors
///
/// Returns an error if the token name is empty or if the factory is paused.
pub fn create_token(
env: &Env,
name: String,
symbol: String,
decimals: u32,
) -> Result<Address, ContractError> {
// implementation
}- Use
Resulttypes for fallible operations - Define custom error types
- Provide meaningful error messages
// Good
pub fn mint_tokens(
env: &Env,
token_id: Address,
amount: i128,
) -> Result<(), ContractError> {
if amount <= 0 {
return Err(ContractError::InvalidAmount);
}
// implementation
}
// Avoid
pub fn mint_tokens(env: &Env, token_id: Address, amount: i128) {
let result = perform_mint(token_id, amount).unwrap(); // Don't unwrap!
}- Write comprehensive tests for all contract functions
- Test both success and error cases
- Use property-based testing with proptest for complex logic
#[test]
fn test_create_token_success() {
let env = Env::default();
let factory = TokenFactory::new(&env);
let token_addr = factory.create_token(
String::from_utf8(b"MyToken".to_vec()).unwrap(),
String::from_utf8(b"MTK".to_vec()).unwrap(),
18,
).unwrap();
assert!(token_addr.is_valid());
}
#[test]
fn test_create_token_empty_name() {
let env = Env::default();
let factory = TokenFactory::new(&env);
let result = factory.create_token(
String::from_utf8(vec![]).unwrap(),
String::from_utf8(b"MTK".to_vec()).unwrap(),
18,
);
assert!(result.is_err());
}cd frontend
# Run all tests once
npm run test -- --run
# Run tests in watch mode (for development)
npm run test
# Run tests with interactive UI
npm run test:ui
# Generate coverage report
npm run test:coveragecd contracts/token-factory
# Run all tests
cargo test
# Run specific test
cargo test test_create_token
# Run tests with output
cargo test -- --nocapture
# Run tests with coverage (requires tarpaulin)
cargo tarpaulin --out HtmlFrom the root directory:
# Frontend
cd frontend && npm run test -- --run && cd ..
# Contracts
cd contracts/token-factory && cargo test && cd ../..StellarForge is designed to support multiple languages for the UI. To add a new language:
Create a new language file in frontend/src/config/i18n/:
// frontend/src/config/i18n/es.ts
export const es = {
common: {
submit: 'Enviar',
cancel: 'Cancelar',
loading: 'Cargando...',
},
tokens: {
create: 'Crear Token',
name: 'Nombre del Token',
},
// ... more translations
};Update the language registry in frontend/src/config/i18n/index.ts:
import { es } from './es';
export const languages = {
en: en,
es: es,
// ... other languages
};
export type Language = keyof typeof languages;Update the language selector component to include the new language:
// frontend/src/components/LanguageSelector.tsx
const AVAILABLE_LANGUAGES = [
{ code: 'en', name: 'English' },
{ code: 'es', name: 'Español' },
// ... add new language
];- Test the language switcher
- Verify all UI text displays correctly
- Check for text overflow issues
- Test with RTL languages if applicable
Include in your PR:
- Complete translation file
- Screenshots showing the new language in use
- Any special considerations (RTL, character encoding, etc.)
The contracts currently pin the following SDK versions in contracts/token-factory/Cargo.toml:
| Crate | Version | Reason |
|---|---|---|
soroban-sdk |
25.0.0 |
Matches Stellar Protocol 22 (the current mainnet protocol). Pinned to avoid unexpected breaking changes from minor/patch releases. |
soroban-token-sdk |
25.0.0 |
Must match soroban-sdk exactly — mismatched versions cause type incompatibilities at compile time. |
Important:
soroban-sdkandsoroban-token-sdkmust always be on the same version. When upgrading one, upgrade both together.
When upgrading Soroban SDK or other major dependencies, follow this process:
- Check the soroban-sdk CHANGELOG for breaking changes
- Check the soroban-token-sdk releases — confirm the matching version
- Review migration guides
- Identify affected code
Edit contracts/token-factory/Cargo.toml to set the new version for both crates:
[dependencies]
soroban-sdk = "NEW_VERSION"
soroban-token-sdk = { version = "NEW_VERSION" }
[dev-dependencies]
soroban-sdk = { version = "NEW_VERSION", features = ["testutils"] }Then regenerate the lockfile:
cd contracts
cargo update- Fix any breaking changes in the contract code
- Update TypeScript types if needed
- Update configuration files
# Contract tests
cd contracts/token-factory
cargo test
# Frontend tests
cd frontend
npm run test -- --run
npm run lint
# Manual testing on testnet
# Deploy to testnet and test all features- Update CHANGELOG.md with upgrade details
- Document any breaking changes
- Update the version table in this section of CONTRIBUTING.md
- Update README if needed
Include in your PR:
- Dependency update commits
- Code changes for compatibility
- Updated documentation (including the version table above)
- Test results
# 1. Edit contracts/token-factory/Cargo.toml — bump both soroban-sdk and soroban-token-sdk
# 2. Regenerate lockfile
cd contracts && cargo update
# 3. Fix any compilation errors
cargo build --target wasm32-unknown-unknown
# 4. Run tests
cd token-factory && cargo test
# 5. Update CHANGELOG.md
# Add entry: "Upgraded soroban-sdk and soroban-token-sdk to vX.Y.Z"
# 6. Commit
git commit -m "chore(contracts): upgrade soroban-sdk and soroban-token-sdk to vX.Y.Z"Please read and follow our Code of Conduct. By participating, you are expected to uphold this code.
- Review our Security Policy
- Understand the security considerations for blockchain applications
- Never commit sensitive data: Private keys, API secrets, or credentials
- Always test on testnet first: Before any mainnet deployment
- Validate user input: Especially for contract interactions
- Use secure random generation: For any cryptographic operations
- Handle errors gracefully: Don't expose sensitive information in error messages
If you discover a security vulnerability:
- Do not open a public issue
- Email security details to the maintainers (see SECURITY.md)
- Include: Description, affected versions, reproduction steps, and potential impact
- Allow time for the team to respond and prepare a fix
See SECURITY.md for detailed vulnerability reporting procedures.
- GitHub Discussions: Ask questions in the Discussions tab
- GitHub Issues: Search existing issues or create a new one
- Documentation: Check README.md and existing docs
- Code Examples: Review existing components and tests
npm run prepare# Clear cache and reinstall
rm -rf node_modules package-lock.json
npm install
npm run test -- --run# Update Rust
rustup update
# Clean build
cd contracts/token-factory
cargo clean
cargo build --target wasm32-unknown-unknown- Ensure Freighter wallet is installed
- Check that you're on the correct network (testnet/mainnet)
- Clear browser cache and reload
This project is licensed under the Apache License 2.0. See the LICENSE file for details.
Thank you for contributing to StellarForge! Your efforts help make token deployment on Stellar accessible to everyone.