[2510] Grant Proposal - Self Sovereign Identity (SSI) sandbox rootstock integration, maturity and alpha launch

Hi community! Glad to hear your feedback. I just recorded the android application

  • Creating a DID
  • Backing up DID by email
  • Requesting a VC (verifiable credential)
  • The user sees his approved request.
  • I attach also, the issuer screens in which the issuer approves the request and submits the VC (see the link in the main post to do it yourself)



In our main post we have all the link for the contract, in which you can verify DID - CIDs relationship is being publicly stored.

About language support: Yes, our first language in spanish, but the app is build to easily add other languages, here our settings screen

About security,
both verification and contract will be audited, coinfabrik is the ones we contacted already to start.

Let us know if you have more questions.

Thanks!

Also:

Yes

2 Likes

Thank you @mrmtech for sharing the video demo. Given that your users are all Spanish speakers right now, it’s okay for the app to only support Spanish only for the first few milestones. That said, would you be able to add an English language option as part of your final milestone?

3 Likes

Hello Axia! Yes, we definitle have english support in our roadmap. I shoewd the app is ready to add a new language. I’ll add it to the next milestone.

Regards!!

2 Likes

Hello @DAOstar_gov and team!
We collected all the feedback for our milestone 2 request. Here our analysis and next steps.

First, we apologize for the administrative mistake in requesting 12.500 instead of 11.500. We took the value from the original plan, and not updated it with our latest agreement. This has been properly noted, and our request will be made correctly.

Second, our communication plan will take please on this thread. We communicated our status using other channels, which lead to confusion. We will change that.

Third, the communication will be more active. For the next milestone, we think weekly updates will be correct.

Next steps

  1. Security audit of the DidManifestRegistry contract
  2. Remediations based on findings
  3. Optimization based on audit recommendations
  4. Final report published for community review

Please let us know if we are missing anything.

Regards!

2 Likes

Congratulations @mrmtech on the thorough M1 report! The level of documentation, verifiable on-chain evidence, and working testable APK demonstrate a professionalism and laser focus on delivery.

Thanks @Tane for auditing the contract and repository.

I’d have a few pointers to clarify:

On the audit budget:
$10k seems high for auditing the “DidManifestRegistry” contract, which is a relatively focused, single purpose registry with owner only writes and standard key derivation. Save any mistakes, similar single contract audits are ranging from $3-8k these days. Which auditor are you engaging with, and how was this estimate done?

On access control architecture:
The current design relies on owner only write permissions. While I understand this may be an early stage design, this seems somewhat at odds with the self-sovereign philosophy where users control their own identity. Is there a roadmap for decentralizing write access, perhaps through issuer permissioning, multisig controls, or other mechanisms?

On infrastructure dependencies:
The backendless discovery flow is a solid step toward decentralization. However, issuance still relies on Pinata for IPFS and AWS for the issuer portal. Are there plans to reduce these centralized dependencies over time, again on the self-sovereign and decentralized philosophy.

1 Like

Hi @ChronoTrigger !
We very much appreciate your feedback, we are putting a lot of effort into improving the solution, its very well received!

On the audit budget:
The budget is meant not only for the audit, but for fixes, and optimizations based on recommendations. We are playing it safe, maybe too much, we are willing to reduce this milestone to 8k, if that is agreeable.

On access control architecture:
YES we have plans to improve further (this is alpha launch). SSI is a huge topic, and hard to tackle, we are taking it step by step.
Having said this, the first goal is for the users to be able to retain their credentials if the issuer is no longer available. On many cases however, the issuer of the credentials needs authority to revoke them (think of driver licenses, or access passes to campuses). So we are going to expand to more uses cases in the future.

On infrastructure dependencies:
Yes, IPFS is the preferred solution because storing content onchain is the first step. We may need to change vendor in the future, but we are keeping the technology.

Regards!

2 Likes

Hello everyone! If there are no more questions or messages, we’ll proceed to the voting soon!
Regards!

1 Like

Thank you so much for your responses and clarifications regarding communications, we truly appreicate your intent for consistant updates.

