I have a Logic contract(caller), which calls a another contract named StorageContract (calle). I’m call a function of Storage contract through the LogicContract and I have put a require inside that function, which doesnt satistfy. But im unable to get thet require message in my Logic Contract
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
import "hardhat/console.sol";
error InsufficientBalance(string data);
contract Storagecontract{
address public owner;
function set(string memory _name)public view {
console.log(owner,msg.sender);
revert InsufficientBalance({data: "Nothing"});
}
}
contract Logiccontract{
string public stat;
function changename(address add, string memory name)public {
(bool send, bytes memory data)=add.call(abi.encodeWithSignature("set(string)", name));
console.log("status",send);
}
}
I have updated the above code, please have a look. All i want is when i make a call from logicContract to StorageContract (set func). I need that custom error back in my Logic contract
This doesn’t look like a valid question for Language Design topic and sorry for dead post bump but let me try to answer the question
Retrieving error parameters of call result to another SC is quite challenging and usually unreasonable but not impossible
For example, StringError(string data) with parameter "Go Back" is encoded as follows
0xd842448a ← error signature
0000000000000000000000000000000000000000000000000000000000000020 ← pointer to string (because string is dynamic type)
0000000000000000000000000000000000000000000000000000000000000007 ← string length
476f204261636b + some trailing zeros ← string itself
Though, you need to validate the error data you’ve received matches the error signature, dynamic data pointer is set correctly, error data length is not exceeded by dynamic parameter length, and only then get the string by the calculated pointer
Here is the whole code
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;
// contract which reverts with custom error with a string parameter
contract Destination {
constructor() {}
error StringError(string data); // error signature is 0xd842448a
fallback() external {
revert StringError("Go Back");
}
}
// contract to deploy and execute
contract Target {
// prepare contract to call internally
address destination;
constructor() {
destination = address(new Destination());
}
function exec() external returns (string memory) {
// execute call to some contractt
(bool success, bytes memory data) = destination.call("");
// process the error if execution was not successful
if (!success) {
// get the string parameter from error
string memory errorData;
// some safe checks that can be omitted (not recommended)
{
// get error signature
bytes4 errorSignature;
if (data.length < 4) revert();
assembly {
errorSignature := mload(add(data, 32))
}
// validate the signature is the expected one
if (errorSignature != bytes4(0xd842448a)) revert();
uint256 pointer;
uint256 length;
// validate data has place for pointer and string length
if (data.length < 4 + 32 * 2) revert();
// load string length and pointer
assembly {
pointer := mload(add(data, 36))
length := mload(add(data, 68))
}
// validate pointer is abi compliant
if (pointer != 32) revert();
// validate data provides all the string bytes
if (data.length < 4 + 32 * 2 + length) revert();
}
// set pointer for error string
assembly {
errorData := add(68, data)
}
// return the error string if call errored with StringError
return errorData;
}
// return nothing if execution was successful
return "";
}
}