Soul-Bound Tokens (SBTs) for Credentials
Soul-Bound Tokens (SBTs) are immutable, non-transferable digital assets that represent educational credentials, achievements, and certifications. Stored securely on the blockchain, SBTs provide an innovative solution to credentialing challenges by ensuring qualifications are verifiable, tamper-proof, and universally recognized.
They form a cornerstone of the Decentralized Learning Protocol (DLP) by giving learners lifelong ownership over their educational records. These tokens eliminate reliance on centralized institutions for certification validation, making learning credentials accessible across multiple platforms.
SBT Implementation on EVM Chains
In Ethereum Virtual Machine (EVM)-compatible blockchains, SBTs are built using a modified ERC-721 standard, ensuring non-transferability while retaining on-chain verifiability.
Key Features of EVM-Based SBTs
Non-Transferability: Overrides transferFrom and safeTransferFrom functions to prevent transfers.
Immutable Credentialing: Once issued, SBTs remain unchangeable and tied to the recipient.
On-Chain Verification: Institutions and employers can validate credentials instantly.
Revocation Mechanism: Allows authorized issuers to revoke credentials in case of fraud or updates.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract SoulBoundToken is ERC721Enumerable, Ownable {
struct SBTMetadata {
string credentialName;
string institution;
string issuedDate;
bool revoked;
}
mapping(uint256 => SBTMetadata) public tokenMetadata;
event CredentialIssued(uint256 tokenId, address recipient, string credentialName, string institution);
event CredentialRevoked(uint256 tokenId);
constructor() ERC721("SoulBoundToken", "SBT") {}
function mint(address recipient, uint256 tokenId, string memory credentialName, string memory institution, string memory issuedDate) external onlyOwner {
_safeMint(recipient, tokenId);
tokenMetadata[tokenId] = SBTMetadata(credentialName, institution, issuedDate, false);
emit CredentialIssued(tokenId, recipient, credentialName, institution);
}
function revoke(uint256 tokenId) external onlyOwner {
require(_exists(tokenId), "Token does not exist");
tokenMetadata[tokenId].revoked = true;
emit CredentialRevoked(tokenId);
}
function isRevoked(uint256 tokenId) public view returns (bool) {
return tokenMetadata[tokenId].revoked;
}
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal override {
require(from == address(0), "SBTs are non-transferable");
super._beforeTokenTransfer(from, to, tokenId);
}
}
Last updated