Help to get variable in a pseudo random lottery contract

Hi everyone at the other side!

I'm doing a psudo random lottery contract on solidity. It's working 100% good. The logic of the contract is that a player pays for getting a number in order to match with the number that owner put when did deploy. If it's match the jackpot is splitted in both. But, I cannot get the way to show the user the number that he/she got. I want to do that in order to then develop a DApp and show transparency to user. The variable call "numero" and you can see that I tried to do a function called verPremio(), but it doesn't work.

Please, your help will be very appreciated, thank you in advance.

pragma solidity ^0.5.0;

contract Loteriados{
    

    address internal owner;         //creador del contrato
    uint256 internal num;           //contador numero de intentos
    uint256 public precio;          //precio para participar
    uint256 public numeroGanador;   //numero ganador definido por el creador del contrato
    bool public juego;              //indicador si o no esta habilitado el juego para jugar
    address public ganador;         //direccion wallet del ganador de la Loteria
    uint256 public fondoInicial;    //pozo inicial aportado por el creador del contrato
//    uint256 public numero;          //numero obtenido al participar 



//seteo de las variables iniciales e instrucciones que ocurren por unica vez en el deploy
    constructor(uint256 _numeroGanador, uint256 _precio) public payable{
        owner = msg.sender;
        num = 0;
        numeroGanador = _numeroGanador;
        precio = _precio;
        juego = true;
        fondoInicial = msg.value;
    }

//modificador que obliga a que el valor pagado por participante sea igual al precio por particiar
    modifier filtroPrecio(){
        require(precio == msg.value);
        _;
    }

//modificador que define que olo el creador pueda ejecutar partes del contrato
    modifier onlyOwner(){
        require(msg.sender == owner);
        _;
    }

//funcion que define la pseudo aleatoriedad, para el resultado del participante    
    function numeroRandom() private view returns(uint256){
        return uint256( keccak256( abi.encode(block.timestamp, msg.sender, num) ) ) % 10;
    }

//funcion que comprueba si el participante ha acertado 
    function comprobarAciertos(uint256 _numUsuario) private view returns(bool){
        if(_numUsuario == numeroGanador)
                {return true;}
        else    {return false;}    
        }
    
//funcion core del juego de loteria, pide que lo pagado sea igual al precio
    function participar() external payable filtroPrecio returns(bool resultado, uint256 numero){
        require(juego == true);                                 //el juego tiene que estar habilidado para jugar
        uint256 numUsuario = numeroRandom();                    //define que numUsuario es el dado por la funcion psudo aleatoria
        bool acierto = comprobarAciertos(numUsuario);           //usando la funcion comprobarAciertos define si o no el usuario ha acertado
        if(acierto == true)                                     //Si se ha acertado
            {juego = false;                                         //se para eljuego
            msg.sender.transfer((address(this).balance)/2);         //se transfiere la mitad del balance al participante
            ganador = msg.sender;                                   //se obtiene el adress wallet del participante
            resultado = true;                                       //se dice que el acierto es verdadero
            numero = numUsuario;                                   //se escribe el numero del usuario en variable numero
            }
            
        else(acierto == false);                                 //si el participante no ha acertado
            {num = num + 1;                                         //se suma 1 al contador para registrar un nuevo intento
            resultado = false;                                      //se dice que el resultado es falso
            numero = numUsuario;                                    //se escribe el numero del usuario en variable numero
            }                                   
    }


//funcion getter para ver el pozo del premio mientras se encuentre activo el juego    
    function verPremio() public view returns(uint256) {
        if(juego == true)
            {return address(this).balance/2;}
        else
            {return 0;}
    }    
    

//funcion que permite al creador del contrato retirar 50% del monto siepre y cuando un participante haya ganado antes
 function retirarFondosContrato() onlyOwner external returns(uint256) {
        require(juego == false);                                        //ni siquiera el creador puede sacar monto, esto es transparencia!!
        uint256 pagoCreador = address(this).balance;
        msg.sender.transfer(pagoCreador);
        return pagoCreador;
    }
    
}

Hi, welcome! :wave:

I am not sure what do you mean. I just deployed this contract and had a try:

It looks like it works well.

Hi, It's work well. My mistake about said that verPremio() doesn't work.
The thing that I cannot get is variable called "numero" which is the number that user has gotten in every try.
Do you know how can I get it ? I cannot get the way.

Best Regards

I think you use a shadow variable. You have a variable named numero which is defined as uint256 public numero;, and for you function participar(), its returning value is also named numero, so it only change this returning value rather than the global value, so when you call numero, it always is 0

Yes, that is the problem.
número always return 0 value even though it has a different one (you can check it in the log).
I defined numero as global variables trying to do the getter that I looking for. But it doesn't work.

Actually, the número defined at the function participar() is the right one but I said cannot get the output.

Any idea how to do the getter for numero?
Thanks in advance !!

