Repository navigation
[NF-01] [CONTRACT] Multi-Position Support Per Tier Vault (True Laddering) #76
Description
Overview
The protocol is named YieldLadder, but no vault currently lets a single user hold multiple independent positions in the same tier with staggered maturities — the core idea of a bond/CD ladder. This issue adds real multi-position support to vault_l3, vault_l6, and vault_l12.
Problem
Each locked tier vault stores exactly one balance record per user: DataKey::Balance(Address), DataKey::Shares(Address), DataKey::LockUntil(Address). In the current deposit():
let current_balance = ...Balance(user.clone())... .unwrap_or(0);
env.storage().persistent().set(&DataKey::Balance(user.clone()), &(current_balance + amount));
...
let lock_until = env.ledger().sequence() + lock_duration;
env.storage().persistent().set(&DataKey::LockUntil(user.clone()), &lock_until);A second deposit into the same tier merges principal/shares into the same slot and overwrites LockUntil with a fresh now + lock_duration for the entire combined balance — the first deposit's original maturity date is lost. Users cannot actually build a ladder of staggered maturities within one tier today.
Proposed Solution
- Add
DataKey::PositionCount(Address)andDataKey::Position(Address, u32)(a struct withprincipal,shares,lock_until,checkpoint) to each locked tier vault. deposit(user, amount) -> u32creates a new position record and returns itsposition_id, instead of merging into a single slot.withdraw(user, position_id) -> i128andearly_exit(user, position_id) -> i128operate on one position at a time.- Add
positions(user) -> Vec<Position>and keepbalance(user)/shares(user)as aggregate sums across all of a user's positions for backward compatibility with existing callers (VaultRouter). - Update
VaultRouter'sdeposit/withdraw/early_exitto pass throughposition_idwhere applicable.
Acceptance Criteria
- A user can hold 2+ concurrent positions in the same tier vault with independent
lock_untilvalues - A second deposit does not alter the maturity of any prior position
-
withdraw/early_exitrequire aposition_idand only affect that position -
positions(user)returns all of a user's open positions in the tier with correct principal/shares/lock_until per entry -
balance(user)/shares(user)aggregate correctly across all open positions - Unit tests cover: two deposits with different lock_until, independent withdrawal of one position while the other remains locked, early_exit of one position not affecting others
Activity
mftee commentedon Jul 16, 2026
Hey there, Kindly help assign me this issue. ETA 1 day.
grantfox-oss commentedon Jul 16, 2026
🦊 GrantFox — @mftee has been assigned to this issue as part of the Official Campaign | FWC26 campaign!
Next steps:
Closes #76)Good luck! Track your progress on GrantFox.
grantfox-oss commentedon Jul 21, 2026
🎉 This issue has been marked as completed on GrantFox as part of the Official Campaign | FWC26 campaign!
@mftee's PR #131 was approved and merged by @wumibals.
🏆 @mftee: You earned 35 FoxPoints for this contribution! Your current tier: Explorer (939 total points). Track your full progress on GrantFox.
👏 Great work, @mftee! Keep contributing to LadderMine.