feat: add openItemPurchase to the restricted actions service - #462
feat: add openItemPurchase to the restricted actions service#462juanmahidalgo wants to merge 1 commit into
Conversation
Test this pull request
|
decentraland-bot
left a comment
There was a problem hiding this comment.
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_result → result 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_FAILEDprevents 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
Changes
Adds
OpenItemPurchasetoRestrictedActionsService, 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 prefixedOIP_because proto3 enum values are siblings of their enum: bareUNSPECIFIED/REJECTED_*would collide withOpenExplorerUiResultin the same file.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.Shaped after
OpenExplorerUi, which this mirrors in gating (current scene + user gesture) and in returning a typed verdict instead of throwing.Test plan
buf lintbuf buildbuf breakingagainstmain— additive only, no breaking changesOIP_PURCHASEDand reacted