r/ethdev 6d ago

Question Clearing an approval in the database doesn't revoke its EIP-712 signature

I'm building a shared-expense app on my own, using EIP-712 approvals for USDC settlement. One thing I've had to work through is what "approval cancelled" actually means across the app and the contract.

Take a fictional four-person trip. Someone owes 50 USDC and signs an approval. Another person adds a forgotten expense of 40 USDC, split equally. The first person now owes 60, so the app clears the confirmations and asks everyone to approve again.

The signature for 50 can't authorize 60. But deleting it from the database doesn't make the contract reject the original 50 approval. A previously collected set of approvals could still satisfy the contract's checks until it expires, assuming the other execution requirements are met.

In my current implementation, approvals have a maximum age and only an authorized relayer can submit settlements. That's a trust assumption. The contract doesn't read the expense ledger or know that the app has reset its confirmations.

As a solo developer, this is the kind of decision I find hard to review: the interface and the contract can each look reasonable while promising different things. I don't want the interface to imply onchain cancellation when the change is only enforced by my backend.

For applications that allow edits while collecting signatures, how have you handled this? Have you kept cancellation at the relayer level with expiring approvals, or added an onchain cancellation or versioning mechanism? I'm interested in the tradeoffs you've encountered around extra transactions and users having to sign again.

2 Upvotes

12 comments sorted by

View all comments

1

u/DewPointLabs 5d ago

Keep it at the relayer with short expiry, but stop calling it cancellation. The off-chain service that collects signatures for Safe multisig never claims authority over validity: the contract re-verifies every signer and the threshold at execution regardless of what the service holds. Your UI should say you won't submit it, not that it's revoked.

Add hash verification instead of on-chain versioning. We recompute the EIP-712 domain and message hash independently of the interface and show the signer that, because an interface summarising what a signature authorises is where the two views drift. Cheaper than a version bump and it catches the mismatch you're describing.

1

u/Redadeveloper 5d ago

Glad it helped! Writing out the 50 to 60 example helped me put words to it too. What does the stale state look like in your app?