We do have a question about the M2 proposal on Tally currently, since the you stated that the revised M2 budget is $8K for the audit budget (which we agree with @ChronoTrigger comments above) however, we thought that M2 budget was audit budget + $2,500 for development hours for fixes/testing.

Can you please clarify the breakdown of the M2 budget with audit + dev hours, before we submit our vote? As the original proposal for M2 included both. Thks!

Hello @DAOstar_gov and team!
Happy to clarify and further breakdown the milestone.

To reduce the cost of the external audit, we redesigned the sprint, and moved some items we would request on a full/complex audit out, and will run those separately. We agree with @ChronoTrigger that our contract is simple enough that we can do that safely.
Given that we are running some of those items ourselves, it made sense to include other hardening tasks in the same sprint.

What the external audit still covers is the security review of our smart contract plus the tests, this is a very good practice we want to keep.

The milestone now includes:

  • Remediation and optimization of code based on audit findings

Plus the items we moved out from the audit, that we will execute:

  • Gas profiling
    Tools: hardhat-gas-reporter (Hardhat), optionally Foundry forge test --gas-report

  • Symbolic execution (time-boxed)
    Tools: Mythril, Manticore

  • Fuzz testing / property testing
    Tools: Foundry (fuzz/invariants), or Echidna

  • Monitoring + alerting

Let us know if this level of detail is sufficient.

Regards!

1 Like

Thank you so much, @mrmtech for this level of details and response to our clarification. We also agree that the external audit plus tests is a very good practice and demonstrates to us that your intentions are true. We support that your M2 deliverables as completed as identified, and we will be voting in favor. Thank you for the fantastic communications!

Hi @mrmtech

I have voted in favor of the current Milestone 2 proposal.

Milestone 1 delivery was properly evidenced, and based on the latest clarification, the revised M2 scope (external audit of the contract + tests, remediation, and additional internal hardening tasks) appears reasonable at the ~8k level.

That said, given the number of budget iterations we’ve seen (original proposal → revised $30k structure → incorrect on-chain amount → now reduced M2), I believe it would be very helpful for governance clarity if the team could publish a single consolidated table showing:

  • Each milestone (M1–M4)

  • The current agreed scope per milestone

  • The current agreed budget per milestone

  • The resulting total grant amount

Having one updated budget breakdown in this thread would prevent future inconsistencies and make voting more straightforward for delegates.

Appreciate the responsiveness so far, and looking forward to the audit results in M2.

2 Likes

Hello, @mrmtech , we have to echo @Kaf_Anode request for posting an updated and complete budget and scope into one view. For use, this would be helpful to understand clearly the full breakdown. Keep up the great work on communications!

1 Like

Hello community,
sure, here is the updated milestones for our project.
We incorporated some requests for milestone 3.
Let us know if more details are needed.

Regards!

Milestone 1 - Complete - (usd 10.000)

Deliverables

  • Testnet launch with Rootstock integration.
  • Smart contract design + deployment for CID storage.

Budget: New architecture and Web3 development

KPIs:

  • Smart contract deployed to Rootstock testnet.
  • CID written/read cycle functional.

Budget: Architecture, infrastructure, and web2 development ($6.000), Smart contract development ($4.000)

Milestone 2 - (1 month – usd $8,000)

  • Security Audit of Rootstock smart contracts and tests

  • Apply fixes and recommendation from the audit

  • Gas profiling
    Tools: hardhat-gas-reporter (Hardhat), optionally Foundry forge test --gas-report
    Symbolic execution (time-boxed)
    Tools: Mythril, Manticore

  • Fuzz testing / property testing
    Tools: Foundry (fuzz/invariants), or Echidna

  • Monitoring + alerting

Milestone 3 - (2 months – $4,000)

Mainnet launch of the Rootstock-enabled.

  • Backend API adapted to interact with Rootstock mainnet.
  • Issuer hardening (add authentication)
  • Issuer working against Rootstock mainnet.
  • Validator apps working against rootstock (on open source repo)
  • Add english language (validator request)
  • Ensure IPFS option besides pinata to support other storage options for content (validators request)
  • Infrastructure set-up for production readiness (Amazon + web2 services)
  • Demo credential issuance + validation flow working end-to-end

Milestone 4 (3 months – $4,500)

