Por qué recibo: Error de transacción. ¿Excepción lanzada en el código de contrato en Rinkeby?

Estoy creando un token que genera nuevos tokens cada vez que se le envía ETH. Toma esos tokens recién generados y los envía a la dirección de la billetera que envió el ETH. El maxTokens es 40mil. La TASA es de 20 mil (tratando de simplificar las cosas para mi prueba). Es bastante sencillo.

El problema que encuentro con mi contrato de prueba es que tratar de enviar 1 ETH está bien y la transacción se realiza. Intentar enviar una cantidad mayor, como digamos 1.5, produce esta advertencia: "Error de transacción. Excepción lanzada en el código del contrato. Límite de gas establecido peligrosamente alto. Es probable que la aprobación de esta transacción falle".

Después de jugar un rato, me di cuenta de que podía enviar cantidades más pequeñas de ETH que pasarían después de enviar el 1ETH. Sin embargo, cuanto más me acercaba a los tokens máximos, obtenía el error mencionado anteriormente.

¿Alguien puede explicar por qué estoy recibiendo este error? No puedo entender por qué se produce un error cuando alguien envía una cantidad de ETH que está relativamente cerca de los maxTokens.

Editar: he podido comprar con éxito hasta 39,999,700 de los tokens. Sin embargo, tengo que seguir comprando cantidades más pequeñas cada vez o recibo los errores mencionados anteriormente.

pragma solidity ^0.4.11;

import './IERC20.sol';
import './SafeMath.sol';

contract ChekOutToken is IERC20 {

using SafeMath for uint256;

uint public _totalSupply = 0;

string public constant symbol = "CHEKS";
string public constant name = "ChekOut Token";
uint8 public constant decimals = 18;

// 1 ETH = 1000 CHEKS
uint256 public constant RATE = 20000000;

// Sets Maximum Tokens to be Created
uint256 public constant maxTokens = 40000000000000000000000000;

address public owner;

mapping (address => uint256) public balances;
mapping(address => mapping(address => uint256)) allowed;

function () payable{
    createTokens();
}

function ChekOutToken(){
    owner = msg.sender;
}

function createTokens() payable{
    require(msg.value > 0);
    require(_totalSupply.add(tokens) <= maxTokens);
    uint256 tokens = msg.value.mul(RATE);
    balances[msg.sender] = balances[msg.sender].add(tokens);
    _totalSupply = _totalSupply.add(tokens);
    owner.transfer(msg.value);
    require(_totalSupply.add(tokens) <= maxTokens);
}

function totalSupply() public constant returns (uint256 totalSupply) {
    return _totalSupply;
}

function balanceOf(address _owner) public constant returns (uint256 balance) {
    return balances[_owner];
}

function transfer(address _to, uint256 _value) public returns (bool success) {
    require(balances[msg.sender] >= _value && _value > 0);
    balances[msg.sender] = balances[msg.sender].sub(_value);
    balances[_to] = balances[_to].add(_value);
    Transfer(msg.sender, _to, _value);
    return true;
}

function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
    require(allowed[_from][msg.sender] >= _value && balances[_from] >= _value && _value > 0);
    balances[_from] = balances[msg.sender].sub(_value);
    balances[_to] = balances[_to].add(_value);
    allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
    Transfer(_from, _to, _value);
    return true;
}

function approve(address _spender, uint256 _value) public returns (bool success) {
    allowed[msg.sender][_spender] = _value;
    Approval(msg.sender, _spender, _value);
    return true;
}

function allowance(address _owner, address _spender) public constant returns (uint256 remaining) {
    return allowed[_owner][_spender];
}

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

event Approval(address indexed _owner, address indexed _spender, uint256 _value);

}

Respuestas (1)

Veo dos problemas, y creo que el segundo es el origen de su error:

function createTokens() payable{
    require(msg.value > 0);
    require(_totalSupply.add(tokens) <= maxTokens);
    uint256 tokens = msg.value.mul(RATE);
    balances[msg.sender] = balances[msg.sender].add(tokens);
    _totalSupply = _totalSupply.add(tokens);
    owner.transfer(msg.value);
    require(_totalSupply.add(tokens) <= maxTokens);
}

La línea require(_totalSupply.add(tokens) <= maxTokens);ocurre dos veces. Cada vez es problemático:

  1. La primera vez, tokensaún no se le ha asignado un valor. (Me sorprendió que esto incluso se compilara, pero aparentemente se elevan las declaraciones de variables). Entonces, esto verifica agregar 0, que no hace lo que desea.
  2. La segunda vez, ya ha agregado tokensa _totalSupply, por lo que está comprobando efectivamente "¿Puedo agregar tokensdos veces y aún permanecer debajo maxTokens?"

Arreglaría la función moviendo lo anterior requirea después del cálculo tokensy deshaciéndome de él requireal final:

function createTokens() payable{
    require(msg.value > 0);
    uint256 tokens = msg.value.mul(RATE);
    require(_totalSupply.add(tokens) <= maxTokens);
    balances[msg.sender] = balances[msg.sender].add(tokens);
    _totalSupply = _totalSupply.add(tokens);
    owner.transfer(msg.value);
}
¡Lo resolviste! Funciona bien ahora. Gracias por señalar el doble uso de la función require. Me siento tonto porque pensé que había borrado el primero, pero obviamente no lo hice...