Additional Solidity Concepts - Discussion

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

2 Likes

I have a question to the quiz. The question is: “When is the function modifiers code executed?”
The correct answer is “Before the function”
But are the modifiers not being executed every time they are called in a function?

1 Like

Maybe it’s worded badly. You are correct the modifiers are executed every time you call a function. The quiz points out that the code of the modifier is executed prior to the function code. Does that make sense?

3 Likes

Of course. My question was anyway more a newbie question.

1 Like

@filip when you need to retrieve properties to emit from your event, is it typically cheaper to only retrieve the properties you need, or, with a large struct, is it the same cost to retrieve the entire struct and then access its properties? e.g. Person memory person = people[creator]; string name = person.name; bool senior = person.senior; ?

1 Like

It should cost less if you only retrieve the values you need instead of the whole struct. The use of a local memory variable as an intermediary, like in your example, will also increase the cost since you’re making a copy.

2 Likes

Why do we have to specify the data location to memory for function scope arguments and variables. This behaviour seems antithetical to convention where these variables should be cleared from memory once the scope is cleared. Why was this not the default/implicit behaviour and specifying storage the exception. @filip

1 Like

Good questions. I think the reason they decided that you have to put the storage location explicitly was because a lot of people assumed that a variable declared locally was in memory and would be cleared after each run. But in some circumstances with arrays, structs or mapping it would be a storage variable. That mistake would lead to completely different behavior of the code, as you saw in the video.

So instead they force you to write either memory or storage. That way you are forced to think about which one you want.

3 Likes

@filip or anyone who can assist, I’m working on a project to better understand all of the concepts we learned; however, I’m running into difficulty with creating a function that’ll push a string into a dynamic string array. Here’s what I have:

pragma solidity 0.6.3;

contract DexquisiteCorpse {

string [] public etherPoem = ["let "];

modifier costs(uint cost) {
    require(msg.value >= cost);
    _;
}

function addToPoem(string memory newWord) public payable costs(1 ether){
    etherPoem.push(newWord);
}

}

When I deploy the contract, the string does not append to the array. I tried throwing in a return statement, but an error citing that I need to input memory keeps occuring. I read that I should be using storage with a dynamic string array. I’m unsure of how to rectify the code and move forward.

Hi @andrewfleming

The new string is happened to the etherPoem array. If i add a new string i can see it at index 1.
Then an other one at index 2. An array start at index 0

3 Likes

Hey @gabba

Haha a complete oversight on my part. Thank you so much!

1 Like

@gabba, @filip, @ivga80, @pedromndias

  • Is the following a correct summary of how data location works for different data types/structures?

  • Are my two lists, categorising different data types/structures as either value types or complex types, also correct?


VALUE TYPES

int and uint < 256 bits
bool
address

Data location is never specified, because by default it is always:

  • storage when they are state variables;
  • memory when they are function arguments/parameters;
  • stack when they are local variables;

COMPLEX TYPES

struct
string
arrays
mappings

Data location is never specified when they are state variables, because by default this is always storage.
However, when they are used as either function arguments/parameters or local variables, data location must always be specified as either memory or storage.

4 Likes

@filip @gabba
I am having trouble mapping my array and getting values back…
I’m entering the address in the struct, and I would like to be able to call values using the address…
Also, when I re-enter data for an address I would like the old data overwritten.
I’ve been through Ethereum stack exchange, and as best I can tell I’m using the same mapping formatting when I try to getPony. I’ve tried setting the arguments and return values in that function a few different ways.

I’m pretty sure it has to do with the array…
But I want both.
I’m not using owner, but I think it needs to be ownable?

Do I need to create the ponies in the array without addresses then transfer them to their addresses?

I know if I pound at this a few more days I’ll probably figure it out,
but I’ve been hitting it a couple of days and it’s slowing me down.
I want to learn to web3 interface and set up something where my Twitter friends can store their horses. I have a game in mind. Well, a few games. If you aren’t horse crazy you won’t get them. :wink:

pragma solidity 0.5.12;

import "./Ownable.sol";
import "./Destroyable.sol";

//trying to get ponies to update at same address instead of double recording
//Trying to retrieve ponies using address

