Solidity Basics

Hi Filip and fellow developers,

I love the module Solidity Basics! It’s easy to follow along and easy to understand!

Regarding the lesson about arrays, instead of adding a value to an array, is it possible to subtract values/indices from the array in Solidity?

If it is, how do we go about doing that ?

Cheers,
Built

It is possible, but not the best approach in terms of blockchain and Solidity, when you delete/substract values/indices from the array, you have to move the entire array to a new order of the indexes (array position) if you want to completely remove it, but it could be for example that you just leave the index in black (default value, like 0).

You can read more about it here:

Carlos Z

In this lecture it was mentioned that it’s good practice to name private functions prepended with an underscore like so _functionName. Is there a document of best practices to follow when writing smart contracts in Solidity?

Hi,
Is it possible to return the entire populated struct people?

Also would we specify the returns(type) as returns (uint, string memory) or as returns (Person[] memory) in this case?
Best wishes,
Aonia

1 Like

Hi so had a question on why I’m getting the following error with the code below when attempting to compile my contract.

This was your example for visibility.

CODE:

pragma solidity 0.7.5;

contract bank {

mapping(address => uint) balance;

function addBallance(uint _toadd) public returns (uint) {
balance[msg.sender] += _toadd; // This will set the balance to whatever the user inputs for _Todadd. This is the equivalent of writing balance[msg.sender]=balance[msg.sender]+_toAdd
return balance[msg.sender];
}

function getBalance() public view returns (uint){
return balance[msg.sender];
}

function transfer(address recipient, uint amount) public {

  _transfer(msg.sender, amount, recipient); // We can use the public function to call the private function which facilitates the transfer. This conceals the actual function and shows an example of the reusability of functions, even within other functions.

}

function _transfer(uint amount, address from, address to) private {
balance[from] -= amount; //
balance[to] += amount; // Alone, This is a crude transfer function that subtracts from the senders balance and adds to the recipient but doesn’t check to see if the msg.sender has the balance (value)

}

}

ERROR:

contracts/Mapping.sol:22:17: TypeError: Invalid type for argument in function call. Invalid implicit conversion from address payable to uint256 requested.
_transfer(msg.sender, amount, recipient); // We can use …
^--------^

1 Like

Tjena Filip :slight_smile: Det är lätt att följa dig :slight_smile:

I am wondering if mapping(address => uint) balance; is a contract state as we had before with the state variable?

// Mappings
contract Bank{

// defining the mapping(adress=key balance=uint) named: balance
mapping(address => uint) balance;

// adding more tokens to an adress
// unsigned int named _toAdd (uint cannot be negative) is added to existing balance of address
function addBalance(uint _toAdd) public returns (uint){
    
    // _toAdd uint is then added to the balance of msg.sender(address)
    // same as balance[msg.sender] = balance[msg.sender] + _toAdd
    balance[msg.sender] += _toAdd;
    
    // gives back the updated balance after the transaction within the function scope
    return balance[msg.sender];
    
}

// function to view the new balance (view because we are not changing, just viewing)
function getBalance() public view returns (uint){
    
    // returns updated balance of the adress(msg.sender) 
    return balance[msg.sender];
}

}

1 Like

Hey @Aonia, hope you are ok.

There is a way to return the values from an struct, which can be something like:

struct Person{
  uint id,
  string name,
  uint balance
} 

mapping(address => Person) people;

function getData() public view returns(uint, string memory, uint){
  return(
    people[msg.sender].id,
    people[msg.sender].name,
    people[msg.sender].balance
  );
}

This is an example, you could find a little bit more of info over internet about it.

Carlos Z

Hey @donhuey, hope you are ok.

Please share your code in the following way so I can review it properly and help you solve the issue:

Carlos Z

hii @filip…any error in the code mentioned below?

function withdraw(uint amount,address _address)public {balance[msg.sender]-=amount; address payable tosend=_address;tosend.transfer(amount);}

Some actual tangible, on-hands training. I haven’t seen much yet, but I like what I did. Have to say I like it much better than the ‘topical’ courses such as Blockchain Business Masterclass.

1 Like

Hi @bhallasatyansh13,

function withdraw(uint amount, address _address) public {
    // INCLUDE A SUITABLE REQUIRE STATEMENT HERE
    balance[msg.sender] -= amount;
    address payable tosend = _address;   // ERROR HERE
    tosend.transfer(amount);
}

To be able to assign a non-payable address (such as your parameter _address) to a payable address variable, you also need to explicitly convert the address value you are assigning, as follows…

address payable tosend = payable(_address);

Your function body also needs to start with a require statement to check whether the caller has enough balance to cover the requested withdrawal amount.


Please make sure you format your code before posting it, as described here, so that it’s clearer, easier to read, and easier to debug :slight_smile:

Hi Filip

In your Solidity Programming 101 under - Contract Structure, can you explain the following code

function hello () public pure returns ( string memory ) {

      return " Hello World ";

}

Question-. What’s the difference between returns and return ( without the s)?

Thanks
Eric

1 Like

Hi @ecbwong,

This difference is dictated by the Solidity syntax.

Solidity requires the data types of variables, parameters (function inputs) and returned values (function outputs) to be explicitly defined. This is in contrast to JavaScript, which is a dynamically-typed programming language, where data types do not need to be defined by the programmer in the source code.

These differences are reflected in each programming language’s syntax:

  • In both Solidity and JavaScript the return statement in the function body, which contains, or evaluates to, the actual value(s) returned by the function, is preceded by the keyword return

  • In Solidity, the data type(s) of the value(s) which the function returns (in the return statement) has/have to be defined in the function header using the syntax returns()

