contrato de herencia? Necesito ayuda para entender ciertas cosas.

Estoy usando testrpc y trufa. Creé un token simple como se ve en muchos tutoriales que se usará para comprar o habilitar ciertas acciones al hacer clic en un botón en una interfaz de usuario.

contract MyToken {
    mapping (address => uint) balanceOf;

    event CoinTransfer(address indexed _from, address indexed _to, uint256 _value);

    function MyToken() {
        balanceOf[msg.sender] = 21000000;
    }

    function sendCoin(address receiver, uint amount) returns(bool sufficient) {
        if (balanceOf[msg.sender] < amount) return false;
        balanceOf[msg.sender] -= amount;
        balanceOf[receiver] += amount;
        CoinTransfer(msg.sender, receiver, amount);
        return true;
    }

    function getBalance(address addr) returns(uint) {
        return balanceOf[addr];
    }
}

Hasta aquí todo bien.

La interfaz de usuario tiene un botón "comprar 10 MyToken" que funciona porque implementé una función en app.js con el objeto JS implementado de ese contrato.

function buyMyToken(amount) {
  var mytoken = MyToken.deployed();

  showStatus("Initiating transaction... (please wait)");

  mytoken.sendCoin(myaccount, amount, {from: spender}).then(function() {
    showStatus("Transaction complete!");
    refreshBalance();
  }).catch(function(e) {
    console.log(e);
    showStatus("Error sending coin; see log.", true);
  });
}; 

Ahora quiero crear otro contrato que le permita al usuario comprar una licencia, un servicio o habilitar alguna acción, por ejemplo, al hacer clic en otro botón. En ese caso, habilitará una imagen de forma permanente en la interfaz de usuario cuando se compre una vez con ese token. Entonces, ese segundo botón debería habilitar un truco de forma permanente y el costo es, por ejemplo, 5 de mi propio token creado -> "habilitar truco (5 MyToken)"

Para ese contrato se necesita herencia ¿no? Porque el segundo contrato tiene que verificar si el usuario ya compró algunos de los tokens con el primer contrato, lo que le permitiría comprar alguna licencia, servicio o habilitar alguna acción con el segundo contrato. Entonces, ¿qué necesito para ese segundo contrato y cómo puedo construirlo y usarlo en relación con el primer contrato?

¿Podría el segundo contrato ser así o qué más necesito? Sé que necesito, por ejemplo, la función getBalance del primer contrato, ¿verdad? Pero, ¿cómo y dónde la coloco?

contract PermService {
  address vendor;

  event ServiceTransfer(address _from, address _to, uint _amount)

  function PermService() {
  vendor = msg.sender;


  }

  function buyPermService() returns (bool success) {
  if...
  ...
  ServiceTransfer(msg.sender, receiver, amount);
  return true;
  }
}

¿Eso tiene algún sentido?

Realmente no puedo encontrar buenos tutoriales para subdivisas y cómo usarlos con otros contratos. También soy un novato y no un programador profesional.

¿Y puedo simular eso con la consola de trufas?

La ayuda es muy apreciada. Gracias de antemano.

Respuestas (3)

Ok, esto es lo que he hecho hasta ahora. Y sí, no es herencia de contratos lo que estaba buscando, son contratos que interactúan entre sí.

contract MyToken {
    mapping (address => uint) balanceOf;

    event CoinTransfer(address indexed _from, address indexed _to, uint256 _value);

    function MyToken() {
        balanceOf[msg.sender] = 21000000;
    }

    function sendCoin(address receiver, uint amount) returns(bool sufficient) {
        if (balanceOf[msg.sender] < amount) return false;
        balanceOf[msg.sender] -= amount;
        balanceOf[receiver] += amount;
        CoinTransfer(msg.sender, receiver, amount);
        return true;
    }

    function transfer(address from, address to, uint amount) returns(bool sufficient) {
        if (balanceOf[from] < amount) return false;
        balanceOf[from] -= amount;
        balanceOf[to] += amount;
        CoinTransfer(from, to, amount);
        return true;
    }

    function getBalance(address addr) returns(uint) {
        return balanceOf[addr];
    }
}

contract PermService {
    mapping (address => bool) customerPaid;
    address vendor;

    function PermService() {
        vendor = msg.sender;
    }

    function buy(address tokenContractAddress) returns (bool success) {
        if (customerPaid[msg.sender]) {
            // permanent: the customer already bought the service!
            return true;
        }
        MyToken mt = MyToken(tokenContractAddress);
        if (mt.getBalance(msg.sender) < 5) {
            throw;
            return false;
        }
        mt.transfer(msg.sender, vendor, 5);
        customerPaid[msg.sender] = true;
        return true;
    }
}

contract OnetimeService {
    address vendor;

    function OnetimeService() {
        vendor = msg.sender;
    }

    function buy(address tokenContractAddress) returns (bool success) {
        MyToken mt = MyToken(tokenContractAddress);
        if (mt.getBalance(msg.sender) < 2) {
            return false;
        }
        mt.sendCoin(vendor, 2);

        return true;
    }

}

contract TimeLimitedService {
     ....
     //block.timestamp an option??

}

