Thank you for contributing to BOXMEOUT — a decentralized boxing prediction market on Stellar. This guide covers everything you need to pick an issue, write code, and get your PR merged.
- Project Overview
- Getting Started
- How to Pick an Issue
- Coding Standards
- Naming Conventions
- Commit Messages
- Pull Request Process
- Testing Requirements
- Labels Explained
BOXMEOUT has three workspaces — pick the one that matches your skills:
| Workspace | Language | What you will work on |
|---|---|---|
/contracts |
Rust (Soroban) | Smart contract logic — betting, resolution, claims |
/backend |
TypeScript (Node.js) | Indexer, REST API, oracle service |
/frontend |
TypeScript (Next.js) | UI components, React hooks, wallet integration |
Every function in the codebase is already stubbed with a signature and a doc comment. Your job as a contributor is to implement the function body — nothing else.
git clone https://github.com/YOUR_USERNAME/boxmeout.git
cd boxmeoutgit checkout -b feat/issue-{number}-short-description
# Example: feat/issue-7-place-betContracts
cd contracts
cargo build
cargo testBackend
cd backend
cp .env.example .env # fill in your Stellar Testnet + PostgreSQL credentials
npm install
npm run db:generate
npm run db:migrate
npm run devFrontend
cd frontend
npm install
npm run dev # opens http://localhost:3000# Contracts
cargo test
# Backend
npm run type-check && npm test
# Frontend
npm run type-check && npm test-
Browse GitHub Issues filtered by your workspace label:
smart-contract— for/contractsworkbackend— for/backendworkfrontend— for/frontendwork
-
New contributors: start with issues labelled
good first issue. These are self-contained and require no knowledge of the full system. -
Claim an issue before starting. Comment "I'll take this" on the issue thread. If no one responds to your claim within 48 hours, you may take it over.
-
Do not work on an issue someone else has already claimed. Check whether there is an open PR linked to the issue before claiming.
-
Ask questions in the issue thread before writing any code. It is far cheaper to clarify requirements upfront than to rewrite later.
-
Stick to one issue per PR. Do not bundle unrelated changes.
- Follow the official Soroban SDK patterns.
- Every public function must have a
///doc comment explaining the WHY, not just the what. - All persistent storage reads and writes must go through typed wrapper functions — no raw
env.storage()key calls in business logic. - Use
require_auth()orrequire_auth_for_args()on every state-changing function that involves a user address. - Use checked or saturating arithmetic for all pool math — no unchecked
+or*oni128. - Mark bets as claimed before transferring tokens (checks-effects-interactions pattern).
- Run before committing:
cargo fmt cargo clippy -- -D warnings cargo test
- TypeScript
strictmode is enforced — no implicitany. - All
asyncfunctions must surface errors to the caller — no silentcatch {}blocks. - Never use
console.login committed code. Use the logger service (pino) in the backend. - Do not add
// TODOcomments. Either implement it or leave thethrow new Error("Not implemented")stub. - Run before committing:
npm run lint npm run type-check npm test
- Functional components only — no class components.
- Every component receives props through a typed
interfacenamed{ComponentName}Props. - No inline styles — use Tailwind CSS utility classes only.
- No
useEffectfor data that can be fetched in a server component. Prefer server components where possible. - Client components (
"use client") should be as small as possible — push state down.
| Entity | Convention | Example |
|---|---|---|
| Soroban function | snake_case |
place_bet() |
| Soroban struct / enum | PascalCase |
MarketStatus |
| Soroban storage key | SCREAMING_SNAKE_CASE |
MARKET_COUNT |
| TypeScript function | camelCase |
getMarketById() |
| TypeScript type / interface | PascalCase |
CreateMarketDTO |
| React component | PascalCase |
MarketCard |
| React component file | PascalCase.tsx |
MarketCard.tsx |
| React hook | use prefix, camelCase |
useMarkets() |
| Hook file | camelCase.ts |
useMarkets.ts |
| Database model | PascalCase |
Market, Bet |
| Database column | camelCase |
bettingEndsAt |
| API route | kebab-case |
/api/market-stats |
| Environment variable | SCREAMING_SNAKE_CASE |
STELLAR_RPC_URL |
| Git branch | feat/, fix/, docs/, test/ prefix |
feat/issue-7-place-bet |
Use the Conventional Commits format:
<type>(<scope>): <short description>
[optional body]
Types: feat, fix, docs, test, refactor, chore
Scopes: contracts, backend, frontend, docs
Examples:
feat(contracts): implement place_bet() in Market contract
fix(backend): handle duplicate bet_id on event replay in recordBet()
test(frontend): add unit tests for useMarkets hook
docs(contracts): document all emitted events in contracts.md
Rules:
- Subject line max 72 characters
- Use the imperative mood: "implement" not "implemented"
- Reference the issue:
Closes #42in the commit body or PR description
-
Ensure your branch is up to date with
mainbefore opening a PR:git fetch origin git rebase origin/main
-
Make sure all checks pass locally:
# Contracts cargo fmt && cargo clippy -- -D warnings && cargo test # Backend / Frontend npm run lint && npm run type-check && npm test
-
Open a PR against
mainwith:- A clear title matching your commit message format
- A description explaining WHAT changed and WHY
Closes #<issue-number>linking the issue- Screenshots or test output for frontend / API changes
-
Do not merge your own PR. Wait for a maintainer review.
-
Address all review comments before requesting a re-review.
-
Squash your commits into one clean commit if asked.
-
Once approved, a maintainer will merge with squash-and-merge.
| Workspace | Minimum requirement |
|---|---|
/contracts |
Unit tests for every public function — happy path + at least one error case |
/backend |
Integration test for every API endpoint using a real test database |
/frontend |
Unit test for every hook; snapshot test for every display component |
Test files live next to the code they test:
contracts/market/src/lib.rs→ tests in#[cfg(test)]module in the same filebackend/src/services/market.service.ts→market.service.test.tsin the same folderfrontend/hooks/useMarkets.ts→useMarkets.test.tsin the same folder
| Label | Meaning |
|---|---|
good first issue |
Self-contained, no deep system knowledge needed. Start here. |
intermediate |
Requires understanding of the surrounding module. |
advanced |
Cross-cutting concern, security-sensitive, or complex logic. |
smart-contract |
Work is in /contracts |
backend |
Work is in /backend |
frontend |
Work is in /frontend |
indexer |
Relates to the blockchain event indexer |
api |
Relates to the REST API layer |
hooks |
Relates to React hooks in /frontend/hooks |
components |
Relates to React components in /frontend/components |
security |
Security-sensitive — requires extra review care |
testing |
Writing or improving tests |
docs |
Documentation only |
oracle |
Relates to fight result submission and oracle trust |
devops |
CI, deployment scripts, environment config |
database |
Prisma schema or migration related |
Open a GitHub Discussion or ask in the issue thread. Do not DM maintainers — public threads help everyone.