hi @jon_m,
I made âkillâ function in my Destroyable contract âinternalâ to Ownable contract (its parent contract), which is a parent contract of âhello worldâ. So, because Destoryable is a child of Ownable, and Ownable is a child of âHello Worldâ, why doesnât the âinternalâ kill function show up when I deploy Hello World??? Wouldnât an internal function of a parent contract show up in itâs childâs child contract?
// Destroyable Contract
import â./Ownable.solâ;
pragma solidity 0.5.12;
contract Destroyable is Ownable{
function kill() internal onlyOwner{
selfdestruct(address(uint160(owner)));
}
}
// Ownable Contract
pragma solidity 0.5.12;
contract Ownable{
address internal owner;
modifier onlyOwner(){
require(msg.sender == owner);
_; // underscore just means continue the execution
}
constructor() public{
owner = msg.sender;
}
}
//HelloWorld Contract
import â./Ownable.solâ;
import â./Destroyable.solâ;
pragma solidity 0.5.12;
// Inheritance in Solidity
contract HelloWorld is Ownable, Destroyable{ //Ownable is the Parent
struct Person {
string name;
uint age;
uint height;
bool senior;
uint balance;
} // Struct is like an object that has data structure
event personCreated(string name, bool senior);
event personDeleted(string name, bool senior, address deletedBy);
uint public totalBalance;
modifier costs(uint cost){
require(msg.value >= cost);
_;
}
mapping(address => Person) private people; // Need review on Mapping
address [] creators;
function createPerson(string memory name, uint age, uint height) public payable costs(1 ether){
require(age <= 150, "Age needs to be below 150");
// require(msg.value >= 1);
totalBalance += msg.value;
// people.push(Person(people.length, name, age, height));
Person memory newPerson;
newPerson.name = name;
newPerson.age = age;
newPerson.height = height;
newPerson.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);
}
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 insertPerson(Person memory newPerson) private {
address creator = msg.sender; // "msg.sender" will give the address of the sender in solidity, this is highly used
// pay attention to payable address vs. normal address
//convert from normal to payable address
// address payable test = address(uint160(creator)); // wrap with uint160() and then address()
people[creator] = newPerson;
}
function deletePerson(address creator) public onlyOwner {
// require(msg.sender == owner); // removed for Modifier
string memory name = people[creator].name;
bool senior = people[creator].senior;
delete people[creator];
assert(people[creator].age == 0);
emit personDeleted(name, senior, msg.sender);
}
function getCreator (uint index) public view onlyOwner returns(address) {
// require(msg.sender == owner, "caller needs to be owner");
return creators[index];
}
function withdrawAll () public onlyOwner returns(uint) {
//VERY IMPORTANT, WE ALWAYS NEED TO MAKE CHANGES TO THE STATE 'BEFORE' TRANSFER
// TRANSFER IS A BETTER USED FUNCTION BECAUSE IT WILL AUTOMATICALLY REVERT IF FAILED, USE "SEND" FUNCTION ONLY IF YOU WANT CUSTOM ERROR MESSSAGE
// uint toTransfer = totalBalance;
// totalBalance = 0;
// msg.sender.transfer(toTransfer); // Automatic Revert
// return toTransfer; //WHY DO YOU NEED TO RETURN?
uint toTransfer = totalBalance;
totalBalance = 0;
if(msg.sender.send(toTransfer)){
return toTransfer;
}
else {
totalBalance = toTransfer;
return 0;
} //return false instead of reverse
}
}