solidity – Why Concatenated String Reason Message in require() Not Displaying in Solidity

requiresoliditystringtruffle-migration

I'm using Solidity 0.8.13 and Truffle 5.5.6.

I'm just trying to debug a transaction call that fails then reverts when I do truffle migration.
I temporarily changed my onlyOwner modifier to make the reason message display the values of my owner and msg.sender into something like below:

modifier onlyOwner() {
    //require( msg.sender == owner, "Only Owner can call." ); // this reason message works
    require( msg.sender == owner, string( abi.encodePacked( "Owner mismatch: ", owner, " != ", msg.sender ) ) );
    _;
}

However, in the output of truffle migrate --reset (where my original issue was happening), it doesn't display the reason message at all and just display:

"Foo" hit a require or revert statement somewhere in its constructor. Try:
   * Verifying that your constructor params satisfy all require conditions.
   * Adding reason strings to your require statements.

Can anyone tell me what's wrong with passing in concatenated string reason message in require()?

Best Answer

You can use Strings.sol library about OpenZeppelin and strings.sol about Arachnid to concatenate strings and build your message.

You can see this example:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.0;

import "https://github.com/Arachnid/solidity-stringutils/blob/master/src/strings.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Strings.sol";

contract Test {
    using Strings for *;
    using strings for *;
    address owner;

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, getMessage(msg.sender, owner));
        _;
    }

    function test() public onlyOwner {
        // TODO: your logic
    }

    function getMessage(address _callingAddress, address _owner) private returns(string memory){
        // Convert Address to String
        string memory _ownerAddress = Strings.toHexString(uint160(uint160(_owner)));
        string memory _calledAddress = Strings.toHexString(uint160(uint160(_callingAddress)));
        // Define two pieces about message
        string memory _firstMessage = "Owner mismatch: ".toSlice().concat(_ownerAddress.toSlice());
        string memory _secondMessage = " != ".toSlice().concat(_calledAddress.toSlice());
        // Concat in one message
        string memory _message = _firstMessage.toSlice().concat(_secondMessage.toSlice());
        return _message; 
    } 
}

UPDATED ANSWER:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Strings.sol";

contract Test {
    using Strings for *;
    address owner;

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        string memory _ownerAddress = Strings.toHexString(uint160(uint160(owner)));
        string memory _calledAddress = Strings.toHexString(uint160(uint160(msg.sender)));
        require(msg.sender == owner, string(abi.encodePacked( "Owner mismatch: ", _ownerAddress, " != ", _calledAddress)));
        _;
    }

    function test() public onlyOwner {
        // your logic
    }
}
Related Topic