Thank you for your interest in contributing to Stellar-Save. This document explains how to get involved, what standards to follow, and how to submit your work.
- Code of Conduct
- Getting Started
- Code Style Guidelines
- Commit Message Conventions
- Pull Request Process
- Testing Requirements
By participating in this project, you agree to treat all contributors with respect. We do not tolerate harassment, discrimination, or hostile behaviour of any kind. If you experience or witness a violation, please open a private issue or contact a maintainer directly.
- Rust (stable toolchain)
- Soroban CLI
- Node.js v18+ and npm
- Freighter wallet (for manual testing)
# Clone the repository
git clone https://github.com/Xoulomon/Stellar-Save.git
cd Stellar-Save
# Install frontend dependencies
cd frontend
npm install
# Build the smart contract
cd ../contracts/stellar-save
cargo build --target wasm32-unknown-unknown --releaseAlways branch from main:
git checkout main
git pull origin main
git checkout -b your-branch-nameUse descriptive branch names:
fix/contribution-overflowdocs/api-referencefeat/custom-tokens
Note: Avoid using
feature/as a prefix — usefeat/instead to prevent directory conflicts on some remotes.
- Follow standard Rust formatting — run
cargo fmtbefore committing - Run
cargo clippyand resolve all warnings before opening a PR - Keep functions small and focused — one responsibility per function
- Use descriptive variable names; avoid single-letter names outside of iterators
- Document public functions with
///doc comments - Prefer
Result<T, ContractError>over panics for recoverable errors - Group related logic into modules (see existing
contribution.rs,payout.rs, etc.)
/// Verifies that the caller is the group creator.
/// Returns an error if the caller is not authorised.
pub fn require_creator(env: &Env, group: &Group) -> Result<(), ContractError> {
let caller = env.invoker();
if caller != group.creator {
return Err(ContractError::Unauthorized);
}
Ok(())
}- Use functional components with hooks — no class components
- Type all props and state with TypeScript interfaces or types
- Use
constby default; only useletwhen reassignment is needed - Keep components small — extract sub-components when a file exceeds ~150 lines
- Co-locate component CSS files (e.g.
Button.tsx+Button.css) - Use semantic HTML elements for accessibility (
<button>,<nav>,<main>, etc.) - Run
npm run lintbefore committing
interface ButtonProps {
label: string;
onClick: () => void;
disabled?: boolean;
}
const Button = ({ label, onClick, disabled = false }: ButtonProps) => (
<button onClick={onClick} disabled={disabled} className="btn">
{label}
</button>
);We follow the Conventional Commits specification.
<type>(<scope>): <short description>
[optional body]
[optional footer]
| Type | When to use |
|---|---|
feat |
A new feature |
fix |
A bug fix |
docs |
Documentation changes only |
style |
Formatting, whitespace (no logic change) |
refactor |
Code restructuring without behaviour change |
test |
Adding or updating tests |
chore |
Build process, dependency updates, tooling |
feat(contract): add custom token support for contributions
fix(frontend): correct payout position display off-by-one error
docs: add contributing guidelines
test(contract): add edge case tests for missed contribution handling
- Use the imperative mood in the description: "add" not "added" or "adds"
- Keep the first line under 72 characters
- Reference issues in the footer:
Closes #42
- Open an issue first for non-trivial changes so the approach can be discussed before you invest time coding
- Branch from
main— never commit directly tomain - Keep PRs focused — one feature or fix per PR; avoid bundling unrelated changes
- Fill in the PR template — describe what changed, why, and how to test it
- Ensure CI passes — all tests must pass before a review is requested
- Request a review from at least one maintainer
- Address review comments — push follow-up commits to the same branch; do not force-push after review has started
- Squash on merge — maintainers will squash commits when merging to keep history clean
Follow the same Conventional Commits format as commit messages:
feat(contract): implement penalty for missed contributions
- All new public functions must have at least one unit test
- Cover both the happy path and expected error cases
- Use
#[should_panic]orassert_eq!(result, Err(...))for error cases - Run the full test suite before opening a PR:
cargo test- Snapshot tests live in
test_snapshots/— update them if your change affects output
- Add tests for any new utility functions or hooks
- Component tests are encouraged but not yet required for all components
- Run the linter before committing:
npm run lint- Do not reduce overall test coverage — PRs that delete tests without replacement will be rejected
- If you find a bug, write a failing test that reproduces it before fixing it
Open a GitHub Discussion or comment on the relevant issue. We're happy to help you get your contribution across the line.