This is the user adoption phase

Focused on accessibility, documentation, and SSO integration.

  • Publish comprehensive guides for developers and institutions.
  • Improve onboarding flows for community use cases.
  • Communication on various channels
  • Documentation and SSO integration live
  • At least 2 external developers/institutions onboarded as pilot adopters
3 Likes

Thank you so much, @mrmtech , this detailed (and updated) budget, milestone and KPI’s, the list looks good, thank you. We’re looking forward to reviewing the M3 deliverables!

2 Likes

Hey @mrmtech we have voted FOR the proposal, it is great to see the successful delivery of Milestone 1. We also really appreciate the team taking the feedback from other delegates on board and providing a clear, detailed breakdown of all the milestones moving forward. What stood out to us about this grant is how it actively minimizes execution risk.
Excited to see how further milestones take shape.

2 Likes

Hello Community. We said we were going to have better communication, so here is our first update.

  • We prepared our code, and sent it to the auditor. They have replied, very good results, 1 minor find and two enhancements.
  • We reviewed, adopted actions for all of them, and sent it back for final review.

After the final review, we’ll proceed with the other hardening steps.

Regards!

3 Likes

Hello team! Here with our weekly update.

  • We are waiting for the final result of the audit.
  • We completed gas profiling, here draft results ( for the milestone we’ll include the complete report)
  1. Deployment: 755,359 gas
    So deploying the contract is cheap relative to the block limit.
  2. setManifestCid is in the ~33k–50k gas range per call depending on storage (cold vs warm). Average ~48k.
  3. Batching helps: Two mappings in one tx (setManifestCidsBatch ~78k) cost less than two separate setManifestCid calls (2 × ~48k ≈ 96k), so you save on per-tx overhead.
  4. Deletes are relatively cheap (~26k per delete) due to storage refunds.
  • We are analyzing symbolic execution results.
    We have a warning “Arithmetic operator can underflow”, which seems a false positive, but we are analyzing it.

Next week we expect to finish symbolic execution, and fuzz testing / property testing.

Regards!

2 Likes

So appreciate the updates, @mrmtech ! Looking forward to seeing the final audit report. Tks!

1 Like

Hello team! Here with our weekly update.
First, the audit final report is in . You can read it in:

In summary, we fixed both the minor finding, and implemented the two enhancements., great result overall.

Next, we finished our fuzzing / property testing with interesting results.

During the fuzz test run for testFuzz_batchSetAndGet (F-07), the fuzzer discovered on run 6 that a batch containing a duplicate key (the same bytes32 appearing twice in the didKeys array) causes the first entry to be silently overwritten by the second. This is not a bug — it is correct and consistent with the contract’s design as a simple mapping — but it is behaviour that was not covered by the existing Hardhat unit tests. So, the fuzzer found a missing test that we should be including, so we will.

We’ll upload the full fuzzing report when we complete the milestone.

Next week: Monitoring / Alerting. We are going to introduce mechanisms to act on the events that our contract is generating. We are studying Tenderly, alchemy, and maybe Moralis.

If everything goes well, we may even finish the milestone by next week!

Will keep you updated.
Regards!

2 Likes

Milestone 2 Completion Post — [2510] SSI Sandbox Rootstock Integration

Hello team! We are pleased to announce that Milestone 2 is complete.

As you know we have been posting regular updates with each of the tasks completed, now we present each deliverable, what we did, our results, and the supporting evidence.

After discussion, we’ll move to milestone 3 voting.
All feedback is welcome.


Summary

# Deliverable Status Highlights
1 Security Audit of Rootstock smart contracts and tests Complete CoinFabrik audit: 0 critical/high/medium findings. 1 low + 2 enhancements — all resolved.
2 Apply fixes and recommendations from the audit Complete Deletion mechanism added, Ownable2Step adopted, gas optimizations applied. Full test suite passes (18 tests).
3 Gas profiling Complete hardhat-gas-reporter integrated. Per-function gas benchmarks documented.
4 Symbolic execution (time-boxed) Complete Mythril analysis executed. 3 findings reported — all confirmed false positives (compiler-generated ABI decoder code).
5 Fuzz testing / property testing Complete Foundry fuzz + invariant testing. 14 tests (9 fuzz, 5 invariant), ~59,000 total fuzzer executions. All pass. 1 notable edge case surfaced.
6 Monitoring + alerting Complete Tenderly alerts configured for contract events. Successfully receiving alerts on new contract transactions.

