Fidesium’s latest customer, Sumvin, is a soulbound ERC-721 identity protocol. Our engagement covered the full Solidity codebase, the UUPS upgrade path, and the Safe-based governance model. The engagement produced 9 actionable findings (0 Critical, 1 High, 2 Medium, 2 Low, 4 Info). A Low overall risk posture. Here’s how our multi-pass Framework, applied to a small, deliberately-scoped EVM contract, surfaces the issues that matter on identity infrastructure: upgrade safety, deployment hygiene, and centralization blast radius.
Why identity infrastructure needs a different kind of audit
Identity contracts lack many of the attack surfaces prevalent across DeFi. There is no liquidity to drain, no oracle to manipulate, no MEV to extract. Failure modes are however no less damaging: upgrades can be stranded by incorrectly managed storage slots, or initialization can hand an attacker admin control via front-running.
This high impact risk posture is compounded by soulbound tokens. Once issued, a soulbound credential cannot be transferred away from a compromised holder, and once written, its data cannot be rewritten by the holder. Therefore all trust assumptions live within the issuer’s OpSec and code correctness, with no path to recovery.
Sumvin is a UUPS-upgradeable, soulbound ERC-721 identity token. It uses Safe multi-sig governance for every privileged role, on-chain Base64 JSON metadata, and the ERC-7201 namespaced storage pattern to preserve upgrade safety. Fidesium reviewed the protocol end-to-end ahead of mainnet deployment.
The client: Sumvin
Sumvin is a soulbound identity primitive. Each address holds at most one identity token; transfers are permanently disabled per ERC-5192; identity payload is a { sub, iat, schema } credential plus an arbitrary key/value dat map exposed through an on-chain tokenURI. All admin roles are held by a Safe multi-sig after deployment; the deployer EOA retains nothing.
The scoping was disciplined. They asked for a full audit before any mainnet activity, shipped a comprehensive test suite alongside the contracts so behaviour could be verified, and explicitly flagged the issuer-controlled trust model up front. That kind of context-setting saves engagement time and concentrates effort on real risk.
The engagement in numbers
- ~290 lines of Solidity across the implementation, proxy, and soulbound interface.
- 3 roles mapped to 6 privileged entry points, every one of them held by a Safe in production.
- 9 actionable findings: 0 Critical, 1 High, 2 Medium, 2 Low, 4 Informational.
- Risk score: 11/100 Low overall posture, with the High finding sitting on deployment process rather than runtime logic.
Small surface, high-quality codebase: no Criticals, and the single High is a process gap (a missing chain-id assertion in the deployment script). The Mediums concentrate on classic UUPS surfaces (initializer front-running, admin role centralization).
Our approach: Multiple focussed passes for layered interlocking security
Fidesium’s audit methodology is organised around a multi pass framework that we apply before a human auditor reads a single line of business logic. The framework has different components correlating to different types of projects. As a result, the search operates against a fully enumerated attack surface rather than an ad-hoc one. A non-exhaustive list follows
Pass 1) Protocol Mapping
For Sumvin, this produced a function matrix classifying every external and public entry point by access tier and noting the state it mutates. Admin-gated functions are where governance risk lives; permissionless functions are the high-priority attack surface; and on an upgradeable contract, the upgrade path itself gets its own tier.
Pass 2) State & Storage Flow
For an upgradeable contract, the most valuable artifact is a mutation matrix showing which fields are written by which functions, paired with a storage layout map. For Sumvin this surfaced the ERC-7201 namespaced storage slot, the addressToToken and credentials mappings, and the datKeys enumeration array used to assemble the on-chain tokenURI. The output of this pass is a set of invariants which can then become assertions in the test layer.
Pass 3) External Call & Inheritance Surface
On EVM this is the inheritance graph plus any external calls. Sumvin inherits from OpenZeppelin v5’s upgradeable ERC-721, AccessControl, and UUPS modules, so this pass becomes a careful read of which OZ functions are exposed (and whether soulbound semantics override them safely).
Pass 4) Cross-Verification
The next pass looks for internal consistency bugs. For Sumvin, this is where the ERC-7201 slot mismatch surfaced. The contract claims ERC-7201 compliance but the actual slot constant is not the canonical derivation, which limits tool support and forces every future upgrade to follow the non-canonical path. It is also where the deployment script’s missing chain-id guard surfaced: the contract is correct in isolation but the deployment process can target the wrong chain.
Pass 5) Adversarial Modelling
An actor x capabilities matrix allows us to show what different actors can do if compromised, and what recovery and observability would look like.
Sample finding
We’re going to walk through one of the higher-severity findings, because it illustrates the kind of issue that structured enumeration surfaces. (The full report contains more, we’re not going to reproduce exploit details here.)
Front-Runnable Initializer
Sumvin uses the UUPS proxy pattern: an ERC1967 proxy delegates to an implementation, and the proxy’s storage is set up by a single initialize() call on the proxy after deployment. The implementation contract itself defends against direct initialization with _disableInitializers() in its constructor, which is correct at the implementation, but does nothing for the proxy.
If the proxy is deployed and initialize() is not called atomically in the same transaction, the call enters the mempool as a standalone transaction. Any observer can submit a competing initialize() with their own address as admin, paying higher gas. The legitimate deployer’s transaction reverts; the attacker now holds DEFAULT_ADMIN_ROLE, MINTER_ROLE, and UPGRADER_ROLE on the proxy and can mint, mutate, or upgrade the contract at will.
Sumvin’s deployment script bundles deploy-and-initialize into a single script invocation, which closes the practical window. The contract-layer remediation is cheap and worth doing anyway: pin the deployer in the constructor and gate initialize to that address.
address private immutable _deployer;
constructor() {
_deployer = msg.sender;
_disableInitializers();
}
function initialize(string memory name, string memory symbol, address admin)
public initializer
{
require(msg.sender == _deployer, “Only deployer can initialize”);
// …
}
Fidesium’s recommendation: layer the contract-level guard on top of the deployment-script bundling, so the safety property does not depend on operational discipline alone. The same pattern appears in the High finding (deployment script missing a chain-id assertion).
The test suite
Sumvin shipped a 700+ line Hardhat + Viem test suite alongside the contracts. Fidesium’s review of that suite, and the supplementary tests we wrote against findings, follows the same principle we apply on every engagement: every finding should generate at least one runnable test. The correspondence between a finding ID in the report and a test in the codebase is mechanical. Remediation review reduces to “does the test that previously failed now pass.”
- Unit tests over pure logic_setDat / removeDat key-existence semantics, soulbound transfer reverts, role-guard reverts on every privileged entry point. Fast, deterministic, exhaustive over enumerated inputs.
- Lifecycle tests mint → mutate → burn → re-mint flows for the same address, covering the addressToToken invariant and the datKeys reset on burn.
- Upgrade-path tests deploy implementation A, deploy proxy, upgrade to implementation B, assert that storage at the namespaced slot is preserved and that role state survives the upgrade. This is the test that catches an ERC-7201 slot regression before it strands a mainnet contract.
Why this approach works
Audits fail in a variety of ways. The most common are the auditor finding fewer issues than existed, because the search was pattern-matching, or the auditor finding the issues but the remediation regressing, because the findings were prose paragraphs rather than runnable tests.
Our framework addresses the first; the test-first model addresses the second. By building a regression lock for every finding, remediation review becomes mechanical and future refactors inherit the guardrails. We can help the Sumvin team ship the next version of this contract with the same confidence on the issues in this report that they had on the day we delivered it.
Identity infrastructure is a category where this matters more than usual. The contract will live longer than any one audit, will accumulate features as the protocol grows into its full scope, and will be upgraded multiple times against the same namespaced storage slot.
What this says about Sumvin
The codebase is clean, the architecture is conservative, Safe multi-sig for every privileged role is a good call for a centralized-issuer identity model. Most of the findings above are the kind of issue a team already thinking hard about correctness makes: compositional, fixable in isolation, surfaced more by systematic enumeration than by inspiration.
What next
If you’re building identity, attestation, or any issuer-controlled primitive on EVM, the time to engage with security is before mainnet. Soulbound contracts have no exit; upgradeable contracts compound security oversights. Sumvin engaged at the right point in the lifecycle, and the result is a protocol that ships with a Low residual risk score and a regression lock for every finding.
If you’re building on any EVM chain and want an audit that ships runnable tests alongside the report, reach out at fidesium.xyz. Our multi-pass methodology, our upgrade-safety toolkit, and our static analyzer are available to every client.
If you’re at an earlier stage wWhiteboard, architecture, role design, we work up-funnel too. We’d rather catch a storage-slot mistake on a draft contract than a missed invariant on a deployed proxy.
The best time to make your protocol auditable was the day you opened the repository. The second best time is today.



