Here my contract

pragma solidity >=0.4.21 <0.6.0;

import "./CertificateOwnable.sol";
import "./CertificateStorage.sol";

contract Certificate is CertificateOwnable {

    CertificateStorage certificateStorage;

    constructor(address _certificateAddress) public {
        certificateStorage = CertificateStorage(_certificateAddress);

    function addCertificateTotal(string memory _universityName, 
                        string memory _typeOfDegree, 
                        string memory _major, 
                        string memory _name, 
                        uint256 _dateOfBirth) public onlyOwner returns(address) {

        address certificateNo = certificateStorage.setCertificateTotal(_universityName, 

        return (certificateNo);

My CertificateOwnable

pragma solidity >=0.4.21 <0.6.0;

contract CertificateOwnable {

    address public ownerAddress;

    event OwnershipRenounced(address indexed previousOwner);
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    constructor() public {
        ownerAddress = msg.sender;

    modifier onlyOwner() {
        require(msg.sender == ownerAddress);

    function transferOwnership(address newOwner) public onlyOwner {
        require(newOwner != address(0));
        emit OwnershipTransferred(ownerAddress, newOwner);
        ownerAddress = newOwner;

    function renounceOwnership() public onlyOwner {
        emit OwnershipRenounced(ownerAddress);
        ownerAddress = address(0);

My CertificateStorage

pragma solidity >=0.4.21 <0.6.0;

import "./CertificateStorageOwnable.sol";

contract CertificateStorage is CertificateStorageOwnable {

    address public certificateAddress;

    event AuthorizedCaller(address caller);
    event DeAuthorizedCaller(address caller);

    function authorizeCaller(address _caller) public onlyOwner returns(bool) {
        authorizedCaller[_caller] = 1;
        emit AuthorizedCaller(_caller);
        return true;

    constructor() public {
        authorizedCaller[msg.sender] = 1;
        emit AuthorizedCaller(msg.sender);

    modifier onlyAuthCaller(){
        certificateAddress = msg.sender;
        require(authorizedCaller[msg.sender] == 1);
    struct certificate_total {
        string universityName;
        string typeOfDegree;
        string major;
        string name;
        uint256 dateOfBirth;
    mapping(address => certificate_total) certificateTotalMapping;

    certificate_total certificateTotal;

    function setCertificateTotal(string memory _universityName, 
                        string memory _typeOfDegree, 
                        string memory _major, 
                        string memory _name, 
                        uint256 _dateOfBirth) public onlyAuthCaller returns(address) {

        uint tmpData = uint(keccak256(abi.encodePacked(msg.sender, now)));
        address certificateNo = address(tmpData);

        certificateTotal.universityName = _universityName;
        certificateTotal.typeOfDegree = _typeOfDegree;
        certificateTotal.major = _major;
        certificateTotal.name = _name;
        certificateTotal.dateOfBirth = _dateOfBirth;

        certificateTotalMapping[certificateNo]= certificateTotal;

        return certificateNo;

CertificateStorageOwnable is like a CertificateOwnable

Please help me, I am learning how to write a smart contract. When I debug on REMIX, there is an error like in the picture

transact to Certificate.addCertificateTotal errored: VM error: revert.
revert  The transaction has been reverted to the initial state.
Note: The constructor should be payable if you send value.  Debug the 
transaction to get more information.
  • 1
    Most likely some of the require statements reverts the transaction. One option is to just comment out the require statements one by one and see which one causes the revert and then figure out what's wrong with your input. – Lauri Peltonen Apr 24 '19 at 4:59

The error is when you call setCertificateTotal and happens with the modifier onlyAuthCaller.

You probably didn't set up beforehand the calling contract as authorized by calling authorizeCaller(address _caller).

  • Thank you! I think I have an authorization when deploy contract. But it still doesn't work – Công Nghệ Apr 24 '19 at 7:49
  • You have authorization for you, for the address you control. When you call the addCertificateTotal function, it calls the setCertificateTotal function, and in there, msg.sender is not your address but the address of the contract that called it. – Elisha Drion Apr 24 '19 at 7:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.