DESCRIPTION
Every account gets a custodial Stellar wallet created via WalletService.createWalletRecord() (apps/api/src/escrow/wallet.service.ts). When funding fails, the wallet is silently persisted with status: 'failed' (see AuthService.register and UsersService.ensureProfileWallet in apps/api/src/auth/auth.service.ts / apps/api/src/users/users.service.ts) — there is no retry, no reconciliation job, and no admin-facing way to recover a user stuck without a working wallet. Since the wallet is required to hold bond tokens on-chain, a failed wallet silently breaks that user's ability to participate. This epic builds the missing resilience layer.
GOAL
Wallets that failed to create/fund are automatically retried, an admin can see which accounts have a broken wallet and trigger a manual retry, and this status is visible where user data is already surfaced.
REQUIREMENTS
- A reconciliation routine (scheduled job or on-demand endpoint — pick whichever fits the current deployment, e.g.
@nestjs/schedule if acceptable, or an admin-triggered endpoint if a scheduler is out of scope) that finds profiles/parties with stellar_wallet_status: 'failed' and retries WalletService.createWalletRecord().
- Bounded retry (e.g. backoff + max attempts) so a permanently-broken dependency doesn't loop forever; record the last error (
stellar_wallet_error, already a column) and attempt count.
POST /users/:id/wallet/retry (admin-only, mirroring the authorization pattern in UsersService.listUsers/setRole) to manually trigger a retry for one user.
- Surface wallet status (
created / funded / failed, with last error) in the admin-facing user data — wire into the user-directory admin console if that epic has landed, otherwise expose it via GET /users for now.
ACCEPTANCE CRITERIA
- A profile/party with
stellar_wallet_status: 'failed' is retried automatically (or via the admin endpoint) and transitions to funded/created once the retry succeeds — proven with a test against a mocked WalletService.
- Retries are bounded and don't hammer the network indefinitely on a permanent failure.
POST /users/:id/wallet/retry is admin-only and audited via AuditService.emit().
npm run build, npm run lint, npm run test pass in apps/api with NO VELAR credentials — the reconciliation logic must be testable against a mocked WalletService/SupabaseService, not real Stellar testnet calls.
docs/BACKEND.md updated describing the reconciliation flow and the manual-retry endpoint.
NOTES
Relevant files: apps/api/src/escrow/wallet.service.ts, apps/api/src/auth/auth.service.ts, apps/api/src/users/users.service.ts, apps/api/src/users/users.controller.ts, apps/api/src/audit/audit.service.ts. Do not change the wallet creation/funding logic itself — only add retry/reconciliation around the existing createWalletRecord() (docs/AGENTS.md §3).
No VELAR credentials required: verifiable locally with a mocked WalletService/SupabaseService — no real Stellar testnet calls or VELAR credentials required for tests.
Difficulty: Advanced
Priority: Medium
PR REQUIREMENTS
- Ship this as a single pull request — do not split into stacked/sequential PRs.
- Your PR description must include
Closes #<this-issue-number> (this issue's GitHub number) so merging auto-closes it.
CAMPAIGN REQUIREMENTS (FWC26)
To be eligible for the reward on this issue, the contributor must:
DESCRIPTION
Every account gets a custodial Stellar wallet created via
WalletService.createWalletRecord()(apps/api/src/escrow/wallet.service.ts). When funding fails, the wallet is silently persisted withstatus: 'failed'(seeAuthService.registerandUsersService.ensureProfileWalletinapps/api/src/auth/auth.service.ts/apps/api/src/users/users.service.ts) — there is no retry, no reconciliation job, and no admin-facing way to recover a user stuck without a working wallet. Since the wallet is required to hold bond tokens on-chain, a failed wallet silently breaks that user's ability to participate. This epic builds the missing resilience layer.GOAL
Wallets that failed to create/fund are automatically retried, an admin can see which accounts have a broken wallet and trigger a manual retry, and this status is visible where user data is already surfaced.
REQUIREMENTS
@nestjs/scheduleif acceptable, or an admin-triggered endpoint if a scheduler is out of scope) that finds profiles/parties withstellar_wallet_status: 'failed'and retriesWalletService.createWalletRecord().stellar_wallet_error, already a column) and attempt count.POST /users/:id/wallet/retry(admin-only, mirroring the authorization pattern inUsersService.listUsers/setRole) to manually trigger a retry for one user.created/funded/failed, with last error) in the admin-facing user data — wire into the user-directory admin console if that epic has landed, otherwise expose it viaGET /usersfor now.ACCEPTANCE CRITERIA
stellar_wallet_status: 'failed'is retried automatically (or via the admin endpoint) and transitions tofunded/createdonce the retry succeeds — proven with a test against a mockedWalletService.POST /users/:id/wallet/retryis admin-only and audited viaAuditService.emit().npm run build,npm run lint,npm run testpass inapps/apiwith NO VELAR credentials — the reconciliation logic must be testable against a mockedWalletService/SupabaseService, not real Stellar testnet calls.docs/BACKEND.mdupdated describing the reconciliation flow and the manual-retry endpoint.NOTES
Relevant files:
apps/api/src/escrow/wallet.service.ts,apps/api/src/auth/auth.service.ts,apps/api/src/users/users.service.ts,apps/api/src/users/users.controller.ts,apps/api/src/audit/audit.service.ts. Do not change the wallet creation/funding logic itself — only add retry/reconciliation around the existingcreateWalletRecord()(docs/AGENTS.md§3).No VELAR credentials required: verifiable locally with a mocked
WalletService/SupabaseService— no real Stellar testnet calls or VELAR credentials required for tests.Difficulty: Advanced
Priority: Medium
PR REQUIREMENTS
Closes #<this-issue-number>(this issue's GitHub number) so merging auto-closes it.CAMPAIGN REQUIREMENTS (FWC26)
To be eligible for the reward on this issue, the contributor must: