Skip to content

feat(patterns): add token-gated access pattern#506

Open
DevZenPro wants to merge 1 commit intoMystenLabs:mainfrom
DevZenPro:feat/token-gated-pattern
Open

feat(patterns): add token-gated access pattern#506
DevZenPro wants to merge 1 commit intoMystenLabs:mainfrom
DevZenPro:feat/token-gated-pattern

Conversation

@DevZenPro
Copy link

Summary

Implements the token-gated access pattern proposed in #466. This gates encrypted content on ownership of a specific on-chain object type (NFT, DAO token, game asset). Access travels with the asset automatically — transfer the token, transfer decryption access — with no admin update required.

Design

  • seal_approve<T: key> — generic entry function; the Move VM enforces that only the owner of an owned object can pass &T as a transaction argument
  • type_name::with_original_ids<T>() — stores the required type using original IDs so the gate survives package upgrades (same approach as key_request.move)
  • TokenGate as a frozen object — immutable after creation, zero consensus overhead on reads, prevents accidental mutation via future upgrades
  • Prefix-bound key IDs[pkg id][gate id][nonce], same structure as whitelist.move
  • Cap returned to creator for future extensibility

Security Model

This pattern assumes token type T is owned, never shared or frozen. If T can be shared/frozen, anyone could pass &T and bypass the gate. This is an intentional tradeoff — it enables the "access travels with the asset" property that no other pattern provides. For high-value content with token types you don't control, a collection-specific integration with concrete types would be more appropriate.

Comparison with Existing Patterns

Pattern Access based on Access transfers with asset?
whitelist.move Admin-managed address list No
account_based.move Caller's address No
subscription.move Payment + time No
token_gated.move (this PR) Object ownership Yes

Tests

6 tests added, all passing:

  • Valid approval with correct type and prefix
  • Multiple nonces per gate
  • Type confusion rejection (ETypeMismatch)
  • Wrong prefix rejection (ENoAccess)
  • Empty ID rejection
  • Create and destroy lifecycle

Full test suite (13 patterns + 42 seal) passes with no regressions.

Usage

// Client-side PTB construction
tx.moveCall({
    target: `${SEAL_PATTERNS}::token_gated::seal_approve`,
    typeArguments: [myNftType],  // e.g., "0x123::my_nft::MyNFT"
    arguments: [
        tx.pure.vector('u8', fromHex(id)),
        tx.object(myNftId),
        tx.object(gateId),
    ],
});

Closes #466


Credit to @Danny-Devs for the detailed proposal, testnet deployment, and ValidPtb compatibility verification in #466.

Add a new access pattern that gates encrypted content on ownership of a
specific on-chain object type (NFT, DAO token, game asset). Access
travels with the asset: transfer the token, transfer decryption access.

Key design decisions:
- Generic seal_approve<T: key> validates ownership via Move VM
- type_name::with_original_ids<T>() survives package upgrades
- TokenGate frozen after creation (immutable, no consensus overhead)
- Prefix-bound key IDs (same structure as whitelist.move)

Security: assumes token type T is owned, never shared/frozen.

Includes 6 tests: valid approval, multiple nonces, type confusion
rejection, wrong prefix rejection, empty ID, create/destroy.

Closes MystenLabs#466
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add token-gated access pattern

1 participant