Introduction
The Ethereum blockchain is very distinct as it is the first to implement smart contracts, which changed the blockchain use cases with the invention of decentralized apps, digital agreements, token creations, and so much more. This article introduces you to smart contracts on the Ethereum blockchain—what they are, smart contract languages and their features, and how smart contracts work in the EVM..
History
The term “smart contracts” was first coined by Nick Szabo, -a computer scientist- in 1997, when he expressed his thoughts that various contractual agreements can be embedded in software or hardware in such a way to make any possible breach of agreement expensive.
One cannot mention smart contracts without a tribute to the Ethereum blockchain, as it is the first to implement smart contracts. After the launch of Bitcoin in 2009, Vitalik Buterin(Ethereum co-founder) argued that Bitcoin and blockchains could have more benefits than just handling digital money. He also noted that a different, turing complete language would be needed for blockchains to handle application development.
In early 2014, Vitalik Buterin, alongside Gavin Wood, Charles Hoskinson, Anthony Di Iorio, and Joseph Lubin, started the development of the Ethereum blockchain. In July 2015, the Ethereum blockchain went live, and the genesis block -the first block in a blockchain- was mined. So started the blockchain that let applications be built on it.
What exactly is a smart contract?
Let us look at a simple definition of a smart contract; "A smart contract is a program that runs on the Ethereum blockchain. It's a collection of code (its functions) and data (its state) that resides at a specific address on the Ethereum blockchain."
A smart contract is simply code deployed to the blockchain. Just like a regular contract defines the terms and conditions of a deal, a smart contract contains logic that makes up the terms of a transaction or an agreement on a blockchain, whatever that transaction may be. Smart contracts can be used for things like voting, crowdfunding, token creation(fungible and non-fungible tokens), and ownership registration. Another important use of smart contracts is building decentralised applications(Dapps).
What exactly is a decentralised application?
A decentralised application has its backend built on the blockchain with smart contracts, while its frontend looks like any website or mobile application interface. The logic governing a Dapp's behaviour is written in a smart contract language and stored on the blockchain.
To communicate with the blockchain and to be able to sign transactions, a dapp needs a wallet.
What exactly is a Wallet?
A wallet is a service that stores private keys, account information and an individual's blockchain assets.Metamask, Trustwallet, and Gemini are examples of wallet services, among others. Currently, about 2970 Dapps are built on the Ethereum blockchain. Common examples of dapps built on the Ethereum blockchain are OpenSea, Sushi, StableFund, etc.
Given that the blockchain itself is immutable, any smart contract deployed to the blockchain is also immutable. For this reason, smart contracts are highly sensitive, and developers must take extreme care to ensure that a smart contract code is ridden of all unwanted behaviour and attacks from hackers. Before deployment to production, smart contracts are compiled and tested using tools like Remix, Hardhat, Truffle, Foundry, Ganache, Mocha, and others.
Role of addresses in smart contracts development
When deploying a smart contract, two accounts are usually involved
- an externally owned account(EOA) and
- a contract account(CA).
To deploy a smart contract initially, an externally owned account is needed. An EOA is an account already owned by a person or an organisation, controlled by private and public keys, and capable of sending transactions.
A contract account can hold Ether balance, just like an EOA and is only obtained when a smart contract is deployed. This address comes from hashing the EOA address and the nonce of that account.
A nonce is a number depicting the number of transactions an address has sent. The unique thing about a contract account is that it houses a smart contract. By knowing the address of a smart contract, you can interact with the functions of that contract, either from an EOA or another contract. Each contract account is unique and tied to a smart contract.
Smart contract languages
For smart contracts to be deployed to the Ethereum blockchain, they are written in an EVM-compatible programming language. The Ethereum virtual machine(EVM) is the runtime environment for smart contracts on the Ethereum blockchain. The EVM is completely isolated, meaning it has no access to external data, processes or systems. The two most active and maintained smart contract languages are Solidity and Vyper. Yul/ Yul+ is also an EVM-compatible language, albeit more advanced than those mentioned earlier. Fe is another language for smart contracts development on the EVM, though still in its early development stages. Let us check out some features of the two most active and maintained smart contract languages, Vyper and Solidity.
Vyper
Vyper is a lightweight, pythonic programming language for writing smart contracts on EVM-compatible chains but with fewer features than solidity.
Features
- Statically typed - each variable data type needs to be specified whether it is an integer, a string, a boolean value, etc.
Strong typing
Small and understandable compiler code
Support for signed integers and fixed point numbers, unlike solidity, which doesn’t support fixed point numbers.
Vyper does not support inheritance, modifiers, recursive calling, binary fixed point, infinite-length loops and inline assembly.
Below is an example of an auction smart contract written in Vyper
beneficiary: public(address)
auctionStart: public(uint256)
auctionEnd: public(uint256)
highestBidder: public(address)
highestBid: public(uint256)
ended: public(bool)
pendingReturns: public(HashMap[address, uint256])
@external
def __init__(_beneficiary: address, _bidding_time: uint256):
self.beneficiary = _beneficiary
self.auctionStart = block.timestamp
self.auctionEnd = self.auctionStart + _bidding_time
@external
@payable
def bid():
assert block.timestamp < self.auctionEnd
assert msg.value > self.highestBid
self.pendingReturns[self.highestBidder] += self.highestBid
self.highestBidder = msg.sender
self.highestBid = msg.value
@external
def withdraw():
pending_amount: uint256 = self.pendingReturns[msg.sender]
self.pendingReturns[msg.sender] = 0
send(msg.sender, pending_amount)
@external
def endAuction():
assert block.timestamp >= self.auctionEnd
assert not self.ended
self.ended = True
send(self.beneficiary, self.highestBid)
Source: Ethereum developers documentation
Solidity
Solidity is an object-oriented, high-level, statistically typed programming language for implementing smart contracts on the Ethereum blockchain and other EVM compatible chains. Solidity is inspired by Python, C++ and Javascript.
Features
- Statically typed
- Curly-bracketed language
- Supports inheritance - you can use other contract methods and functions.
- Supports libraries and complex user-defined types like enums and structs.
Here is a simple example of a smart contract written in Solidity;
//SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;
contract simpleStorage{
uint storedata;
function set(uint x) external {
storedata = x;
}
function get() external view returns(uint){
return storedata;
}
}
Source - Solidity documentation
EVM and Smart contracts(ABI and bytecode)
After a smart contract is compiled successfully, its bytecode and abstract binary interface (ABI) are generated. The bytecode of a smart contract contains all the opcodes that perform the needed logic stated in a smart contract. Bytecode is not human readable and is generated in a JSON(Javascript object notation) format. When a smart contract is deployed to the Ethereum blockchain(or other EVM compatible chains), only its bytecode gets executed in the EVM. Here is the bytecode of a smart contract written in Solidity
{
"functionDebugData": {},
"generatedSources": [],
"linkReferences": {},
"object": "608060405234801561001057600080fd5b50610150806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806360fe47b11461003b5780636d4ce63c14610057575b600080fd5b610055600480360381019061005091906100c3565b610075565b005b61005f61007f565b60405161006c91906100ff565b60405180910390f35b8060008190555050565b60008054905090565b600080fd5b6000819050919050565b6100a08161008d565b81146100ab57600080fd5b50565b6000813590506100bd81610097565b92915050565b6000602082840312156100d9576100d8610088565b5b60006100e7848285016100ae565b91505092915050565b6100f98161008d565b82525050565b600060208201905061011460008301846100f0565b9291505056fea26469706673582212204177bb08d38a8a5212b946dc78eb92765d76c48aef6ac7651bd6beb7d03b5ef164736f6c634300080d0033",
"opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x150 DUP1 PUSH2 0x20 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x36 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x60FE47B1 EQ PUSH2 0x3B JUMPI DUP1 PUSH4 0x6D4CE63C EQ PUSH2 0x57 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x55 PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 PUSH2 0x50 SWAP2 SWAP1 PUSH2 0xC3 JUMP JUMPDEST PUSH2 0x75 JUMP JUMPDEST STOP JUMPDEST PUSH2 0x5F PUSH2 0x7F JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x6C SWAP2 SWAP1 PUSH2 0xFF JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST DUP1 PUSH1 0x0 DUP2 SWAP1 SSTORE POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD SWAP1 POP SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x0 DUP2 SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH2 0xA0 DUP2 PUSH2 0x8D JUMP JUMPDEST DUP2 EQ PUSH2 0xAB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP JUMP JUMPDEST PUSH1 0x0 DUP2 CALLDATALOAD SWAP1 POP PUSH2 0xBD DUP2 PUSH2 0x97 JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0xD9 JUMPI PUSH2 0xD8 PUSH2 0x88 JUMP JUMPDEST JUMPDEST PUSH1 0x0 PUSH2 0xE7 DUP5 DUP3 DUP6 ADD PUSH2 0xAE JUMP JUMPDEST SWAP2 POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH2 0xF9 DUP2 PUSH2 0x8D JUMP JUMPDEST DUP3 MSTORE POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 ADD SWAP1 POP PUSH2 0x114 PUSH1 0x0 DUP4 ADD DUP5 PUSH2 0xF0 JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 COINBASE PUSH24 0xBB08D38A8A5212B946DC78EB92765D76C48AEF6AC7651BD6 0xBE 0xB7 0xD0 EXTCODESIZE 0x5E CALL PUSH5 0x736F6C6343 STOP ADDMOD 0xD STOP CALLER ",
"sourceMap": "64:204:0:-:0;;;;;;;;;;;;;;;;;;;"
}
The smart contract ABI is an array of objects generated and used to communicate with dapp frontends. This ABI is used for function calls from the dapp frontend to the smart contract on the blockchain. Below is the ABI generated from our simple, smart contract earlier.
[
{
"inputs": [
{
"internalType": "uint256",
"name": "x",
"type": "uint256"
}
],
"name": "set",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "get",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
]
Other blockchains and smart contracts
Many other blockchains have implemented smart contracts too, but not all use EVM-compatible languages in writing their contracts. For example, the Solana blockchain uses Rust language to write smart contracts, while the Algorand blockchain uses TEAL(Transaction execution approval language). Other EVM compatible chains allow smart contracts written in Solidity to be deployed to their blockchain. Some EVM compatible chains are Polygon, Binance Smart Chain, Cardano, and Avalanche.
Conclusion
No doubt that smart contracts are very powerful and have revolutionised the way blockchains are used. Smart contracts have made possible digital ownership, immutable binding contracts, creation of tokens(apart from a blockchain’s native token), useful decentralised apps. In the future, we might see more use cases of smart contracts as I believe blockchain technology is still developing. The ride is just getting started!