Skip to main content

Legacy v0.2 contracts

Before v0.3, Certichain was one contract, AcademicRecords, released as v2.0.0. It is still deployed on Sepolia and the app still supports it when NEXT_PUBLIC_CONTRACT_VERSION is not v03, but all new work targets the v0.3 registries. This page documents it for maintenance and for comparison.

Plaintext on chain

v0.2 stores the student's name, the student id, the student wallet, the institution name and the IPFS CID of the document in contract storage. Everything in contract storage is public, whatever the getters check. The permission checks on its views control what the app shows, not what the chain reveals. v0.3 was designed to remove this; see Privacy design.

Structure​

PartFileRole
RoleManagerblockchain/contracts/abstract/RoleManager.solAbstract base: OpenZeppelin 4.9 AccessControl and Pausable, the three roles, university names
AcademicRecordsblockchain/contracts/AcademicRecords.solRecords, sharing, custom types, student registration, pause
IAcademicRecordsblockchain/contracts/interfaces/IAcademicRecords.solThe RecordType enum (32 values), the Record and CustomRecordType structs, events
RecordStorageblockchain/contracts/libraries/RecordStorage.solExternal library holding record, share and custom type logic; linked at deployment
StudentManagementblockchain/contracts/modules/StudentManagement.solStudent id to wallet registry, owned by AcademicRecords

All of it compiles with OpenZeppelin ^4.9.3 under the default Paris EVM profile and uses require strings, not custom errors.

Roles​

RoleHow it is heldPowers
Super adminThe deployer, fixed forever in the immutable SUPER_ADMIN; also granted DEFAULT_ADMIN_ROLE, SUPER_ADMIN_ROLE and ADMIN_ROLEAdd and remove admins (cannot remove itself), everything an admin can do
Admin (ADMIN_ROLE)Added by the super adminAdd, remove and rename universities, register and migrate students, pause and unpause
University (UNIVERSITY_ROLE)Added by an admin with a unique nameAdd records, delete a student's records, create and update custom types
StudentA wallet registered to a student id in StudentManagementShare and unshare its own records, read its own records

grantRole, revokeRole and renounceRole are blocked for the registry roles ("Use registry functions"); roles change only through addAdmin, removeAdmin, addUniversity and removeUniversity, which keep the lists returned by getAllUniversities and getAllAdmins consistent. There is no transfer of the super admin.

Records​

A Record holds id, studentId, studentName, studentAddress, universityName, ipfsHash, metadataHash, recordType, timestamp, isVerified (always set to true on creation) and issuer.

FunctionWhoNotes
addRecord(studentId, studentName, studentAddress, ipfsHash, metadataHash, recordType)University, not pausedSix arguments. Binds the student id to the wallet on first use (_bindStudent); refuses "Student ID mismatch" or "Student wallet mismatch" when either is already bound differently. The university name is taken from the registry, not from the caller. Emits RecordAdded
deleteStudent(studentId)University, not pausedRemoves that university's records for the student and revokes their shares. Emits StudentDeleted
getRecord(recordId)Anyone (view)Returns the full record
getRecordWithPermission(recordId)Issuer, a wallet it is shared with, an admin, the super admin, or the record's own student (view)Otherwise "No permission to view this record"
getStudentRecords(studentId), getStudentRecordsByAddress(address), getUniversityRecords()ViewsgetStudentRecordsByAddress loops over every record of the wallet and of its student id to remove duplicates, so its cost grows with stored data
verifyRecord(recordId)ViewReturns isVerified
recordAccess(recordId)Anyone, not pausedEmits RecordAccessed
getTotalRecords(), getTotalCustomTypes()ViewsCounters

Sharing​

FunctionWhoNotes
shareRecord(recordId, sharedWith)The record's student, not pausedAt most 32 sharees per record ("Share limit reached"). Emits RecordShared
unshareRecord(recordId, sharedWith)The record's student, not pausedEmits RecordUnshared
getSharedRecords(sharedWith), isRecordSharedWith(recordId, address)Views

The 32 sharee cap bounds the work deleteStudent does per record. The app rebuilds the "Shared With Me" list from RecordShared and RecordUnshared events (it needs NEXT_PUBLIC_START_BLOCK to know where to start scanning).

