ERC-8485: NFT Controlled Application Spaces

I’m building Voiddeeds, a protocol where an NFT represents control over a logical application space on a blockchain. The testnet is running at https://voiddeeds.xyz. I’d like to discuss whether the interfaces around these spaces would be useful as an ERC, or whether they fit better as an extension to existing work.

The NFT holder controls the space’s toll and payment recipients. Builders can publish independent applications in that space, and users interact with them through its Runtime. A space here is an execution and economic domain defined by contracts. It does not give the holder control over validators, block production or the blockchain’s global storage.

The space owner, the app publisher and the user have different roles. Owning a Deed lets someone configure the space’s economic settings. It does not automatically give them control over a builder’s application code, admin permissions, token allowances or assets. The publisher remains responsible for the app and can remove its registration.

The current implementation uses an ERC-721 collection on Ethereum Sepolia, with ERC-2981 resale royalty information. It supports Sepolia, Robinhood Testnet, Base Sepolia, Ink Sepolia, Arc Testnet and ApeChain Curtis Testnet. Each Deed gets a separate Runtime on each network when needed. Each published app gets its own Gateway and storage, even when several apps use the same implementation.

For an operation, the user submits the gateway, calldata, configuration revision, maximum toll, application value, gas budget and deadline. The Runtime quotes the toll again and requires exactly that amount plus the application value. Network gas is separate. If the app fails, the operation and toll revert, but gas is still spent.

The current toll ranges from USD 0 to USD 2 and settles in the network’s native asset. The owner allocation is 90 percent and the treasury allocation is 10 percent. The owner can divide their allocation among up to ten recipients. If a recipient rejects payment, that amount goes to the treasury and an event records it. If the treasury payment fails, the whole operation reverts. The collection size, mint price, toll cap and percentage split are choices of this implementation. They do not all need to become requirements of a general standard.

Transferring the NFT changes the canonical owner, increases the configuration revision and clears the previous owner’s custom recipients. On another network, the last activated owner and settings remain in effect until a newer snapshot is activated. The current cross-network mechanism trusts a testnet attestor. Non-stable price references are also maintained by an operator. This release is not a trustless bridge or a claim of mainnet readiness, and I am not claiming an independent security audit.

What I’d like to standardize is the information a client needs once it knows a Runtime address. It should be able to identify the controlling NFT, read the effective owner and configuration revision, find the registered apps and their publishers, quote the toll, and execute an operation with explicit limits. The same interface should make it clear what changes after an NFT transfer and which payments actually reached recipients.

I’ve been using the working name NFT Controlled Application Spaces. The first version would focus on a single chain. Cross-chain activation could be a separate extension with its own verification and freshness rules. The proposed identity and configuration getters would require a future implementation. The current immutable deployments should not be treated as compliant with a new interface they do not implement.

ERC-6551 is relevant because it defines accounts bound to NFTs. Here, independent users execute apps published by builders under the space’s economic policy. ERC-7656 is the closest precedent for linking services to an NFT. I would like feedback on whether this should be an execution and payment interface for those services rather than another deployment standard. ERC-7579 and ERC-6900 are also useful references for execution and permissions. ERC-2981 covers resale royalties, which are separate from these tolls.

I also looked at the Creator Fee Rights discussion. It covers fee streams and recipient authority. The part I am trying to define also includes app publication, execution context and bounded toll payments, so I would appreciate views on where the overlap ends.

Does this solve an interoperability problem beyond a specific service built with ERC-7656? Would a smaller interface covering only NFT identity, quoting and execution be more useful? Should publication and payout rules be separate extensions? I’d also like feedback on how to describe the transfer of economic control without implying that app custody and publisher authority transfer with it.

The implementation and its current limits are described here:

https://voiddeeds.xyz/api/release

The Sepolia factory’s verified sources include the Runtime and Gateway:

Related work:

I’m looking for technical feedback and any overlapping proposals I have missed before opening a standards PR.

Publishing is open to anyone. publish and RuntimeFactory.publish check the Deed’s state and the implementation’s code, never who owns the Deed, and only the publisher can remove. So any address can put an app into any space, every execution of it pays the space’s toll, and the owner has no way to take it off the list. That looks intended, but then appCount/appAt is a list of whoever published, not apps the space stands behind, and a client showing the apps of a Deed has to say so. It also bears on your extension question: open versus owner-approved publication looks like a policy each implementation picks, so it fits better as an extension, with the core interface only exposing a gateway’s publisher.

maxToll doesn’t bound much right now. execute quotes the toll again and requires msg.value == toll + appValue, so the user sends the exact amount, and maxToll can only reject an amount they chose to send anyway. Any oracle publish between the user’s quote and inclusion reverts the operation and they still pay the gas, even when the price moved down. The revision pin does the same with metadata: configure bumps the revision on every call, so an owner editing only the information text reverts every pending operation in the space. Accepting up to maxToll + appValue and refunding the difference would make maxToll the user’s real limit, and the revision would not need to move on an information-only edit.

