Skip to main content

The rule

No single key can move user funds on PredictStreet. Vault.withdrawERC20 on-chain checks two signatures:
  1. User signature — EIP-712 from the vault owner EOA.
  2. Backend signature — EIP-712 from a platform backend key: any address holding BACKEND_ROLE on the VaultFactory (VaultFactory.isBackend(signer)).
Both must cover the exact same typed-data struct. If either is missing or invalid, the vault reverts. msg.sender of the tx is unconstrained — a relayer, the user, or a third party can submit.

Sequence

Why two signatures

  • User signature. Proves user authorised this specific withdrawal.
  • Backend signature. Attests the request passed platform compliance (AML, banned-destination, restrictions).
  • Unilateral backend moves are impossible. The backend’s key alone doesn’t unlock the vault.

What the on-chain verifies

Simplified, in check order:
Key invariants:
  • Digest-based replay protection — single-use per digest.
  • Revocable before execution — the vault owner or a platform backend key can call invalidateDigest(digest) (or the batch invalidateDigests) to burn a signed withdrawal before it is submitted; any later submission of that digest reverts. See Digest invalidation.
  • Emergency withdraw — if the backend is gone or refusing legitimate withdrawals, the vault owner calls initiateEmergencyWithdraw(); after a 7-day timelock it can drain the vault to the owner address during a 7-day window, with no backend signature. See Emergency withdraw.

Backend co-signer security

The backend co-signing keys are the addresses holding BACKEND_ROLE on the VaultFactory. More than one can be active at a time, and any of them can be revoked on-chain. The vault checks isBackend when the withdrawal executes, so a signature from a revoked key no longer verifies.