Skip to main content

Legacy v0.2 roles

The v0.2 generation (release v2.0.0) is one contract, AcademicRecords, built on OpenZeppelin 4.9 AccessControl and Pausable through the abstract RoleManager, with a linked RecordStorage library and a StudentManagement module it deploys and owns. It stays deployed on Sepolia, and the app still runs against it whenever NEXT_PUBLIC_CONTRACT_VERSION is not v03. New work targets v0.3; this page exists so the older pages and roles are documented. See Legacy v0.2 contract and Contract versions and sets.

Personal data on chain

v0.2 stores the student's name, student ID and wallet address and the document's IPFS hash in contract storage, which anyone can read from the chain. The app reads records only through the permission-aware call getRecordWithPermission, and every page shows the banner "Test network demo. Do not upload real personal documents. Data written to the blockchain is public." The v0.3 registries store none of this. See Privacy design.

The four roles​

RoleOn-chain markerGranted byPowers
Super adminThe immutable SUPER_ADMIN address (the deployer), which also holds SUPER_ADMIN_ROLE, ADMIN_ROLE and DEFAULT_ADMIN_ROLEThe constructorEverything an admin can do, plus addAdmin and removeAdmin
AdminADMIN_ROLEThe super admin (addAdmin)addUniversity, removeUniversity, registerStudentFor, migrateStudentWallet, pause, unpause; read any record
UniversityUNIVERSITY_ROLE plus a registered nameAn admin (addUniversity(address, name))addRecord, deleteStudent, addCustomRecordType, updateCustomRecordType, read its own records
StudentA student ID bound to a wallet in StudentManagementAn admin (registerStudentFor), or automatically by a university's first addRecord for that ID and walletRead own records, shareRecord and unshareRecord

The registry roles cannot be moved with the generic grantRole, revokeRole or renounceRole: RoleManager refuses those for its roles, so universities and admins change only through the named functions.

How the app recognises them​

IssuerAccessService.accessOf reads hasRole on AcademicRecords:

ResultWorkspaceSign-in goes to
ADMIN_ROLE or SUPER_ADMIN_ROLEAdmin/admin
UNIVERSITY_ROLEIssue (links Overview, Records, Add a record)/dashboard
NeitherMy credentials (link My records)/student

The /admin page loads LegacyAdminPage when the contract version is not v03; it checks ADMIN_ROLE, SUPER_ADMIN_ROLE and UNIVERSITY_ROLE and sends any wallet without an admin role to /login.

Super admin and admin pages​

/admin (System management, eyebrow Super admin or Admin, lead "Universities, admins, students and record types on the v0.2 contract.") has a pause control and these tabs:

TabWho sees itActions
OverviewBoth"Where to start" links into the other tabs
UniversitiesBothAdd a university form, submit Add university; Remove per row (shown to the super admin only), confirmed in a dialog
AdminsSuper admin onlyAdd an admin form, submit Add admin; Remove per row, confirmed with Remove admin
StudentsBothRegister a student, submit Register student; Move a student to a new wallet, submit Migrate wallet (dialog: "Move this student to a new wallet?")
Record typesBothLists standard and custom types; the add form is shown only when the wallet also holds UNIVERSITY_ROLE. The tab notes that custom types cannot be attached to records on this contract version

The pause control (Pause contract with the dialog "Pause the contract?", or Unpause contract) is shown to the super admin only.

The pages are stricter than the contract

The contract lets any admin call removeUniversity, pause and unpause (onlyAdminOrSuper). The admin page offers Remove for universities and the pause control only to the super admin, and its paused notice says a super admin unpauses.

While paused, addRecord, deleteStudent, shareRecord, unshareRecord, custom type changes, recordAccess, registerStudentFor, migrateStudentWallet, addUniversity and setUniversityName revert. pause, unpause, addAdmin, removeAdmin, removeUniversity and the role functions stay available, and reads are never paused.

University pages​

RoutePageActions
/dashboardUniversity dashboard ("Every record your university issued on the v0.2 contract.")Issue record; the Issued records list with View per row
/records/addAdd Academic RecordStudent Name, Student ID, Student Ethereum Address, Record Type, the Document file with Upload to IPFS (plain upload, not encrypted), then Issue Record
/records/[id]Academic recordThe record sheet with Verified or Unverified and View on IPFS

addRecord binds the student ID to the wallet on first use and refuses a later record whose ID or wallet does not match the existing binding ("Student ID mismatch", "Student wallet mismatch"). The institution name is taken from the registry, not from the form. deleteStudent exists in the contract but no page calls it. The Records link in the university's top bar opens /records, which sends a university back to /dashboard.

Flow: Issuing (v0.2 variant).

Student pages​

RoutePageActions
/studentMy recordsIf the wallet is not yet registered, "No student record yet" with Check Registration. Otherwise the tables My Records and Records Shared With Me, each with View
/recordsYour academic recordsView and Verify per record
/records/[id]Academic recordFor the record's own student: Share this record with a Wallet address and Share, and Revoke per existing grant

Records Shared With Me is rebuilt from RecordShared events, so it needs NEXT_PUBLIC_START_BLOCK set to the block the contract was deployed in; without it the page says the share history is not configured. Flow: Sharing (v0.2 variant).

Verifier page​

On v0.2, /verify shows Verify an academic record with a Record ID field (a number). The result shows Record found on-chain or Issuer no longer registered, the holder name, university, issue date and issuer, without the IPFS hash.

What each role cannot do​

  • A university cannot issue for another university, change a record after issuing, or register students directly (only through addRecord).
  • An admin cannot add or remove admins; the super admin cannot be removed.
  • A student cannot share a record that is not theirs ("Not your record") or share one record with more than 32 wallets.
  • No v0.2 role can revoke a record in the v0.3 sense; v0.2 has no status lifecycle, and isVerified is set at issuance.

Source files​

  • blockchain/contracts/AcademicRecords.sol, blockchain/contracts/abstract/RoleManager.sol, blockchain/contracts/modules/StudentManagement.sol, blockchain/contracts/libraries/
  • src/app/admin/LegacyAdminPage.tsx, src/app/admin/legacy/, src/app/admin/CustomTypesTab.tsx
  • src/app/dashboard/LegacyDashboardPage.tsx, src/app/records/LegacyRecordsPage.tsx, src/app/records/[id]/LegacyRecordDetailPage.tsx, src/app/records/[id]/SharePanel.tsx
  • src/app/student/LegacyStudentView.tsx, src/app/verify/VerifyPageContent.tsx
  • src/services/domain/role-service.ts, src/services/domain/record-service.ts, src/services/domain/sharing-service.ts
  • src/components/layout/DemoBanner.tsx, src/components/layout/navigation.ts

Tests​

  • Contracts: blockchain/test/Registry.test.ts, StudentRegistration.test.ts, RecordPermission.test.ts, Sharing.test.ts, ShareLimit.test.ts, Pause.test.ts, UniversityName.test.ts, UniversityNameIntegrity.test.ts, Smoke.test.ts, Coverage.test.ts
  • Rendered: src/app/admin/legacy/AdminForm.test.tsx, src/app/admin/legacy/SectionTabs.test.tsx, src/app/admin/CustomTypesTab.test.tsx, src/app/verify/VerifyPageContent.test.tsx, src/components/layout/DemoBanner.test.tsx
  • Source scan: src/app/data-exposure.test.ts (pages read records only through the permission-aware call)
  • E2E: none. The E2E harness deploys only v0.3.