Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ dist/
.next/
out/
build/
*.tsbuildinfo

# Environment
.env
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ Versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

### Added

- Expanded `api/utils/horizonError.ts` to map the full set of known Stellar transaction and operation result codes (`tx_bad_seq`, `op_underfunded`, `tx_too_late`, `op_low_reserve`, etc.) to friendly, actionable error messages, with full unit test coverage (#166).
- `GET /api/v1/prices/xlm` returning XLM/USD market price from public feeds with Redis caching and multi-provider failover (#137).
- `StellarService.isTestnet()` and `StellarService.isMainnet()` helper methods to inspect active Stellar network configuration (#141).
- `POST /api/v1/trustlines/build` to generate unsigned trustline establishment XDR for wallet signing (#124).
- `GET /api/v1/accounts/:publicKey` returning full Stellar account details from Horizon with Zod validation, retries, and mapped error codes (#122).
- `POST /api/v1/transactions/unsigned` to build unsigned Stellar payment XDR for wallet signing (#146).
- `GET /api/v1/balances/:publicKey/history` for paginated balance-change audit history from `transactions_log` (#145).
- `GET /api/v1/communities` pagination support via `page`, `limit`, and `offset` query parameters. When `offset` is provided, it takes precedence for querying and calculates the appropriate page in the metadata.
Expand Down
11 changes: 6 additions & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -417,24 +417,25 @@ We will acknowledge within 24 hours and disclose responsibly after a fix is depl

## 12. Maintainer Responsibilities

Maintainers are community members with write access to the main repository. Their responsibilities:
[BigNathan1](https://github.com/BigNathan1) is the sole maintainer of this repository, with the only
write access to `main`. Responsibilities:

- **Triage new issues** within 72 hours (add labels, request clarification, or close as duplicate)
- **Review PRs** within 72 hours of opening or update
- **Enforce** the branch model and commit convention on all merges
- **Maintain** the `main` branch in a deployable state at all times
- **Keep** the roadmap in PRD.md current each quarter
- **Release** tagged versions (`v0.x.y`) monthly during active development phases
- **Rotate** maintainer access reviews every 6 months

### Becoming a Maintainer

Sustained contributors (5+ merged PRs, positive community engagement) may be nominated by existing maintainers. Nominations are approved by simple majority of current maintainers.
Contributors are recognized on the [Contributors leaderboard](CONTRIBUTORS.md) rather than through
maintainer nomination — there is no path to write access via contribution volume.

---

## Thank You

Every contribution matters — whether it's fixing a typo, adding a test, or building a new lending flow. We're building something that can genuinely improve financial access for underserved communities worldwide. We're glad you're here.

Merged PRs earn recognition on the [Contributors leaderboard](CONTRIBUTORS.md).

**Happy building. ◆**
25 changes: 25 additions & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Contributors

CoopLumen recognizes external contributions with a simple points tally, awarded by the maintainer
on merge. This is recognition, not a governance mechanism — see [CONTRIBUTING.md](CONTRIBUTING.md)
for how the project is run.

## How points are awarded

Points are assigned per merged PR based on scope, judged by the maintainer at merge time:

| Points | Scope |
| ------ | ------------------------------------------------------------------------------- |
| 1–2 | Small fix, docs correction, or single small test |
| 3–5 | One feature/endpoint, a focused refactor, or a meaningful test suite addition |
| 6–10 | Multi-part PR closing several issues, a new subsystem, or foundational plumbing |

## Leaderboard

| Contributor | Points | Merged PRs |
| ------------------------------------- | -----: | ---------- |
| [Hallab7](https://github.com/Hallab7) | 8 | #581 |

## Ledger

- **2026-08-27** — [Hallab7](https://github.com/Hallab7) — **+8 points** — [#581](https://github.com/BigNathan1/CoopLumen/pull/581) _"add Stellar transaction and database foundation work"_ (merged via [#583](https://github.com/BigNathan1/CoopLumen/pull/583)): a new unsigned-payment XDR endpoint, a paginated balance-history audit endpoint, a completed database ERD, and a genuinely-fresh-database migration integration suite — four issues (#54, #56, #145, #146) closed in one well-tested, well-documented PR.
47 changes: 47 additions & 0 deletions backend/src/api/routes/__tests__/accounts.integration.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Integration test: verifies loading account details from Stellar testnet Horizon.
* Skipped gracefully when Horizon testnet is not reachable.
*/

import request from 'supertest';
import { Keypair } from '@stellar/stellar-sdk';
import app from '../../../app';
import { StellarService } from '../../../contracts/stellar';

describe('Accounts testnet integration', () => {
let isTestnetReachable = false;
// Well-known persistent testnet account
const testnetPublicKey = 'GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5';

beforeAll(async () => {
isTestnetReachable = await StellarService.ping();
});

it('fetches real account details from Stellar testnet', async () => {
if (!isTestnetReachable) {
return;
}

const response = await request(app).get(`/api/v1/accounts/${testnetPublicKey}`);
expect(response.status).toBe(200);
expect(response.body.data).toBeDefined();
expect(response.body.data.id).toBe(testnetPublicKey);
expect(response.body.data.account_id).toBe(testnetPublicKey);
expect(Array.isArray(response.body.data.balances)).toBe(true);
expect(Array.isArray(response.body.data.signers)).toBe(true);
expect(typeof response.body.data.sequence).toBe('string');
});

it('returns 404 for an unfunded valid public key on testnet', async () => {
if (!isTestnetReachable) {
return;
}

// Unfunded random valid public key
const unfundedKey = Keypair.random().publicKey();
const response = await request(app).get(`/api/v1/accounts/${unfundedKey}`);
expect(response.status).toBe(404);
expect(response.body.data).toBeNull();
expect(response.body.error).toBe('Stellar account or asset not found.');
});
});
Loading
Loading