Skip to content

feat(contracts): savings inheritance (#439) and savings challenge contracts (#442) - #488

Merged
nayt9 merged 2 commits into
stowp:mainfrom
Peace-001:feat/savings-inheritance-and-challenges
Oct 24, 2026
Merged

nayt9 merged 2 commits into
stowp:mainfrom
Peace-001:feat/savings-inheritance-and-challenges

Conversation

@Peace-001

Copy link
Copy Markdown

Summary

Closes #439
Closes #442

Adds two new Soroban smart-contract features to the savings vault, each following the same patterns (storage, error codes, events, TTL management) established by the existing modules.


Issue #439 — Savings Inheritance

New file: contracts/savings-vault/src/inheritance.rs

Lets a flexible-savings account owner designate beneficiaries who can claim the balance if the owner becomes inactive.

Feature breakdown

Requirement Implementation
Beneficiary designation designate_beneficiary(owner, beneficiary, share_bps) — adds or updates a beneficiary's share. Multiple calls build up a plan; shares must eventually sum to 10_000 bps (100%) for a claim to succeed.
Inactivity timeout set_inactivity_timeout(owner, timeout_seconds) — configures how long the owner must be inactive before beneficiaries can claim. Zero disables inheritance.
Activity tracking inheritance::touch_owner is called by flexible::deposit and flexible::withdraw to reset the inactivity clock on every owner interaction.
Claim process claim_inheritance(claimer, owner) — verifies: plan exists, timeout > 0, elapsed, shares sum to 10 000, caller is a beneficiary. Pays each beneficiary their proportional share atomically and zeros the flexible account.
Remove beneficiary remove_beneficiary(owner, beneficiary)

Storage

DataKey::Inheritance(Address) — persistent, TTL bumped on every read/write.

Errors used

CooldownActive (timeout not elapsed or zero), InvalidShares (shares ≠ 10 000), Unauthorized (caller not a beneficiary), NotFound, InsufficientBalance, Overflow, DivisionByZero.

Events

inherit_benef_set, inherit_benef_rm, inherit_timeout_set, inherit_claimed.

Tests (9)

  • Designate single beneficiary
  • Designate two beneficiaries with split
  • Update existing beneficiary share
  • Reject zero or >10 000 bps
  • Set timeout stores value
  • Claim succeeds after timeout
  • Claim rejected before timeout elapsed
  • Claim rejected for non-beneficiary
  • Claim rejected when shares ≠ 10 000
  • Claim rejected when timeout is zero
  • Deposit resets inactivity clock (prevents early claim)
  • Multi-beneficiary proportional payout (60/40)

Issue #442 — Savings Challenge Contracts

New file: contracts/savings-vault/src/challenge.rs

A fixed-duration savings competition: participants race to save a target amount by a deadline. First to verify wins the prize pool (sum of all entry fees). No winner → refund.

Feature breakdown

Requirement Implementation
Challenge creation create(creator, target_amount, entry_fee, deadline, min_participants) — creator pays the entry fee and becomes the first participant. Returns challenge id.
Join join(participant, challenge_id) — pays entry fee, adds to participant list. Deadline and duplicate checks enforced.
Save save(participant, challenge_id, amount) — deposits toward the caller's personal target. Tracked per-participant inside the Challenge record.
Verification & winner payout claim_winner(participant, challenge_id) — verifies on-chain that participant.saved >= target_amount AND participants.len() >= min_participants. Pays the full prize pool to the winner.
Expired refund refund_expired(caller, challenge_id) — permissionless after deadline. Returns each participant's fee_paid + saved individually.

Storage

DataKey::Challenge(u64) — persistent, TTL bumped. DataKey::NextChallengeId — instance counter.

Types added

ChallengeStatus (Open / Won / Expired), ChallengeParticipant, Challenge.

Errors used

InvalidAmount, InvalidTimestamp, InvalidParameters, NotFound, GroupClosed, OperationExpired, MemberAlreadyExists, NotAMember, GoalNotReached, TimeWindowNotOpen, Overflow.

Events

challenge_created, challenge_joined, challenge_saved, challenge_won, challenge_expired.

Tests (10)

  • Create returns id
  • Create rejects past deadline
  • Create rejects min_participants < 2
  • Join adds participant and grows prize pool
  • Join duplicate rejected
  • Join after deadline rejected
  • Save updates participant progress
  • Claim winner pays full prize pool
  • Claim rejected when target not met
  • Claim rejected when min_participants not met
  • Refund expired returns fees + savings to all participants
  • Refund before deadline rejected

Files changed

File Type Change
contracts/savings-vault/src/inheritance.rs New Inheritance module (beneficiary, timeout, claim)
contracts/savings-vault/src/challenge.rs New Challenge module (create, join, save, verify, payout, refund)
contracts/savings-vault/src/types.rs Modified Beneficiary, InheritancePlan, ChallengeStatus, ChallengeParticipant, Challenge types; DataKey::Inheritance, DataKey::Challenge, DataKey::NextChallengeId variants
contracts/savings-vault/src/lib.rs Modified Module declarations + public entrypoints for both features
contracts/savings-vault/src/events.rs Modified Event topic constants for inheritance and challenge events

@vercel

vercel Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
stow Error Error Oct 24, 2026 6:32pm UTC

@nayt9
nayt9 merged commit 4d77e8b into stowp:main Oct 24, 2026
1 check was pending

This branch had an error being deployed

1 failed deployment
Preview — 79ebe097 Deployed Oct 24, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Create savings challenge contracts Create savings inheritance feature

3 participants