Thank you for your interest in contributing! Very-prince is an open-source infrastructure project built on Stellar Soroban. We welcome contributions of all kinds — from fixing typos to implementing new contract features.
- Code of Conduct
- Getting Started
- Branching & Commits
- How to Add a New Contract Function (end-to-end)
- How to Add a New API Endpoint
- How to Add a New Frontend Page or Component
- Running Tests
- Pull Request Process
- Security Disclosures
This project follows the Contributor Covenant Code of Conduct. By participating you agree to uphold a welcoming, harassment-free environment.
- Fork the repository on GitHub.
- Clone your fork locally:
git clone https://github.com/<your-username>/Very-prince.git cd Very-prince
- Install dependencies (see README Prerequisites section first):
npm install
- Copy the environment template:
cp .env.example .env # Fill in CONTRACT_ID after running deploy.sh - Verify setup:
# Test the contract (Rust) cd packages/contracts && cargo test # Build all TypeScript packages npm run build
| Branch | Purpose |
|---|---|
main |
Stable, released code. Direct pushes prohibited. |
develop |
Integration branch. All PRs target this. |
feature/<name> |
New features or enhancements. |
fix/<issue-number>-<short-desc> |
Bug fixes linked to a GitHub Issue. |
docs/<name> |
Documentation-only changes. |
We follow Conventional Commits:
<type>(<scope>): <short summary>
[optional body]
[optional footer: Closes #<issue>]
Types: feat, fix, docs, chore, refactor, test, ci
Scopes: contracts, backend, frontend, root
Examples:
feat(contracts): add remove_maintainer function
fix(backend): handle missing CONTRACT_ID gracefully
docs(readme): update deploy instructions for CLI v21
This is the most impactful type of contribution. Follow all four steps.
- If you need a new data structure, add it as a
#[contracttype]enum or struct before thePayoutRegistrystruct. - Add the new function to the
#[contractimpl]block. Follow the existing patterns:- Gate access with
address.require_auth()wherever a specific Stellar address must authorise the call. - Use
env.storage().persistent()for data that must survive ledger expiry. - Emit an event via
env.events().publish(...)so off-chain indexers can react. - Add inline doc comments explaining each parameter and panic condition.
- Gate access with
- Add unit tests in the
#[cfg(test)]block — at minimum, one happy path and one test per panic condition.
// Example skeleton:
pub fn remove_maintainer(env: Env, org_id: Symbol, maintainer: Address) {
let admin: Address = env.storage().persistent()
.get(&DataKey::OrgAdmin(org_id.clone()))
.expect("organization not found");
admin.require_auth();
// ... implementation ...
env.events().publish(
(symbol_short!("registry"), symbol_short!("mnt_rmvd")),
(org_id, maintainer),
);
}- Run tests:
cargo test - Run clippy:
cargo clippy --target wasm32-unknown-unknown -- -D warnings
Add a corresponding method to StellarService:
- For read-only operations: use
_simulateContractCall. - For state-changing operations: use
_submitContractCall.
async removeMaintainer(orgId: string, maintainer: string, signerSecret: string) {
return this._submitContractCall("remove_maintainer", [
nativeToScVal(orgId, { type: "symbol" }),
nativeToScVal(maintainer, { type: "address" }),
], signerSecret);
}Add a method to contractController.ts, then a new route in routes/contract.ts:
// routes/contract.ts
fastify.delete<{ Params: { orgId: string; address: string } }>(
"/orgs/:orgId/maintainers/:address",
// ...schema, handler
);If the new operation needs UI:
- Add a new call in
sorobanClient.ts(for reads) or call the backend viafetch()(for writes). - Add a new component in
src/components/or extend an existing page.
- Define a Zod schema for request validation in
routes/contract.ts. - Add the Fastify route with an OpenAPI-compatible
schemaobject (for future Swagger docs). - Add a controller method in
contractController.tsthat calls the service. - Write a test in
vitestthat mocksstellarServiceand asserts the correct response shape.
- Create the file in
packages/frontend/src/components/<ComponentName>.tsx. - Mark as
"use client"only if the component uses browser APIs, React hooks, or event handlers. - Export a single named function component.
- Use Tailwind utility classes — prefer the
glass-cardandgradient-textutilities fromglobals.css.
- Create
packages/frontend/src/app/<route>/page.tsx. - Export a default function component.
- Export a
metadataobject for SEO. - Use the
WalletButtonin the nav if the page requires wallet access — gate content with theisConnectedstate fromuseFreighter.
# All tests (via Turborepo)
npm test
# Contract tests only
cd packages/contracts && cargo test
# Backend tests only
cd packages/backend && npm test
# Frontend tests only
cd packages/frontend && npm test- Open a GitHub Issue first (use the provided templates) to discuss the change before spending time implementing it.
- Branch off
developusing the naming convention above. - Keep PRs focused — one feature or fix per PR. Large PRs are hard to review and harder to revert.
- Update documentation: If you add a contract function, update the Contract Reference table in
README.md. - Ensure CI passes — the CI pipeline must be green before a PR can be merged.
- Request a review from a maintainer. PRs require at least one approval.
- Maintainers squash-merge to
developto keep a clean history.
Before opening your PR, make sure:
-
cargo testpasses locally. -
cargo clippy -- -D warningsemits no warnings. -
npm run buildsucceeds. -
npm run lintpasses. - New public contract functions have doc comments.
- New unit tests are added for all new behaviour.
-
README.mdContract Reference table is updated (if applicable). - Wallet interactions are manually tested according to the QA Checklist (if applicable).
Please do not open public GitHub Issues for security vulnerabilities. Instead, use GitHub's private Security Advisory feature so we can coordinate a fix before public disclosure.