Summary
Gateways (ticket senders) currently must unlock and withdraw deposit and reserve together. Gateways that want to reclaim idle deposit while keeping reserve funded for ticket coverage cannot do so without also unlocking (and eventually withdrawing) their reserve.
At minimum, TicketBroker should support unlocking / withdrawing deposit funds separately from reserve. Optionally, deposit withdrawal could skip (or use a shorter) unlock period, since reserve is what covers winning tickets claimed during the unlock / following-round window.
Current behavior
In MixinTicketBrokerCore:
Sender has a single withdrawRound shared by deposit + reserve.
unlock() starts one unlock that applies to both balances.
withdraw() always clears both sender.deposit and the sender's reserve (clearReserve), then transfers the sum.
- Ticket redemption requires the sender to be locked (
isLocked), and pays from deposit first, then reserve when face value exceeds deposit.
// withdraw() — deposit and reserve are inseparable today
sender.deposit = 0;
clearReserve(msg.sender);
withdrawTransfer(payable(msg.sender), deposit.add(reserve));
Funding paths already treat deposit and reserve independently (fundDeposit, fundReserve, fundDepositAndReserve), but unlock/withdraw do not.
Motivation
- Capital efficiency for gateways — A gateway may hold more deposit than needed for day-to-day ticket face values while keeping reserve sized for worst-case / following-round claims. Today, reclaiming excess deposit forces unlocking reserve too, which either:
- blocks further ticket redemptions once the unlock completes (
sender is unlocked), or
- requires cancelling unlock / re-funding to stay operational.
- Reserve already covers the lock-period risk — The unlock period exists so tickets created before unlock can still be redeemed afterward. Reserve is the mechanism that covers claims when deposit is exhausted during that window (and for the following round). If reserve remains locked and funded, withdrawing deposit does not remove that safety net.
- Symmetric with funding API — Deposit and reserve can already be funded independently; unlock/withdraw should match that model.
Proposed requirements
Minimum (required)
- Support unlocking / withdrawing deposit only, without clearing or unlocking reserve.
- Reserve-only unlock/withdraw can remain as today, or stay coupled only when the sender explicitly unlocks both.
- Preserve existing security invariants for reserve:
- Reserve still subject to unlock period before withdrawal.
- Sender remains locked for ticket redemption as long as reserve (and any remaining deposit policy) requires it — exact locking rules to be specified in design.
- Events / getter updates so indexers and UIs can distinguish deposit vs reserve unlock/withdraw.
Stretch / discuss
- Allow immediate (or shorter-period) deposit withdrawal while reserve stays locked, on the rationale that reserve covers tickets claimed in the unlock / following round.
- If deposit can be withdrawn without a lock period, document how redemption behaves when deposit is zero but reserve is still locked and funded (already partially supported: redemption allows
deposit == 0 if remainingReserve > 0).
Design questions
- API shape — e.g.
unlockDeposit() / withdrawDeposit() vs parameterized unlock(UnlockTarget) / withdraw(WithdrawTarget)?
- Locking semantics — If deposit is withdrawn but reserve remains, should
isLocked stay true solely based on reserve state (likely yes, so tickets remain redeemable)?
- Partial deposit withdraw — Withdraw full deposit only, or allow withdrawing an amount up to
sender.deposit?
- Self-funding cancel behavior — Today, funding deposit/reserve as the sender cancels an in-progress unlock. How should that interact with separate deposit vs reserve unlocks?
- Upgrade path — Proxy upgrade of
TicketBroker target; any storage layout changes for separate withdraw rounds?
Acceptance criteria
References
contracts/pm/mixins/MixinTicketBrokerCore.sol — unlock, withdraw, redeemWinningTicket, Sender
contracts/pm/mixins/MixinReserve.sol — reserve claim / clear semantics
- Repo: https://github.com/livepeer/protocol
Summary
Gateways (ticket senders) currently must unlock and withdraw deposit and reserve together. Gateways that want to reclaim idle deposit while keeping reserve funded for ticket coverage cannot do so without also unlocking (and eventually withdrawing) their reserve.
At minimum,
TicketBrokershould support unlocking / withdrawing deposit funds separately from reserve. Optionally, deposit withdrawal could skip (or use a shorter) unlock period, since reserve is what covers winning tickets claimed during the unlock / following-round window.Current behavior
In
MixinTicketBrokerCore:Senderhas a singlewithdrawRoundshared by deposit + reserve.unlock()starts one unlock that applies to both balances.withdraw()always clears bothsender.depositand the sender's reserve (clearReserve), then transfers the sum.isLocked), and pays from deposit first, then reserve when face value exceeds deposit.Funding paths already treat deposit and reserve independently (
fundDeposit,fundReserve,fundDepositAndReserve), but unlock/withdraw do not.Motivation
sender is unlocked), orProposed requirements
Minimum (required)
Stretch / discuss
deposit == 0ifremainingReserve > 0).Design questions
unlockDeposit()/withdrawDeposit()vs parameterizedunlock(UnlockTarget)/withdraw(WithdrawTarget)?isLockedstay true solely based on reserve state (likely yes, so tickets remain redeemable)?sender.deposit?TicketBrokertarget; any storage layout changes for separate withdraw rounds?Acceptance criteria
unlock/withdrawbehavior is either preserved (both) or clearly migrated with tests.References
contracts/pm/mixins/MixinTicketBrokerCore.sol—unlock,withdraw,redeemWinningTicket,Sendercontracts/pm/mixins/MixinReserve.sol— reserve claim / clear semantics