Thank you for considering a contribution to FlowPay. This document covers everything you need to know to get your changes merged cleanly.
- Code of Conduct
- Ways to Contribute
- Good First Issues
- Development Setup
- Branching & Workflow
- Contract Contribution Guidelines
- Frontend Contribution Guidelines
- Commit Style
- Generated TypeScript Bindings
- Pull Request Checklist
- Questions
Be respectful. We welcome contributors of all experience levels. Harassment, gatekeeping, or dismissive behaviour will not be tolerated.
- Fix a bug (open an issue first if it's non-trivial)
- Add a feature from the roadmap
- Improve documentation or fix typos
- Write additional contract tests
- Build a keeper/scheduler service
- Review open pull requests
These are well-scoped tasks that don't require deep knowledge of the whole codebase:
| Task | Area | Difficulty |
|---|---|---|
| Add USDC / custom SAC token support | Contract | Medium |
Build a Node.js keeper service that calls charge() on a schedule |
Backend | Medium |
| Add subscription pause/resume functions | Contract | Medium |
| Improve frontend error messages with human-readable contract panics | Frontend | Easy |
Add test_pay_per_use unit test |
Contract | Easy |
Add test_double_initialize unit test |
Contract | Easy |
| Display transaction history using contract events | Frontend | Hard |
# Install Rust
curl https://sh.rustup.rs -sSf | sh
# Add WASM target
rustup target add wasm32-unknown-unknown
# Install Soroban CLI
cargo install --locked soroban-cli
# Run tests
cd contract
cargo testcd frontend
npm install
cp .env.example .env.local # then fill in VITE_CONTRACT_ID
npm run dev- Fork the repository
- Create a feature branch from
main:git checkout -b feat/your-feature-name # or git checkout -b fix/bug-description - Make your changes
- Run tests — they must all pass before opening a PR
- Push your branch and open a Pull Request against
main
Branch naming conventions:
feat/— new featurefix/— bug fixdocs/— documentation onlytest/— adding or improving testsrefactor/— code changes with no behaviour change
- Keep
#![no_std]— Soroban contracts cannot use the Rust standard library - Every new public function must have at least one test in
test.rs - Any function that moves funds or mutates user state must call
user.require_auth() - Use
env.storage().persistent()for user data,env.storage().instance()for contract-wide config - Emit an event via
env.events().publish()for every state-changing action - Do not introduce floating point — use integer arithmetic in stroops (1 XLM = 10,000,000 stroops)
- Run
cargo clippyand resolve all warnings before submitting
See the full guide: docs/CONTRIBUTING-FRONTEND.md.
- All contract calls must go through
src/stellar.ts— React components should never import@stellar/stellar-sdkdirectly - Do not add external UI component libraries — keep the bundle minimal
- Use TypeScript strictly — no
anyunless absolutely necessary and commented - Keep components small and focused on a single responsibility
- Run
npm run lintto check for ESLint errors before submitting - Run
npm run formatto auto-format all source files with Prettier - Run
npm run buildto confirm there are no TypeScript errors before submitting
We follow Conventional Commits:
feat: add pause/resume subscription functions
fix: prevent double-initialize on contract
docs: expand DEPLOYMENT.md with mainnet steps
test: add pay_per_use unit test
refactor: extract token client helper in lib.rs
FlowPay uses auto-generated TypeScript types derived directly from the Soroban contract ABI. These bindings live at:
frontend/src/generated/contract.ts
Generated bindings provide compile-time type safety for every contract call made from the frontend. Instead of manually defining TypeScript interfaces that mirror the contract's public API, the soroban contract bindings typescript command reads the contract's ABI and produces accurate type definitions automatically.
When the contract adds a new function, changes a parameter type, or renames a field, the generated bindings update automatically. Without them, the frontend types would silently diverge from the contract (ABI drift), causing runtime errors that TypeScript cannot catch. Regenerating bindings after every contract change ensures the compiler catches mismatches immediately.
Re-run the binding generator whenever:
- You add, remove, or rename a public contract function
- You change the signature (parameters or return type) of any public function
- You modify any struct or enum that appears in the contract's public interface
- You deploy a new version of the contract
To regenerate:
npm run generate:typesThis invokes scripts/generate-types.sh, which requires either:
CONTRACT_IDenv var pointing to a deployed contract, or- A compiled WASM artifact at
contract/target/wasm32-unknown-unknown/release/payflow.wasm
All generated files are written to frontend/src/generated/. Do not manually edit files in this directory — they will be overwritten on the next generation run.
Before opening a PR, confirm:
-
cargo testpasses (contract changes) -
npm run lintpasses with no errors (frontend changes) -
npm run buildpasses (frontend changes) - New functions have tests
- No secrets or
.envfiles committed - PR description explains what changed and why
- Linked to a relevant issue if one exists
Open a GitHub Discussion or leave a comment on the relevant issue. We're happy to help you get unstuck.