Thank you for your interest in contributing to StellarSplit SDK — the open-source TypeScript toolkit for Stellar-based split payments, invoicing, and multi-wallet management. This project is part of the Drips Wave Program, a monthly open-source bounty initiative run by the Stellar Development Foundation.
- Introduction
- Prerequisites
- Fork & Clone Workflow
- Branch Naming Conventions
- Commit Message Format
- Development Setup
- Code Style
- Testing
- Pull Request Process
- Issue Workflow
- Architecture Overview
- Security Guidelines
- Contributor Checklist
StellarSplit SDK is a TypeScript-first library that provides:
- Invoice management — create, fund, track, and settle payment invoices on Stellar
- Multi-wallet support — connect MetaMask, WalletConnect, Ledger, Freighter, and more
- Batch operations — group payments and Soroban contract calls for efficiency
- SEP integrations — SEP-31 cross-border payments, SEP-10 auth, and more
- Telemetry and observability — hooks for error monitoring, performance tracking
We welcome contributions of all sizes — from typo fixes in docs to large new features. Every issue in our tracker is a candidate for community contribution. Please read this guide in full before opening a pull request.
Important: Do not begin coding until a maintainer has assigned you to an issue. Comment on the issue first and wait for assignment.
Before contributing, ensure your local environment meets the following requirements:
| Tool | Minimum Version | Recommended | Notes |
|---|---|---|---|
| Node.js | 18.x | 20.x LTS | Required for ESM + top-level await support |
| npm | 9.x | 10.x | Bundled with Node.js |
| Git | 2.35+ | latest | Required for signed commits |
| TypeScript | 5.x | 5.4+ | Installed as dev dependency |
node --version # should output v18.x or higher
npm --version # should output 9.x or higher
git --version # should output 2.35 or higher- Visual Studio Code — recommended editor with TypeScript IntelliSense
- ESLint + Prettier VSCode extensions — for real-time lint feedback
- GitHub CLI (
gh) — for branch creation and PR management from the terminal
Click Fork on the Stellar-split/split-sdk repository page to create your own copy.
git clone https://github.com/<your-username>/split-sdk.git
cd split-sdkThis allows you to pull in changes from the main repository:
git remote add upstream https://github.com/Stellar-split/split-sdk.git
git fetch upstreamgit remote -v
# origin https://github.com/<your-username>/split-sdk.git (fetch)
# origin https://github.com/<your-username>/split-sdk.git (push)
# upstream https://github.com/Stellar-split/split-sdk.git (fetch)
# upstream https://github.com/Stellar-split/split-sdk.git (push)Before starting any new work, always sync with upstream:
git checkout main
git fetch upstream
git merge upstream/main
git push origin mainCreate a feature branch from main. Use the following prefixes to indicate the type of change:
| Prefix | Purpose | Example |
|---|---|---|
feat/ |
New feature or capability | feat/issue-1130-freighter-adapter |
fix/ |
Bug fix | fix/issue-42-null-address-crash |
docs/ |
Documentation changes only | docs/issue-1081-contribution-guide |
chore/ |
Tooling, build, CI, dependencies | chore/upgrade-vitest-2.0 |
refactor/ |
Code refactoring with no behavior change | refactor/split-calculator-cleanup |
test/ |
Adding or improving tests only | test/invoice-state-machine-coverage |
perf/ |
Performance improvements | perf/batch-payment-optimization |
<prefix>/issue-<NUMBER>-short-description
# Examples
git checkout -b feat/issue-1130-freighter-adapter
git checkout -b fix/issue-42-null-address-crash
git checkout -b docs/issue-1081-contribution-guideKeep descriptions short (3–5 words), lowercase, hyphenated. Never commit directly to main.
This project follows the Conventional Commits specification. All commit messages must follow this format:
<type>(<optional scope>): <short description>
[optional body]
[optional footer(s)]
| Type | When to use |
|---|---|
feat |
A new feature |
fix |
A bug fix |
docs |
Documentation only changes |
style |
Code formatting, missing semicolons (no logic changes) |
refactor |
Code restructuring without feature/bug change |
test |
Adding or updating tests |
chore |
Build process, tooling, dependency updates |
perf |
Performance improvements |
ci |
CI/CD configuration changes |
revert |
Reverting a previous commit |
feat(wallet): add FreighterAdapter for Stellar browser extension (#1130)
fix(invoice): handle undefined return from freighter signTransaction (#42)
docs(contributing): add Conventional Commits guidance (#1081)
test(batch): add coverage for 101-operation rejection case
chore: upgrade vitest to 2.0.0
- Subject line: ≤ 72 characters, imperative mood ("add feature", not "added feature")
- Reference the issue in the footer or subject:
(#42)orCloses #42 - Use the body to explain why, not just what
- Keep commits atomic — one logical change per commit
npm install --save-dev @commitlint/cli @commitlint/config-conventional
# Add to package.json: "commitlint": { "extends": ["@commitlint/config-conventional"] }npm installIf you encounter peer dependency conflicts, use:
npm install --legacy-peer-deps
npm run buildThis compiles TypeScript to the dist/ directory using the project's tsconfig.json.
npm run build -- --watchnpx tsc --noEmitnpm run lintThe SDK does not require environment variables for development. If you are running integration tests against a real Stellar testnet, you may optionally set:
STELLAR_NETWORK=testnet
HORIZON_URL=https://horizon-testnet.stellar.orgStellarSplit SDK enforces TypeScript strict mode across the entire codebase. The following rules are non-negotiable:
The tsconfig.json enables:
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"noUncheckedIndexedAccess": true
}
}- No
anytypes. Useunknownand narrow with type guards instead. Ifanyis truly unavoidable, add a comment explaining why. - Explicit return types on all exported functions and class methods.
- JSDoc comments on all exported functions, classes, and interfaces.
- Prefer
constoverlet. Avoidvar. - No unused imports — remove them before committing.
- Use
.jsextensions in all import paths (required for ESM compatibility):import { StellarSplitError } from './errors.js'; // ✅ import { StellarSplitError } from './errors'; // ❌
- Error handling — always extend
StellarSplitErrorfor SDK errors, never throw raw strings. - Async/await preferred over
.then()chains. - Keep functions small — aim for ≤ 40 lines per function. Extract helpers.
- Immutable data — prefer
readonlymodifiers on interface properties.
/**
* Fetches the current balance for a Stellar account.
* @param accountId - The Stellar public key to query.
* @param asset - The asset to look up, defaults to XLM.
* @returns The balance as a string with 7 decimal places.
* @throws {@link StellarSplitError} when the account does not exist.
*/
export async function getAccountBalance(
accountId: string,
asset: Asset = Asset.native()
): Promise<string> {
// ...
}The project uses Vitest as the test runner. Tests are located in the test/ directory.
npm testnpm test -- freighterAdapter
npm test -- batchOperations.test.tsnpm test -- --reporter=verbosenpm test -- --watchAll new functionality must include tests. Test files should:
- Live in
test/and follow the pattern<FeatureName>.test.ts - Use
describeblocks to group related cases - Use
itfor individual test cases (descriptive names) - Use
vi.fn()andvi.mock()for mocking dependencies
Example test structure:
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { MyFeature } from '../src/myFeature.js';
describe('MyFeature', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('returns the correct result for valid input', () => {
const result = MyFeature.compute('valid-input');
expect(result).toBe('expected-output');
});
it('throws MyError when input is invalid', () => {
expect(() => MyFeature.compute('')).toThrow(MyError);
});
});- New features: aim for ≥ 90% coverage on the new code
- Bug fixes: add a test that reproduces the bug before the fix
- Run coverage report:
npm test -- --coverage
Ensure all of the following are true:
- Your branch is up-to-date with
upstream/main -
npm testpasses (all tests green) -
npm run lintpasses with no errors -
npx tsc --noEmitpasses with no type errors - New code has corresponding tests
- All exported symbols have JSDoc comments
- The PR references the issue it closes
Follow Conventional Commits format for the PR title:
feat(wallet): add FreighterAdapter for Stellar browser extension
## Summary
Brief description of what this PR does.
## Changes
- Added `FreighterAdapter` implementing `WalletAdapter`
- Exported from `multiWallet.ts`
- Added test suite in `test/freighterAdapter.test.ts`
## Testing
Describe how you tested the changes.
## Related Issues
Closes #1130- Submit the PR — a maintainer will review within a few business days.
- Address any requested changes by pushing additional commits to your branch (do not force-push unless asked).
- Once approved, a maintainer will squash-merge your PR.
- Your issue will be closed automatically when the PR is merged.
- Browse open issues and find one labeled
good first issue,help wanted, or matching your skill level. - Read the full issue description including any linked discussions.
- Comment: "I'd like to work on this."
- Wait for a maintainer to assign you. Do not fork and start coding before assignment.
- Only one contributor per issue at a time — respect active assignments.
- Search existing issues to check if the bug is already reported.
- If not found, open a new issue using the Bug Report template.
- Include:
- SDK version (
npm list split-sdk) - Node.js version
- Minimal reproduction code snippet
- Expected vs. actual behavior
- Stack trace if applicable
- SDK version (
- Open a Discussion first to gauge interest.
- If the maintainers support it, they will open a tracked issue.
- Feature requests become issues only when they are scoped and actionable.
- Use GitHub Discussions — not issues — for questions.
- For quick questions, comment on the relevant issue thread.
Understanding the repository layout will help you find where to make changes.
split-sdk/
├── src/ # All library source code (TypeScript)
│ ├── index.ts # Public API entry point — re-exports all public symbols
│ ├── client.ts # StellarSplitClient — main SDK facade
│ ├── errors.ts # StellarSplitError base class and typed subclasses
│ ├── types.ts # Shared TypeScript interfaces and type definitions
│ ├── multiWallet.ts # MultiWalletManager and wallet adapter re-exports
│ ├── wallets/
│ │ └── adapters/ # Concrete WalletAdapter implementations
│ │ ├── FreighterAdapter.ts
│ │ ├── MetaMaskAdapter.ts
│ │ ├── LobstrAdapter.ts
│ │ └── XBullAdapter.ts
│ ├── adapters/ # Additional adapters (WalletConnect, Ledger)
│ ├── invoice/ # Invoice creation, state machine, diff utilities
│ ├── payments/ # Payment flows, batch operations, routing
│ ├── sep/ # SEP-10, SEP-31 protocol implementations
│ ├── soroban/ # Soroban contract interaction utilities
│ ├── horizon/ # Stellar Horizon API client wrappers
│ ├── telemetry/ # Telemetry hooks, metrics, OTEL export
│ └── utils/ # General-purpose utilities
├── test/ # Vitest test suites (*.test.ts)
├── docs/ # Supplementary documentation
│ ├── INTEGRATION_TESTING.md
│ ├── MIGRATION.md
│ ├── SIGNING_VAULT.md
│ └── ...
├── dist/ # Compiled output (do not edit — git-ignored)
├── CONTRIBUTING.md # This file
├── CHANGELOG.md # Version history and notable changes
├── package.json
└── tsconfig.json
- Adapter pattern — all wallet integrations implement the
WalletAdapterinterface fromtypes.ts - Error hierarchy — all SDK errors extend
StellarSplitErrorwith acodestring for programmatic handling - Event emitters — typed event emitters (
TypedEventEmitter) for observable state changes - Pure functions — utility modules (e.g.,
diff.ts,paymentSplitCalculator.ts) are side-effect-free
Security vulnerabilities must not be reported in public GitHub issues. Follow these guidelines:
- Email the maintainers privately at the address listed in
SECURITY.md. - Provide: description, steps to reproduce, affected versions, and potential impact.
- Allow 14 days for an initial response before public disclosure.
- We aim to release a fix within 90 days of confirmed reports.
- Never commit private keys, secrets, or API tokens — not even testnet keys.
- Use
.envfor local secrets and ensure.envis in.gitignore. - Validate all external input — treat Horizon API responses as untrusted.
- Use
StellarSplitErrorsubclasses — never leak internal stack traces to end users. - When implementing cryptographic operations, use established libraries (e.g.,
@stellar/stellar-sdk) — do not roll your own. - Avoid
eval(),Function(), or dynamicimport()with user-controlled strings. - Dependencies: check
npm auditbefore adding new packages.
npm audit
npm audit fixUse this checklist before every pull request submission:
- I have read the full CONTRIBUTING.md
- My Node.js version is 18 or higher
- I was assigned to this issue before I started coding
- I created a branch with the correct naming convention
- My code compiles without TypeScript errors (
npx tsc --noEmit) - I did not introduce any
anytypes without explanation - All new exported functions and classes have JSDoc comments
- Import paths end with
.jsfor ESM compatibility - I extended
StellarSplitErrorfor any new error classes
- I wrote tests for all new functionality
- All existing tests pass (
npm test) - My tests cover both success paths and error paths
- I updated the relevant docs if behavior changed
- I updated
CHANGELOG.mdunder theUnreleasedsection
- My branch is rebased on current
upstream/main - My PR title follows Conventional Commits format
- My PR description references the closed issue (
Closes #NNN) - I have not included unrelated changes
Thank you for contributing to StellarSplit SDK! Every contribution — large or small — helps make Stellar payments more accessible for developers worldwide.