Skip to content

feat: add VaultV2.depositFor() for Trial Market Program treasury seeding#7

Merged
MrTalecky merged 1 commit into
mainfrom
feat/vault-deposit-for-treasury
Mar 1, 2026
Merged

feat: add VaultV2.depositFor() for Trial Market Program treasury seeding#7
MrTalecky merged 1 commit into
mainfrom
feat/vault-deposit-for-treasury

Conversation

@MrTalecky

Copy link
Copy Markdown
Member

Summary

Implements the treasury seeding mechanism required by the Trial Market Program (see flipcoin-app docs/TRIAL_MARKET_PROGRAM.md §8.1).

The problem: VaultV2.deposit() only credits msg.sender. The platform treasury could not top up another user's vault balance, so the factory's pullForNewMarket(creator, market, seed) would fail for free trial markets where the creator has $0.

The solution: depositFor(address recipient, uint256 amount) — a treasury-only function that deposits USDC on behalf of a recipient.

Changes

  • contracts/v2/interfaces/Types.sol — adds LedgerReason.PlatformSeed for audit trail clarity
  • contracts/v2/VaultV2.sol:
    • address public treasury state variable
    • NotTreasury error, TreasuryUpdated event, onlyTreasury modifier
    • depositFor(address recipient, uint256 amount) external nonReentrant whenNotPaused onlyTreasury
    • setTreasury(address) external onlyAdmin
  • test/VaultV2.t.sol — 13 new tests (30 total)

Full trial market seeding flow (after this PR)

admin.setTreasury(TRIAL_TREASURY_ADDRESS)
treasury.approve(vault, type(uint256).max)  // one-time setup

// Per trial market:
treasury → vault.depositFor(creator, 30_USDC)   // top up creator balance
factory  → vault.pullForNewMarket(creator, market, 30_USDC)  // seed market

Security properties

  • onlyTreasury — only the configured treasury address can call
  • nonReentrant — reentrancy protection
  • whenNotPaused — respects global pause
  • Global invariant preserved: USDC.balanceOf(vault) >= totalBalances + splitReserve + feePool
  • Treasury can be cleared (setTreasury(address(0))) to disable the mechanism

Test plan

  • forge test --match-contract VaultV2Test — 30/30 ✅
  • forge test — 387/387 ✅ (including fuzz invariants)
  • Fuzz: vault solvency invariant holds with depositFor in the mix

Adds a permissioned treasury seeding mechanism to VaultV2:

- `depositFor(address recipient, uint256 amount)` — allows a designated
  treasury EOA/multisig to top up any address's vault balance with USDC.
  Used by the Trial Market Program: treasury covers the $30 seed for
  trial market creators so factory.pullForNewMarket() can succeed.
- `setTreasury(address)` — admin-only function to configure the treasury.
- `NotTreasury` error and `TreasuryUpdated` event.
- `LedgerReason.PlatformSeed` added to Types.sol for audit trail clarity.

The function is protected by `onlyTreasury` modifier, `nonReentrant`,
and `whenNotPaused`. The global invariant is preserved (USDC transfer
increases totalBalances by the same amount).

Tests (13 new, 30 total in VaultV2Test):
- depositFor credits recipient, invariant holds, allows subsequent
  pullForNewMarket (full trial market seeding flow)
- reverts for non-treasury, unset treasury, zero amount, zero address,
  and when paused
- setTreasury: admin access, event emission, clear treasury

Related: flipcoin-app docs/TRIAL_MARKET_PROGRAM.md §8.1

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@MrTalecky MrTalecky merged commit 992fc1e into main Mar 1, 2026
2 checks passed
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.

1 participant