Skip to content

docs: add DApp security notes#99

Open
skyc1e wants to merge 2 commits into
circlefin:mainfrom
skyc1e:docs/safe-svg-tokenuri-rendering
Open

docs: add DApp security notes#99
skyc1e wants to merge 2 commits into
circlefin:mainfrom
skyc1e:docs/safe-svg-tokenuri-rendering

Conversation

@skyc1e

@skyc1e skyc1e commented May 27, 2026

Copy link
Copy Markdown

Adds a small DApp security page and links it from the README.

It covers two things Arc app developers can easily get wrong:

  • rendering on-chain SVG metadata from tokenURI() without injecting untrusted SVG into the page DOM
  • payment escrow contract basics: bounded release delays, a payee recovery path, fee snapshots at funding time, and two-step ownership transfers

Closes #85
Closes #86

Checked with git diff --check.

@skyc1e
skyc1e marked this pull request as ready for review May 27, 2026 22:49
@skyc1e skyc1e changed the title docs: add safe SVG tokenURI rendering note docs: add DApp security notes May 27, 2026
@osr21

osr21 commented Jun 2, 2026

Copy link
Copy Markdown

Good additions. One more security finding that's Arc-specific and might be worth including in the DApp security page, especially since ERC-4337 gasless flows are a natural fit for Arc's USDC-native model.


ERC-4337 Paymaster: nonReentrant on validatePaymasterUserOp violates ERC-7562 and gets UserOps silently dropped

If you build a USDC-funded Paymaster for gasless transactions on Arc, adding the common nonReentrant modifier to validatePaymasterUserOp causes all UserOperations to be silently rejected by ERC-7562-compliant bundlers (Pimlico, Alchemy) during simulation — with no on-chain revert, no useful error message.

The reason: nonReentrant writes to a global _locked boolean. ERC-7562 forbids unstaked paymasters from writing to global storage during validation — only sender-keyed storage is allowed. The bundler catches this at simulation and drops the UserOp before it ever reaches the chain.

// ❌ Rejected by bundler — _locked is global storage
function validatePaymasterUserOp(...) external nonReentrant onlyEntryPoint { ... }

// ✅ Correct — onlyEntryPoint is sufficient; EntryPoint never re-enters validation
function validatePaymasterUserOp(...) external onlyEntryPoint { ... }

nonReentrant is safe (and recommended) on user-callable functions like deposit() and withdraw() — just not on validatePaymasterUserOp.

A companion invariant: if your paymaster tracks both a balances[user] and a locked[user] reservation for in-flight UserOps, the deductGas (legacy path) check must test available = balance − locked, not the total balance. Testing the total allows a concurrent pending UserOp and a legacy deduction to both succeed against the same funds.

Reference: ERC-7562 validation scope rules.

@skyc1e
skyc1e force-pushed the docs/safe-svg-tokenuri-rendering branch from db31f19 to 8b7dd3e Compare July 14, 2026 15:33
@ZhiyuCircle ZhiyuCircle added documentation Improvements or additions to documentation ecosystem Component: ecosystem labels Jul 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation ecosystem Component: ecosystem

Projects

None yet

3 participants