Response to the external contracts and interfaces assignment:
function getExternalBalance() public view returns (uint){
return dcInstance.getBalance();
}
Response to the external contracts and interfaces assignment:
function getExternalBalance() public view returns (uint){
return dcInstance.getBalance();
}
Good insights! Let me share an example, using our dogcontract, to demonstrate the difference in effectiveness between a mapping and an array.
In contract 1. We store all of the dogs in a mapping (address => Dog).
In contract 2. We have no mapping. Instead we store all of our dogs in a general array (Dog[]).
Letās assume that both contracts have 10 users that each have inserted 1 dog.
If one of our users, Bob, wants to retrieve his dog from contract 1, he inputs his address into the mapping and out comes the dog. Thatās only 1 operation to get the dog.
Now letās do the same thing in contract 2. Bob calls a search function, that searches the array for his dog. It needs to start at the first dog, look at itās owner, compare it to Bobs address. If it matches, it is returned. If it doesnāt match, the function checks the 2nd dog in the array. And so it continues, until the right dog is found. On average, it will take 5 operations to find the Dog. Worse case it takes 10 operations (Bobs dog is the last in the list).
Now letās say our contracts holds 1000 dogs. Contract 1 still only requires 1 operation to find one dog. Contract 2 takes on average 500 operations. It is unsustainable.
You see what I mean?
function updateBalance(uint id, uint balance) public {
users[id].balance = balance;
}
My solution for the MemoryAndStorage exercise
Oh wow! Yeah, that makes the difference extremely clear. I can see why mappings are necessary to improve the efficiency in contracts as opposed to arrays alone. So if I understand correctly, arrays are primarily used to dynamically store data, but mappings are necessary to locate the data within those arrays. Mappings can also be used to search through more than one array if thatās the case, correct?
Also, kind of a minor question, but would all those operations of comparing Bobās address with those in the array cost gas?
And, one more unrelated question that I was going to post in the general forum:
Do you know where to find the +/- icon to increase and decrease the font size of the text in the new Remix layout? I canāt find it in the top left like it was in the old layout, and the documentation says it should be there.
Iād like to get familiar with the new layout, but itās difficult to read and straining on my eyes using the default size. Btw I just started the Ethereum Dapps section, and Iām really excited to start implementing everything youāve taught me so far! Thanks again!
Great!
Well, arrays and mappings are still completely separate data structures. They are not connected the way you describe it. Rather, they are 2 different data structures made for different purposes.
Mappings are great if you need to do quick lookups for a specific key to itās value. For example, all token contract have mappings to keep track of the balances. So if you input an address (the key), you get the balance (the value) instantly. But there is no way to search through the mapping for letās say, all addresses with a balance higher than 10. Nor is it possible to find āall investors who has bought this tokenā. Itās not possible with a mapping. A mapping can only do 1 thing, go from a key to a value, nothing else.
So if you apart from the normal balance functionality, need the functionality to find all addresses which own tokens. You will need to place all addresses in an array as well. Then you can go through that array, from start to finish, and for example find all addresses which holds more than 10 tokens. Something thatās impossible do with only a mapping.
Oke. The problem is that you can map only one dog to an address or user. When you add on other dog, information of the first dog will be overwritten. To solve this, we probably have to make use of a combination of an an array and a mapping.
Yes, thatās correct. Good analysis!
Hi All, Is it possible to deploy a smart contract, which generates other smart contracts? e.g. Possible use case to better understanding:
My base contract (e.g. ERC20 generator) - I put some variables there and according to them, it deploys the new ERC20 to the blockchain.
Generated contract has his own address, and the creator is my base contract.
If I put different variables to my base contract, it will generate different ERC20 on different address. Is this configuration possible?
I Made in Remix an ERC20 that has input variables in constructor function and it worked when I deployed all ERC20s manually. BUT! Is it possible to call somehow this constructor function with other contract? Thanks
@filip, could you look at my post, please?
Yes you can actually do that.
ExampleContract instance = new ExampleContract(constructor_parameters);
will create new a new contract of type ExampleContract.
In order to do that you need to have imported the ExampleContract into your ERC20 Generator contract.
Yes you can actually do that.
ExampleContract instance = new ExampleContract(constructor_parameters);
will create new a new contract of type ExampleContract.
In order to do that you need to have imported the ExampleContract into your ERC20 Generator contract.
Thanks very much, I will try it and post a result here if it worked
Hey @Dodd @filip I am just finishing this error handling assignment and I canāt get my head around why in the following code ⦠require(ownerToDog[msg.sender].age == 0); why age == 0? is that the index of the currentDog? and if another is added it is indexed as 1? cheers
Kim
The purpose of that is to check so that there is no dog that has been added for that address. But in order to do that in a simple way we need to check one of the properties of the dog.
An important thing you need to keep in mind is that when we create an entirely new mapping which is completely āemptyā, it actually isnāt empty. It just points all addresses to empty dogs where all properties are in itās initial state.
So the name would be an empty string, and the age would be 0.
So if we want to check that an address doesnāt have a dog added, we need to check one of the properties, and the simplest thing is to check an integer property for 0.
Itās not a perfect check, but itās useful to know. We go through this in better detail in the updated course. I believe you are still taking the old one.
here is my answer for the Data Location Assignment
function updateBalance(uint id, uint balance) public {
User storage user = users[id];
user.balance = balance;
}
Hey, I am stuck with the external contracts lesson.
note: I switched from create Persons to create Soccer Clubs
When I want to create a club from the external contract I get a error message in solidity:
transact to ExternalContract.externalCreateClub errored: VM error: revert.
revert The transaction has been reverted to the initial state.
Note: The called function should be payable if you send value and the value you send should be less than your current balance. Debug the transaction to get more information.
Here are my codes:
HelloWorld:
import ā./Ownable.solā;
import ā./Destroyable.solā;
pragma solidity 0.5.12;
contract HelloWorld is Ownable, Destroyable{
struct Clubs {
string name;
uint titel;
uint members;
bool champion;
}
event clubCreated(string name, bool Champion);
event clubDeleted(string name, bool Champion, address deletedBy);
uint public balance;
modifier costs(uint cost){
require(msg.value >= cost);
_;
}
mapping(address => Clubs) private soccerteam;
address[] private creators;
function createClubs(string memory name, uint titel, uint members) public payable costs(1 ether) {
require(titel <= 150, āTitel müssen mind. 150 seinā);
require(msg.value >= 1 ether);
balance += msg.value;
// this creates a soccerteam
Clubs memory newClubs;
newClubs.name = name;
newClubs.titel = titel;
newClubs.members= members;
if(titel < 18){
newClubs.champion = false;
}
else {
newClubs.champion = true;
}
insertClubs(newClubs);
creators.push(msg.sender);
//soccerteam[msg.sender] == newClubs;
assert(
keccak256(
abi.encodePacked(
soccerteam[msg.sender].name,
soccerteam[msg.sender].titel,
soccerteam[msg.sender].members,
soccerteam[msg.sender].champion
)
)
==
keccak256(
abi.encodePacked(
newClubs.name,
newClubs.titel,
newClubs.members,
newClubs.champion
)
)
);
emit clubCreated(newClubs.name, newClubs.champion);
}
function insertClubs(Clubs memory newClubs) private{
address creator = msg.sender;
soccerteam[creator] = newClubs;
}
function getClubs() public view returns (string memory name, uint titel, uint members, bool champion){
return (soccerteam[msg.sender].name, soccerteam[msg.sender].titel, soccerteam[msg.sender].members, soccerteam[msg.sender].champion);
}
function deleteClubs(address creator) public{
string memory name = soccerteam[creator].name;
bool champion = soccerteam[creator].champion;
delete soccerteam[creator];
assert(soccerteam[creator].titel == 0);
emit clubDeleted(name, champion, msg.sender);
}
function getCreator(uint index) public view onlyOwner returns(address){
return creators[index];
}
function withdrawAll() public onlyOwner returns(uint){
uint toTransfer = balance;
balance = 0;
if(msg.sender.send(toTransfer)){
return toTransfer;
}
else{
balance = toTransfer;
return 0;
}// revert
}
}
External:
//Interface
contract HelloWorld{
function createClubs(string memory name, uint titel, uint members) public payable;
}
contract ExternalContract{
HelloWorld instance = HelloWorld(0xB87213121FB89CbD8B877Cb1Bb3FF84dD2869cfA);
function externalCreateClub (string memory name, uint titel, uint members) public payable {
//Call createrClub in HelloWorld Contract
//Forward any ether to HelloWorld
instance.createClubs.value(msg.value)(name, titel, members);
}
}
thanks for your help!
It works for me. Did you remember to send in 1 eth in your external call as well? You get that error because some require statement is throwing an error. And itās probably the require(msg.value) one.
I like your idea of changing it to soccer clubs!
Btw, next time you submit code here please format the code using the ācodeā type here in the forum editor. I know it can be difficult in the beginning, but itās so much easier to read
hi filipā¦thank you!
yes I have send in 1 eth in my external call. I have looked at the require(msg.value) codes but I cant find the error.
I still get the mentioned error from solidity.
Here is my code in the code type:
import "./Ownable.sol";
import "./Destroyable.sol";
pragma solidity 0.5.12;
contract HelloWorld is Ownable, Destroyable{
struct Clubs {
string name;
uint titel;
uint members;
bool champion;
}
event clubCreated(string name, bool champion);
event clubDeleted(string name, bool champion, address deletedBy);
uint public balance;
modifier costs(uint cost){
require(msg.value >= cost);
_;
}
mapping(address => Clubs) private soccerteam;
address[] private creators;
function createClubs(string memory name, uint titel, uint members) public payable costs(1 ether) {
require(titel <= 150, "Titel must be min. 150");
require(msg.value >= 1 ether);
balance += msg.value;
// this creates a soccerteam
Clubs memory newClubs;
newClubs.name = name;
newClubs.titel = titel;
newClubs.members= members;
if(titel < 18){
newClubs.champion = false;
}
else {
newClubs.champion = true;
}
insertClubs(newClubs);
creators.push(msg.sender);
//soccerteam[msg.sender] == newClubs;
assert(
keccak256(
abi.encodePacked(
soccerteam[msg.sender].name,
soccerteam[msg.sender].titel,
soccerteam[msg.sender].members,
soccerteam[msg.sender].champion
)
)
==
keccak256(
abi.encodePacked(
newClubs.name,
newClubs.titel,
newClubs.members,
newClubs.champion
)
)
);
emit clubCreated(newClubs.name, newClubs.champion);
}
function insertClubs(Clubs memory newClubs) private{
address creator = msg.sender;
soccerteam[creator] = newClubs;
}
function getClubs() public view returns (string memory name, uint titel, uint members, bool champion){
return (soccerteam[msg.sender].name, soccerteam[msg.sender].titel, soccerteam[msg.sender].members, soccerteam[msg.sender].champion);
}
function deleteClubs(address creator) public{
string memory name = soccerteam[creator].name;
bool champion = soccerteam[creator].champion;
delete soccerteam[creator];
assert(soccerteam[creator].titel == 0);
emit clubDeleted(name, champion, msg.sender);
}
function getCreator(uint index) public view onlyOwner returns(address){
return creators[index];
}
function withdrawAll() public onlyOwner returns(uint){
uint toTransfer = balance;
balance = 0;
if(msg.sender.send(toTransfer)){
return toTransfer;
}
else{
balance = toTransfer;
return 0;
}// revert
}
}
pragma solidity 0.5.12;
//Interface
contract HelloWorld{
function createClubs(string memory name, uint titel, uint members) public payable;
}
contract ExternalContract{
HelloWorld instance = HelloWorld(0xB87213121FB89CbD8B877Cb1Bb3FF84dD2869cfA);
function externalCreateClub (string memory name, uint titel, uint members) public payable {
//Call createrClub in HelloWorld Contract
//Forward any ether to HelloWorld
instance.createClubs.value(msg.value)(name, titel, members);
}
}
Hello people @filip
Question regarding msg.sender.balance
Expectation: returns account balance;
What happens:
function readCustomerBalance() public view returns (uint){
return msg.sender.balance;
}
Correct balance should be 88.48 ether
Any idea? If I find a solution in the meantime will be posted here for everybody.
Yeah I donāt see any error in your code. I copied your code into remix and it works for me. So Iām thinking there might be an error in how you deploy or use it. But Iām not sure.
The process should be. Deploy Helloworld. Copy address of Helloworld and add it into the ExternalContract. Deploy ExternalContract. Call externalCreateClub with correct args and 1 eth attached.
That works for me. You still get an error?
Whatās the code you are using to console log the balance?