LIP-118 secured one side of the network. The other side still has one key holding everything

Summary. Livepeer’s payment protocol already contains the machinery to let a
sender authorise other addresses to sign its tickets. It is present in the codebase
and switched off. Turning it on would let a gateway’s funds be held by a Safe or
any contract account, while a hot key does the per-second signing.

The symmetry, which is the whole argument.

LIP-118 established that an address can act on behalf of another — reward
calling delegated, bounded, revocable on chain. The orchestrator side of the
network got materially safer
, because the key that performs the frequent action
stopped having to be the key that holds the stake.

The gateway side never got the same treatment. A gateway must keep a key online
to sign tickets many times a minute, and today that key is the sender — so the
key that has to be online is also the key holding the deposit and the reserve.

Remote signing helps and is worth doing. A signing machine that handles no media
has a far smaller attack surface. But it changes where the key runs, not what the
key controls.
The online key still commands the balance. That is a property of the
protocol, not of anyone’s deployment, and it is the part that can be fixed here.

So: the same principle LIP-118 established, applied to the other half of the
protocol.

What already exists in the code. In pm/sigverifier.go there is an
ApprovedSigVerifier — it recovers the address from a ticket signature and, if it
does not match the sender, asks the broker whether that address is an approved
signer
for the sender. The entire type is commented out. The live
DefaultSigVerifier does a plain ECDSA recover and requires the recovered address
to equal the sender. The Broker interface declares no ApproveSigners, and the
deployed TicketBroker ABI has no such function.

The design anticipated this. It was never finished.

What it unlocks.

Custody. A gateway’s deposit and reserve held by a Safe. Compromise of a
signing key then costs the tickets it can sign before removal — not the balance.

Rotation. A signer replaced by a transaction, rather than by moving funds to a new
sender and rebuilding the channel.

More than one operator. Several approved signers for one sender, so a gateway
survives an operator being unavailable without anybody sharing a key.

Collectives. A Safe with two or more owners funding a gateway that neither owner
individually controls — two people sharing a broadcast’s cost, a venue and a
producer splitting a bill, a group funding a public service. Today every Livepeer
payment channel is owned by exactly one private key on one machine. That is a limit
on who can participate, not only on how safely.

There is a working precedent next door. Swarm’s Volume Registry separates
owner, payer and chunk signer as distinct on-chain roles: one party pays
for storage, a different party writes to it, neither can do the other’s job. I have
that running — a Safe owns and funds storage that a separate operator key writes to.
The shape is proven; Livepeer is missing only the approved-signer half.

Scope, as far as I can tell. Restoring ApprovedSigVerifier is roughly forty
lines that already exist. The contract side needs an approved-signer registry and
the Broker interface extended to read it. I am not close enough to the contracts
to estimate that half honestly, and would rather be corrected than guess.

A design question I cannot answer. Should approval be per-sender-per-signer, or
should a sender nominate a contract that decides? The second is more flexible and
much more to review.

What I can contribute. I run a gateway that pays orchestrators directly from one
key, and I have the Safe-and-delegated-writer half working on the storage side. I am
happy to test, to write the client half, or to be told this is the wrong shape and
why.

1 Like

Forum reply — amending the proposal after Doug’s critique

For the existing thread. Unwrapped for pasting.


Correcting the custody claim, and a better version of the proposal

Doug has pointed out that the central claim in my post does not hold as written, and I want to correct it in the thread rather than leave it standing.

What I claimed: that separating the signer from the sender means a compromised signing key costs “the tickets it can sign before it is removed — not the balance.”

Why that is wrong: a ticket’s faceValue is chosen by whoever signs it. So a compromised signing key signs one enormous ticket and takes the deposit. Splitting custody, on its own, does not protect the deposit at all.

What does survive, and it is narrower than I said: the reserve is protected. Withdrawal stays with the account keyholder, so a compromised signing key cannot pull the reserve even though it can sign. That is a real benefit and it is half of what I claimed.

The stronger proposal, which is Doug’s

His suggestion, in a parenthesis: put a limit on ticket size from the signing key.

That changes what an approved-signer registry is for. Instead of recording whether an address may sign for a sender, it records how much a signature from that address may be worth. Bounded delegation rather than binary delegation.

And that is a better mechanism than the one I proposed, for a reason worth stating plainly: it makes the loss ceiling explicit rather than making it a function of how quickly somebody notices a compromise and gets a revocation transaction mined. With a cap, the worst case is a number you chose in advance. Without one, the worst case is your reaction time.

It also composes with the reserve behaviour rather than replacing it. Cap bounds the deposit; withdrawal delay protects the reserve. Together they cover both halves of a sender’s balance, and neither covers both alone.

An open design question

Where does the cap live? My instinct is that it belongs with the approval — the sender sets a maximum when authorising a signer, and the verifier only checks it — rather than being a parameter of the verifier itself. That keeps the authority with the party whose money it is, and means changing a cap is the same kind of action as granting or revoking.

But I am not close enough to the contracts to argue that. It may be cleaner in the broker, or as a per-sender rather than per-signer bound. Interested in views from anyone who is.

A caveat on the ground this stands on

Doug also flagged that the deposit/reserve model may be rethought under an uncapped node operator set in 2.0: the reserve exists to secure against double spends across a limited orchestrator set, and that reasoning does not hold if the set is unlimited.

Worth surfacing before anyone builds on it. If the reserve goes, then the reserve half of the argument above goes with it — and what remains is the deposit and the cap, which is also the half that does the real work. I would rather this thread be about the durable part.

Where this leaves the ask

Still small, and now more precise. ApprovedSigVerifier exists in pm/sigverifier.go and is commented out; the Broker interface declares no ApproveSigners and the deployed ABI has no such function. The change is no longer “restore the commented-out type” but “restore it with an amount attached” — which is more contract work than I first suggested and a better thing to build.

I would rather have a correct proposal than my proposal. Thanks to Doug for the correction; the version above is his.