Skip to content

feat(admin): add approve_loan endpoint for admin loan approval#29

Merged
ogazboiz merged 1 commit into
LabsCrypt:mainfrom
osasfaith:feat/add-admin-approve-loan-endpoint
Jun 19, 2026
Merged

feat(admin): add approve_loan endpoint for admin loan approval#29
ogazboiz merged 1 commit into
LabsCrypt:mainfrom
osasfaith:feat/add-admin-approve-loan-endpoint

Conversation

@osasfaith

Copy link
Copy Markdown
Contributor

Closes #11

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Refactoring (no functional or behavioral changes)
  • Performance improvement
  • Documentation update
  • Build / CI configuration change
  • Dependency update
  • Other:

Summary

The sorobanService.buildApproveLoanTx function was implemented but never exposed through an API endpoint, meaning there was no way for an admin to approve a requested loan. This PR adds a new admin-authenticated endpoint that builds the unsigned approve_loan transaction for the admin to sign with their wallet.

Motivation / Context

Fixes #11

Every other contract wrapper (request/repay/deposit/withdraw) is exposed via an API endpoint, but approve_loan was missing. Without this endpoint, admins cannot approve loans through the API, creating a gap in the loan lifecycle.

Detailed Changes

  • Added POST /admin/approve-loan endpoint with JWT authentication and admin RBAC enforcement
  • Added approveLoan controller function in indexerController.ts that calls sorobanService.buildApproveLoanTx
  • Added approveLoanBodySchema with zod validation for loanId (positive integer required)
  • Added Swagger documentation for the new endpoint
  • Endpoint follows the existing build/submit pattern: returns unsigned XDR for the admin to sign and submit via the generic /api/loans/submit endpoint
  • Audit logging enabled via auditLog middleware
  • Rate limiting applied via strictRateLimiter

Current Behavior vs. New Behavior

Before: No API path exists for an admin to approve a requested loan.

After: Admin can call POST /admin/approve-loan with { loanId: number } to get an unsigned transaction XDR, sign it with their wallet, and submit via the generic submit endpoint.

Testing

  • 5 new tests added covering:
    • Successful transaction build for admin
    • Non-admin user rejection (403)
    • Missing loanId rejection (400)
    • Invalid loanId rejection (400)
    • Missing authentication rejection (401)
  • All 220 existing tests pass
  • TypeScript type-check clean
  • Lint clean (only pre-existing warnings)

Breaking Changes

No.

Checklist

Self-Review

  • I have read the entire diff line by line
  • No debug code remains
  • No hardcoded secrets
  • Naming is consistent with the existing codebase
  • Error handling is present
  • Edge cases are addressed

Testing

  • All existing tests pass
  • New tests added for new logic
  • Edge cases and failure paths tested

Documentation

  • Swagger documentation added

Reviewer Notes

  • The endpoint follows the same build/submit pattern as request_loan and repay_loan
  • Admin role is enforced via requireRoles("admin") middleware
  • Audit logging and rate limiting are applied
  • The buildApproveLoanTx service method already existed — this PR only exposes it via an API endpoint

- Add POST /admin/approve-loan endpoint with JWT auth and admin RBAC
- Add approveLoan controller function in indexerController.ts
- Add approveLoanBodySchema with zod validation for loanId
- Add Swagger documentation for the new endpoint
- Add 5 tests covering: successful build, non-admin rejection, missing loanId, invalid loanId, and missing auth
- All 220 tests pass

@ogazboiz ogazboiz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is exactly what the issue asked for. the route is gated correctly (requireJwtAuth + requireRoles("admin") + the strict rate limiter + audit log + zod body validation), the loanId schema is a positive int, and it builds the right approve_loan soroban call via sorobanService. esm mocks are ordered before the dynamic app import and the connection mock is complete. 5/5 tests pass, full suite green, tsc clean.

one small non-blocking heads up: the handler lives in indexerController.ts rather than loanController.ts so it reads slightly off-theme, and there's a redundant 401 check on adminPublicKey that requireJwtAuth already guarantees. neither is worth holding the merge, just something to tidy if you touch it again. merging.

if you want to keep contributing, join us on Telegram: https://t.me/+DOylgFv1jyJlNzM0

@ogazboiz ogazboiz merged commit 7de1647 into LabsCrypt:main Jun 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Backend] No admin endpoint exposes the on-chain approve_loan flow

2 participants