Skip to content

[NF-01] [CONTRACT] Multi-Position Support Per Tier Vault (True Laddering) #76

Closed

Description

@wumibals

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) and DataKey::Position(Address, u32) (a struct with principal, shares, lock_until, checkpoint) to each locked tier vault.
  • deposit(user, amount) -> u32 creates a new position record and returns its position_id, instead of merging into a single slot.
  • withdraw(user, position_id) -> i128 and early_exit(user, position_id) -> i128 operate on one position at a time.
  • Add positions(user) -> Vec<Position> and keep balance(user)/shares(user) as aggregate sums across all of a user's positions for backward compatibility with existing callers (VaultRouter).
  • Update VaultRouter's deposit/withdraw/early_exit to pass through position_id where applicable.

Acceptance Criteria

  • A user can hold 2+ concurrent positions in the same tier vault with independent lock_until values
  • A second deposit does not alter the maturity of any prior position
  • withdraw/early_exit require a position_id and 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

  1. mftee commented on Jul 16, 2026

    @mftee
    Contributor

    Hey there, Kindly help assign me this issue. ETA 1 day.

  2. grantfox-oss commented on Jul 16, 2026

    @grantfox-oss

    🦊 GrantFox — @mftee has been assigned to this issue as part of the Official Campaign | FWC26 campaign!

    Next steps:

    1. Open a Pull Request referencing this issue (e.g., Closes #76)
    2. Your PR will be reviewed by the LadderMine maintainers

    Good luck! Track your progress on GrantFox.

  3. grantfox-oss commented on Jul 21, 2026

    @grantfox-oss

    🎉 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions