Day 7 / #100DaysOfWeb3 Structure of a Smart Contract
Today, I will learn about the Structure of a Smart Contract
I use principally this source from Deric Cheng Dev Education at Web3U.
Defining Ethereum smart contracts differ from web2 development paradigm.
This is a quick contract sample
contract Sample
{
//state variables
uint256 data;
address owner;
//event definition
event logData(uint256 dataToLog);
//function modifier
modifier onlyOwner() {
if (msg.sender != owner) throw;
_;
}
//constructor
function Sample(uint256 initData, address initOwner){
data = initData;
owner = initOwner;
}
//functions
function getData() returns (uint256 returnedData){
return data;
}
function setData(uint256 newData) onlyOwner{
logData(newData);
data = newData;
...
Types
- Contract Contract type is a struct that organize a set of related functions around a single purpose.
- Address Address types are Ethereum addresses that equate to 20 bytes, and are represented in hexadecimal form beginning with the prefix 0x.
- Int / Uint explained by this stack overflow response
The primitive data types prefixed with "u" are unsigned versions with the same bit sizes. Effectively, this means they cannot store negative numbers, but on the other hand they can store positive numbers twice as large as their signed counterparts. The signed counterparts do not have "u" prefixed.
The limits for int (32 bit) are:
int: –2147483648 to 2147483647
uint: 0 to 4294967295
Most other types are familiar like Booleans, integers, fixed-point numbers, byte arrays, and literals.
Data storage
In Solidity, reference data values can be stored as storage, memory or calldata depending on the role of the data stored. In particular:
- Storage keeps the data permanently on the blockchain, and is extremely expensive.
- Memory values are stored only for the lifetime of the smart contract's execution, and are inexpensive to use (costing only small amounts of gas).
- Calldata is a special data location that contains the function arguments, and is only available for external function call parameters.
Function Modifiers
Functions exist to get / set information based on calls initiated by external transactions. In particular, a smart contract can never run unless initiated by an external transaction. They don't execute silently in the background.
Access modifiers include:
. public: Can be accessed by all functions or callers
. external: Can be accessed only by external callers, not internal functions
. internal: Can be accessed only by this contract, or contracts deriving from it
. private: Can be accessed only from this contract itself
Other modifiers include:
. view: This guarantees that the function will not modify the state of the contract's data (or data in storage).
. pure: This guarantees that the function with neither read nor modify the state of the contract's data.
. payable: Functions and addresses declared payable can receive ether into their contracts.
Special Functions and Variables
There are a number of global variables and functions that will be helpful to remember you have access to! Some special variables are:
.block.number (uint256): The number of the most recent block.
. block.timestamp (uint256): The UNIX timestamp of the most recent block.
. block.gaslimit (uint256): The gas limit of the current block.
. msg.sender (address payable): The sender of the transaction triggering the contract.
. msg.value (uint256): The number of wei transferred with the message.
Special functions include:
. receive(): Contracts may only have one of these functions declared. It serves as the default destination when a contract is sent Ether. It cannot have arguments, return anything, and must be external and payable.
. fallback(): Contracts may only have one of these functions declared. It serves as the fallback if a call to the contract does not match any function, or if no data was supplied and the receive() function was not declared. It cannot have arguments, return anything, and must be external.
Events
Solidity events are roughly equivalent to logging in other programming paradigms. They're emitted when a contract is executed, stored permanently on the blockchain, but aren't accessible to be modified / read by smart contracts.
You can declare and emit an event like this:
event TestEvent (
uint256 date,
string value
);
emit TestEvent(block.timestamp,’My first event!”);
Events can be accessed in a variety of different ways:
Events are stored in the receipts of transactions, and can be accessed there.
You can subscribe to an event with
myContract.events.TestEvent([options][, callback])
You can request past events using a request like
myContract.getPastEvents(event[, options][, callback])
.
This should give me a broad overview of the key components of a smart contract!