solidity – Calling One Contract Method from Another Contract

contract-developmentremixsolidity

I want to call the method getdata() and retrieve the returns value to use in another contract. But the call only returns bool on success or failure.

  1. How do I get the return value from getdata() from caller() function in contract extra .

  2. How do I modify the state:- send transaction to setdata(uint,bytes32) from contract extra and change the state of data1 and data2.

Above problem are based on following code.

pragma solidity 0.4.21;
contract Base{
    uint public data1;
    bytes32 public data2;

    function setdata(uint a, bytes32 b){
        data1 = a;
        data2 = b;
    }
    function getdata() public view returns(uint){
        return data1 ;
    }

}
contract extra{
   bool public retrive;
   bool public retrive_setter;
   address public baseaddress = 0xca598f876f79a5f8f479bfa1dcc8f4f2dffbd5c2;
   uint a = 5;
   bytes32 b ="Lina";
   function caller(){
        retrive = baseaddress.call.gas(10000)(bytes8(keccak256("getdata()")));
        retrive_setter = baseaddress.call.gas(1000000)(bytes24(keccak256("setdata(uint, bytes32)")),a,b);
   }
}

Either you can Modify the code and give your answer. I saw this problem on many devs who are newby. Every possible answers are acceptable.

simply on testing using Remix . 

retrive 0:bool: true
retrive_setter 0:bool: false

Best Answer

pragma solidity 0.4.21;

contract Base {

    uint public dataA;
    bytes32 public dataB;

    function setAB(uint a, bytes32 b) public {
        dataA = a;
        dataB = b;
    }

    function getA() public view returns(uint) {
        return dataA ;
    }

    function getB() public view returns(bytes32) {
        return dataB ;
    }

}

contract Extra {

   Base base;

   function Extra() public {
       base = new Base();
   }

   function getBaseAddres() public view returns(address) {
       return address(base);
   }

   function baseGetA() public view returns(uint) {
        return base.getA();
   }

   function baseGetB() public view returns(bytes32) {
       return base.getB();
   }

   function baseSetAB(uint a, bytes32 b) public returns(bool success) {
       base.setAB(a,b);
       return true;
   }
}

Hope it helps.

UPDATE

The above example just creates a new Base with each deployment of Extra to show them talking in the simplest manner I can think of. Another way to go is to deploy a Base separately. It's location can then be relayed to Extra.

You could pass it into the constructor:

Base base;

function Extra(address baseAddress) public {
  base = Base(baseAddress);
}

It's not checking anything, merely assuming the deployer knows what they're doing. You can also make the address of the base something the owner can change.

Add an owner to the state and the constructor:

address public owner;

function Extra(address baseAddress) public {
  base = Base(baseAddress);
  owner = msg.sender;
}

Add a modifier (after state and before constructor, by convention) to restrict access to the sensitive function.

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

Add a restricted function to change the base.

function changeBase(address newBase) public onlyOwner returns(bool success) {
  base = Base(newBase);
  return true;
}

You might want to know the address of the Base:

return address(base);

It would be good practice to add event emitters to the state-changing functions in both contracts.

Related Topic