Define a function
A function looks like this:
function name(string memory _var1, uint _var2)
function name() public pure returns (uint)
function _name() private view
pure
means we don’t access any states in the contract. view
means we don’t update the state but only view it.
It’s a convention to put _
before private functions or function arguments.
You also have to specify which type you return. Note that you shouldn’t forget memory
or other data area (storage
, calldata
) where the type is stored when defining a parameter for reference types. The reference types include string, struct, and array. Updating their value in the function changes the original value where as updating value types only change their copies.
Address
In Ethereum, there are accounts and each of them has its unique address. The function in a smart contract is never executed until someone calls it. We can use msg.sender
to get that person’s address.
Mapping
You can create a map in Solidity.
contract Bank {
mapping (uint => address) public moneyToOwner;
mapping (address => uint) ownerToBalance; function updateBalance(uint update) public {
ownerToBalance[msg.sender] += update;
}
}
Pretty straightforward.
Require
There’s a keyword equivalent to assert
in Python.
function _generateRandomDna(string memory _name) private pure returns (uint) {
uint rand = uint(keccak256(abi.encodePacked(_name));
return rand % dnaModulus;function createZombie(string memory _name) public {
require(ownerZombieCount[msg.sender] == 0); // LINE 1
uint randDna = _generateRandomDna(_name);
_createZombie(_name, randDna);}
Look at the LINE 1 where it uses require
. It raises an error if the logic statement doesn’t meet the condition. This way, we can ensure the code runs only when the condition we want is met.
Inheritance
Inheritance is pretty straightforward and you can do it just to make codes cleaner.
contract Animal {}
contract Cat is Animal {}
Data Area — Memory vs Storage vs
Internal vs External
- public: any other functions can call it
- private: only the functions inside the same contract can call it
- external: only the functions outside the contract can call it
- internal: only the functions inside the same contract and its inheritors can call it
Interface
We can use a code deployed on Ethereum by using an interface if we know its address on the network.
Let’s say that there is a contract like this:
contract LuckyNumber {
mapping(address => uint) numbers;
function setNum(uint _num) public {
numbers[msg.sender] = _num;
} function getNum(address _myAddress) public view returns (uint) {
return numbers[_myAddress];
}
}
In our code, we should declare an interface that can interact with the contract above. By doing so, we let our contract know what functions we used and how they look like.
contract NumberInterface {
function getNum(address _myAddress) public view returns (uint)
}
You just copy-paste the function you’d like to use.
To actually use the interface,
contract MyContract {
address NumberAddress = 0x3bsuijs3f2... # address of the contract on Ethereum NumberInterface numberInterface = NumberInterface(NumberAddress); function doSomething() {
uint number = numberInterface.getNum(msg.sender);
}
}
Multiple return values
A function in Solidity has an interesting property: it can return multiple values.
function getUserInfo(string memory _userId) public view returns (
string memory username,
uint age
)// to unpack multiple return values:
function unpackValues() {
uint age; (, age) = getUserInfo(msg.sender); // alternatively, you can put a variable before , to store the value.}