1

I'm trying to call a function from another contract and need a way to accommodate errors.

Say contract A has the method getBalance:

    function getBalance(address x) 
      public 
      view 
      returns(uint output)
        { output = Balance(x);}

I'd like to call this function and treat a null response as a zero. Currently, I can't get my function to simply revert, in that if I call addressA.getBalance(x), and x or addressA is misspecified, the function reverts and does not allow me to simply assume it is zero. I'd like it to find something like 'try:' in python for solidity.

Note: It's hard to communicate because I just wanted to abstract from contract logic that would be distracting, but that generates sloppy examples (so, thanks for your patience). Contract A has daughter contracts A(i). Contract B calls Contract A looking for data on A(1), A(2), and A(3). If A(1) doesn't exist, the getter function reverts, and contract B doesn't look for A(2) or A(3). I changed the code so that Contract A reports null values if A(i) doesn't exist, so that if A(1) does not exist, it presumes the output is set to default values (zero). I did this by adding an if statement within the getter function in contract A that looks to see if A(i) exists:

import "./DaughterTemplate";
    .....
    function getter(playerAddress) public view returns (uint data)
    {
        address daughter = activeDaughters[playerAddress];
        if (daughter != address(0)) {
            DaughterTemplate d = DaughterTemplate(daughter);
            data = d.data;
        }
    }
  • 1. What is "a null response"??? 2. "x or addressA is misspecified" - those are two completely different cases! For x, there is no such thing as "misspecified". Any value is legitimate, and your function should (and probably does) return a valid uint value. For addressA - why would you ever "misspecify" it??? You should show your could and explain how you've managed to write a contract with this case being possible. In any case, you'll have to do that "try thing" in assembly. If you showed your code, then I might be able to explain in more specific details and an actual coding example. – goodvibration Oct 18 '19 at 6:13
  • You can make a low level call with .call and abi.encodeWithSignature, but it is usually not a good idea. – Ismael Oct 18 '19 at 15:44
  • say I am calling a function in contract A from contract B, where the argument is an address that has been restricted (eg, 'require(arguementAddress != EricAddress )') . Then if I call that function, my result in the logs of Remix are call to ContractA.callContractB errored: VM error: revert. revert The transaction has been reverted to the initial state. This causes everything to stop within contract B That’s a silly example, but it also applies if I’m calling, say, another contract that has a totally different ABI (eg, I put in a correct eth address, just it’s the wrong address). – Eric Falkenstein Oct 18 '19 at 17:06
0

We're all having a hard time understanding this:

I can't get my function to simply revert, in that if I call addressA.getBalance(x), and x or addressA is misspecified

This part looks malformed:

output = Balance(x);

You started with:

getBalance(address x)

This implies that x is a contract or EOA.

When you say

output = Balance(x);

You are instantiating contract Balance at address x. I understand that such may not be what you intend to do, and I am making educated guesses about the parts of the code you did not show. On the face of it, it makes no sense because:

output = Balance(x);

and

returns(uint output)

do not appear to be compatible. You seem to be returning an instance of a contract, cast as a uint. That conversion is not possible and it shouldn't compile.

Assuming there is a contract Balance with a function balanceOf(address a), where a corresponds to an account, then it would look like:

return Balance(contractAddress).balanceOf(a); // contract address set elsewhere

A typical Balance contract would not throw if it used something like mapping(address => uint) public balanceOf; It would just return 0, and invalid addresses should not make it that far.

In case it helps, something like this:

pragma solidity 0.5.1;

contract Trivial {

    mapping(address => uint) public balances;

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw() public payable {
        uint amount = balances[msg.sender];
        balances[msg.sender] = 0;
        msg.sender.transfer(amount);
    }
}

contract Curious {

   function inspect(Trivial trivial, address account) public view returns(uint balance) {
       balance = trivial.balances(account); 
   } 
}

Nothing will complain as long as valid addresses are passed in - one for the Trivial contract to check, and one for the account to check.

Hope it helps.

| improve this answer | |

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.