contract FatAssPonies is Ownable, Destroyable {
    
    struct Pony {
       
        string name;
        string breed;
        uint height;
        uint weight;
        string color;
        bool truePony;
        address stall;
    } 
   
    
    uint public balance;
   
    modifier costs(uint cost) {
        require(msg.value >= cost);
        _;
    }
    
    Pony[] public ponies;
    //So I was down at the bottom of createPony trying to remember how to save my ponies into arrays...
    //Had to go back to Filip's vid/ All I have to do is declare the array at the beginning and push at the end, derp.
    
    mapping (address => Pony) public stables;
    //instanciate... create an instance of... the struct.
    function createPony( string memory name, string memory breed, uint height, uint weight, string memory color, address stall) public payable {
        //ponies.push(Pony(ponies.length, name, breed, height, weight, color, truePony, stall));
        //Not sure how to do a boolean with the above slick array push.
        //when the boolean is in the array it doesn't return a result. 
        
        balance += msg.value;  //here I changed to += because the ponies need jingle
        Pony memory newPony;
        newPony.name = name;
        newPony.breed = breed;
        newPony.height = height;
        newPony.weight = weight;
        newPony.color = color;
        if(height<=56){
            newPony.truePony = true;
        }
        else {
            newPony.truePony = false;
        }
        newPony.stall = stall;
        ponies.push(newPony);
        
    }
    
    //I didn't have a way to access my ponies because I hadn't made the array public,
    //so I was down here trying to figure out how to write that function
    //Then the next thing Filip mentioned was to make the array public 
    //so that Solidity creates the getter function.
    //I know this is super basic, but it's the stuff I missed copy/pasting and modifying until it works
    //and having to write the same thing we just did in lectured really IS helping.
    //I have a website interface in mind for this, so it is the basis of an ongoing project.
    
    
    
    //function getPony() public view returns(string memory name, string memory breed, uint height, uint weight, string memory color, bool truePony, address stall){
    //    address pony = Pony[stall];
       
    //return (ponies[pony].name, ponies[pony].breed, ponies[pony].height, ponies[pony].weight, ponies[pony].color, ponies[pony].truePony, ponies[pony].stall);
    //}
    
    //function updatePony(string memory name, string memory breed, uint height, uint weight, string memory color, bool truePony, address stall) public {
    //    stables[stall] = Pony(name, breed, height, weight, color, truePony, stall);
    //}
// This is not updating info to the struct array...But it compiles
 
    
   
   //The following did not compile...     
   // function getPony(address stall) view public returns (string memory, string memory, uint, uint, string memory, bool, address) {
   //     return (stables[stall].name, stables[stall].breed, stables[stall].height, stables[stall].weight, stables[stall].truePony, stables[stall].color, stables[stall].stall);


}

pragma solidity 0.5.12;

contract Ownable {

address public owner;

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

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

}

pragma solidity 0.5.12;
import "./Ownable.sol";

contract Destroyable is Ownable {
    
    function close() public onlyOwner { //onlyOwner is custom modifier
        selfdestruct(msg.sender);  // `owner` is the owners address
    }
    
    
}
1 Like

Hi @petra
I really love the name of your contract ahahah.
I m not sure if it’s what you want to do so let me know.

At the end of your createPony function i ll store the msg.sender address in the stall variable of your structure but you can use an other address if you want too
Then use this address to store the newPony at this address in the stables mapping.

        newPony.stall = msg.sender;
        ponies.push(newPony);
        stables[msg.sender] = newPony;

To access it in your getter you will have nothing to do, because we will use the msg.sender address to get it back.

    function getPony() public view returns(string memory name, string memory breed, uint height, uint weight, string memory color, bool truePony, address stall){
        Pony memory pony = stables[msg.sender];
       
        return (pony.name, pony.breed, pony.height,pony.weight, pony.color, pony.truePony, newPony.stall);
    }

We get the Pony object and we display back his parameters

1 Like

Ty @gabba

Thank you for the fast response.

Of course as soon as I posted and took off for the night I thought of a couple of new approaches.

I’m trying to avoid msg.sender being the address.

People need to be able to register as many ponies as they like. Also, I would like to make the addresses stalls, so the ponies will be able to move from barn to barn.

