Contrato que cambia el estado de otro contrato

En mi sistema, los usuarios pueden solicitar ser verificados por un contrato de confianza. Cuando un usuario crea una cuenta, implementa este contrato (omitiendo partes no relacionadas)

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
        */
    }
}

Existe una entidad de confianza conocida, cuya dirección de contrato será conocida por todos, que debe ser la única entidad capaz de verificar a los usuarios. Su contrato (omitiendo partes no relacionadas) es

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
        */
    }   
}

Cada ejemplo que veo de un contrato que interactúa con otro contrato, ambos están en el mismo archivo ( docs , esta pregunta ), por lo que no sé si es posible que un contrato llame a otro contrato (o, en este caso específico , para insertar una dirección en la variable de estado de otro contrato/cambiar la variable de estado de otro contrato).

Respuestas (2)

Sí.

El contrato de llamada necesita dos cosas; la dirección del contrato a llamar, y una descripción de la ABI. El ABI es, en resumen, una descripción de los nombres de las funciones y el diseño de los argumentos.

A menudo ve los contratos en el mismo archivo porque le da al compilador la información que necesita sobre la ABI. En muchos casos, uno o más de los contratos no se implementarán manualmente, sino a través de un proceso en uno o más contratos.

Es posible que vea algo como esto:

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
  }
}

En lo anterior, la idea es que se implementa la Utilidad, y el implementador conoce la dirección, por lo que se la pasan al constructor cuando implementan la Fábrica (de lo contrario, ¿cómo lo sabrá?). No necesitan implementar una Instancia porque Factory lo hace. El compilador aún necesita ver los tres archivos fuente cuando se compila Factory. Factory necesita una copia del código de bytes con el que se supone que debe implementarse new Instance();y necesita la interfaz de Utility porque los otros dos contratos se comunican con él.

Un ejemplo un poco más práctico aquí: ¿Existe un patrón de fábrica de contrato simple?

Espero eso ayude.

Cada ejemplo que veo de un contrato que interactúa con otro contrato, ambos están en el mismo archivo (documentos, esta pregunta)

Puede tener contratos en varios archivos. No es necesario que dos contratos que interactúen estén en el mismo archivo. usted informa el otro contrato con el que desea interactuar a través de la declaración de importación.

En este caso, si el contrato del usuario desea interactuar con TrustEntity, entonces debería ser como se muestra a continuación

pragma solidity ^0.4.11;
import "TrustEntity.sol"; -- Import statement

contract User {
....
...
}

No sé si es posible que un contrato llame a otro contrato (o, en este caso específico, insertar una dirección en la variable de estado de otro contrato/cambiar la variable de estado de otro contrato).

Sí, es posible. Pasa la instancia del otro contrato en el constructor (Idealmente, es la dirección donde se implementa el contrato). En este caso

 pragma solidity ^0.4.11;
    import "TrustEntity.sol"; -- Import statement
    Trustentity trustentity;
    contract User {
   function User(address _trustentity )
    {
  trustentity= Trustentity(_trustentity); // This will pick the address where your contract is deployed. 
    }

Para cambiar la variable de estado de otro contrato, accede a través de otra instancia de contrato. es decir, trustentity.pendingRequests le dará todas las solicitudes pendientes de los usuarios en el contrato de usuario.

¡Gracias por la explicación! Todo parece funcionar bien, sin embargo, todavía hay un problema. trustEntity.pendingRequestsdebería devolver la matriz de solicitudes pendientes, entonces, ¿por qué recibo un error si intento escribir trustentity.pendingRequests.push(owner)desde el contrato de usuario? Pensé que se comportaría igual. el error que me sale esbrowser/User.sol:19:6: TypeError: Member "push" not found or not visible after argument-dependent lookup in function (uint256) constant external returns (address) trustEntity.pendingRequests.push(owner); ^------------------------------^
De hecho, hice una nueva pregunta con respecto a esto aquí porque es un problema un poco diferente.