Custom record types and students​

FunctionWhoNotes
addCustomRecordType(name, description)University, not pausedReturns a numeric id; emits CustomRecordTypeCreated
updateCustomRecordType(typeId, isActive)The university that created it, not paused"Not the creator" otherwise; emits CustomRecordTypeUpdated
getCustomRecordType(typeId), getUniversityCustomTypes()Views
registerStudentFor(studentId, wallet)Admin or super admin, not pausedRegisters a student in StudentManagement. There is no student self-registration
migrateStudentWallet(studentId, newWallet)Admin or super admin, not pausedMoves a student id to a new wallet; existing share grants are kept

StudentManagement accepts writes only from its owner, the AcademicRecords contract that deployed it ("Only AcademicRecords"). It refuses an empty id, a zero address, an id already registered and a wallet already used, and emits StudentRegistered and StudentAddressUpdated.

Pause​

From the contract's own comment:

PausedExempt
addRecord, deleteStudent, shareRecord, unshareRecord, addCustomRecordType, updateCustomRecordType, recordAccess, registerStudentFor, migrateStudentWallet, addUniversity, setUniversityNamepause, unpause, addAdmin, removeAdmin, removeUniversity, grantRole, revokeRole, renounceRole; views are never paused

v0.2 compared with v0.3​

Topicv0.2v0.3
Personal dataName, id, wallet, CID in storageSalted commitments and hashes only
Who proves authorshipThe university role sent the transactionThe issuer's EIP-712 signature, carried in an event and checkable offline
Document bindingA CID and a metadata stringSHA-256 of the document bytes
StatusisVerified (always true); records can be deletedActive, suspended, revoked, superseded; nothing deleted
Student linkAdmin registers a walletIssuer-signed invitation redeemed by the wallet
AdminA fixed super admin, plain rolesDelayed two-step admin, a Safe, then a timelock; a guardian for emergencies
UpgradesNoneVersioned sets side by side
Unbounded loopsgetStudentRecordsByAddress, deleteStudent work grows with dataNone

Deployment on Sepolia​

Deployed and verified for release v2.0.0 (ADR-0041):

ContractAddress
AcademicRecords0x475Bb8555d160c85f0175df117576193984C8083
StudentManagement0xA742a8C965468b1E59C84c5254Dcc507589accD1
RecordStorage (library)0x3aba3A4Ed6822bABc7ef801Ed7d922F9f5e69dcc

npm run deploy:local and npm run deploy:sepolia in blockchain/ run blockchain/scripts/deploy.ts, which deploys RecordStorage, links it into AcademicRecords (blockchain/scripts/lib/deploy-system.ts), writes deployments/<network>.json and exports the ABIs to src/contracts/. See Deployment and scripts. The role-by-role view of the old app is in Legacy v0.2 roles.

Source files​

  • blockchain/contracts/AcademicRecords.sol
  • blockchain/contracts/abstract/RoleManager.sol
  • blockchain/contracts/interfaces/IAcademicRecords.sol
  • blockchain/contracts/libraries/RecordStorage.sol
  • blockchain/contracts/modules/StudentManagement.sol
  • blockchain/scripts/deploy.ts, blockchain/test/fixtures.ts

Tests​

All in blockchain/test/ (top level), using test/fixtures.ts, which deploys RecordStorage and links it:

FileCovers
AcademicRecords.tsFixture with the linked library, roles, adding and listing records, access control, pause
StudentRegistration.test.tsAdmin-only registration and wallet migration, no self-claim
RecordPermission.test.tsWho may read a full record
Sharing.test.ts, ShareLimit.test.tsSharing rules and the 32 sharee cap
Registry.test.tsAdmin and university lists, blocked role functions
UniversityName.test.ts, UniversityNameIntegrity.test.tsNames from the registry, unique names
Pause.test.tsThe paused and exempt lists
Deployment.tsDeployment tooling: linked deploy, deployments/<network>.json, safe network names, ABI export, missing environment on public networks
Smoke.test.tsThe read and write checks of the Sepolia smoke script and its verify targets
Coverage.test.tsRemaining branches: admin management, non-super admins, university list edits