This is an ownable contract. The contract implementation is the following:
Only an authority can generate a certificate. On contract deployment, the authority is the account that deploys the contract. The authority is the contract owner.
The contract owner can transfer their authority.
//SPDX-License-Identifier:MIT// DocStamp.solpragma solidity ^0.5.0;import './Ownable.sol';contract DocStamp is Ownable { mapping (bytes32 => address) public records; event CertificateIssued(bytes32 indexed record, uint256 timestamp, bool returnValue); function issueCertificate(string calldata name, string calldata details) external onlyOwner { bytes32 certificate = keccak256(abi.encodePacked(name, details)); require(certificate != keccak256(abi.encodePacked(""))); records[certificate] = msg.sender; emit CertificateIssued(certificate, block.timestamp, true); } function owningAuthority() external view returns (address) { return owner; } function verifyCertificate(string calldata name, string calldata details, bytes32 certificate) external view returns (bool) { bytes32 certificate2 = keccak256(abi.encodePacked(name, details)); // are certificates the same? if (certificate == certificate2) { // does the certificate exist on the blockchain? if (records[certificate] == owner) { return true; } } return false; }}
This is the main contract. The contract handles the generation and verification of certificates.
issueCertificate() — generates a certificate by calculating a hash of the student name and details.
Can be called only by the owner.
Emits a certificate generation event with the timestamp.
The issuer puts the certificate on the blockchain by storing it in the global variable records by passing records[certificate] = msg.sender.
owningAuthority() — returns the address of issuer/authority.
verifyCertificate() — calculates a hash of the student name and details, and checks if the contract is on the blockchain.
Can be called by anyone.
Create 2_deploy_contracts.js in the migrations directory.
var DocStamp = artifacts.require("./DocStamp.sol");module.exports = function(deployer) {deployer.deploy(DocStamp);};
Since DocStamp inherits from Ownable, Ownable will be deployed together with DocStamp.
Compile the contracts:
truffle compile
This will compile the contracts and put them in your build/contracts directory in the .json format. If the contract does not compile, check the compiler version in your truffle-config.js file and ensure that your compiler version matches the pragma solidity version of the contract.
Note the record value in the output. This is the hash of the certificate values: name and details. You will need this hash to create the contract test later in this tutorial.
Run the certificate verification:
let verify = await instance.verifyCertificate("NAME", "DETAILS", "CERTIFICATE_HASH", {from: owner})
where
NAME — the student name on the certificate used on the issuing step.
DETAILS — any details
CERTIFICATE_HASH — the hash of DETAILS and NAME. You should have received this hash in the record field at the previous step by running result.logs.
Example:
let verified = await instance.verifyCertificate("John", "graduate","0x837e31a66aa8eec0d7adfd41f84175803ddcae69afd451598f2672f652b2c153", {from: owner})
Running verify will now print true if there is a match, and false if there is no match.
NAME — the student name on the certificate used on the issuing step.
DETAILS — any details
CERTIFICATE_HASH — the hash of DETAILS and NAME. You should have received this hash in the record field at one of the previous steps by running result.logs.
sepolia — any network name that you will pass to the truffle migrate --network command.
HDWalletProvider — Truffle’s custom provider to sign transactions
mnemonic — your mnemonic that generates your accounts. You can also generate a mnemonic online with Mnemonic Code Converter. Make sure you generate a 15-word mnemonic.