Solidity – Contract Changing Another Contract’s State: Best Practices

contract-designcontract-developmentcontract-invocationsolidityweb3js

In my system, users can request to be verified by a trusted contract. When a user creates an account he deploys this contract (omitting non-related parts)

pragma solidity ^0.4.11;

contract User {
    // State variables
    address owner = msg.sender;
    bool verified = false;
    uint creationTime = now;
    struct PersonalInfo {
        string firstName;
        string LastName;
        string email;
    }
    uint level = 0;

    function requestVerification(address trustEntity) {
        /*
            This function should send a verification request
            to a trust entity's contract
        */
    }
}

There is a known trusted entity, whose contract address will be known to everyone, who should be the only entity capable of verifying the users.
Its contract (omitting non-related parts) is

pragma solidity ^0.4.11;

contract TrustEntity {
    address owner;
    address registry;
    address[] public pendingRequests;

    function verifyUsers(address user) {
        /*
            Whenever a user requests verification, his
            address should be pushed to the pendingRequests
            array, so it can then be fetched to verify or
            reject
        */
    }   
}

Every example I see of a contract interacting with another contract, they're both in the same file (docs, this question) so I don't know if it is possible for a contract to call another contract (or, in this specific case, to push an address into another contract's state variable / change another contract's state variable).

Best Answer

Yes.

The calling contract needs two things; the address of the contract to be called, and a description of the ABI. The ABI is, in summary, a description of the function names and layout of the arguments.

You often see the contracts in the same file because it gives the compiler the information it needs about the ABI. In many cases, one or more of the contracts won't be deployed manually, but rather through a process in one or more other contracts.

You might see something like this:

import "/Utility.sol"; // something already deployed. We want the code so the compiler can see the interface.

contract Factory { // something that deploys instances
  Utility utility; // Type is Utility (contract)
  function Factory(address _utility) {
    utility = Utility(_utility); // Utility at the supplied (known) address
  }
  function newInstance() returns(address contract) {
    Instance = new Instance(utility); // make a new instance and inform about another contract's address
    return instance;
}

contract Instance { // something that will copied/deployed many times
  Utility utility;
  function Instance(address _utility) { // utility address passed in
    utility = Utility(_utility); // get set to use the Utility
  }
}

In the above, the idea is that Utility is deployed, and the deployer knows the address, so they pass it into the contructor when they deploy the Factory (otherwise, how will it know?). They don't need to deploy an Instance because the Factory does that. The compiler still needs to see all three source files when Factory gets compiled. Factory needs a copy of the bytecode it's supposed to deploy with new Instance(); and it needs the interface to Utility because the other two contracts both talk to it.

A little more practical example over here: Is There a Simple Contract Factory Pattern?

Hope it helps.

Related Topic