deposit() at lib.rs:349 always credits the same address that authorizes and pays — user.require_auth(), the transfer(user → contract), and the balance credit all use one address. There is no way for one account to top up another account's vault. That blocks natural funding flows:
- a team/treasury wallet funding an employee's task budget,
- a sponsor pre-paying for a user,
- an onboarding/faucet flow that seeds a brand-new user before they hold any USDC.
Goal
Add deposit_for(env, from, beneficiary, asset, amount) -> Result<(), VaultError> that separates the payer (from) from the beneficiary who is credited in the vault.
Requirements & constraints
- Only
from authorizes (from.require_auth()); the beneficiary does not sign.
- The beneficiary's
UserConfig and UserAssetAccount are created if they don't exist yet (funding a user with no prior vault activity must work).
- Enforce the same guards as
deposit: not-paused, positive amount, supported asset.
deposit's existing behavior must not change. Strongly prefer refactoring deposit to delegate to deposit_for(env, user, user, asset, amount) so the credit logic lives in one place.
Design decisions left to the implementer
- Event semantics.
DepositEvent currently keys on the credited user — that should stay the beneficiary so task/deposit history remains consistent. Decide whether to also record the payer (e.g. a funded_by topic); if it complicates the event schema, defer it and note the follow-up.
Edge cases to consider
- Funding a beneficiary who has never interacted with the vault (no config, no asset account).
- Funding an existing beneficiary who already has a balance in that asset.
- Pause active / non-positive amount / unsupported asset — all must reject.
Acceptance criteria
Notes for contributors
If you'd like to work on this, comment below so we can assign it to you.
Questions welcome — see CONTRIBUTING.md for setup
and workflow.
deposit()atlib.rs:349always credits the same address that authorizes and pays —user.require_auth(), thetransfer(user → contract), and the balance credit all use one address. There is no way for one account to top up another account's vault. That blocks natural funding flows:Goal
Add
deposit_for(env, from, beneficiary, asset, amount) -> Result<(), VaultError>that separates the payer (from) from the beneficiary who is credited in the vault.Requirements & constraints
fromauthorizes (from.require_auth()); the beneficiary does not sign.UserConfigandUserAssetAccountare created if they don't exist yet (funding a user with no prior vault activity must work).deposit: not-paused, positive amount, supported asset.deposit's existing behavior must not change. Strongly prefer refactoringdepositto delegate todeposit_for(env, user, user, asset, amount)so the credit logic lives in one place.Design decisions left to the implementer
DepositEventcurrently keys on the credited user — that should stay the beneficiary so task/deposit history remains consistent. Decide whether to also record the payer (e.g. afunded_bytopic); if it complicates the event schema, defer it and note the follow-up.Edge cases to consider
Acceptance criteria
deposit_for(from, beneficiary, asset, amount)debitsfrom, creditsbeneficiaryfromauthorizes; beneficiary does not signDepositEventrecords the beneficiary as the credited userdepositbehavior unchanged (ideally via delegation, verified by existing deposit tests passing)cargo testandcargo clippy --all-targets -- -D warningspassNotes for contributors
If you'd like to work on this, comment below so we can assign it to you.
Questions welcome — see CONTRIBUTING.md for setup
and workflow.