Thanks for your interest in contributing to Checkmate-Escrow! This guide will help you get started.
- Rust 1.70 or later
- Soroban CLI
- Stellar CLI
- Git
- Fork the repository
- Clone your fork:
git clone https://github.com/your-username/checkmate-escrow.git cd checkmate-escrow - Set up your environment:
cp .env.example .env # Edit .env with your configuration - Build the project:
./scripts/build.sh
- Run tests to verify your setup:
./scripts/test.sh
Create a feature branch from main:
git checkout -b feature/your-feature-nameUse descriptive branch names:
feature/for new featuresfix/for bug fixesdocs/for documentation updatesrefactor/for code refactoring
- Write clear, concise commit messages
- Keep commits focused on a single change
- Add tests for new functionality
- Update documentation as needed
Run the full test suite before submitting:
cargo testFor specific contract tests:
cargo test -p escrow
cargo test -p oracle- Follow Rust standard formatting:
cargo fmt - Run clippy for linting:
cargo clippy - Keep functions small and focused
- Add comments for complex logic
- Use descriptive variable names
- Update relevant documentation in
docs/for architectural changes - Add inline comments for non-obvious code
- Add or update Soroban contract guidance in
docs/contributing-contracts.mdwhen changing contract storage, TTL, or auth behavior - Add or update oracle guidance in
docs/CONTRIBUTING_ORACLE.mdwhen changing the oracle service, adding platform clients, or modifying result verification - Update README.md if adding new features or changing setup steps
- Check repository health and link validity with
./scripts/repository_health_check.sh
See docs/repository-health-checklist.md for checklist details.
- Push your branch to your fork:
git push origin feature/your-feature-name
- Open a Pull Request against the
mainbranch - Fill out the PR template with:
- Clear description of changes
- Related issue numbers (if applicable)
- Testing performed
- Screenshots (for UI changes)
- Wait for review and address feedback
- Keep PRs focused on a single feature or fix
- Ensure all tests pass
- Update documentation
- Respond to review comments promptly
- Squash commits if requested
We use a shared label taxonomy to keep issue and PR triage consistent. See docs/label-taxonomy.md for definitions of labels like good first issue, wave-ready, and help-wanted.
- Use
snake_casefor functions and variables - Use
PascalCasefor types and enums - Prefer explicit error handling over panics
- Use
Result<T, Error>for fallible operations - Document public APIs with doc comments
- Validate all inputs at function entry
- Use appropriate storage types (instance, persistent, temporary)
- Extend TTL for long-lived data
- Emit events for state changes
- Require authentication for privileged operations
- Write unit tests for all public functions
- Test error cases and edge conditions
- Use descriptive test names:
test_function_name_condition_expected_result - Mock external dependencies
- Verify events are emitted correctly
When testing that a contract function returns a specific error, prefer the typed
try_ variant over #[should_panic]. The try_ approach asserts the exact
error variant, making failures easier to diagnose and preventing tests from
accidentally passing due to an unrelated panic.
Avoid — #[should_panic] only checks that something panicked:
#[test]
#[should_panic(expected = "Error(Contract, #10)")]
fn test_create_match_with_zero_stake_fails() {
let (env, contract_id, _oracle, player1, player2, token, _admin) = setup();
let client = EscrowContractClient::new(&env, &contract_id);
client.create_match(&player1, &player2, &0, &token,
&String::from_str(&env, "game"), &Platform::Lichess);
}Prefer — try_ asserts the exact error variant:
#[test]
fn test_create_match_with_zero_stake_returns_invalid_amount() {
let (env, contract_id, _oracle, player1, player2, token, _admin) = setup();
let client = EscrowContractClient::new(&env, &contract_id);
let result = client.try_create_match(&player1, &player2, &0, &token,
&String::from_str(&env, "game"), &Platform::Lichess);
assert_eq!(result, Err(Ok(Error::InvalidAmount)));
}Use #[should_panic] only for cases where the contract panics with a plain
string message rather than a typed error (e.g. double-initialization):
#[test]
#[should_panic(expected = "Contract already initialized")]
fn test_double_initialize_fails() {
// ...
client.initialize(&oracle, &admin);
client.initialize(&oracle, &admin); // panics with a string, not a typed Error
}For changes to contracts/escrow or contracts/oracle, see docs/contributing-contracts.md for detailed guidance on:
- Authorization patterns and
require_auth - Storage tiers and state layout
- TTL management
- Contract initialization and upgrade safety
- Events and observability
For changes to the off-chain oracle service, see docs/CONTRIBUTING_ORACLE.md for detailed guidance on:
- Local oracle setup and environment configuration
- Running and writing oracle integration tests
- Adding support for new chess platform clients
- Result verification and security patterns
- API rate limiting and error handling
Checkmate-Escrow participates in Drips Wave contributor funding. Issues labeled wave-ready are eligible for funding:
trivial(100 points): Documentation, simple tests, minor fixesmedium(150 points): Oracle helpers, validation logic, moderate featureshigh(200 points): Core escrow logic, Oracle integrations, security enhancements
See docs/wave-guide.md for details on earning funding.
- Open an issue for bugs or feature requests
- Join discussions in existing issues
- Ask questions in pull request comments
Please read and follow our Code of Conduct.
By contributing, you agree that your contributions will be licensed under the MIT License.