fix(xswd): prohibit native-DERO burns entirely#18
Merged
Conversation
A transfer carrying a burn on the zero SCID (native DERO) with no smart contract attached destroys the coins permanently with no recipient. The generic XSWD transfer path read a caller-supplied burn straight into the transaction with no guard, so a request that set burn without a contract would build and broadcast a destroying transaction, and the approval modal presented it as an ordinary cost line. Add defense in depth so this requires deliberate, explicit confirmation: - Backend: reject a zero-SCID burn with no SC call unless the request carries an explicit confirmDestroy flag. The flag is honored only when the burn is actually destructive, so it can never weaken a normal transfer or a contract deposit. (detectDestructiveBurn / shouldBlockBurn) - Approval modal: render a destructive burn as a permanent-destruction warning (amount, no recipient, unrecoverable) and require typing "BURN <amount>" to enable approval. Disable the Enter-to-approve shortcut for this case. - Relabel a burn that routes to a contract as "Deposit to contract" so the destructive case is no longer visually identical to a deposit. - Wire confirmDestroy from the modal through the XSWD approval path. - Add regression tests for detection and the block-unless-confirmed policy.
HOLOGRAM is a consumer wallet and never burns DERO. Replace the confirm-to-burn flow with an outright prohibition: a native-DERO (zero-SCID) burn with no smart contract attached is rejected with no override and no approve path. Anyone who genuinely intends to burn DERO must use the DERO CLI wallet. - Backend: shouldBlockBurn now blocks every destructive burn unconditionally; remove the confirmDestroy flag and its plumbing (ProcessApprovalConfirmDestroy, the RespondToXSWDRequestConfirmDestroy bridge, and the param injection). Rejection points users to the CLI. - Apply the guard at the scinvoke broadcast site too, so the prohibition is explicit at every path that builds a transfer rather than relying on chain-side refund behavior if the code is later refactored. - Approval modal: a destructive burn renders as a "REQUEST BLOCKED" notice with only a Dismiss action -- no Approve/Destroy button, no type-to-confirm. Mirror the backend's SC-call check (real entrypoint / sc_data, not a bare scid) so a dApp cannot make the UI show Approve for a request the backend blocks. - Keep "Deposit to contract" labeling for contract-attached burns. - Tests: assert destructive burns are always blocked while token transfers and deposits stay allowed; add a source-level sentinel that fails the build if a burn-override path is ever reintroduced.
d636181 to
16d4513
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A transfer carrying a
burnon the zero SCID (native DERO) with no smart contract attached destroys the coins permanently — they go to no recipient and cannot be recovered. The generic XSWDtransferpath read a caller-suppliedburnstraight into the transaction with no guard, so a request that setburnwithout a contract would build and broadcast a destroying transaction. The approval modal presented it as an ordinary cost line, with no indication the funds would be destroyed.A
burnon a non-zero SCID is the normal token-transfer mechanism, and aburnwith a contract attached is a legitimate deposit — neither is affected by this change.Fix — outright prohibition
HOLOGRAM is a consumer wallet and never burns DERO. A native-DERO (zero-SCID) burn with no contract attached is rejected entirely — no override, no approve path. Anyone who genuinely intends to burn DERO must use the DERO CLI wallet.
shouldBlockBurnblocks every destructive burn unconditionally; the rejection error points the user to the CLI. The guard is applied at every broadcast site (thetransfercase and thescinvokecase), so the prohibition is explicit and does not depend on chain-side refund behavior if the code is later refactored. The block applies only to the destructive case — token transfers (non-zero SCID) and contract deposits (burn with a contract) are unaffected.scidstring) so a dApp cannot make the UI show Approve for a request the backend blocks.burn_guard_test.goasserts destructive burns are always blocked while token transfers and deposits stay allowed, plus a source-level sentinel test that fails the build if a burn-override path is ever reintroduced.Verification
The change was adversarially audited (multi-agent) against the pinned on-chain DERO code. Result: no path can broadcast a destructive native-DERO burn, no regressions to token transfers / deposits / normal sends, and no dangling references. Two issues surfaced by the audit — a UI/backend
hasSCCallmismatch and missing defense-in-depth on thescinvokepath — are fixed in this PR.Full Go suite,
go vet, and the frontend build all pass.