Skip to content

feat: add openItemPurchase to the restricted actions service - #462

Open
juanmahidalgo wants to merge 1 commit into
mainfrom
feat/open-item-purchase-from-scenes
Open

feat: add openItemPurchase to the restricted actions service#462
juanmahidalgo wants to merge 1 commit into
mainfrom
feat/open-item-purchase-from-scenes

Conversation

@juanmahidalgo

Copy link
Copy Markdown

Changes

Adds OpenItemPurchase to RestrictedActionsService, so an SDK7 scene can ask the client to offer a marketplace item for sale in-world (e.g. a vending machine) and learn the outcome.

  • OpenItemPurchaseRequest { string urn } — the URN is the only thing the scene supplies. A scene-supplied price would let it overcharge the player, and a scene-supplied transaction could redirect the payment, so price resolution, signing and the confirmation UI all stay in the client.
  • OpenItemPurchaseResult — a verdict enum rather than a bool, so new outcomes stay expressible. Values are prefixed OIP_ because proto3 enum values are siblings of their enum: bare UNSPECIFIED / REJECTED_* would collide with OpenExplorerUiResult in the same file.
  • The verdict is deliberately coarse: any incomplete purchase is OIP_FAILED, never a reason. Reporting "insufficient credits" separately would let scene code probe a wallet's balance by offering items at different prices, and the client already tells the player what happened.
  • No quantity field: one offer, one confirmation.

Shaped after OpenExplorerUi, which this mirrors in gating (current scene + user gesture) and in returning a typed verdict instead of throwing.

Test plan

  • buf lint
  • buf build
  • buf breaking against main — additive only, no breaking changes
  • Validated end to end with a client implementation: a scene offered an item, the client resolved its catalog price, ran its own confirmation, completed the purchase against Amoy, and the scene received OIP_PURCHASED and reacted

@github-actions

Copy link
Copy Markdown

Test this pull request

  • The @dcl/protocol package can be tested in scenes by running
    npm install "https://sdk-team-cdn.decentraland.org/@dcl/protocol/branch//dcl-protocol-1.0.0-31508413180.commit-2faaa7a.tgz"

@decentraland-bot decentraland-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review — PR #462

PR: #462 — feat: add openItemPurchase to the restricted actions service
File changed: proto/decentraland/kernel/apis/restricted_actions.proto (+38 lines, 0 deletions)

Summary

Clean, well-designed, purely additive proto change. Adds OpenItemPurchase to RestrictedActionsService following the typed-verdict pattern established by OpenExplorerUi. The security design is sound — only a URN crosses the scene→client boundary; price resolution, signing, and confirmation stay entirely in the client, which eliminates overcharging and payment-redirection attacks. The deliberately coarse OIP_FAILED bucket prevents wallet-balance probing via differential error analysis.

Findings

No P0 or P1 issues found.

[P2] result vs open_result field naming inconsistency
OpenItemPurchaseResponse.result differs from OpenExplorerUiResponse.open_result. Since these are distinct message types there is no wire conflict, and result is the cleaner name — this PR is setting the better convention. Consider a follow-up to align open_resultresult in OpenExplorerUiResponse (with a reserved field number for the old one). Not blocking.

[P2] Pre-existing enum prefix inconsistency
OpenItemPurchaseResult correctly uses the OIP_ prefix to avoid proto3 namespace collisions. The older OpenExplorerUiResult uses bare names (UNSPECIFIED, OPENED, etc.), which is a latent hazard for future enums in this package. Not introduced by this PR — just noting for awareness.

[P2] OIP_REJECTED_NOT_PURCHASABLE reveals catalog state
A scene could enumerate URNs to discover listing status. Acceptable because the marketplace catalog is already public API. No action needed.

Security Review

No security issues found. Key security properties verified:

  • ✅ No price, balance, credit, or transaction data flows to the scene
  • ✅ Coarse OIP_FAILED prevents balance-probing via differential errors
  • ✅ User-gesture gate (OIP_REJECTED_NO_USER_GESTURE) and current-scene gate prevent spam/abuse
  • ✅ No secrets, credentials, or sensitive data in the change

Consumer Impact

Consumers found: unity-explorer, bevy-explorer, godot-explorer, hammurabi-headless. This is purely additive (new enum + messages + RPC, zero deletions), confirmed by buf breaking. Existing consumers are unaffected — they simply won't serve the new RPC until they add support. No breaking changes.

CI Status

CI checks are still in progress (check_and_build, validate-compatibility).

Verdict

Approved. Well-structured additive change with good proto3 conventions, strong security design, thorough documentation in the comments, and no breaking changes. The three P2 items are informational only.


Reviewed by Jarvis 🤖 · Requested by juanmahidalgo via GitHub

@juanmahidalgo
juanmahidalgo requested a review from popuz August 11, 2026 17:14
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.

2 participants