Solidity Payable Functions - Discussion

Welcome to the forum discussion for this section. Here you can ask questions or post feedback.

1 Like

@filip

Hello Filip,

Regarding how to get the Smart Contract balance, you suggest to create a variable and store the balance there, however I did create a function that does that automatically without needing to create a variable. Is this correct or better to use your method? thanks :slight_smile:

function getContractValue () public view returns (uint){  
  
    return address(this).balance; 
}

Then, to withdrawal the funds I have done like this:

function withdrawalAll () public onlyOwner {
msg.sender.transfer(getContractValue());
assert(getContractValue()==0);
}

// The assert function is just to look cool xD, if that is useless please tell me and I will remove it

4 Likes

pragma solidity 0.5.12;

contract HelloWorld{
struct Person {
uint id;
string name;
uint age;
uint height;
bool senior;
uint balance; //////ADDED :checkered_flag:
}
event personCreated(string name, bool senior);
event personDeleted(string name, bool senior, address deletedBy);
address public owner;
modifier onlyOwner(){
require(msg.sender == owner);
_; //Continue execution
}
constructor() public{
owner = msg.sender;
}
mapping (address => Person) private people;
address[] private creators;
function createPerson(string memory name, uint age, uint height) public payable {
require(age < 150, “Age needs to be below 150”);
require(msg.value >= 1 ether);
//This creates a person
Person memory newPerson;
newPerson.name = name;
newPerson.age = age;
newPerson.height = height;
newPerson.balance = msg.value; //////ADDED :checkered_flag:
if(age >= 65){
newPerson.senior = true;
}
else{
newPerson.senior = false;
}
insertPerson(newPerson);
creators.push(msg.sender);
assert(
keccak256(
abi.encodePacked(
people[msg.sender].name,
people[msg.sender].age,
people[msg.sender].height,
people[msg.sender].senior
)
)
==
keccak256(
abi.encodePacked(
newPerson.name,
newPerson.age,
newPerson.height,
newPerson.senior
)
)
);
emit personCreated(newPerson.name, newPerson.senior);
}
function insertPerson(Person memory newPerson) private {
address creator = msg.sender;
people[creator] = newPerson;
}
function getPerson() public view returns(string memory name, uint age, uint height, bool senior, uint balance){
address creator = msg.sender;
return (people[creator].name, people[creator].age, people[creator].height, people[creator].senior, people[creator].balance); //////ADDED :checkered_flag:
}
function deletePerson(address creator) public onlyOwner {
string memory name = people[creator].name;
bool senior = people[creator].senior;
delete people[creator];
assert(people[creator].age == 0);
emit personDeleted(name, senior, owner);
}
function getCreator(uint index) public view onlyOwner returns(address){
return creators[index];
}
}

3 Likes

Yes, that will work fine as well :slight_smile:

@filip I misunderstood the point of the homework, which is to store the balance for the contract and not for the individual people. I was looking at this as a bank system, where to create an account, you have to do an initial deposit. Anyhow, I get it, the contract can “own” funds as well.

But let’s say we did want to store user’s balances, specifically within the contract. I did it like this – I created a mapping, but apparently we can’t map anything but simple types, so I had to do use the Person’s hash:

mapping(bytes32 => uint) private balances;

and then to store upon creation, I just added to the mapping using the hash function you taught us already:

bytes32 hash = keccak256(abi.encodePacked(newPerson.name, newPerson.age, newPerson.height));
balances[hash] = msg.value;

Is that basically how it would have to be done if solidity can’t use a struct as a key?

No, in almost all cases you use the address as the key.

mapping(address => uint) private balances;
1 Like

Ah, okay, thank you. That does make a lot more sense. So in a real-world case, as we can’t iterate over people, we’d have to change our creators array to be an array of a struct, like Person, but also add an address property to it, correct?

Well, in most cases we don’t need an array of the creators. I don’t remember what we used it for in this case. But in most cases it’s enough to just have the mapping where the address points to what ever resource we need.

The exception would be if we need to know the addresses or People instance of everyone who used the contract.

I used a similar approche and was going to ask the same thing. :slight_smile:
Thanks for asking :ok_hand:

1 Like

@filip The link doesn’t open a sol file, it just goes to the repo. There is no file called payable-assignment. I am taking it that its meant to link to payable-receive.sol?

1 Like

Hi, Thanx for letting us know, can you post the link here? So we can test it?
Ivo

Yes.
You can use payable-receive.sol to correct your own code. Good luck.
Ivo

I added a line to keep track of the contract’s balance and a variable at the end of the function getPerson to return the contract’s balance whenever someone calls the function

pragma solidity 0.5.12;

