function withdrawERC20(
address token,
address to,
uint256 amount,
uint256 salt,
uint256 deadline,
bytes calldata ownerSig,
bytes calldata backendSig
) external {
require(deadline >= block.timestamp, "expired");
require(!usedDigests[digest], "replayed");
bytes32 digest = _hashTypedDataV4(...);
require(ECDSA.recover(digest, ownerSig) == vaultOwner, "bad owner sig");
require(ECDSA.recover(digest, backendSig) == factory.owner(), "bad backend sig");
usedDigests[digest] = true;
IERC20(token).safeTransfer(to, amount);
}