Ohhh, I see. Cause your function is not a view function, so you can not get the return value directly when you call it. Maybe you can use another variable to get the result of this function, and then try to read that variable.

hi again, I have been trying the thing that you said me but I cannot get the variable even if I use another variable such as numero, numUsuario and numeroRandom.
Also, I did a new getter function recalling the random variable like that:

//funcion que define la pseudo aleatoriedad, para el resultado del participante    
    function numeroRandom() private view returns(uint256){
//        return uint256( keccak256( abi.encode(block.timestamp, msg.sender, num) ) ) % 10;
//    }    
        uint256 rand = uint256( keccak256( abi.encode(block.timestamp, msg.sender, num) ) ) % 10;
        return rand;
    }

Also, I change the private definition for public and could get numeroRandom at the output. But I a push the the button I getting a different number regarding that the log is saying me that I doing the transaction with participar().

Please @Skyge can you please help me maybe coding it?, I battle with that contract to much and I got nothing, no ideas to try.
I appreciate you valuable time, regards!

So do you mean you want to get the result of the function participar when a user calls it? I think it could be

uint256 public numero;          //numero obtenido al participar

function comprobarAciertos(uint256 _numUsuario) public view returns(bool){
        if(_numUsuario == numeroGanador)
                {return true;}
        else    {return false;}    
        }

function participar() external payable filtroPrecio {
        require(juego == true);                                 //el juego tiene que estar habilidado para jugar
        uint256 numUsuario = numeroRandom();                    //define que numUsuario es el dado por la funcion psudo aleatoria
        bool acierto = comprobarAciertos(numUsuario);           //usando la funcion comprobarAciertos define si o no el usuario ha acertado
        if(acierto == true)                                     //Si se ha acertado
            {juego = false;                                         //se para eljuego
            msg.sender.transfer((address(this).balance)/2);         //se transfiere la mitad del balance al participante
            ganador = msg.sender;                                        //se dice que el acierto es verdadero
            numero = numUsuario;                                   //se escribe el numero del usuario en variable numero
            }
            
        else(acierto == false);                                 //si el participante no ha acertado
            {num = num + 1;                                    //se dice que el resultado es falso
            numero = numUsuario;                                    //se escribe el numero del usuario en variable numero
            }                                   
    }

So now user calls participar(), the previous return value numero is equal to the global variable numero, and the resultado is equal to the return value of comprobarAciertos(numero), so now, does it satisfy your requirement?

But there is another question, if two users call the function participar() at the same block, it seems like the first confirmed user can not get a valid numero, so maybe you can use a mapping(address => uint256) public numeros to record for different users.
And here is another question, if one user just calls the function participar() twice, it seems like we can not get the return value of the first transaction.

Hi @Skyge, you are awesome ! I did the changes and it works for me.

Hi @Skyge, I did the code doing the mapping for users which call participar() at the same time. It works perfect, recording numero for more that one user. See the code below.

mapping(address => uint256) public numeros;

function participar() external payable filtroPrecio { //returns(bool resultado, uint256 numero){
    require(juego == true);                                 //el juego tiene que estar habilidado para jugar
    uint256 numUsuario = numeroRandom();                    //define que numUsuario es el dado por la funcion psudo aleatoria
    bool acierto = comprobarAciertos(numUsuario);           //usando la funcion comprobarAciertos define si o no el usuario ha acertado
    if(acierto == true)                                     //Si se ha acertado
        {juego = false;                                         //se para eljuego
        msg.sender.transfer(fondoInicial + ( num * (precio/2)));         //se transfiere la mitad del balance al participante
        ganador = msg.sender;                                   //se obtiene el adress wallet del participante
        numero = numUsuario;                                   //se escribe el numero del usuario en variable numero
        numeros[msg.sender] = numero;
        }
        
    else(acierto == false);                                 //si el participante no ha acertado
        {num = num + 1;                                         //se suma 1 al contador para registrar un nuevo intento
        numero = numUsuario;                                    //se escribe el numero del usuario en variable numero
        numeros[msg.sender] = numero;
        }                                   
}

But, I couldn't get the code for your second question. I not sure how I can save two o more values for the same msg.sender (user) if it activates twice the function participar(). I just thinking to do something like that.

mapping(address => uint256[]) public numeros;

but, I wasn't be able to modify the code for participar()
Do you have any idea how to do it?

I much appreciate your valuable help!
Regards

Yeah, for the later case, I also think so.

And kind reminder, I am not sure whether the condition else in the function participar is really you want, that is no matter what is the value of the variable acierto, it will execute the last lines:

{num = num + 1;                                         //se suma 1 al contador para registrar un nuevo intento
numero = numUsuario;                                    //se escribe el numero del usuario en variable numero
numeros[msg.sender] = numero;
} 

cause you do nothing in the condition else(acierto == false);, but I think the code is OK, just a little confusing.

1 Like