contract HelloWorld{
    
    struct Person {
      uint id;
      string name;
      uint age;
      uint height;
      bool senior;
    }

    event personCreated(string name, bool senior, uint person_balance);
    event personDeleted(string name, bool senior, address deletedBy);
    
    uint public balance;
    address public owner;

    modifier onlyOwner(){
        require(msg.sender == owner);
        _; //Continue execution
    }

    constructor() public{
        owner = msg.sender;
    }

    mapping (address => Person) private people;
    address[] private creators;

    function createPerson(string memory name, uint age, uint height) public payable {
      require(age < 150, "Age needs to be below 150");
      require(msg.value >= 1 ether);
        
        balance += msg.value;
        //This creates a person
        Person memory newPerson;
        newPerson.name = name;
        newPerson.age = age;
        newPerson.height = height;

        if(age >= 65){
           newPerson.senior = true;
       }
       else{
           newPerson.senior = false;
       }

        insertPerson(newPerson);
        creators.push(msg.sender);

        assert(
            keccak256(
                abi.encodePacked(
                    people[msg.sender].name,
                    people[msg.sender].age,
                    people[msg.sender].height,
                    people[msg.sender].senior
                )
            )
            ==
            keccak256(
                abi.encodePacked(
                    newPerson.name,
                    newPerson.age,
                    newPerson.height,
                    newPerson.senior
                )
            )
        );
        emit personCreated(newPerson.name, newPerson.senior, balance);
    }
    function insertPerson(Person memory newPerson) private {
        address creator = msg.sender;
        people[creator] = newPerson;
    }
    function getPerson() public view returns(string memory name, uint age, uint height, bool senior, uint contract_balance){
        address creator = msg.sender;
        return (people[creator].name, people[creator].age, people[creator].height, people[creator].senior, balance);
    }
    function deletePerson(address creator) public onlyOwner {
      string memory name = people[creator].name;
      bool senior = people[creator].senior;

       delete people[creator];
       assert(people[creator].age == 0);
       emit personDeleted(name, senior, owner);
   }
   function getCreator(uint index) public view onlyOwner returns(address){
       return creators[index];
   }

}
1 Like

I assigned the message value to the createPerson function, then I called out this balance from the memory. This showed the price of createPerson for the creator.
After I made a new function to check the contract value .

Spoiler
pragma solidity 0.5.12;

contract HelloWorld{

    struct Person {
      uint id;
      string name;
      uint age;
      uint height;
      bool senior;
    }

    event personCreated(string name, bool senior);
    event personDeleted(string name, bool senior, address deletedBy);

    address public owner;
    
    modifier onlyOwner(){
        require(msg.sender == owner);
        _; //Continue execution
    }

    constructor() public{
        owner = msg.sender;
    }

    mapping (address => Person) private people;
    address[] private creators;

    function createPerson(string memory name, uint age, uint height) public payable {
      require(age < 150, "Age needs to be below 150");
      require(msg.value >= 1 ether);
        //This creates a person
        Person memory newPerson;
        newPerson.name = name;
        newPerson.age = age;
        newPerson.height = height;
        balance = msg.value;               // <-------------------------------------------------------

        
        if(age >= 65){
           newPerson.senior = true;
       }
       else{
           newPerson.senior = false;
       }
        
        insertPerson(newPerson);
        creators.push(msg.sender);

        assert(
            keccak256(
                abi.encodePacked(
                    people[msg.sender].name,
                    people[msg.sender].age,
                    people[msg.sender].height,
                    people[msg.sender].senior
                )
            )
            ==
            keccak256(
                abi.encodePacked(
                    newPerson.name,
                    newPerson.age,
                    newPerson.height,
                    newPerson.senior
                )
            )
        );
        emit personCreated(newPerson.name, newPerson.senior);
    }
    uint public balance;                                                 // <-------------------------------------------------------
    function contractBalance() public view returns(uint){               // <------------------------------------------------
         return address(this).balance;                                 // <-------------------------------------------------------
    }                                                                 // <-------------------------------------------------------
    
    function insertPerson(Person memory newPerson) private {
        address creator = msg.sender;
        people[creator] = newPerson;
    }
    function getPerson() public view returns(string memory name, uint age, uint height, bool senior){
        address creator = msg.sender;
        return (people[creator].name, people[creator].age, people[creator].height, people[creator].senior);
    }
    function deletePerson(address creator) public onlyOwner {
      string memory name = people[creator].name;
      bool senior = people[creator].senior;

       delete people[creator];
       assert(people[creator].age == 0);
       emit personDeleted(name, senior, owner);
   }
   function getCreator(uint index) public view onlyOwner returns(address){
       return creators[index];
   }

}

1 Like

I discovered one mistyping in the GitHub code. @filip

 function withdrawAll() public onlyOwner returns(uint) {
       toTransfer = balance;
       balance = 0;
       msg.sender.transfer(***balance***);
       return toTransfer;
   } 

