Constructor is a function that runs immediately when the smart contract is initialized
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
// Base contract X
contract X {
string public name;
constructor(string memory _name) {
name = _name;
}
}
State variable visibility
public - Public variables are similar to internal variables (allowing the current contract and inherited contracts to access) but will automatically create a getter function so that external contracts can also access it.
internal - The variable can only be accessed by the current contract and inherited contracts. This is also the default visibility for state variable.
private - The variable can only be accessed by the current contract.
Note: The internal and private variables only restrict access to other contracts. The value of the variable remains visible to everyone.
Function visibility
external - function that can only be called from outside.
public - function can both be called by another function in contract, and can also be called from outside.
internal - function can only be called by an existing contract or an inherited contract.
private - function can only be called by the current contract.
Getter function
function is used to call the public variable that the compiler automatically creates. Also used to refer to the concept of function used to query variables to view.
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
contract C {
uint public data = 42;
}
contract Caller {
C c = new C();
function f() public view returns (uint) {
return c.data();
}
}
Constants and immutable state variables
constant - variables whose values ββare fixed immediately upon compilation (put into contract bytecode).
immutable - variables whose values ββcan be assigned during construct.
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.21;
uint constant X = 32**22 + 8;
contract C {
string constant TEXT = "abc";
bytes32 constant MY_HASH = keccak256("abc");
uint immutable decimals = 18;
uint immutable maxBalance;
address immutable owner = msg.sender;
constructor(uint decimals_, address ref) {
if (decimals_ != 0)
// Immutables are only immutable when deployed.
// At construction time they can be assigned to any number of times.
decimals = decimals_;
// Assignments to immutables can even access the environment.
maxBalance = ref.balance;
}
function isBalanceTooHigh(address other) public view returns (bool) {
return other.balance > maxBalance;
}
}
Pure function
function does not read or change the state of the blockchain. Or used as a calculation function.
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
contract C {
function f(uint a, uint b) public pure returns (uint) {
return a * (b + 42);
}
}
Payable functions and addresses
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
contract Payable {
// Payable address can send Ether via transfer or send
address payable public owner;
// Payable constructor can receive Ether
constructor() payable {
owner = payable(msg.sender);
}
// Function to deposit Ether into this contract.
// Call this function along with some Ether.
// The balance of this contract will be automatically updated.
function deposit() public payable {}
// Call this function along with some Ether.
// The function will throw an error since this function is not payable.
function notPayable() public {}
// Function to withdraw all Ether from this contract.
function withdraw() public {
// get the amount of Ether stored in this contract
uint256 amount = address(this).balance;
// send all Ether to owner
(bool success,) = owner.call{value: amount}("");
require(success, "Failed to send Ether");
}
// Function to transfer Ether from this contract to address from input
function transfer(address payable _to, uint256 _amount) public {
// Note that "to" is declared as payable
(bool success,) = _to.call{value: _amount}("");
require(success, "Failed to send Ether");
}
}
Receive Ether and Fallback function
A contract can have at most one receive function, declared using receive() external payable { ... } (without the function keyword). This function must have no arguments, cannot return anything and must have external visibility as well as payablestate mutability. It can be virtual, it can be override and it can have modifiers.
Which function is called, fallback() or receive()?
send Ether
|
msg.data is empty?
/ \
yes no
/ \
receive() exists? fallback()
/ \
yes no
/ \
receive() fallback()
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
contract Fallback {
event Log(string func, uint256 gas);
// Fallback function must be declared as external.
fallback() external payable {
// send / transfer (forwards 2300 gas to this fallback function)
// call (forwards all of the gas)
emit Log("fallback", gasleft());
}
// Receive is a variant of fallback that is triggered when msg.data is empty
receive() external payable {
emit Log("receive", gasleft());
}
// Helper function to check the balance of this contract
function getBalance() public view returns (uint256) {
return address(this).balance;
}
}
contract SendToFallback {
function transferToFallback(address payable _to) public payable {
_to.transfer(msg.value);
}
function callFallback(address payable _to) public payable {
(bool sent,) = _to.call{value: msg.value}("");
require(sent, "Failed to send Ether");
}
}
Oracle
Oracle for smart contracts is a bridge between blockchain and the outside world. It provides data to smart contracts from sources outside the blockchain, such as APIs, market data, weather data, etc.
Here are some examples of how to use oracle for smart contracts:
Providing price data for decentralized markets (DeFi): Oracle can provide price data for crypto assets, allowing traders to make trades on decentralized exchanges.
Activate insurance contracts: Oracle can provide data about insurance events, such as accidents or natural disasters, to trigger insurance payments.
Automate processes: Oracle can be used to automate processes, such as bill payment or supply chain management.