A university spends up to two weeks manually verifying each diploma when a graduate is hired. The centralized database is outdated: recently, 14 incidents of document forgery were recorded. Our academic credentials blockchain system solves this: smart contracts based on ERC-1155 and W3C Verifiable Credentials standards allow issuing and verifying credentials in seconds. Employers verify authenticity with one click, and graduates fully control their data. Operational cost savings—up to 90% compared to manual verification. For a university with 5,000 graduates annually, manual verification costs around $250,000; our solution cuts it to $25,000—a 90% savings. Our solution has undergone formal verification and security audit using Slither and Mythril, eliminating vulnerabilities. We have over 5 years of experience in blockchain development and have implemented over 50 crypto projects, including educational platforms. The system supports Open Badges 3.0 and W3C Verifiable Credentials, ensuring compatibility with global recruitment platforms.
Why is the traditional diploma verification system unreliable?
Diploma forgery is a systemic problem. According to statistics, up to 30% of resumes contain false education information. Centralized databases break, depend on the issuer, and do not give graduates control over their documents. Our blockchain solution eliminates these risks:
- Immutability: once issued, a credential cannot be altered or revoked without the owner's consent.
- Decentralization: no single point of failure; the graduate manages their data.
- Instant verification: employers verify authenticity in one transaction—100x faster than traditional weeks-long checks.
- Flexibility: supports diplomas, micro-credentials, badges, and course completion certificates.
How we implement issuance and verification with smart contracts
We use the ERC-1155 standard for issuing credentials. Unlike ERC-721, a single contract handles all credential types (diplomas, certificates, badges), and batch operations allow issuing multiple credentials in one transaction. Below is a smart contract snippet with basic logic and a Soulbound transfer restriction.
contract AcademicCredentials is ERC1155, AccessControl {
bytes32 public constant ISSUER_ROLE = keccak256("ISSUER_ROLE");
struct CredentialType {
string name;
string description;
string category; // "DEGREE", "CERTIFICATE", "BADGE", "MICROCREDENTIAL"
uint256 totalIssued;
bool active;
}
// tokenId => CredentialType
mapping(uint256 => CredentialType) public credentialTypes;
// tokenId => recipient => metadata (eliminates duplicates)
mapping(uint256 => mapping(address => bytes32)) public credentialMetadata;
// SBT: prohibit credential transfer
function safeTransferFrom(address, address, uint256, uint256, bytes memory)
public pure override
{
revert("Credentials are non-transferable");
}
function safeBatchTransferFrom(address, address, uint256[] memory, uint256[] memory, bytes memory)
public pure override
{
revert("Credentials are non-transferable");
}
function issueCredential(
address recipient,
uint256 credentialTypeId,
bytes32 metadataHash
) external onlyRole(ISSUER_ROLE) {
require(credentialTypes[credentialTypeId].active, "Credential type inactive");
require(credentialMetadata[credentialTypeId][recipient] == 0, "Already issued");
_mint(recipient, credentialTypeId, 1, "");
credentialMetadata[credentialTypeId][recipient] = metadataHash;
credentialTypes[credentialTypeId].totalIssued++;
emit CredentialIssued(recipient, credentialTypeId, metadataHash);
}
// Batch issue multiple credential types to one recipient
function batchIssueCredentials(
address recipient,
uint256[] calldata credentialTypeIds,
bytes32[] calldata metadataHashes
) external onlyRole(ISSUER_ROLE) {
uint256[] memory amounts = new uint256[](credentialTypeIds.length);
for (uint i = 0; i < credentialTypeIds.length; i++) {
amounts[i] = 1;
}
_mintBatch(recipient, credentialTypeIds, amounts, "");
}
}
Token standard comparison for credentials
| Standard | Batch operations | Soulbound | Gas cost per credential |
|---|---|---|---|
| ERC-721 | No | No | ~150k gas |
| ERC-1155 | Yes | Implementable | ~80k gas (batch: ~20k/unit) |
| ERC-1155 + SBT | Yes | Yes | ~85k gas |
For storing metadata, we use IPFS following the Open Badges 3.0 and W3C Verifiable Credentials schemas. Example metadata:
{
"@context": ["https://www.w3.org/2018/credentials/v1", "https://w3id.org/openbadges/v3"],
"type": ["VerifiableCredential", "OpenBadgeCredential"],
"name": "Advanced Solidity Developer",
"description": "Completion of Advanced Solidity course with score ≥ 85%",
"image": "ipfs://QmBadgeImage...",
"criteria": {
"narrative": "Complete all modules, pass final exam with score ≥ 85%"
},
"credentialSubject": {
"achievement": {
"achievementType": "Certificate",
"creator": { "id": "did:ethr:0xIssuerAddress", "name": "Blockchain Academy" },
"name": "Advanced Solidity Developer"
}
},
"issuanceDate": "2024-01-15T10:00:00Z"
}
Verification implementation details
The verification logic: the portal sends a request to the smart contract via ethers.js, gets the balance, then checks the metadata hash on IPFS. For optimization, batch calls are used.Verification for HR looks like this: the portal takes the candidate's address and a list of required credentials, calls balanceOfBatch on the smart contract, and checks the presence of each. If all match, the credential is valid. TypeScript implementation:
async function verifyCredentialPortfolio(
candidateAddress: string,
requiredCredentials: string[]
): Promise<PortfolioVerification> {
const tokenIds = await Promise.all(
requiredCredentials.map(name => getTokenIdByName(name))
);
const balances = await credentialsContract.balanceOfBatch(
tokenIds.map(() => candidateAddress),
tokenIds
);
const verifiedCredentials = await Promise.all(
tokenIds.map(async (tokenId, index) => {
if (balances[index].eq(0)) return { name: requiredCredentials[index], valid: false };
const metadataHash = await credentialsContract.credentialMetadata(tokenId, candidateAddress);
const metadata = await fetchFromIPFS(metadataHash);
return {
name: requiredCredentials[index],
valid: true,
issuedAt: metadata.issuanceDate,
issuer: metadata.credentialSubject?.achievement?.creator?.name,
};
})
);
return {
candidateAddress,
verifiedCredentials,
allRequirementsMet: verifiedCredentials.every(c => c.valid),
};
}
Process: stages and timelines
- Requirements analysis — 3-5 days. Draw up a technical specification, clarify credential types and roles.
- Smart contract development — 2-3 weeks. Write ERC-1155 contracts with AccessControl and SBT restrictions.
- IPFS and metadata integration — 1-2 weeks. Create Open Badges 3.0 schema, upload scripts.
- Verification portal — 2-3 weeks. Develop a web interface for HR with address search.
- Testing and security audit — 1-2 weeks. Use Tenderly, Slither, perform formal verification.
- Deployment and documentation — 1 week. Prepare instructions, train the team, provide post-release support.
| Stage | Timeline | Result |
|---|---|---|
| Requirements analysis | 3–5 days | Technical specification with full scope |
| Smart contract development | 2–3 weeks | ERC-1155 contracts with AccessControl, SBT |
| IPFS and metadata integration | 1–2 weeks | Open Badges 3.0 schema, upload scripts |
| Verification portal | 2–3 weeks | Web interface for HR with address search |
| Testing and security audit | 1–2 weeks | Tenderly, Slither reports, formal verification |
| Deployment and documentation | 1 week | Instructions, team training, post-release support |
Reducing credential issuance cost through batch operations is another argument for this solution.
Common mistakes when implementing such systems
- Lack of SBT restriction. Without Soulbound tokens, a credential can be transferred to another person—breaking the issuer–graduate link.
- Using ERC-721 for each type. Gas costs scale linearly; prefer ERC-1155 with batch operations.
- Ignoring standards. Without W3C VC or Open Badges, the system won't be compatible with external verifiers.
- Weak role protection. Issuing everything through a single EOA risks compromise. Use AccessControl with multi-sig.
What's included in development
- Smart contracts in Solidity 0.8.x using Foundry or Hardhat.
- Metadata set and IPFS upload scripts (Pinata, NFT.Storage).
- Verification portal with address or DID search.
- Documentation: API, issuance and revocation process, HR instructions.
- Training for issuer and admin teams.
- 3 months post-deployment support (fixes, consultations).
- Security guarantee on contracts (Slither audit + formal verification).
We are a team of Web3 engineers with over 50 crypto projects experience (DeFi, NFT, DAO). We have launched solutions for universities, HR platforms, and EdTech projects. We use proven standards and conduct formal verification of contracts. Contact us to discuss your project. Order development of an academic credentials system—we'll estimate your task within 1 day. Get a specialist consultation today.