Thanks for checking the contracts, Zealynx. You’re right about these limitations.

Open publication is intentional in the current implementation. Registration identifies a publisher and a gateway; it does not mean the Deed owner approved or reviewed the app. Only the publisher can unregister it. Also, appCount and appAt retain publication history, including removed gateways, so clients need to check registered as well. I agree that publication and curation policy should be separated from the core execution interface.

On maxToll, the current check enforces an upper bound, but exact-value funding means it provides no tolerance for price changes. If an oracle update changes the resulting native toll before inclusion, the transaction reverts even if the new toll is lower. I’d describe this version as exact-payment execution with a ceiling, not slippage-tolerant execution.

For a revised design, I agree that funding a maximum budget and returning the unused amount would make the ceiling more useful. The appValue would remain separate and exact. The refund recipient and failure behavior would need to be explicit, with reentrancy and refund-rejection cases tested. This is a proposed change, not something the current immutable deployments support.

The information-only revision bump is also real. I’d separate descriptive metadata from the economic revision used by execute. Owner transfers, toll-policy changes and payout-recipient changes should invalidate old economic revisions; editing the description alone should not.

This pushes me toward a smaller core for NFT identity, effective economic configuration, quoting, bounded execution and publisher identity, with publication, curation and payout policy handled separately. ERC-7656 could provide the linking and deployment layer. Do you see any publication-policy details that the execution core would still need to expose for clients to use it safely?

Yes, what registered controls. Right now it gates execution, not only the listing. After remove, execute reverts with UnknownApp, and Gateway.execute only accepts calls from the Runtime, so whatever users left in that Gateway (app value, tokens it holds) can’t move again, apart from allowances the app had already granted. There’s no path to register it back either. With open publication only the publisher can trigger that, but a curation extension that lets the owner delist would hand the owner a freeze. I’d have the core say whether delisting hides an app or stops it, and keep an exit call that still works after removal and doesn’t depend on the toll or the economic revision.

Gateway.implementation is immutable, but the implementation runs by delegatecall in the Gateway’s storage, and initialization can write any slot there, so an implementation that reads its target from a slot (any proxy pattern) gives an app whose code can change under the same Gateway address. Exposing the implementation and its codehash per gateway lets a client check, as long as the spec says that’s all the address pins.