1. Security Audit

Auditor: CoinFabrik — specialized Web3 security firm with 500+ decentralization projects audited.

Scope: DidManifestRegistry.sol — our on-chain registry that maps DID keys (bytes32) to IPFS manifest CIDs.

Methodology: Manual code review covering arithmetic errors, reentrancy, DoS, gas abuse, function qualifier misuse, centralization, upgradeability, and more. Severity classification based on Immunefi v2.3.

Results

Severity Count
Critical 0
High 0
Medium 0
Low 1
Enhancements 2

Finding LO-01 — No Manifest Deletion Mechanism (Low): The contract had no way to delete a mapping once set, forcing the owner to overwrite with a placeholder string.

Enhancement EN-01 — Two-step Ownership: Recommended adopting Ownable2Step to prevent accidental ownership transfers to uncontrolled addresses.

Enhancement EN-02 — Gas Optimizations: Recommended replacing string-based require with custom errors, using unchecked loop increments, and emitting a single batch event instead of per-item events.

Evidence:

  • Audit final report (PDF)Identity Audit 02-2026-final.pdf by CoinFabrik
  • Initial report: 2026-02-06 (commit 680ca31)
  • Re-audit (fixes verified): 2026-03-19 (commit 94c02b1)

2. Apply Fixes and Recommendations from the Audit

All findings were addressed. The fixes were verified by CoinFabrik in their re-audit.

LO-01 Fix: Deletion Mechanism — Resolved

We added two new functions:

  • deleteManifestCid(bytes32 didKey) — deletes a single mapping; reverts with ManifestNotFound if the entry does not exist.
  • deleteManifestCidsBatch(bytes32[] calldata didKeys) — batch deletion in a single transaction; reverts if any key is not found.

Both emit events (ManifestCidDeleted, ManifestCidsBatchDeleted) for on-chain traceability.

EN-01 Fix: Two-step Ownership — Implemented

Migrated from Ownable to Ownable2Step (OpenZeppelin). Ownership transfer now requires:

  1. Current owner calls transferOwnership(newOwner) → sets pending owner.
  2. New owner calls acceptOwnership() → completes transfer.

This prevents accidental transfer to addresses that cannot interact with the contract.

EN-02 Fix: Gas Optimizations — Implemented

  1. Custom errors: Replaced all string-based require statements with custom errors (InvalidCid, ArrayMismatch, ManifestNotFound), reducing deployment and revert gas costs.
  2. Unchecked loop increments: Loop counters in batch functions use unchecked { ++i; } since array bounds cannot overflow.
  3. Batch events: setManifestCidsBatch now emits a single ManifestCidsBatchSet event (instead of N individual ManifestCidSet events), saving ~7% gas on a 100-item batch per the auditor’s estimate.

Verification

  • All 18 unit tests pass, including new tests for deletion, batch deletion, and two-step ownership.
  • The contract was redeployed on Rootstock Testnet after the fixes were applied.

Evidence:

  • Fix commit: 94c02b1a892d72367e05c8319ea8d84911262730
  • Re-audit confirmation in the final report (page 4: “Resolved” / “Implemented” for all findings)

3. Gas Profiling

Tool: hardhat-gas-reporter v1.x integrated into the Hardhat project.

Configuration: Solidity 0.8.20, optimizer enabled, 200 runs; enabled via REPORT_GAS=1 npx hardhat test.

Results

Method Min (gas) Max (gas) Avg (gas) # calls Notes
setManifestCid 32,695 49,831 47,910 9 Min = warm slot; Max = cold/new slot
setManifestCidsBatch 78,224 78,272 78,256 3 Batch of 2 items; ~39k per item
deleteManifestCid 26,258 2 SSTORE refund on clear
deleteManifestCidsBatch 31,129 2 Batch of 2 items
transferOwnership 47,800 2 OpenZeppelin Ownable2Step
acceptOwnership 28,278 1 Second step of 2-step transfer
Deployment Gas % of block limit
DidManifestRegistry 755,359 1.3%