Como puede ver, creé 4 contratos en un archivo. 4 botones en la interfaz de usuario y para cada uno creé un contrato. El primer contrato crea el token que los clientes pueden usar para comprar servicios del emisor de ese token. Como mencioné en mi comentario de apertura, esto ya está funcionando. El cliente presiona el botón "Comprar 10 Mytoken" y listo.

El segundo contrato habilitará un servicio permanente que sólo necesita ser comprado una vez. Hasta ahora, esto funciona principalmente. Cuando no compré nada de MyToken y presioné el botón "habilitar truco", devuelve "Error al comprar el servicio, consulte el registro". Esto es correcto. Y cuando compro algo de MyToken primero y luego presiono "habilitar truco", aparece un truco y el saldo se reduce en 5 MyToken. Cuando presiono el botón "habilitar truco" nuevamente, no retira ningún token porque ya comprado antes. Sin embargo, todavía hay transacciones en curso. No es la solución perfecta que tengo hasta ahora. Estoy seguro de que hay formas mucho mejores de codificar eso. Se agradecen las mejoras y simplificaciones.

¿Y alguna idea de cómo puedo escribir un contrato inteligente con algún tipo de servicio/acción por tiempo limitado? Leí que block.timestamppodría ser una opción. La idea es que cuando se presiona un botón en la interfaz de usuario, a partir de ese momento, o cuando esta transacción se incluye en un bloque, el color del fondo puede cambiar durante 30 segundos o algo así. También se agradece algo de ayuda aquí.

Es posible que no esté buscando herencia de contrato aquí.

Cuando el contrato B hereda del contrato A, es (generalmente) una copia completa de A, así como cualquier cosa que B agregue. Entonces, si crea un contrato de token y luego crea un segundo contrato que hereda del contrato de token, ¡en realidad tendrá dos tipos de tokens!

Esto, sin embargo, podría no ser algo malo. Si la venta de este servicio está intrínsecamente vinculada al token, podría tener más sentido tener solo un contrato que realice un seguimiento de los tokens y venda servicios. Sin embargo, hay una serie de razones por las que es posible que no desee hacer esto. (Complejidad, dificultad en la actualización, etc...)

Entonces, ¿cómo lo haces con dos contratos? Esencialmente, deberá otorgar al contrato de vendedor el derecho de modificar el saldo del contrato de token. Aquí hay un fragmento de una manera simple de hacerlo.

modifer onlyseller() {
    if(msg.sender != seller) throw;
    _;
}

function takeTokens(address buyer, uint amount) onlyseller {
    if(balanceOf[buyer] < amount) throw;
    balanceOf[buyer] -= amount;
    balanceOf[seller] += amount;
    CoinTransfer(msg.sender, receiver, amount);
}

Esto creará una función en el contrato de token a la que solo sellerse puede acceder. Cualquier otra llamada lo hará throw. (En este caso, eso es probablemente algo bueno. throw(generalmente) deshace toda la transacción).

Luego, en el contrato de vendedor, puede utilizar esta función.

// in the constructor.
mytoken = MyToken(tokenContractAddress);

// in buyPermService(). I assume msg.sender is the buyer.
// you'll need to mark balanceOf as public for this to work.
if(mytoken.balanceOf(msg.sender) > priceOfService) { 
    mytoken.takeTokens(msg.sender, priceOfService);
    // Actually provide the service here.
}  

Sin embargo, este no es el mejor método.

El estándar de token ERC20 (un gran recurso sobre tokens en general) especifica un método llamado transferFrom()y recomienda un método llamado approve(). Una dirección puede usarse approve()para permitir que otra dirección retire algunos tokens a través de transferFrom(). Con esto, sería sencillo crear un contrato de vendedor. El comprador le da al vendedor el derecho de retirar tantos tokens a través approve()de , y el vendedor los usa transferFrom()para obtener esos tokens. De hecho, esto es mucho mejor, porque usted (o cualquier otra persona) puede agregar nuevos vendedores al sistema. Sería bien vale la pena su tiempo para implementar esto.

Gracias por su respuesta. Tendré que revisar sus recomendaciones más tarde. Jugué un poco con mi propia versión. La publicaré aquí también y tal vez podría echarle un vistazo para ver algunas mejoras.

De acuerdo con Mathew sobre ERC20 versus token de rollo propio. No estoy seguro de que el tiempo limitado sea realmente lo que desea para un oneTimeService. Aquí hay otra forma de ver un tiempo en cualquier caso:

 function f(uint durationInMinutes) {
    uint deadline = now + durationInMinutes * 1 minutes;
 } // unit time in seconds +/- 900 seconds

No estoy seguro de que necesite un contrato por separado para oneTimeService... No estoy seguro de que el tiempo sea el camino a seguir. Considere hacerlo explícitamente una sola vez si esa es la intención:

contract C {

mapping(address => bool) alreadyDone;

function oneTime(address user) returns(bool success) {
    if(alreadyDone[user]) throw;
    // do something
    alreadyDone[user]=true;
}

}

Si esto está en servicio con la interfaz de usuario, entonces probablemente desee usar el patrón de una sola vez y un emisor de eventos o una transacción extraída para confirmar que algo realmente sucedió.

agregar:

event LogItHappened(address user); // initialize it

//do something
LogItHappened(user); // UI can watch for this with an event listener.