After systematic search, there are THREE main yield-tier entry points that accept parameters:
- Location: lib.rs, line 1810
- Parameters related to yield tiers:
yield_bps: i64- base escrow yield in basis pointsyield_tiers: Option<Vec<YieldTier>>- optional tier configurationprotocol_fee_bps: Option<i64>- protocol fee in basis points (NEW, added to validate)
- Location: lib.rs, line 3904
- Parameters related to yield tiers:
committed_lock_secs: u64- investor's lock duration for tier selection
- Location: lib.rs, line 2738
- Parameters:
amount: i128- funding amount (currently unused in logic)lock: u64- lock duration for tier selection
Existing error codes that are ALREADY VALIDATED:
TierYieldOutOfRange = 10- Tier yield_bps not in0..=10_000TierYieldBelowBase = 11- Tier yield_bps < base yield_bpsTierLockNotIncreasing = 12- Tier min_lock_secs not strictly increasingTierYieldNotNonDecreasing = 13- Tier yield_bps not non-decreasingYieldBpsOutOfRange = 2- Base yield_bps not in0..=10_000ProtocolFeeBpsOutOfRange = 215- Protocol fee not in0..=10_000
Current validation location: validate_yield_tiers_table() (lib.rs, line 1711)
Currently validated: YES
- Existing check:
(0..=10_000).contains(&yield_bps)at line 1838 - Error code:
YieldBpsOutOfRange = 2 - Derived reasoning:
- Basis points convention: 1 bps = 0.01% = 1/10,000
- Maximum: 10,000 bps = 100% = valid full-amount yield
- Minimum: 0 bps = 0% = valid zero yield (passive bond)
- Used in:
compute_investor_payout()(line 2640) →coupon = principal * yield / 10_000 - Arithmetic:
i128::MAX * 10_000 / 10_000 = i128::MAX✓ no overflow - Arithmetic:
0 * yield / 10_000 = 0✓ safe
- Status: Already properly bounded
Currently validated: YES
- Existing check:
(0..=10_000).contains(&protocol_fee_bps)at line 1850 - Error code:
ProtocolFeeBpsOutOfRange = 215 - Derived reasoning:
- Same basis points convention as yield_bps
- Maximum: 10,000 bps = 100% = route all SME payout to treasury
- Minimum: 0 bps = 0% = no fee (default)
- Used in:
withdraw()(line 4225+) → fee calculation splits SME payout - Arithmetic: Same overflow safety as yield_bps
- Status: Already properly bounded
Currently validated: YES (but at per-tier level)
- Existing checks in
validate_yield_tiers_table():- Per-tier
yield_bpsin0..=10_000→TierYieldOutOfRange = 10 - Per-tier
yield_bps >= base_yield→TierYieldBelowBase = 11 min_lock_secsstrictly increasing →TierLockNotIncreasing = 12yield_bpsnon-decreasing →TierYieldNotNonDecreasing = 13
- Per-tier
- Missing: No validation on individual tier
min_lock_secsrange!- Issue:
min_lock_secsis au64(unsigned 64-bit) - Min valid: 0 (no minimum lock)
- Max valid:
u64::MAX(18,446,744,073,709,551,615 seconds ≈ 584 billion years) - Actual risk:
min_lock_secsis only used for comparison ineffective_yield_for_commitment()(line 1778)if committed_lock_secs >= t.min_lock_secs- Pure comparison, no arithmetic, no overflow risk
- Conclusion:
u64range is inherently safe; no additional bounds needed
- Issue:
- Status: Already properly bounded
Currently PARTIALLY validated:
- Existing check:
CommitmentLockExceedsMaturity = 111at line 4126- Validates:
now + committed_lock_secsmust not exceed escrow maturity
- Validates:
- Missing: Validation that
committed_lock_secsitself is reasonable - Analysis:
- Min valid: 0 seconds (no lock commitment)
- Max valid: Should be bounded to prevent overflow when added to current timestamp
- Safe maximum:
u64::MAX(no arithmetic danger in effective_yield_for_commitment) - But logically: should not lock investor past escrow maturity
- Already checked:
CommitmentLockExceedsMaturityguard preventsnow + committed_lock_secs > maturity
- Safe maximum:
- Used in:
effective_yield_for_commitment()(line 1778) → pure comparison - Used in: Setting
InvestorClaimNotBefore(line 4122) →now + committed_lock_secs - Overflow check: Line 4124 checks
checked_add→ already guarded withInvestorClaimTimeOverflow
- Conclusion: All arithmetic is already guarded;
u64range is safe - Status: Already properly bounded at critical points
Currently NOT validated:
- What it does: Parameter is explicitly unused (line 2740:
let _ = amount) - Why it exists: Signature parity with
fund_with_commitment()for API consistency - Risk: Zero (not used in any logic)
- Conclusion: No validation needed
- Status: No validation required (intentionally unused)
Currently NOT validated as standalone parameter:
- What it does: Passed to
effective_yield_for_commitment()(line 2742) - Risk analysis:
- Used in comparison only:
committed_lock_secs >= t.min_lock_secs(line 1778) - Returns tuple
(i64, u64)with best yield and best_lock - No arithmetic, no overflow, pure comparison logic
- Used in comparison only:
- Conclusion:
u64::MAXis safe; no additional bounds needed - Status: No validation required (pure comparison logic)
- ✅
init()::yield_bps- validated to0..=10_000 - ✅
init()::protocol_fee_bps- validated to0..=10_000 - ✅
init()::yield_tierstable structure - all checks in place - ✅
fund_with_commitment()::committed_lock_secs- guarded by maturity overflow check - ✅
preview_yield_tier()::lock- used in pure comparison only
⚠️ preview_yield_tier()::amount- intentionally unused, no risk⚠️ fund_with_commitment()::committed_lock_secs- already guarded by maturity check
Issue: Current validation in validate_yield_tiers_table() (called from init()) is GOOD.
However, there's no documentation on what makes a "valid" tier table.
Missing Documentation:
- The function
validate_yield_tiers_table()lacks comprehensive rustdoc - The error conditions could be better documented in the init() function docs
- No doc comments explaining the constraints
STATUS: Yield-tier bounds validation is already comprehensive. The existing code already:
- Validates base
yield_bpsto0..=10_000 - Validates protocol fee to
0..=10_000 - Validates all tier
yield_bpsto0..=10_000 - Validates tier
yield_bps >= base_yield - Validates tier
min_lock_secsstrictly increasing - Validates tier
yield_bpsnon-decreasing - Prevents
committed_lock_secsfrom exceeding maturity - Prevents overflow in investor claim-not-before calculations
What's Missing:
- Documentation: The bounds are not explicitly documented in rustdoc
- Visibility: Error codes are typed but constraints not clearly explained in function docs
Action for Issue #807:
- Add comprehensive rustdoc to
init()explaining all yield-tier validation rules - Add rustdoc to
fund_with_commitment()explaining lock-secs constraints - Add rustdoc to
preview_yield_tier()explaining parameters and bounds - Add rustdoc to
validate_yield_tiers_table()(currently private, but should be explicit) - Optionally: Add validation tests to explicitly cover boundary cases
| Parameter | Function | Valid Range | Derivation | Error Code |
|---|---|---|---|---|
yield_bps |
init() |
0..=10_000 |
Basis points; 10_000 = 100%; math uses / 10_000 | YieldBpsOutOfRange |
protocol_fee_bps |
init() |
0..=10_000 |
Basis points; same convention as yield_bps | ProtocolFeeBpsOutOfRange |
Tier yield_bps |
init() |
0..=10_000 |
Basis points; >= base_yield | TierYieldOutOfRange |
Tier min_lock_secs |
init() |
0..=u64::MAX |
u64 natural range; only used in comparison (no arithmetic) | N/A (already safe) |
committed_lock_secs |
fund_with_commitment() |
0..=u64::MAX |
u64 natural range; guarded by maturity check | CommitmentLockExceedsMaturity |
lock |
preview_yield_tier() |
0..=u64::MAX |
u64 natural range; pure comparison logic | N/A (already safe) |
amount |
preview_yield_tier() |
Any i128 |
Unused parameter; no validation needed | N/A |