On 29 April 2026 at 15:57:45 UTC, the owner of a Chainlink VRF subscription on Base offered it to somebody else. The offer is still open. In the 178 days since, that subscription has run 4,938 more draws, taken on 25 more game contracts, and had its balance topped up to nearly five times what it held that afternoon. It is now the single most heavily wired subscription on Base VRF: 49 live consumer contracts against a runner-up of 34. And the address it was offered to can take ownership of all of it with one transaction, at any moment, without asking anybody.
That address has not taken it. It has also never said no, because the contract gives it no way to say no. There is no expiry, no decline, and no automatic withdrawal. An offer on a VRF subscription sits in storage until the current owner overwrites it, and in 178 days this one has not been overwritten.
I pulled the complete ownership-transfer history of the Base VRF 2.5 coordinator at 0xd5d517abe5cf79b7e95ec98db0f0277788aff634, pinned at block 53,038,663 (24 October 2026, 18:31:13 UTC), and then checked the answer a second way by reading the pending-owner slot of every active subscription directly out of contract storage. Both methods name the same three subscriptions.
TL;DR
- 25 ownership offers have ever been made on Base VRF subscriptions across 823 days, and 22 were accepted. Three were not, and all three are still live.
- A real handover is fast: the median time from offer to acceptance is 12 minutes 20 seconds, the quickest was 2 seconds, and 16 of the 22 completed inside an hour.
- Against that, the three unanswered offers have been standing for 394, 190 and 178 days.
- Two of the three are over empty subscriptions. The third runs 5,669 draws and 49 game contracts, the most consumers of any active subscription on Base VRF, and holds 0.095241100930031189 ETH.
- 87.1% of that subscription’s draws happened after the offer was made, and 25 of its 49 game contracts were wired on afterwards. The most recent one was added on 26 July 2026, 88 days into the offer.
- Verified in storage, not just in logs: calling
acceptSubscriptionOwnerTransferfrom a junk address on all 1,175 active subscriptions makes the coordinator revert with the pending owner’s address. Exactly three come back non-zero.
What an ownership offer actually is
Subscription ownership on the VRF 2.5 coordinator moves in two steps. The current owner calls requestSubscriptionOwnerTransfer, and later the named address calls acceptSubscriptionOwnerTransfer. The first function writes one field and emits one event:
SubscriptionConfig storage subscriptionConfig = s_subscriptionConfigs[subId];
if (subscriptionConfig.requestedOwner != newOwner) {
subscriptionConfig.requestedOwner = newOwner;
emit SubscriptionOwnerTransferRequested(subId, msg.sender, newOwner);
}
That is the whole mechanism. There is no deadline parameter, no block height after which the offer lapses, and nothing that reconsiders it if the subscription’s circumstances change. Chainlink’s own comment above the function is candid about the one case it chose not to guard: “Proposing to address(0) would never be claimable so don’t need to check.” Offering a subscription to the zero address is therefore the documented way to withdraw an offer. In 823 days of coordinator history, nobody has ever done it. All 25 offers on record name a real address.
The second step is equally thin. The named address calls acceptSubscriptionOwnerTransfer, the coordinator checks that the caller is the requested owner, and the owner field is rewritten. Nothing else about the subscription changes. The balance stays, the consumer list stays, and every game contract wired to it keeps drawing, now under a different owner’s control.
The whole record: 25 offers, 22 accepted
Across the coordinator’s entire life, from 12 July 2024 to 13 October 2026, there are exactly 25 SubscriptionOwnerTransferRequested events and 22 SubscriptionOwnerTransferred events. They cover 23 distinct subscriptions, 24 distinct offering addresses and 22 distinct recipients. Two subscriptions were offered twice, and one address received three separate subscriptions from three different owners and took all three.
Counts off an indexer are worth nothing on their own, so the pull is anchored to an invariant that does not depend on the indexer being complete. The same source returns 1,361 SubscriptionCreated events and 186 SubscriptionCanceled events. The difference is 1,175, which is exactly the length of getActiveSubscriptionIds(0,0) read from the contract at the pinned block. Every one of the 22 acceptances also pairs cleanly with an earlier offer to the same address on the same subscription, with zero orphans in either direction.
Here is how long the 22 completed handovers took:
| Time from offer to acceptance | Handovers |
|---|---|
| Same block or the next (2 to 6 seconds) | 4 |
| Under 10 minutes | 9 |
| Under 1 hour | 16 |
| Under 24 hours | 18 |
| 1 to 2.3 days | 4 |
| Median | 12 minutes 20 seconds |
The shape is unambiguous. An ownership transfer on Base VRF is not a negotiation that unfolds over weeks. It is two transactions in the same sitting, usually by somebody with both keys open in front of them. The slowest completed handover on record took 2 days 6 hours. Nothing in this dataset takes a month.
It is also a rare thing to do at all. Only 23 of the 1,361 subscriptions ever created on this coordinator have had an offer made on them, which is 1.69%. Most operators create a subscription, wire their games to it and never touch the ownership field again. The handful who do use it cluster into recognisable shapes. One address, 0x9765bc79e98ca0a53726c031e85a435e34143e70, was offered three different subscriptions by three different owners across January, February and March 2026 and accepted all three, which looks like a consolidation. Another subscription, …16242169, passed through three owners in a single afternoon on 15 July 2026, the second handover landing 182 minutes after the first, and was closed by its third owner this afternoon. Ownership of a VRF subscription moves rarely, and when it moves it tends to move decisively.
The three that were never answered
Three offers have no matching acceptance. None of them has been withdrawn, and all three subscriptions are still active.
| Subscription (last 8 digits) | Offered | Days open | Draws | Consumers | Balance |
|---|---|---|---|---|---|
| …07762416 | 25 Sep 2025 | 394 | 0 | 0 | nothing |
| …04054993 | 17 Apr 2026 | 190 | 0 | 1 | nothing |
| …66612306 | 29 Apr 2026 | 178 | 5,669 | 49 | 0.095241100930031189 ETH |
Two of the three are husks. They hold no LINK and no ETH, they have never produced a single draw, and whoever accepted them would inherit an empty shell. The risk they carry is zero, and it is worth saying so plainly rather than counting all three as one problem.
The third is not a husk.
The one with 49 games on it
Subscription …66612306 is owned by 0xdb1820620365984b096ced6f1a124ddf531c4119, an ordinary key with 221 transactions behind it. On 29 April 2026 it offered the subscription to 0x33c828f9a334f871456ab0a7fd7c8bf76fe7767c, another ordinary key, with 65 transactions and about 0.011 ETH on Base.
Reading the subscription’s state at the block of that offer and again at the pinned block today gives the measurement that makes this worth writing about:
| At the offer (29 Apr 2026) | Today (24 Oct 2026) | |
|---|---|---|
| Draws | 731 | 5,669 |
| Consumer contracts | 24 | 49 |
| Native balance | 0.019435334173831702 ETH | 0.095241100930031189 ETH |
4,938 draws, or 87.1% of everything this subscription has ever produced, happened after its owner offered it away and left the offer standing. Twenty-five more game contracts were wired onto it in the same period, with zero removals, bringing it to 49 against a MAX_CONSUMERS ceiling of 100. The last one was added on 26 July 2026, 88 days into the offer. The balance was topped up rather than drained.
Those 49 consumers are not test stubs. Pulling the verified source of one of them, 0xb14df0cfe63e83968136ec1c8080051cb500670f, returns a contract called VRFR built on VRFConsumerBaseV2Plus, with stake tiers literally named shrimp, dolphin, shark and whale, odds and multiplier parameters, a prize cap committed on chain at request time, and a result store. It is a wagering product, and so are its siblings. Across all 1,175 active subscriptions on Base VRF, only 351 have ever drawn at all, and this one ranks 22nd by draw count and first by consumer count. It is one of the busiest gaming rigs on the chain.
It is also worth being precise about what accepting would get somebody. Not the game contracts themselves, which have their own owners and their own switches. What it gets them is the subscription those games draw from: the ability to call removeConsumer on all 49 of them, after which the coordinator refuses their next request with InvalidConsumer, and the ability to call cancelSubscription and send the balance anywhere, which deletes every consumer registration in one transaction. The games would not be hacked. They would simply stop being allowed to ask for randomness.
Proving it from storage, not from the logs
An event-based finding like this is only as good as the indexer that served the events, and I have been burned by that indexer dropping rows before. So the result is checked a second way, against contract storage, with no logs involved at all.
The coordinator does not expose a public getter for requestedOwner. It does something almost as useful: when the wrong caller tries to accept, it reverts with a custom error that carries the right one.
if (s_subscriptionConfigs[subId].requestedOwner != msg.sender) {
revert MustBeRequestedOwner(s_subscriptionConfigs[subId].requestedOwner);
}
So an eth_call of acceptSubscriptionOwnerTransfer(subId) from an address that is definitely not the pending owner returns the pending owner in the revert data. I ran that call from 0x000000000000000000000000000000000000dead against all 1,175 active subscription IDs at the pinned block. All 1,175 reverted with MustBeRequestedOwner, which confirms the method is doing what I think it is doing rather than silently failing. Exactly three returned a non-zero address, and they are the same three subscriptions the event replay found, with the same recipients. Three separate RPC providers return byte-identical revert data for all three.
Two independent methods, a closed invariant on the subscription census, and a control that proves the probe fires. That is the standard this blog tries to hold, and it is the reason the number in the headline is a number rather than an impression.
Accept has no brake on it
Reading the coordinator’s subscription functions side by side turns up an asymmetry that is easy to miss. Both cancelSubscription and removeConsumer open with the same guard:
if (pendingRequestExists(subId)) {
revert PendingRequestExists();
}
acceptSubscriptionOwnerTransfer has no such check. An owner cannot pull the rug while a draw is in flight, but ownership itself can change while a draw is in flight. The randomness already requested is protected from being defunded. It is not protected from changing hands.
In practice that protection is thinner than it sounds, because the guard only blocks while requests are actually pending. I checked all three offered subscriptions at the pinned block: pendingRequestExists returns false on every one. The accept-then-cancel path is open right now on the subscription with 49 games on it, and the only thing standing between that path and 49 broken games is that nobody has chosen to walk it.
What accepting has actually meant
It would be easy to treat acceptance as a friendly formality. The record says otherwise. Of the 20 subscriptions that have changed hands, three were cancelled afterwards by the new owner, which is 15%. Against a baseline where most cancelled subscriptions die young and empty, these died after somebody chose to take them on.
One of them is instructive. Subscription …87551037 was accepted at 16:27:53 UTC on 26 September 2025 and cancelled 14 minutes and 36 seconds later, withdrawing 23.984775008509199765 LINK to an address that was not the accepting one. The acceptance was the wind-down. Another was cancelled 26 days after the handover. The third was closed this afternoon at 14:53 UTC, 101 days after it changed hands, 3 hours and 38 minutes before the block I pinned, which is also why my cancellation count is one higher than the figure I published yesterday.
The address holding the 394-day-old offer deserves a paragraph of its own, because it rules out the comfortable explanation. On 25 September 2025 at 14:13:57 UTC, one owner offered it subscription …07762416. At 14:16:27, 150 seconds and 75 blocks later, a completely different owner offered it a second subscription. It accepted the second one 26 hours later, emptied it a quarter of an hour after that, and has never touched the first. It owns three active Base VRF subscriptions today. This is not an address that lost its keys or stopped paying attention. It read both offers, took the one it wanted, and left the other one lying on the table, where it has now been lying for 56 weeks.
Three posts this is not
This blog has been working through the Base VRF subscription surface for weeks, so the boundaries matter. The 727-owners census established who can call these functions and simulated the permission errors a stranger gets. It also made a claim in its closing section that this post is the test of: that any change of subscription owner “is announced before the acceptSubscriptionOwnerTransfer lands”, and that the two-step handover “gives us a window in which to do it”. The announcement part holds exactly. The window part needs a correction. A window implies a closing edge, and there isn’t one. For three subscriptions the window has been open for 394, 190 and 178 days.
The coordinator admin post measured the two-step handover one level up, at the contract’s own ownership, and found that both of the coordinator’s handovers completed in 27.5 hours and 7.1 days. Both of the ones at the top finished. Three of the ones underneath never did. And yesterday’s consumer census counted the add and remove events that wire games to subscriptions; this is about the single field that decides who commands those wires.
What this means if you play on-chain games
The useful question is not whether somebody is about to steal a gaming operation. Probably nobody is. The useful question is what a provably fair game actually promises you, and the honest answer is narrower than the marketing usually admits.
Chainlink VRF proves that the number a game used was not chosen by the operator. It proves nothing about who is allowed to keep the game supplied with numbers. That is a separate field, in a separate mapping, moved by a separate function, and at this moment it points at somebody other than the operator on a rig running 49 live games. Verifiable randomness and stable custody of the thing producing it are two different guarantees, and only one of them is cryptographic.
This is why Satoshie publishes its subscription ID and its owner rather than just asserting that its raffles and coinflips are fair. Anybody can run the exact census above against us specifically: one eth_call, from any address, no permission needed, and the revert tells you whether there is an offer outstanding on the subscription our games draw from. If there ever is one and we have not said why, that is a fair thing to hold against us. A fairness claim you cannot check is a slogan, and the useful version of provable fairness includes the boring custody questions, not just the cryptographic ones.
Honest limits
- Intent is unknowable. The 178-day offer may be a co-founder arrangement, a stalled migration, a multisig that never got around to it, or a mistake. I can prove the offer exists and is live. I cannot prove anybody forgot about it.
- Repeat offers are silent.
requestSubscriptionOwnerTransferonly emits when the requested owner actually changes, so an owner re-confirming the same address emits nothing. The event stream can therefore undercount intent, though not the final state, which is why the storage census is the load-bearing measurement here. - Cancelled subscriptions are out of scope. The storage census covers the 1,175 active subscriptions. Any offer that was standing on a subscription later cancelled is gone from storage with it, so the historical total of unanswered offers may be higher than three.
- The 49 consumers were not all read. I pulled verified source for one of them and named the operation from it. The other 48 share the subscription and the pattern; I did not confirm every one is a live game.
- Draw counts are the coordinator’s own counter.
reqCountcounts requests, not fulfilments, so some of the 5,669 may have been requested and never delivered. - One of the three offers predates my earliest confident read of the indexer’s completeness. The 394-day offer sits in a 2025 range I have not independently re-pulled from an archive node; the storage census confirms the state today but not that the event is the only one that ever touched that field.
Three questions worth asking any on-chain game
- What is your VRF subscription ID, and who owns it right now? If a game cannot answer this in one line, it has not thought about the question.
- Is there an ownership offer outstanding on it? One
eth_callofacceptSubscriptionOwnerTransferfrom any address answers this in the revert data. Nobody has to grant you access to check. - If the answer is yes, who is it to, and when does it close? The honest answer to the second half is “it doesn’t”, which is the whole point of this post.
Everything here is re-checkable. The coordinator is 0xd5d517abe5cf79b7e95ec98db0f0277788aff634 on Base, the block is 53,038,663, the function selector is 0xb2a7cac5, and the error selector that carries the answer is 0xd084e975. Three subscriptions come back with somebody’s name on them. One of them runs 49 games.