What I’m going to try when I get home:

First, I’m going to map the structs and try making an array from the mapping…

But what I think I need to do is index the array then map to the index.

Ideally I’ll be able to call ponies by name, index, or stall and sort them by height, weight, breed etc.

Hi @petra

Ok so i think you will have to keep track of each pony owner and each stables owner.
you can do something like this.

    struct Pony {
        string name;
        string breed;
        uint height;
        uint weight;
        string color;
        bool truePony;
        uint stall;
        address owner;
    } 
   
    Stall {
         uint index;
         Pony pony;
    }

    Stable {
        address owner;
        Stall [] stall;
        mapping (address => Pony[]) public userPonies;
   }
   mapping (address => Stable) public stables;
   address [] public listOfStables;

Each user will be able to create and own a stable.
Every time a user create a new stable it ll be push in your array of listOfStables.

You can iterate over stables

	/* Get all the poney */
	function getListOfStables() public {
		for(uint i=0; i < listOfStables.length; i++){
			emit LogListOfStables(
			        listOfStables[i],
                    // you can also display all the pony in the stable
                   // getStablePony(listOfStables[i])
                   // And inside getStablePony you can do an iterator to display all the Stall
			     );
		}
	}

For this example i ll use fake address, so you can get a list of stable with the owner address:
listOfStables -> (0x1, 0x2)

then you can access the Stable with the mapping
Stable stable = stables[0x1]

In this stable you have a list of stall, so you can just iterate of stall, i ll take the first one
Stale stale = stable.stall[0]
So i ll get the object
stale.index -> 0
stale.poney -> pony informations

If i want i can use a user address to know all the ponies he have in the Stable.
Stable.userPonies[0x1]

To send a pony to an other barn, you will have to be the owner of the pony, and your function will have to remove the pony from the stable stall and add it to an other stable stall.

I hope it ll help you, let me know if it make sense i ’ m not really familiar with horses vocabulary in english :sweat_smile:

1 Like

This is epic.
Thank-you so much.
I’m working different bits of it right now.

I realized I wasn’t thinking clearly about what the ponies are.
I think they’ll end up non-fungibles, but that’s another day.

I’m still mind blown over how we can just stick words in.
Of course they’re variables, but we don’t have to declare them all.
It’s like the wild west, but better.

Yes using non-fungibles token will be the best choice

I finally wrote out what I want it to do.
This is great because I’m realizing how unclear I am
on what I can actually make this do.

I’m going back over the 101.
Content is different after wrestling with it.
A lot of thinking about how this actually works.

1 Like

Okay…
It’s not done yet,
but I think I have the addresses
working the way I want them to work.

Probably time to start committing
code.

:wink:

pragma solidity 0.5.12;

import "./Ownable.sol";
import "./Destroyable.sol";

/* Okay... all I'm doing in this contract is creating ponies using a pony struct,
mapping the creator address to the pony struct, then pushing the address to an array
and the structs to a separate array. As these are occurring simultaneously
the indices should be the same.*/

contract FatAssPonies is Ownable, Destroyable {
    
    struct Pony {
        string name;
        string breed;
        uint height;
        uint weight;
        string color;
        bool truePony;
        address stall;
        
    }
    
    
    
    
    Pony [] public deets;
    address [] public byAddy;
    mapping (address => Pony) public ponies;
    //Need to push the address to an array separate from the mapping...
    
    uint public balance;
   
    modifier costs(uint cost) {
        require(msg.value >= cost);
        _;
        
    }
    
    function createPony(string memory name, string memory breed, uint height, uint weight, string memory color) public payable costs(1 ether){
        address pony = msg.sender;
        Pony memory newPony;
        newPony.name = name;
        newPony.breed = breed;
        newPony.height = height;
        newPony.weight = weight;
        newPony.color = color;
        if(height<=56){
            newPony.truePony = true;
        }
        else {
            newPony.truePony = false;
        }
        newPony.stall = msg.sender;
        deets.push(newPony);
        byAddy.push(pony);
        ponies[pony]= newPony;
        
    }
    
    
    
}

Still not writing all this from memory,
but that’s why we have files and libraries.
:grimacing:

2 Likes