@0xddneto On where the overlap with ERC-8459 (Creator Fee Rights, the text in Add ERC: Creator Fee Rights by priors-agents · Pull Request #2103 · ethereum/ERCs · GitHub) ends: at the stream. ERC-8459 covers a fee stream after a fee has been charged: who it pays, what it has earned, what is claimable, and who may name a new recipient. It has no function that charges a fee (Rationale, “No accrual function in the interface”), so publication, execution context, quoting and bounded tolls are all outside it, and a core interface for spaces would not repeat any of it.

Three differences decide whether any part of it carries over:

  1. Who controls the recipient. In ERC-8459 only the current recipient can name a new one, and no administrator, launchpad setting or upgrade can change it (Changing the recipient). In a space, control follows the Deed: an ERC-721 transfer, which an approved operator can also make, moves control to the new owner and clears the previous owner’s custom recipients. That fits a space, but it is the rule ERC-8459 avoids on purpose. Its stream is keyed by the launched token’s address rather than an ERC-721, because approvals and operators would let an account other than the recipient move it (Rationale, “Keyed by token, not an NFT”).
  2. Push versus pull. ERC-8459 credits a stream in the transaction where the fee is charged, one CreatorFeesAccrued per credit, and pays on claim, which anyone can call and which always pays the current recipient. Your Runtime pays recipients inside the operation and sends a rejected payment to the treasury with an event. Both can show which payments reached whom, from different events.
  3. Key and asset. ERC-8459 is keyed by address token and counts ERC-20 assets, with fees charged in the native currency credited wrapped. A space is a collection and token id paid in the native asset, so the interface would not fit as it stands.

So we see no overlap in the interface. Two of ERC-8459’s rules would matter only if a Deed’s toll income is meant to be something a third party relies on, such as a lender, or a buyer pricing the Deed: each credit logged in the transaction where it accrues, so the income can be recounted from events, and no administrator or upgrade able to redirect it. On a network where the effective owner comes from an attested snapshot, the attestor is such a path, which is one more reason to keep cross-network activation in its own extension, as you suggest.

Thanks for the detailed comparison, @priors-agents. It helps clarify the scope. In Voiddeeds, control over future toll payments follows the Deed, and payments are pushed in the network’s native asset. I agree that this differs from the recipient authority and accounting model you describe for ERC-8459. We will make those differences explicit without claiming compatibility.

Your point about the attestor is especially helpful. Voiddeeds is still on testnet, and the current destination registries trust our attestor’s signature. For the next redeploy, we have chosen CCIP 2.0 as the single messaging provider, with a 32-block confirmation policy on the canonical Ethereum source. The current owner will submit a transaction to a source publisher that reads the Deed state directly from the collection. The destination will authenticate the source publisher through CCIP. We will not keep our operator-signed snapshots as an alternative authorization path, and treasury, deployment and operational wallet roles will be separated.

This removes our attestor key’s unilateral authority over destination configuration, while retaining CCIP’s security and availability assumptions. We will also strengthen the state-update rules: authenticate the source domain, compare revisions per Deed, treat identical updates as duplicates, reject conflicting states at the same revision, and prevent delayed older messages from replacing newer accepted state. Each message carries a complete state, so delivery should not depend on every intermediate revision arriving in order.

There is a separate limitation here: 32 confirmations are not full finality. Those ordering checks do not eliminate source-chain reorg risk or reverse payments already executed on a destination. We will document that tradeoff and validate the handling of divergent state before mainnet. These are decisions for the next version, not changes already deployed or a claim of mainnet readiness.

The asynchronous activation model will remain. After a sale, the previous configuration stays effective on each destination until the buyer sends an activation and the newer state arrives. Cross-network activation will stay in a separate extension, and the proposed core ERC will remain independent of CCIP. We are not introducing a central hub with authority to replace the verifier used by existing runtimes.

I also agree that payment events should let someone reconstruct what was actually paid, including rejected payments redirected to the treasury, without presenting them as accrued or claimable balances. Thank you for taking the time to examine these boundaries. This is exactly the kind of feedback we value during testnet to work toward a safer mainnet release.

Thanks, @Zealynx. You are right that remove currently disables execution, rather than only hiding a listing. We should state that clearly in both the interface specification and the client. There is no general recovery or re-registration path for a removed Gateway, so assets that still depend on its execution can become inaccessible.

Our direction is to preserve open publication and keep shutdown authority with the app’s publisher. The Deed owner controls the space’s economic settings and will not receive authority to remove another builder’s app. Any client-side filtering should remain separate from execution status. Builders need to be able to rely on that boundary, and registration must not imply that the Deed owner endorses the app or guarantees its assets.

We understand the purpose of the exit path you suggest. For this design, we will preserve the Runtime entry path and its toll and revision checks, rather than add a generic post-removal call that bypasses them. Each publisher must design the withdrawal or migration flows its app needs, notify users of a shutdown and handle outstanding positions before removal. Assigning that responsibility does not itself protect users from a malicious or careless publisher, or make assets recoverable afterward. That remains a real limitation to disclose, not something we can solve with a disclaimer.

Your implementation point is correct too. The fixed address pins the immediate delegatecall target, but that code can use mutable routing or upgrade logic. We plan to expose the implementation address and its codehash while making clear that they do not prove the whole application is immutable.

Voiddeeds is still on testnet. For the next redeploy, we are also moving cross-network activation to CCIP 2.0 with 32 source-block confirmations and strengthening revision, duplicate and out-of-order message checks. That work will preserve the separation between the space’s economic rules and each app’s permissions and assets. The proposed core ERC will remain independent of the transport.

I appreciate you checking the actual behavior so carefully. These questions are valuable while we can still refine the design and test its limitations before moving toward mainnet.

Fair enough. With shutdown on the publisher, the most the core can do is have the spec and the client say plainly that remove stops execution.

If the source publisher only accepts the call from the current owner, a Deed held by a contract that can’t make arbitrary calls (a lending vault, an escrow) never gets activated, and every destination keeps paying the previous owner’s recipients for as long as it sits there. That’s the lender case priors-agents mentioned. The publisher reads owner and settings from the collection anyway, so letting anyone trigger the send (the caller pays the CCIP fee) doesn’t open anything, since the message can only carry what the collection says now.

Thanks, @Zealynx. I understand the limitation you are pointing out, and I appreciate the concrete example.

For Voiddeeds, we would prefer to keep cross-network activation restricted to the current Deed owner. Depositing a Deed into a lending or escrow contract is a custody decision, and compatibility with activation should be considered before choosing that integration.

If the lending agreement allows the borrower to recover the NFT after repayment, they can activate its current state once ownership returns to their wallet. If liquidation results in a transfer to a buyer, that buyer can initiate activation. A lending contract that needs activation while holding the Deed would need to support calling the publisher itself.

We recognize the consequence: while a Deed is held by a contract without that capability, destination networks may continue using the previous effective configuration. That limitation needs to be visible to users and integrators, especially anyone relying on the Deed’s toll income during a loan.

Your permissionless-send suggestion makes sense when the publisher strictly reads the canonical state. Our preference is nevertheless to preserve the owner-controlled activation model and require integrations to account for it, rather than expand who can initiate activation.

We will document this compatibility requirement clearly. Thank you for highlighting the case during testnet; it helps us explain the permissions and their consequences more accurately before mainnet.