comparing features#1
Open
euniceamoni wants to merge 109 commits into
Open
Conversation
- Add DataKey::BorrowerList to track all borrowers who have taken loans - Append borrower to BorrowerList on each request_loan call - Add get_all_loans(page, page_size) admin-only paginated view - Add tests: pagination correctness and empty state - Fix pre-existing bug: duplicate initialize() calls in test setup
- Add grace_period: u64 to Config struct (default 3 days) - Add DEFAULT_GRACE_PERIOD constant (3 * 24 * 60 * 60 seconds) - auto_slash now enforces timestamp > deadline + grace_period using saturating_add to prevent u64 overflow - grace_period = 0 is valid and restores original deadline-only behaviour - set_config accepts any grace_period value (0 is a valid no-grace config) - Add 8 unit tests: blocked during grace period, allowed after, boundary at exact threshold, one second past threshold, zero grace period, blocked on repaid loan, default value check, set_config update Closes QuorumCredit#64
- Add DEFAULT_GRACE_PERIOD constant (3 days in seconds) - Add grace_period: u64 to Config struct with doc comment - Config::default() initialises grace_period to DEFAULT_GRACE_PERIOD - auto_slash enforces timestamp > deadline.saturating_add(grace_period) using saturating_add to prevent u64 overflow - grace_period = 0 is valid; restores immediate post-deadline slashing - set_config comment clarifies 0 is an accepted value - 9 unit tests: blocked during grace period, allowed after, exact boundary rejection, one-second-past-threshold, zero grace period, blocked on repaid loan, blocked on already-defaulted loan, default value assertion, set_config round-trip Closes QuorumCredit#65
) - Add extend_loan(admin_signers, borrower, new_deadline) admin function - Add consent_extension(voucher, borrower) for voucher consent tracking - Add get_extension_consents(borrower) view function - Add ExtensionConsents storage key and LoanNotActive/DeadlineNotExtended errors - Add 6 tests covering happy path, auth rejection, and edge cases
- Extract do_vouch private helper; vouch delegates to it - Add batch_vouch(voucher, borrowers, stakes) — validates lengths match, rejects empty batches, aborts atomically on any per-entry error - Add 4 tests: happy path, length mismatch, empty batch, duplicate abort
…balance before payout loop Fixes QuorumCredit#10 - Compute total_payout (stake + proportional yield) for all vouchers before entering the transfer loop - Return ContractError::InsufficientFunds early if contract balance cannot cover the full payout, preventing a mid-loop panic - Removed duplicate/malformed 'if fully_repaid' block that referenced an undefined variable
Fixes QuorumCredit#13 - Added ContractError::BorrowerHasActiveLoan = 14 - Check has_active_loan before accepting stake transfer in vouch - Prevents voucher stake being locked with no effect on existing loan
Fixes QuorumCredit#14 - Replace raw .is_none() storage check with has_active_loan() so repaid or defaulted loan records no longer permanently block vouch withdrawal - Return ContractError::PoolBorrowerActiveLoan instead of panicking - Return ContractError::UnauthorizedCaller when voucher not found - Add require_not_paused guard - Emit vouch/withdrawn event on success - Change return type to Result<(), ContractError>
… balance Fixes QuorumCredit#15 - Add total_yield field to LoanRecord, locked in at disbursement - Borrower now repays loan.amount + loan.total_yield total - outstanding = (amount + total_yield) - amount_repaid - Vouchers receive stake + proportional yield funded entirely by borrower - Removes pre-funded balance dependency and InsufficientFunds balance check - Apply same total_yield calculation in create_loan_pool disbursement
Add a 60-second minimum age check on all vouches before a loan can be requested. Vouches used in the same transaction (or block) as the loan request share an identical ledger timestamp, so the check now < vouch_timestamp + MIN_VOUCH_AGE → VouchTooRecent reliably blocks the vouch → request_loan → repay flash-loan pattern. Changes: - Add MIN_VOUCH_AGE = 60 constant - Add ContractError::VouchTooRecent (variant 14) - Enforce age check in request_loan after min_vouchers guard - Add advance_past_vouch_age() test helper - Update all existing tests to advance the clock between vouch and loan - Add test_request_loan_rejects_vouch_too_recent - Add test_request_loan_succeeds_after_vouch_age_elapsed
The upgrade() function already existed but had no tests and no documented upgrade process. This commit completes the feature. Contract: - upgrade(admin_signers, new_wasm_hash) calls env.deployer().update_current_contract_wasm() after verifying admin_threshold signatures — same multisig quorum as all other admin operations - Emits an 'upgrade' event with the new WASM hash for auditability - A single compromised admin key cannot unilaterally upgrade Tests added: - test_upgrade_rejected_without_admin_approval - test_upgrade_multisig_rejects_single_signer Docs: - README: full upgrade process documented (pause → install → upgrade → unpause) - Explains why admin_threshold is required and what the WASM hash represents
Admin functions previously had no on-chain audit trail. This adds
events to every state-mutating admin function:
- pause → ("admin", "pause", admin, timestamp)
- unpause → ("admin", "unpause", admin, timestamp)
- set_min_stake → ("admin", "minstake", admin, amount, timestamp)
- set_max_loan_amount → ("admin", "maxloan", admin, amount, timestamp)
- set_min_vouchers → ("admin", "minvchrs", admin, count, timestamp)
- set_config → ("admin", "config", admin, timestamp)
- set_protocol_fee → ("admin", "fee", admin, fee_bps, timestamp)
- set_reputation_nft → ("admin", "repnft", admin, nft_contract, timestamp)
- slash_treasury → ("admin", "treasury", admin, recipient, amount, timestamp)
upgrade and slash already emitted events — unchanged.
Tests added for every new event.
Admin actions (slash, config changes) previously took effect instantly, giving users no time to react. This adds a two-phase timelock: propose_action(admin_signers, action) -> proposal_id execute_action(admin_signers, proposal_id) [after TIMELOCK_DELAY] cancel_action(admin_signers, proposal_id) Constants: TIMELOCK_DELAY = 24 hours TIMELOCK_EXPIRY = 72 hours Supported actions (TimelockAction enum): Slash(borrower) - timelocked slash path SetConfig(config) - timelocked config update (covers admin transfer) Events: (tl, proposed) -> (id, proposer, eta) (tl, executed) -> (id, admin, timestamp) (tl, cancelled) -> (id, admin)
QuorumCredit#102) - Add set_max_loan_to_stake_ratio() admin function to update the ratio without requiring a full set_config() call - Add get_max_loan_to_stake_ratio() view function - Add 7 dedicated tests covering: - Default ratio value (150%) - Admin setter updates config - Zero ratio rejected - Loan at exact ratio limit succeeds - Loan exceeding ratio is rejected - Loan below ratio limit succeeds - Increasing ratio allows larger loans - Ratio enforced correctly with multiple vouchers
…edit#103) Security: a single compromised admin key can no longer unilaterally control slash, config, or treasury operations. Changes: - Add add_admin(): quorum-gated admin set expansion - Add remove_admin(): quorum-gated removal; blocked when removal would make the threshold unsatisfiable - Add rotate_admin(): atomic key rotation preserving count and threshold; the primary mitigation for a compromised key - Add set_admin_threshold(): quorum-gated threshold update - All four functions emit on-chain events for auditability - Add 22 dedicated multisig security tests covering: - Threshold enforcement (zero signers, below threshold, exact, above) - Non-admin signer rejection - add_admin: success, duplicate rejection, quorum requirement - remove_admin: success, unsatisfiable threshold guard, unknown address, quorum requirement - rotate_admin: success, same-address rejection, existing-admin-as-new rejection, unknown old admin, quorum requirement - set_admin_threshold: success, zero rejection, exceeds-count rejection, quorum requirement - End-to-end: rotated-in key can operate; rotated-out key is rejected - validate_admin_config: empty admins, duplicate admins, threshold > count - Document key management recommendations in CONTRIBUTING.md: recommended M-of-N configurations, hardware wallet guidance, rotation procedures, and a function reference table
…t_all_loans feature
…all-loans-paginated feat: implement get_all_loans paginated admin view (QuorumCredit#84)
…-field feat: add loan field
…en are non-zero addresses
… cannot be updated post-deploy
…ation for large vouch counts
…lash-function feat: add slash assertions
Closes QuorumCredit#23 Fix: initialize does not emit an event
Issue 24 Fix: initialize does not validate admin or token are non-zero addresses
Fix YIELD_BPS and SLASH_BPS hardcoded constants
Fixed Integer Overflow Risk in Total Stake Summation
…nt-timestamp-field feat: add repayment_timestamp
fix: validate token address implements SEP-41 on initialize
Feat/voucher cap per loan
- QuorumCredit#74: governance vote_slash with stake-weighted quorum auto-execution - QuorumCredit#75: loan_purpose field on LoanRecord, accepted in request_loan - QuorumCredit#76: multi-asset loan support (USDC/any token), allowed_tokens in Config - QuorumCredit#77: referral bonus for vouchers on successful borrower repayment
feat: implement issues QuorumCredit#74-QuorumCredit#77
euniceamoni
pushed a commit
that referenced
this pull request
May 29, 2026
test: add multi-token vouch test (XLM + USDC)
chukwudiikeh
pushed a commit
that referenced
this pull request
May 30, 2026
Add successor_admin to Config for fallback admin takeover
euniceamoni
pushed a commit
that referenced
this pull request
Jun 29, 2026
Closes #1 ## Summary Implements a fully functional real-time loan status dashboard for borrowers, displaying active loans, repayment progress, yield earned, and reputation tier with live updates streamed over socket.io WebSocket. ## New Files ### dashboard/src/stroops.ts - Exports `stroopsToXlm(stroops)` — converts stroop amounts (number | bigint) to XLM string with exactly 7 decimal places (e.g. 10_000_000 → "1.0000000") - Exports `xlmToStroops(xlm)` — converts XLM float to stroops integer (rounded) - Exports `STROOPS_PER_XLM = 10_000_000` constant - Handles 0, negative, large integers, and bigint inputs safely ### dashboard/src/loanSlice.ts - Redux Toolkit slice for loan state management - Types: `LoanRecord`, `VouchRecord`, `ReputationInfo`, `LoanStatus` - Actions: `upsertLoan` (add or update by id), `setLoans` (replace all), `setReputation`, `setConnected`, with `lastUpdated` timestamp tracking ### dashboard/src/store.ts - Configures Redux store with `loanReducer` - Exports `RootState` and `AppDispatch` types ### dashboard/src/useLoanSocket.ts - React hook using socket.io-client to connect to the loan-status server - Dispatches Redux actions on socket events: - `connect` → `setConnected(true)` - `disconnect` → `setConnected(false)` - `loan:update` → `upsertLoan` - `loan:list` → `setLoans` - `reputation` → `setReputation` - Emits `subscribe` with borrower address on mount - Supports optional `apiKey` in socket auth header - Cleans up and dispatches `setConnected(false)` on unmount ### dashboard/src/LoanCard.tsx - Displays a single `LoanRecord` with: - Borrower address, loan purpose - Principal and yield amounts converted from stroops to XLM (7 d.p.) - Repayment deadline - Status badge (Active / Repaid / Defaulted) with colour coding - Animated repayment progress bar capped at 100% - Fully accessible: `role="article"`, `role="progressbar"` with `aria-valuenow/min/max`, `aria-label` on status badge - Mobile-responsive flex layout ### dashboard/src/LoanStatusDashboard.tsx - Top-level component wrapping its own Redux `Provider` - Props: `borrower`, `wsUrl`, optional `apiKey` - Sections: live indicator, reputation tier/score, active loans, closed loans - Shows "Updated HH:MM:SS" timestamp from `lastUpdated` - Delegates WebSocket lifecycle to `useLoanSocket` ### dashboard/src/__tests__/loanDashboard.test.tsx - 33 tests across 4 suites (all passing): - `stroopsToXlm` — 8 cases: zero, one stroop, large value, bigint, negative, 7 d.p. precision, constant value, XLM-to-stroops rounding - `loanSlice` — 6 cases: setConnected, upsertLoan (add + update), setLoans, setReputation, lastUpdated tracking - `useLoanSocket` — 5 cases: connect/disconnect dispatch, loan:update, loan:list, subscribe emit; uses module-level vi.mock for socket.io-client - `LoanCard` — 11 cases: borrower, purpose, principal XLM, yield XLM, Active/Repaid/Defaulted badges, progress bar value, 0% edge, 100% cap, accessible article label ## Dependencies Added - socket.io-client — WebSocket client for real-time loan updates - @reduxjs/toolkit + react-redux — state management for loan data - tailwindcss — CSS utility framework (available for future Tailwind usage) - @types/socket.io-client — TypeScript types ## Test Results 63 tests passing (33 new + 12 AnalyticsDashboard + 18 analytics), 0 failing
euniceamoni
pushed a commit
that referenced
this pull request
Jun 29, 2026
feat: store custom attributes, stream yield, vouch groups, periodic payments
euniceamoni
pushed a commit
that referenced
this pull request
Jun 29, 2026
…ression-tests fix(contract): resolve 4 bugs and add incentive + regression test suites
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
closes QuorumCredit#105