In Solidity, in certain circumstances, we also need to declare the data location. That’s why the value returned in your example is explicitly defined as both a string and with the memory data location:  returns(string memory) . The concept of data location, and the circumstances under which it needs to be explicity declared, are introduced later in the course.

Let me know if anything is still unclear, or if you have any further questions.

Hi Jon_m

Thanks for your reply. I get it now. Basically, they are Solidity keywords! I wasn’t sure initially, thinking it might be a typo error but then again ReMix would have highlighted it but didn’t.

As for data storage locations, ‘memory’ storage is temporary- is it not? Once the function is executed, the datas are gone? Well then variables declared globally, will it be perpetual i.e datas will be there whenever we run that particular smart contract anytime in the future?

Appreciate your feedback on that.

Thanks

Eric Wong

1 Like

Hi @ecbwong,

That’s right

Yes

Correct

That’s correct … here you are talking about state variables, which are saved persistently in storage, which is another specific data location. All values stored in state variables are automatically saved in storage, so there is no need to explicity declare their data location with storage. It’s only necessary to declare the data location of local variables, parameters, and return values which are defined as complex data types (strings, arrays and struct instances). This is because, in these specific cases, there is a choice of data location. State variables, local variables, parameters and return values defined with any of the other data types (addresses, Booleans, integers or unsigned integers) have their data location automatically assigned by default, so in these cases there is no need to declare the data location.

There is a specific section of this course which introduces the different types of data location, and the circumstances under which it needs to be explicitly declared. So, you’ll get to see more examples and to practise using it in an assignment.

Thanks very much Jonathan. Very precise answers to each and every question. Appreciate it.

1 Like

I would like a plutus course as well, you have any experience with it @danielmain?

1 Like

Would any of you be so nice as to answer this question for me?:

Why doesn’t the .push function work for me?

 address admin1;
     address admin2;
     address admin3;
     address owner;
    address[] admins;
    function push()private{
        admins[].push([owner,admin1,admin2,admin3]);
    }

Line seven always has a pop up that says "push not found " and “Index expression cannot be ommited”
I haave no idea what those mean :woozy_face: :face_with_raised_eyebrow:

Hi Jonathan

Appreciate very much if you could clarify certain matters in Solidity Basic as regards to the topic on Struct.

I will use Filip video and his codes are as follows

A). Struct Person {
unit age ;
string name;
}

I understand this part being the object blueprint for future object creation.

B). Person [ ] people;

I am ok with this. An array of people variables of Person object.

C). I am lost in his Function addPerson. The body of the function goes like this

Person memory newPerson = Person ( 30, " Bob");
people.push( newPerson);

I am utterly confused with the use of the wordings Person, newPerson and people. In part B, since people variables is the name for Person Class, shouldn’t it be written as

Person memory people = people ( 30, “Bob”);
Person.push ( people);

Could you help me out on Solidity syntax on this because I couldn’t figure out why Filip code in the way he did. I haven’t touched on his getPerson function which is unclear to me too.

Thanks
Eric

1 Like

Hey @jakerichguy,

There are several things wrong with your code …

To push values to an array, you need to call the push method on the array name without the square brackets …

admins.push();

To reference a value within an array we append its index value in square brackets to the array name e.g. admins[0] will reference the first value in the array (at index 0). So, you are getting the error message   Index expression cannot be omitted   because the compiler thinks you want to reference an address within the admins array, and so it’s expecting an index number after the opening square bracket.

Once you remove the square brackets as I’ve shown you above, you’ll now get the error message …

Member "push" not found or not visible after argument-dependent lookup in address[] storage ref.

It’s not clear what is meant by argument-dependent lookup, but essentially, the compiler is informing you that you can’t push an array value …
[owner, admin1, admin2, admin3]
… to the admins array (the address[ ] storage reference). This is because admins is defined as an array containing individual address values e.g.

// address[] admins
[0x74...483, 0x38...819, ...]

… and not as an array containing further arrays of address values e.g.

// address[][] admins
[
   [0x74...483, 0x38...819],
   [0x32...715, 0x44...588],
   ...
] 

Before you remove the square brackets from the array name admins (as above), you also get a slightly different version of this error message. Here, the compiler still thinks you are referencing (looking up) a specific address held in the admins array, and I think it’s basically telling you that you can’t push a value to an address: .push() is an array method that can only be called on an array.

However, even if you also remove the square brackets from the 4 addresses you want to push to the array, you’ll still get the same error message…

admins.push(owner, admin1, admin2, admin3);  // => Error

This is because, as far as I’m aware, you can only use the push method to push a single value at a time to an array e.g.

admins.push(admin1);

The following works, but it is obviously very repetitive and inefficient to code it like this …

admins.push(owner);
admins.push(admin1);
admins.push(admin2);
admins.push(admin3);

As you will already need to have assigned address values to the state variables owner, admin1, admin2 and admin3, my question to you would be: Why do you need to store these addresses in separate state variables AND in an array? Such a duplication of data saved in storage is unnecessarily expensive. I would also think about the following:

  • If you need to store these addresses together in an array, then why not just assign them directly to admins, and remove the need for the separate address state variables altogether?

  • If there is a fixed number of admin addresses that you need to store together in a data structure, then you should define the array as a fixed-sized array instead of dynamically-sized (e.g. address[4] admins;) and assign the admin addresses using index numbers instead of the push method. Or you could think about using a struct instead of an array.

Let us know if anything is unclear, or if you have any further questions. And if your code relates to the Multi-Sig project, then please post your questions in the Project - Multisig Wallet discussion topic instead of here. :slight_smile:

1 Like