There is “toTransfer” instead of “balance”. Is clear and correct in the lecture, but after you explained the difference between send and transfer and I guess that was copied after.

1 Like

Code for payable functions ```

pragma solidity 0.5.12;

contract HelloWorld{

    struct Person {
      uint id;
      string name;
      uint age;
      uint height;
      bool senior;
      uint balance;
    }

    event personCreated(string name, bool senior);
    event personDeleted(string name, bool senior, address deletedBy);

    address public owner;

    modifier onlyOwner(){
        require(msg.sender == owner);
        _; //Continue execution
    }

    constructor() public{
        owner = msg.sender;
    }

    mapping (address => Person) private people;
    address[] private creators;

    function createPerson(string memory name, uint age, uint height) public payable {
      require(age < 150, "Age needs to be below 150");
      require(msg.value >= 1 ether);
        //This creates a person
        Person memory newPerson;
        newPerson.name = name;
        newPerson.age = age;
        newPerson.height = height;
        

        if(age >= 65){
           newPerson.senior = true;
       }
       else{
           newPerson.senior = false;
       }

        insertPerson(newPerson);
        creators.push(msg.sender);

        assert(
            keccak256(
                abi.encodePacked(
                    people[msg.sender].name,
                    people[msg.sender].age,
                    people[msg.sender].height,
                    people[msg.sender].senior
                    
                )
            )
            ==
            keccak256(
                abi.encodePacked(
                    newPerson.name,
                    newPerson.age,
                    newPerson.height,
                    newPerson.senior
                    
                )
            )
        );
        emit personCreated(newPerson.name, newPerson.senior);
    }
    function insertPerson(Person memory newPerson) private {
        address creator = msg.sender;
        people[creator] = newPerson;
    }
    function getPerson() public view returns(string memory name, uint age, uint height, bool senior, uint balance){
        address creator = msg.sender;
        return (people[creator].name, people[creator].age, people[creator].height, people[creator].senior, people[creator].balance);
    }
    function deletePerson(address creator) public onlyOwner {
      string memory name = people[creator].name;
      bool senior = people[creator].senior;

       delete people[creator];
       assert(people[creator].age == 0);
       emit personDeleted(name, senior, owner);
   }
   function getCreator(uint index) public view onlyOwner returns(address){
       return creators[index];
   }
   
   function getBalance(uint index) view public returns (uint) {
       
        return creators[index].balance;
    }

}
1 Like

pragma solidity 0.5.12;

contract HelloWorld{

struct Person {
  uint id;
  string name;
  uint age;
  uint height;
  bool senior;
}

uint public balance = 0;

event personCreated(string name, bool senior);
event personDeleted(string name, bool senior, address deletedBy);

address public owner;

modifier onlyOwner(){
    require(msg.sender == owner);
    _; //Continue execution
}

constructor() public{
    owner = msg.sender;
}

mapping (address => Person) private people;
address[] private creators;

function createPerson(string memory name, uint age, uint height) public payable {
  require(age < 150, "Age needs to be below 150");
  require(msg.value >= 1 ether);
  balance += msg.value;
    //This creates a person
    Person memory newPerson;
    newPerson.name = name;
    newPerson.age = age;
    newPerson.height = height;

    if(age >= 65){
       newPerson.senior = true;
   }
   else{
       newPerson.senior = false;
   }

    insertPerson(newPerson);
    creators.push(msg.sender);

    assert(
        keccak256(
            abi.encodePacked(
                people[msg.sender].name,
                people[msg.sender].age,
                people[msg.sender].height,
                people[msg.sender].senior
            )
        )
        ==
        keccak256(
            abi.encodePacked(
                newPerson.name,
                newPerson.age,
                newPerson.height,
                newPerson.senior
            )
        )
    );
    emit personCreated(newPerson.name, newPerson.senior);
}
function insertPerson(Person memory newPerson) private {
    address creator = msg.sender;
    people[creator] = newPerson;
}
function getPerson() public view returns(string memory name, uint age, uint height, bool senior){
    address creator = msg.sender;
    return (people[creator].name, people[creator].age, people[creator].height, people[creator].senior);
}
function deletePerson(address creator) public onlyOwner {
  string memory name = people[creator].name;
  bool senior = people[creator].senior;

   delete people[creator];
   assert(people[creator].age == 0);
   emit personDeleted(name, senior, owner);

}
function getCreator(uint index) public view onlyOwner returns(address){
return creators[index];
}

}

1 Like

function getBalance() public view returns(uint){
return address(this).balance;
}

1 Like

HI.
I’m not sure what you meant, but this line is the correct code:

msg.sender.transfer(toTransfer);

Ivo

2 Likes