Key Takeaways

  • Batching is efficient: 2 mappings via setManifestCidsBatch (~78k gas) is cheaper than 2 individual setManifestCid calls (~96k gas) — saving ~19% on overhead.
  • Deletes are cheap: ~26k gas per delete thanks to storage refunds.
  • Deployment is lightweight: Only 1.3% of the 60M block gas limit.

Evidence:

  • hardhat-gas-reporter output captured during test execution
  • Config: gasReporter block in hardhat.config.ts, script test:gas in package.json

4. Symbolic Execution (Time-boxed)

Tool: Mythril (Docker image mythril/myth:latest) — symbolic execution engine by ConsenSys.

Configuration: Analysis run via Docker with solc-json remappings for OpenZeppelin imports, targeting DidManifestRegistry.sol.

Results

Mythril reported 3 findings, all classified as SWC-101 (Integer Arithmetic Bugs):

# Function Location Warning
1 setManifestCid Line 74: bytes(manifestCid).length == 0 “Arithmetic operator can underflow”
2 getManifestCid #utility.yul:92 (compiler helper) Same
3 setManifestCid #utility.yul:92 (compiler helper) Same

Analysis: All Three Are False Positives

Root cause: Mythril’s SWC-101 detector operates at raw EVM opcode level. It flags any SUB opcode whose operands can symbolically wrap below zero. The flagged code is in the compiler-generated ABI decoder (#utility.yul), not in our contract logic. The Solidity 0.8+ compiler emits a calldatasize() - offset subtraction for string calldata parameter validation, but every execution path where this subtraction underflows immediately hits a compiler-inserted REVERT — making the underflow unreachable.

Verdict:

  • Finding 1 flags a .length == 0 comparison — not arithmetic that can underflow.
  • Findings 2 & 3 flag internal Yul helpers for ABI encoding (eq(outOfPlaceEncoding, lt(length, 32))), not user-written code.
  • This is a known Mythril behaviour on Solidity 0.8+ contracts with calldata string parameters.

Conclusion: No vulnerabilities found. No code changes required. The findings are documented inline in the contract source with SWC-101 false positive comments for future reference.

Evidence:

  • Mythril output from Docker execution
  • Detailed analysis documented in project files

5. Fuzz Testing / Property Testing

Tool: Foundry v1.5.1-stable (forge), installed alongside the existing Hardhat project.

Configuration:

  • Fuzz tests: 1,000 runs per test function
  • Invariant tests: 200 runs x 50 call depth = up to 10,000 state transitions per invariant

Architecture

We created a Foundry test layer alongside Hardhat:

  • test/foundry/DidManifestRegistry.fuzz.t.sol — 9 stateless fuzz tests
  • test/foundry/invariant/RegistryHandler.sol — handler contract with ghost state mirror
  • test/foundry/invariant/DidManifestRegistry.invariant.t.sol — 5 stateful invariant tests

Fuzz Test Results (9/9 PASS)

Test Property Runs Result
F-01 testFuzz_setAndGet set then get returns same value, for any key/CID 1,000 PASS
F-02 testFuzz_emptyStringAlwaysReverts empty CID always reverts InvalidCid 1,000 PASS
F-03 testFuzz_nonOwnerCannotSet any non-owner address is always rejected 1,000 PASS
F-04 testFuzz_setOverwritesValue second write to same key replaces first 1,000 PASS
F-05 testFuzz_deleteAfterSet delete then get returns empty string 1,000 PASS
F-06 testFuzz_batchArrayMismatch mismatched array lengths always revert ArrayMismatch 1,000 PASS
F-07 testFuzz_batchSetAndGet all batch entries are correctly retrievable 1,001 PASS
F-08 testFuzz_bytes32ZeroKeyIsValid bytes32(0) works as a valid key 1,000 PASS
F-09 testFuzz_nonExistentKeyReturnsEmpty unset keys return empty string without reverting 1,000 PASS

Invariant Test Results (5/5 PASS)

Invariant Rule Calls Result
I-01 invariant_ownerIsAlwaysHandler ownership never changes unexpectedly 10,000 PASS
I-02 invariant_storedCidIsNeverEmpty tracked keys always have non-empty CID on-chain 10,000 PASS
I-03 invariant_deletedKeyReturnsEmpty deleted keys always return “” 10,000 PASS
I-04 invariant_ghostMirrorConsistency on-chain value matches ghost state for every key 10,000 PASS
I-05 invariant_nonOwnerCannotMutate no non-owner call ever succeeds in writing 10,000 PASS

Notable Finding: Batch Duplicate-Key Behaviour

During fuzz test F-07, the fuzzer discovered on run 6 that a batch containing a duplicate key causes the first entry to be silently overwritten by the second. This is not a bug — it is correct and consistent with the contract’s design as a simple mapping (last-write-wins) — but it was behaviour not covered by the existing Hardhat unit tests. This is a direct example of the fuzzer finding an edge case that hand-written tests missed. We documented this as a known behaviour and recommend validating for duplicates at the application layer (NestJS backend) before calling the contract.

Totals

Category Tests Passed Failed
Fuzz (stateless) 9 9 0
Invariant (stateful) 5 5 0
Total 14 14 0

Total fuzzer executions: ~9,000 property checks (fuzz) + ~50,000 state-changing calls (invariant) = ~59,000 executions.

Evidence:

  • Full report: docs/identity/DidManifestRegistry-Fuzz-Invariant-Testing-Report.md
  • Test files: identity/contracts/test/foundry/
  • foundry.toml configuration

6. Monitoring + Alerting

Tool: Tenderly — real-time smart contract monitoring and alerting platform.

We configured Tenderly to monitor our DidManifestRegistry contract deployed on Rootstock Testnet at address 0x64dB8b2ccD86d4A36b7F9B9F8A3eA2F35fA86c2a.

What We Set Up

  1. Contract verification on Tenderly — uploaded the contract source (Standard JSON Input with all OpenZeppelin dependencies) so Tenderly can decode function calls and events.
  2. Alert rule — configured an alert that triggers when a ManifestCidSet event is emitted by the contract.
  3. Alert destination — alerts are delivered to the project dashboard (extensible to email, Slack, webhook, PagerDuty, etc.).

Live Verification

We performed an end-to-end test by submitting a DID verification request through the citizen app, which was approved by the issuer. The backend (Web3RegistryWorkerService) successfully wrote the DID-CID mapping to the new contract on Rootstock Testnet.

Transaction: 0x5852b83bf4cd0adf0e38e14505feecf1790224bfd2b40cb4ad786cbaf9ddf5bb

On-chain result:

  • ManifestCidSet event emitted with:
    • didKey: the keccak256 hash of the DID URI
    • manifestCid: QmYihf4squDc5AFCM5PPWeKQQUus7pK94dmUo2APh1812q
    • writer: 0x799f8c5124e8c6C4Ec19b5314be2a214E05f4Be5 (contract owner / backend wallet)

Tenderly alert triggered successfully:

  • Alert: “Event ManifestCidSet emitted in DID Manifest”
  • Tx Hash: 0x5852b83bf4...ddf5bb
  • When: 01/04/2026 12:48:33

Evidence:


Conclusion

All six deliverables for Milestone 2 have been completed:

  • The contract was externally audited by CoinFabrik with a clean result (no critical, high, or medium issues).
  • All audit findings and recommendations were implemented and verified in the re-audit.
  • Gas profiling confirmed efficient gas usage, with batching providing ~19% savings over individual calls.
  • Symbolic execution via Mythril found no real vulnerabilities (3 false positives on compiler-generated code).
  • Fuzz and invariant testing via Foundry exercised ~59,000 random inputs and state transitions with zero failures, and surfaced one undocumented edge case (batch duplicate keys) that was documented.
  • Monitoring and alerting is live via Tenderly, and was validated end-to-end with a real transaction that triggered the configured alert.

The contract has been redeployed on Rootstock Testnet with all audit fixes applied, the backend and mobile app are configured to use the new contract, and the full monitoring pipeline is operational.

We will upload the complete fuzz/property testing report alongside the milestone deliverables.

Regards!

3 Likes