# Livepeer Testnet Implementation Proposal

**URL:** <https://forum.livepeer.org/t/livepeer-testnet-implementation-proposal/3322>\
**Category:** Protocol\
**Created:** [July 31, 2026, 6:03pm UTC](https://forum.livepeer.org/t/livepeer-testnet-implementation-proposal/3322 "2026-07-31T18:03:49Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![drieddate\_sidestream](https://avatars.discourse-cdn.com/v4/letter/d/8e7dd6/32.png) [@drieddate\_sidestream](https://forum.livepeer.org/u/drieddate_sidestream)\
**Post date:** [July 31, 2026, 6:03pm UTC](https://forum.livepeer.org/t/livepeer-testnet-implementation-proposal/3322/1 "2026-07-31T18:03:49Z")

</div>

## The problem

The original [SPE proposal](https://forum.livepeer.org/t/proposal-protocol-r-d-special-purpose-entity/3160) mentioned Testnet development as one of the main deliverables; however, it didn’t specify enough requirements to immediately start working on its implementation. Instead, we had to first evaluate the existing tooling and the actual business need, collect input from community members through interviews we conducted in February, run our observations through the Livepeer Security Committee, collect feedback from a watercooler in March, and receive additional use cases from the Livepeer Foundation in April. After systematising all input, we are ready to propose and develop a new testnet approach for the Livepeer protocol.

## Research and what we found

### Terminology and testnet types

Testing a protocol can be done through different means. While some approaches are clearly outdated, some other solutions can be more useful for certain use cases. Here, we provide a summary of the available testnet types:

1. Local chain with fresh contracts (e.g., using `geth`)

2. Local chain with fresh contracts and cheat codes (e.g., using `anvil`)

3. Local fork with cheat codes (e.g., using `anvil --fork-url`)

4. Remote chain with fresh contracts (e.g., `Arbitrum Sepolia`)

5. Remote fork with cheat codes (`RPC_URL="tenderly.co/..."`)

6. Other Livepeer services are running over the _local fork_ or the _protocol testnet_. (`RPC_URL="tenderly.co/..." docker compose`)

### Existing tooling

Before proposing a new solution, we looked into which testnet-related tooling already exists and how it is being used by the community. TLDR: only type 1 and type 4 tooling were found, both of which are not maintained and outdated.

- The old [“contract addresses” documentation page](https://github.com/livepeer/docs/blob/de6026f63e2ec1bf11bb91f82facf1a86dbf2e39/v1/references/contract-addresses.mdx) listed two old _public testnets_ (type 4), none of which are functional:
  - [Arbitrum Rinkeby was deprecated in Q1 of 2024](https://docs.livepeer.org/v1/references/contract-addresses#arbitrum-rinkeby-confluence)
  - [Ethereum Rinkeby was also deprecated in Q1 2024](https://docs.livepeer.org/v1/references/contract-addresses#ethereum-rinkeby-confluence)

- There are hardhat-based scripts inside the protocol repository (such as [deploy/deploy\_contracts.ts](https://github.com/livepeer/protocol/blob/d03671e2e159bbc856feace83371876cf25124e3/deploy/deploy_contracts.ts#L379) and [deploy/deploy\_poll.ts](https://github.com/livepeer/protocol/blob/d03671e2e159bbc856feace83371876cf25124e3/deploy/deploy_poll.ts#L24)) to deploy some of the protocol contracts (prerequisite for type 1 approach).
  - Combined, those two scripts deploy and configure most contracts (`Controller`, `Minter`, `LivepeerToken`, `TicketBroker`, `JobsManager`, `SortedDoublyLL`, `BondingVotes`, `RoundsManager`, `ServiceRegistry`, `MerkleSnapshot`, `Governor`, `Treasury`, `LivepeerGovernor`, `BondingManager`, `PollCreator`).
    - [`LivepeerTokenFaucet`](https://github.com/livepeer/protocol/blob/delta/contracts/token/LivepeerTokenFaucet.sol) is also deployed for non-production targets.

  - Difference with production or fork-based tests:
    - Some contracts are missing, compared with [the contracts in production](https://docs.livepeer.org/references/contract-addresses): `AIServiceRegistry`, `DelegatorPool`, `L2LPTDataCache`, `L2LPTGateway`, `L2Migrator`.
    - The script does not seem to configure Proxies for the contracts that have them in production.
    - The script uses hard-coded constructor arguments and other parameters, meaning that newly deployed contracts can be configured differently from those in production.

- There is a 4-year-old `livepeer/geth-with-livepeer-protocol` docker image with `geth` tool (type 1).
  - Mentioned in the [livepeer/go-livepeer/…/cmd/devtool/README.md](https://github.com/livepeer/go-livepeer/blob/f117b4423f8614c7475f0bb0c5071433c7037b87/cmd/devtool/README.md) guide. Still used by the go-livepeer team, according to our interview.
  - The [referenced Docker image](https://hub.docker.com/r/livepeer/geth-with-livepeer-protocol) was not updated for over 4 years, as well as [its source code](https://github.com/livepeer/docker-livepeer/tree/master/geth-with-protocol). The image [clones the protocol repo at a specific, very outdated commit](https://github.com/livepeer/docker-livepeer/blob/master/geth-with-protocol/build-protocol.sh#L7) [from 2022](https://github.com/livepeer/protocol/commit/3c01f3a3e8c494ea2f89b77d03eb0a68a4e15518), then runs [yarn deploy](https://github.com/livepeer/protocol/blob/3c01f3a3e8c494ea2f89b77d03eb0a68a4e15518/package.json#L10), which in turn runs deployment scripts described below ([deploy\_contracts.ts](https://github.com/livepeer/protocol/blob/3c01f3a3e8c494ea2f89b77d03eb0a68a4e15518/deploy/deploy_contracts.ts) and [deploy\_poll.ts](https://github.com/livepeer/protocol/blob/3c01f3a3e8c494ea2f89b77d03eb0a68a4e15518/deploy/deploy_poll.ts)). In other words, the Docker image also does not use fork-based testing, but deploys all contracts afresh into an empty geth network. Moreover, since the version of the script is pinned to a commit from 2022, it is even more outdated than the hardhat script outlined above: for example, it doesn’t deploy `Treasury` and `LivepeerGovernor` contracts.
  - The runtime command ([geth-with-protocol/start.sh](https://github.com/livepeer/docker-livepeer/blob/e0926d467043c03a6cc03e7050da8750b94da555/geth-with-protocol/start.sh)) seems to be outdated (pre-proof of stake) and does not enable any admin RPC methods. In other words, it’s not possible to “simulate” any state inside the node.

- We couldn’t find an official guide for the fork-based testing (type 3 approach).
  - The main [hardhat.config.ts](https://github.com/livepeer/protocol/blob/delta/hardhat.config.ts) inside `livepeer/protocol` has no “[forking](https://v2.hardhat.org/hardhat-network/docs/guides/forking-other-networks)” networks configured.
  - Only security fixes (PoC and Fix tests inside the repository) [suggest using fork-based tests](https://github.com/livepeer/protocol/blob/d03671e2e159bbc856feace83371876cf25124e3/src/test/BondingVotesFeeLessVotesFix.sol#L10) via `forge test —-fork-url` command.

- The private `livepeer/governor-scripts` repository has `simulate` command (that we implemented back in 2025) to create a fork-based testnet.

### Insights from the interviews

Community members generally seem to have no established or maintained _integration_ tests – tests that check that a tool or a service correctly interacts with the protocol – as it’s now assumed that the protocol is very stable (which is likely due to the protocol only receiving very few updates over the recent years).

- The most common concern that was brought up when asked about testnets is that many tools have testing dependencies beyond the protocol itself:
  - Example 1. The [Livepeer Explorer](https://github.com/livepeer/explorer) fetches most of its data from the [Subgraph](https://github.com/livepeer/subgraph). So, in addition to simply pointing the Explorer app to a testnet RPC endpoint, the team testing it also needs to start a local Subgraph instance against the same endpoint.
  - Example 2. To test their platform, Embody would require an orchestrator to be active on the testnet. So, in order to test the platform end-to-end, in addition to the protocol, they also need to start an instance of an orchestrator or multiple ones.

- Based on the above, the most common approach for testing products against the protocol is to manually check them against the mainnet network with a wallet that has a small amount of ETH for gas (and tickets). Notes:
  - Some protocol functionality (e.g., being in the earning pool, calling rewards, creating test-LIPs and treasury proposals) is, of course, not testable via this approach.
  - Since this approach uses actual mainnet ETH, it’s simply not suitable for the CI – it will be too expensive to run automated integration testing this way.

### Insights from the provided use-cases

Livepeer Foundation provided (in a private document) concrete use cases in which a testing environment will be beneficial. The main takeaways for this proposal:

- Certain testnet types are more beneficial for certain use cases. For example, most of the time, a local fork (type 3) is desired and sufficient for local testing of an external service. For example, to develop the Explorer or SubGraph, it’s sufficient to use a local fork and easily simulate test events using cheat codes.
- In other cases, it is beneficial to have a persistent sharable state of the protocol (type 5). For example, if a protocol upgrade will introduce breaking changes, each team (Go-client, Explorer, SubGraph, etc) would benefit from having a single command to test compatibility of their service against the new version of the protocol, instead of either waiting for the production update or locally replicating the update.
- Use cases that involve cross-team dependencies that require “product testnet” (type 6) are rare.

So overall, we’re fully aligned that there is no fit-for-all solution, and we need to make different approaches available for the different kinds of use cases. More specifically: make local fork-based testing (type 3) approachable and introduce a harness to create remote forks with protocol updates (type 5).

## Our proposal

Based on the above, we are proposing the following scope:

1. Sidestream will create a new public repository `livepeer/protocol-updates` for the protocol updates, which will replace the existing private repository lacking most of the described features. The new repository will include:

2. Sidestream will create a new public repository, conceptually replacing the outdated [geth-with-protocol](https://github.com/livepeer/docker-livepeer/tree/master/geth-with-protocol). It will include:

## Next steps

Sidestream will work on the two main deliverables outlined above. Once each is approved by the Foundation (or the Security Committee, where needed), we will open the repositories and publicly share them as a follow-up comment in this thread.

## Request for feedback

We’re curious to hear how the proposed changes will affect the teams we already spoke to, but also, especially, those we haven’t reached so far. Please let us know how you plan to use this setup or if you think your use case wasn’t accounted for yet.

---

<div class="post-metadata">

**Author:** ![dob](https://yyz2.discourse-cdn.com/flex030/user_avatar/forum.livepeer.org/dob/32/7_2.png) [@dob](https://forum.livepeer.org/u/dob)\
**Post date:** [August 3, 2026, 10:01pm UTC](https://forum.livepeer.org/t/livepeer-testnet-implementation-proposal/3322/2 "2026-08-03T22:01:27Z")

</div>

Thanks for providing this analysis, writeup, and recommendation. A couple quick thoughts…

1. I definitely encourage others to reveal any key use cases they have which are NOT covered by this proposal. It’s always been easy to “ask” for a full testnet, but not actually clear why people need one…so it is helpful to know exactly what people are trying to do that would not be covered by this.

2. Please keep in mind that the set of changes proposed in Livepeer 2.0 are pretty significant. As the final spec come out we’ll want to develop and test prototypes and migration mechanics, so it is worth taking into account that this approach is compatible with larger changes, as well as just incremental smaller ones. If it feels like there’s a better approach to support a larger protocol overhaul, it’s worth considering that now before wasting work on the incremental process. _Note, I’m using relative terms like “large”, but I’m referring to many logic and state changes deployed within the current protocol most likely - not an entirely new set of protocol state._

---

<div class="post-metadata">

**Author:** ![rickstaa](https://yyz2.discourse-cdn.com/flex030/user_avatar/forum.livepeer.org/rickstaa/32/917_2.png) [@rickstaa](https://forum.livepeer.org/u/rickstaa)\
**Post date:** [August 7, 2026, 8:11am UTC](https://forum.livepeer.org/t/livepeer-testnet-implementation-proposal/3322/3 "2026-08-07T08:11:31Z")

</div>

Hey @drieddate_sidestream,

Great to see this shared with the community. Thanks for taking my feedback into account and working actively with the community on a setup that covers most needs without the complexity of maintaining a separate protocol testnet.

I’m looking forward to using this setup across the clients, Explorer, and subgraph. I’ve had to work around a lot of testing limitations in the past, so this should make things much faster. I also know the initial version has already helped improve protocol release triage and security.

To echo Doug: if community members see any needs this proposal doesn’t cover, please share your feedback, so sidestream can take it into account during their implementation.

---

<div class="post-metadata">

**Author:** ![drieddate\_sidestream](https://avatars.discourse-cdn.com/v4/letter/d/8e7dd6/32.png) [@drieddate\_sidestream](https://forum.livepeer.org/u/drieddate_sidestream)\
**Post date:** [August 10, 2026, 7:31am UTC](https://forum.livepeer.org/t/livepeer-testnet-implementation-proposal/3322/4 "2026-08-10T07:31:34Z")

</div>

Thanks @dob for raising those concerns. To answer question 2, addressed at us: The proposed `livepeer/protocol-updates` repository structure will be better suited for larger protocol updates, as it will allow integration and sanity testing, not available in the current setup. Generally, the new structure (together with the adjusted process) should reduce the risk of protocol misconfiguration for an update of any size.

---

<div class="post-metadata">

**Author:** ![chrishobcroft](https://yyz2.discourse-cdn.com/flex030/user_avatar/forum.livepeer.org/chrishobcroft/32/1340_2.png) [@chrishobcroft](https://forum.livepeer.org/u/chrishobcroft)\
**Post date:** [August 14, 2026, 2:50pm UTC](https://forum.livepeer.org/t/livepeer-testnet-implementation-proposal/3322/6 "2026-08-14T14:50:08Z")

</div>

Strong support for this. The fork harness is exactly right for protocol and contract work, and having it maintained in a real repo is overdue.

One gap I’d like to raise, which may simply be out of scope: an Anvil fork is local and ephemeral. It gives one person a deterministic sandbox, but it doesn’t give two people a shared one. There’s no way for someone running an orchestrator to test against someone else’s gateway — discovery, capability advertisement, PM ticket exchange, redemption — without pointing both at mainnet and spending real ETH.

That’s the situation a lot of us are actually in. I’ve spent the last few weeks testing a capability against mainnet with real deposits, because there is nowhere else to do it. It works, but “deploy it to mainnet and see” is a rough on-ramp for anyone building something new, and it’s a worse one for anyone who wants to test _with_ somebody else.

So: is a shared, persistent deployment in scope here, or explicitly not? Either answer is useful — I’d just rather know which problem this is solving.

If it is in scope, one technical note. I’d suggest **Arbitrum Sepolia** over an L1 testnet. Winning tickets are held until their params expire and redemption fires on the next **L1** block as seen from the L2, so the L1/L2 relationship is part of what needs testing — I lost an afternoon to tickets that looked stuck and were simply 23 L1 blocks early. An L1-only testnet wouldn’t reproduce that class of bug at all.

Happy to help run infrastructure for it if that’s useful.

---

<div class="post-metadata">

**Author:** ![drieddate\_sidestream](https://avatars.discourse-cdn.com/v4/letter/d/8e7dd6/32.png) [@drieddate\_sidestream](https://forum.livepeer.org/u/drieddate_sidestream)\
**Post date:** [August 20, 2026, 9:43am UTC](https://forum.livepeer.org/t/livepeer-testnet-implementation-proposal/3322/7 "2026-08-20T09:43:26Z")

</div>

> [@chrishobcroft](#):
>
> So: is a shared, persistent deployment in scope here, or explicitly not?

A persistent separate deployment is not in scope, as it requires a lot of effort to maintain in sync with production and protect against griefing attacks. But the **Protocol testnet** is in scope – which is there to address the exact problem you’re describing: it will allow us to create a persistent remote fork that can be used by multiple people. This is archived via a Tenderly-like service provider – see testnet type 5 above for more details on what I mean. If you just need a persistent fork with a faucet without any pre-applied changes, you can already create it yourself, without waiting for our infrastructure.

If you tried this approach and it didn’t work for you, please let us know what were the problems that you’ve encountered.

---

<div class="post-metadata">

**Author:** ![Strykar](https://yyz2.discourse-cdn.com/flex030/user_avatar/forum.livepeer.org/strykar/32/758_2.png) [@Strykar](https://forum.livepeer.org/u/Strykar)\
**Post date:** [September 3, 2026, 1:04am UTC](https://forum.livepeer.org/t/livepeer-testnet-implementation-proposal/3322/8 "2026-09-03T01:04:19Z")

</div>

Spent this week verifying LIP-118 client support and ended up on the type 3 path from this proposal. One trap worth baking into the guide, plus a worked example.

**Round numbers are wrong on an Arbitrum fork, and they fail quietly.** Same L1/L2 class of problem @chrishobcroft raised above about tickets redeeming against the next L1 block as seen from L2, but on the fork side.

One sequence on one fork, `anvil --fork-url` against Arbitrum One:

```auto
                     RoundsManager.blockNum() currentRound()
fresh fork 25,893,300 4324
after anvil_mine 1 501,153,912 78851
mainnet reference 25,893,301 4324

```

On a fresh fork `blockNum()` comes back L1-scale and correct, either forwarded upstream or executed locally with `block.number` seeded from the fork block’s L1 number; I did not distinguish the two. The first locally-executed block switches it to anvil’s own counter, seeded from the L2 height, and the round jumps by 74,527. Nothing errors. Any call that mines is enough: in my run `initializeRound()` did it, and a subsequent reward simply recorded the round it found.

The jump follows from the anchor form, using the public getters:

```auto
currentRound = lastRoundLengthUpdateRound
             + (blockNum - lastRoundLengthUpdateStartBlock) / roundLength
             = 2725 + (25,893,300 - 15,696,000) / 6377
             = 4324

```

Worth noting `currentRound()` is not `blockNum() / roundLength`. Without the 2725 / 15,696,000 anchor the arithmetic does not close, which is easy to get wrong when sanity-checking a fork.

So tests should assert on state transitions rather than absolute round numbers, or pin the fork block and avoid round-advancing calls. Anything derived from rounds, inflation and minted amounts especially, inherits the skew silently.

**Worked example of a client-feature check on a fork:** [Verify LIP-118 delegated reward calling against deployed Arbitrum One contracts on a local anvil fork (no mainnet txs) · GitHub](https://gist.github.com/Strykar/1ddef28a20db637677dc05bdbb4670a7)

**What the pinned 2022 commit costs a current client feature:** resolving `BondingManagerTarget` through the Controller on both sides and checking the dispatch table for the LIP-118 selectors.

```auto
                               codesize 5dce9948 47621410 0103e60e 1a8c41f8 b556966a
devnet BondingManagerTarget 18866 yes no no no no
mainnet BondingManagerTarget 23033 yes yes yes yes yes

```

`5dce9948` is `getTranscoder`, present in both as a control.  
The other four are `transcoderToRewardCaller`, `setRewardCaller`, `rewardForTranscoder` and `rewardForTranscoderWithHint`.

---

<div class="post-metadata">

**Author:** ![drieddate\_sidestream](https://avatars.discourse-cdn.com/v4/letter/d/8e7dd6/32.png) [@drieddate\_sidestream](https://forum.livepeer.org/u/drieddate_sidestream)\
**Post date:** [September 10, 2026, 8:20am UTC](https://forum.livepeer.org/t/livepeer-testnet-implementation-proposal/3322/9 "2026-09-10T08:20:52Z")

</div>

Thanks @Strykar for your detailed comment.

We were able to reproduce the error you’re experiencing. While blocks are correctly handled by the Forge CLI inside tests that we primarily use, there seems to be a bug in the Anvil implementation that doesn’t account for the non-standard Arbitrum EVM implementation (which is supposed to return L1 blocks via `block.number`).

We reported this issue to Foundry [here](https://github.com/foundry-rs/foundry/issues/16768) and they already fixed it via [this PR](https://github.com/foundry-rs/foundry/pull/16771) and made a [pre-release](https://github.com/foundry-rs/foundry/releases/tag/nightly-fc14f674bd853bc817c308a5202faa5be8df05e7) with the fix. We’ve confirmed that using this pre-release the block numbers are correctly incremented now, and does not cause any round jumps.

That said, to overcome this problem and play with the Reward Caller functionality we introduced, you could’ve also used the Type 5 testnet. We’ve tested that Tenderly doesn’t have this issue: an Arbitrum fork with one simulated transaction still returns the correct block and round number:

- [Newly created Tenderly testnet with one transaction that sets reward caller](https://dashboard.tenderly.co/explorer/vnet/f5e24409-a5bd-474c-b13c-80f746dff2ec/transactions?perPage=20&page=1)

- You can verify the current round number via the following command:

- The command returns `4331` round as expected

Please let us know if you still experience any issues. If it’s related to the Foundry tools, we recommend to report those issues directly to their GitHub, so it’s fixed even faster.

---

<div class="post-metadata">

**Author:** ![Strykar](https://yyz2.discourse-cdn.com/flex030/user_avatar/forum.livepeer.org/strykar/32/758_2.png) [@Strykar](https://forum.livepeer.org/u/Strykar)\
**Post date:** [September 10, 2026, 9:15am UTC](https://forum.livepeer.org/t/livepeer-testnet-implementation-proposal/3322/10 "2026-09-10T09:15:40Z")

</div>

Confirmed. Built the nightly you linked (fc14f674) and ran the same fork against both builds, pinned to the same block:

```auto
build blockNum() round after anvil_mine 1 round
1.5.1-stable 25,945,937 4332 503,658,271 79244
1.8.2-nightly 25,945,937 4332 25,945,938 4332

```

Thanks for taking it upstream, that was quick.

One thing worth knowing before writing round tests against the patched build. The fix carries a constant L1/L2 offset, so every mined block advances `block.number` by exactly 1.  
I mined 400 in batches and it tracked 1:1 the whole way.

Measured over a 20,000 block window on Arbitrum One, the real ratio is 48.3 L2 blocks per L1 block (0.251s and 12.13s). So a fork advances L1 roughly 48x faster than the chain it forked from. One round is 6377 mined blocks on a fork, against about 21 hours and 308,000 L2 blocks on mainnet.

That is fine, arguably convenient, if you are driving round boundaries deliberately. It bites if a test mines N blocks as a stand-in for elapsed L2 activity and then asserts on rounds, inflation or minted amounts. Cleaner to assert on state transitions, not absolute round numbers.

---

<div class="post-metadata">

**Author:** ![Strykar](https://yyz2.discourse-cdn.com/flex030/user_avatar/forum.livepeer.org/strykar/32/758_2.png) [@Strykar](https://forum.livepeer.org/u/Strykar)\
**Post date:** [September 11, 2026, 3:19am UTC](https://forum.livepeer.org/t/livepeer-testnet-implementation-proposal/3322/11 "2026-09-11T03:19:00Z")

</div>

@dob asked for key use cases this proposal does not cover. I have one, and the useful part is that it does not need a new testnet type. The types already proposed can carry it.

**Signing with a real key, on the hardware the key actually lives on.** Type 3 reaches this already. An anvil fork accepts `eth_sendRawTransaction`, so a transaction signed on a device executes against the real deployed contracts. I signed `setRewardCaller` on a Trezor, broadcast it to a local fork and it was included, `from` recovered as the device’s address, status success, the mapping written. No mainnet transaction and no orchestrator needed.

What is missing is that nothing in the described workflow asks for that run. The word “sign” does not appear anywhere in the proposal. The types are described in terms of cheat codes and simulated state, and the use cases listed, Explorer and Subgraph development, do not involve producing a signature. That is a reasonable default for testing contract logic, and the effect is that the signing path never comes up.

It matters because LIP-118 exists to move the stake-holding key onto hardware. When I actually did that and looked at the screen, the call renders as two pages of raw hex with the delegate address split across the page break. Screens, reproduction and the fix are in my reply on the LIP-118 thread rather than here, since that is where the design discussion lives:

> [@LIP: Delegated Reward Calling Discussion Thread](https://forum.livepeer.org/t/lip-delegated-reward-calling-discussion-thread/3278/18):
>
> Following up on my own post above.. so I signed the LIP-118 call on a device. The PKCS#11 work is still in progress, but I hit something first that affects anyone moving their reward caller onto a hardware wallet. Signing setRewardCaller on a Trezor Model T, current firmware 2.12.4 This is the entire review the device gives you: Four screens, and the problem is not really any one of them. What the device shows is a field labelled DATA, a byte count, a…

I should say that I did not review LIP-118 while it was open either, so this is a gap I walked into, not one I spotted from outside.

For what it is worth, the fixes are in flight:

- an ERC-7730 descriptor for BondingManager, so hardware wallets render these calls as text instead of hex: [ethereum/clear-signing-erc7730-registry#2978](https://github.com/ethereum/clear-signing-erc7730-registry/pull/2978)
- the proxy resolver that descriptor and decoding tooling both need, since ManagerProxy keeps no implementation pointer in a standard slot: [shazow/whatsabi#216](https://github.com/shazow/whatsabi/pull/216) and [argotorg/sourcify#2959](https://github.com/argotorg/sourcify/pull/2959), both merged
- three against MetaMask so software wallets decode our contracts properly: metamask-extension/[#45819](https://github.com/MetaMask/metamask-extension/pull/45819), [#46086](https://github.com/MetaMask/metamask-extension/pull/46086) and [#46089](https://github.com/MetaMask/metamask-extension/pull/46089)

The testnet step is the one piece I cannot do from outside, which is why it is the only thing I am asking for here.

**The suggestion** , which is small: for any change that alters what the stake-holding key must sign, add a run with a real signer on type 3 and attach the screens. No new infrastructure, four commands on the fork tooling already in this proposal, and the kind of thing a reviewer can do in ten minutes.

It also bears on your second point about 2.0. If migration mechanics need that key to sign something new, and the only review available on the hardware wallet is raw calldata across two screens, operators drift back to hot keys for the sake of a software wallet that can at least name the function. That would undo what LIP-118 set out to enable, and it is cheaper to find out while the spec is still open.

---

<div class="post-metadata">

**Author:** ![rickstaa](https://yyz2.discourse-cdn.com/flex030/user_avatar/forum.livepeer.org/rickstaa/32/917_2.png) [@rickstaa](https://forum.livepeer.org/u/rickstaa)\
**Post date:** [September 29, 2026, 9:07am UTC](https://forum.livepeer.org/t/livepeer-testnet-implementation-proposal/3322/12 "2026-09-29T09:07:01Z")

</div>

Hey @strykar, thanks for testing this end to end on real hardware, and for taking the fixes upstream. These are exactly the kinds of things that are easy to overlook when shipping new features.

We discussed this with the team and agree with the suggestion. It is a small addition and fits well into the existing process:

- **Release checklist:** For any protocol change that alters what the stake-holding key needs to sign, add a step to run the call with a real hardware signer on a Type 3 fork.
- **Testnet docs:** Document that signing workflow in the protocol-updates repo so it becomes part of the standard process rather than something people have to discover independently.

If you have other suggestions don’t hesitate to reach out. Thanks again for all your support in getting this feature released.

On behalf of the protocol team.
