0% found this document useful (0 votes)
25 views

Functions_Solidity

Uploaded by

Ansh Singh
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
25 views

Functions_Solidity

Uploaded by

Ansh Singh
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 82

FOUNDATIONS OF

BLOCKCHAIN

CC4167

F U N C T I O N S
A function is basically a group of code that can be reused anywhere in the program, which generally
saves the excessive use of memory and decreases the runtime of the program. Creating a function
reduces the need of writing the same code over and over again. With the help of functions, a
program can be divided into many small pieces of code for better understanding and managing.

Declaring a Function

In Solidity a function is generally defined by using the function keyword, followed by the name of
the function which is unique and does not match with any of the reserved keywords. A function can
also have a list of parameters containing the name and data type of the parameter. The return
value of a function is optional but in solidity, the return type of the function is defined at the time of
declaration.

function function_name(parameter_list) scope returns(return_type) { //


block of code }
pragma solidity >=0.4.22 <0.9.0;
contract Test {
// Defining a function to
calculate sum of two numbers
function add() public pure
returns(uint){
uint num1 = 10;
uint num2 = 16;
uint sum = num1 + num2;
return sum;
}
}
In the above example, you must have seen the usage of “pure”. pure in a function
ensures that they will not modify the state of the function.

The following statements if present in the function will modify the state of the
function and the compiler will throw a warning.

•Modifying state variables.


•Emitting events.
•Creating other contracts.
•Using self-destruct.
•Sending Ether via calls.
•Calling any function which is not marked pure or view.
•Using inline assembly containing certain opcodes.
•Using low-level calls.
pragma solidity >=0.4.22 <0.9.0;
contract Test {
function sqrt(uint _num) public pure
Function Calling returns(uint){
_num = _num ** 2;
A function is called return _num;
when the user wants }
to execute that function add() public pure
function. In Solidity returns(uint){
uint num1 = 10;
the function is simply
uint num2 = 16;
invoked by writing the uint sum = num1 + num2;
name of the function return sqrt(sum); // calling function
where it has to be }
called. Different }
parameters can be
passed to function
while calling, multiple
parameters can be
passed to a function
by separating with a
comma.
pragma solidity >=0.4.22 <0.9.0;
Return Statements contract Test {
function return_example() public pure
A return statement is returns(uint, uint, uint, string memory){
an optional uint num1 = 10;
statement provided uint num2 = 16;
by solidity. It is the uint sum = num1 + num2;
last statement of the uint prod = num1 * num2;
uint diff = num2 - num1;
function, used to
string memory message = "Multiple return
return the values values";
from the functions. In return (sum, prod, diff, message);
Solidity, more than }
one value can be }
returned from a
function. To return
values from the
function, the data
types of the return
values should be
defined at function
declaration.
Function behavior can be changed using function modifiers. Function modifier can be used to
automatically check the condition prior to executing the function. These can be created for
many different use cases. Function modifier can be executed before or after the function
executes its code.

•The modifiers can be used when there is a need to verify the condition automatically before
executing a particular function.

•If the given condition is not satisfied, then the function will not get executed.

How to Create and Use Modifiers?

Function modifiers are created by defining them and invoking the same in the required
function.
modifier modifier_name
{
// action to be taken
}
There are two variations of a function modifier:

1. Function modifier with an argument:


modifier modifier_name(unit arg)
{
// action to be taken
}

2. Function modifier without argument:


modifier modifier_name()
{
// action to be taken
}

If the modifier does not have an argument then parentheses () can be


omitted.
What is Merge Wildcard?
Consider the below function modifier:

modifier isAdmin
{
require(msg.sender == admin);
_;
}

The _; symbol is known as Merge Wildcard and this is replaced by the function
definition during execution.

•In other words, after this wildcard has been used, the control is moved to the location
where the appropriate function definition is located.
•This symbol is mandatory for all modifiers.
•The modifier may contain this wildcard anywhere.
•When the wildcard is placed at the end of the modifier, the condition is verified and
the appropriate function is executed if it is satisfied.
•When it is placed at the beginning, the appropriate function is executed first followed
by the condition verification.
pragma solidity >=0.4.22 <0.7.0;
contract modifierWithoutArg {
address admin;
struct employee
{
uint emp_id;
string emp_name;
uint age;
}

constructor() public
{
admin = msg.sender;
}

modifier isAdmin
{
require(admin == msg.sender);
_;
}
employee e;
function enterDetails (uint _empid, string memory _empname,
uint _empage) public isAdmin {
e.emp_id = _empid;
e.emp_name = _empname;
e.age = _empage;
}
}
pragma solidity >=0.4.22 <0.7.0;
contract modifierWithArg {

struct employee
{
uint emp_id;
string emp_name;
uint age;
}

modifier isExperienced(uint exp)


{
if(exp >= 5)
_;
else
revert("Must have a minimum of 5 years of
experience");
}
employee e;
function enterDetails (uint _empid, string memory _empname,
uint _empage) public isExperienced(7) {
e.emp_id = _empid;
e.emp_name = _empname;
e.age = _empage;
}
}
Multiple Modifiers to Function

Multiple modifiers may be present in a function, and each of these conditions must be met
in order for the function to be successfully executed.

To verify whether only the administrator with 5 years of experience is editing, two
modifiers namely isAdmin and isExperienced are introduced. The function enterDetails will
execute only if the user has administrator authorization and has a minimum of 5 years of
experience.

Syntax:

modifier modifier_name(datatype arg_name)


{
// action to be taken
}
function func_name(arg1, arg2, …) public modifier1 modifier2
{
// function definition
}

Below is the solidity program to implement multiple modifiers to function:


pragma solidity >=0.4.22 <0.7.0;
contract multiplemodifier {
address admin;
struct employee
{
uint emp_id;
string emp_name;
uint age;
}

constructor() public
{
admin = msg.sender;
}

modifier isAdmin
{
require(admin == msg.sender);
_;
}
modifier isExperienced(uint exp)
{
if(exp>=5)
_;
else
revert("Must have a minimum of 5 years of
experience");
}
employee e;
function enterDetails (uint _empid, string memory _empname,
uint _empage) public isAdmin
isExperienced(7) {
e.emp_id = _empid;
e.emp_name = _empname;
e.age = _empage;
}
}
Modifier Overriding

Modifiers can be overridden in a similar way to how functions can be


overridden.

Syntax:
contract base{
modifier overridingmod virtual{
}
}
contract derived is base {
modifier overridingmod override{
}
}
pragma solidity >=0.4.22 <0.7.0;
contract modifierOverride {
modifier isExperienced(uint exp) virtual {
if(exp >= 5)
_;
else
revert("Must have minimum 5 years of experience");
}
}
contract modifierdest is modifierOverride {
struct employee
{
uint emp_id;
string emp_name;
uint age;
}
employee e;
modifier isExperienced(uint exp) override {
if(exp >= 5)
_;
else
revert("Must have minimum 5 years of experience");
}

function enterDetails (uint _empid, string memory _empname,


uint _empage) public isExperienced(7) {
e.emp_id = _empid;
e.emp_name = _empname;
e.age = _empage;
}
}
Modifier with enums

When an enum variable is declared globally, its value can be verified using a
modifier.

Syntax:

enum variablename {inst1, inst2, inst3, …}


variablename v;
modifier modifiername(variablename _v){
require(v==_v);
_;
}
pragma solidity >=0.4.22 <0.7.0;
contract modifierWithEnum {
enum Status{Fresher, Trained, Experienced}
struct employee
{
uint emp_id;
string emp_name;
Status s;
}
Status s1;
modifier isValid(Status _entry)
{
require(s1==_entry);
_;
}

employee e;
function enterDetails (uint _eno, string memory _ename,
Status _s) public isValid(_s) {
e.emp_id=_eno;
e.emp_name=_ename;
e.s=_s;
}
}
Modifier code examples

1. Data Validation: In this example, the input data is validated based on its type.

modifier triggerIfEqualToZero(uint _num)


{
if(_num == 0) throw;
_;
}

Similarly, the other type of data can also be verified.

2. Refund Ether send by accident: For every transaction made in the blockchain, some
amount of Ether needs to be paid. Also, a facility is there for transferring some amount of Ether
to other users. Sometimes, accidentally few transactions may take place.

modifier refundEther {
if(msg.value >0) throw;
_;
}
3. Charge a fee: Modifiers can also be used for verifying whether the user has paid the required
fees as shown below:

modifier payFee (uint _fee) {


if(msg.value >= _fee) throw;
_;
}

4. Send the change back: Suppose a user wants to send back the extra amount paid by a
person, modifiers can be applied to it. The implementation for the same is given below:

modifier sendBackChange(unit _balance)


{
_;
if (msg.value > _balance)
{
msg.sender.transfer(msg.value – _balance)
}
}
The view functions are read-only function, which ensures that state variables cannot be
modified after calling them.

If the statements which modify state variables, emitting events, creating other contracts,
using selfdestruct method, transferring ethers via calls, Calling a function which is not
‘view or pure’, using low-level calls, etc are present in view functions then the compiler
throw a warning in such cases. By default, a get method is view function.
pragma solidity ^0.5.0;
contract Test {

uint num1 = 2;
uint num2 = 4;

function getResult(
) public view returns(
uint product, uint sum){
product = num1 * num2;
sum = num1 + num2;
}
}
The pure functions do not read or modify the state variables, which returns the values only
using the parameters passed to the function or local variables present in it.

If the statements which read the state variables, access the address or balance, access any
global variable block or msg, call a function that is not pure, etc are present in pure functions
then the compiler throws a warning in such cases.
pragma solidity ^0.5.0;

contract Test {

function getResult(
) public pure returns(
uint product, uint
sum){
uint num1 = 2;
uint num2 = 4;
product = num1 *
num2;
sum = num1 + num2;
}
}
Solidity – Fall Back Function

The solidity fallback function is executed if none of the other functions match the function
identifier or no data was provided with the function call.

Only one unnamed function can be assigned to a contract and it is executed whenever the
contract receives plain Ether without any data.

To receive Ether and add it to the total balance of the contract, the fallback function must be
marked payable.

If no such function exists, the contract cannot receive Ether through regular
transactions and will throw an exception.
.
Properties of a fallback function:

1.Declare with fallback() and have no arguments.

2.If it is not marked payable, the contract will throw an exception if it receives plain
ether without data.

3.Can not return anything.

4.Can be defined once per contract.

5.It is also executed if the caller meant to call a function that is not available or receive()
does not exist or msg.data is not empty.

6.It is mandatory to mark it external.

7.It is limited to 2300 gas when called by another function by using transfer() or send()
method . It is so for as to make this function call as cheap as possible
pragma solidity >=0.8.0 <0.9.0;

contract Solid_Fallback
{
string public calledFallbackFun;

fallback() external payable{


calledFallbackFun="Fallback function is executed!";
}

function getBalance() public view returns (uint) {


return address(this).balance;
}
}

contract Sender
{
function transferEther() public payable
{
(bool sent, ) =
payable(0xD4Fc541236927E2EAf8F27606bD7309C1Fc2cbee).call{value: 2 ether}("Transaction
Completed!");
require(sent, "Transaction Failed!");
}

function getBalance() public view returns (uint) {


return address(this).balance;
}
}
1.First deploy the Solid_Fallback smart contract and paste
the deployed smart contract address into
the transferEther function of Sender smart contract.

2.In the Sender smart contract we have also assigned the


transfer value of Ether.

3.After deploying the Sender smart contract, deposit more


than or equal to the assigned Ether value in it at the time
of calling the transferEther function.

4.transferEther function has the call method to transfer


the assigned Ether value from Sender smart contract to
Solid_Fallback smart contract and fallback function
receives these Ethers.

5.Call the calledFallbackFun function of Solid_Fallback


smart contract. It will return a string value “Fallback
function is executed!” and also you can check the smart
contract balance by using the getBalance function.
Solidity Function Overloading

Function overloading in Solidity lets you specify numerous functions with the same name but
varying argument types and numbers.

Solidity searches for a function with the same name and parameter types when you call a
function with certain parameters.

Calls the matching function.

Compilation errors occur if no matching function is found.

Function overloading lets you construct a collection of functions that accomplish similar
operations but utilize various data types.

It simplifies coding.

Function overloading may complicate your code, particularly if you write several overloaded
functions with multiple arguments.
pragma solidity ^0.8.0;

contract OverloadingExample {
function add(uint256 a, uint256 b) public pure returns
(uint256)
{
return a + b;
}

function add(string memory a, string memory b) public


pure returns (string memory)
{
return string(abi.encodePacked(a, b));
}
}
Solidity – Contracts
Solidity Contracts are like a class in any other object-oriented programming
language.

They firmly contain data as state variables and functions which can modify these
variables. When a function is called on a different instance (contract), the EVM
function call happens and the context is switched in such a way that the state
variables are inaccessible.

A contract or its function needs to be called for anything to happen. Some basic
properties of contracts are as follows :

•Constructor: Special method created using the constructor keyword, which is


invoked only once when the contract is created.

•State Variables: These are the variables that are used to store the state of the
contract.

•Functions: Functions are used to manipulate the state of the contracts by


modifying the state variables.
Creating a Contract

Creating contracts programmatically is generally done by using JavaScript API web3.js, which has
a built-in function web3.eth.Contract to create the contracts.

When a contract is created its constructor is executed, a constructor is an optional special method
defined by using the constructor keyword which executes one per contract.

Once the constructor is called the final code of the contract is added to the blockchain.

pragma solidity >=0.8.6 <0.9.0;


contract Test {
string str;

constructor(string memory str_in){


str = str_in;
}
function str_out() public view
returns(string memory){
return str;
}
}
Visibility Modifiers

Solidity provides four types of visibilities for functions and state variables. Functions have to
specified by any of the four visibilities but for state variables external is not allowed.

1.External: External functions are can be called by other contracts via transactions. An external
function cannot be called internally. For calling an external function within the
contract this.function_name() method is used. Sometimes external functions are more efficient
when they have large arrays of data.

2.Public: Public functions or variables can be called both externally or internally via messages. For
public static variables, a getter method is created automatically in solidity.

3.Internal: These functions or variables can be accessed only internally i.e. within the contract or
the derived contracts.

4.Private: These functions or variables can only be visible for the contracts in which they are
defined. They are not accessible to derived contracts also.
pragma solidity >=0.8.6 <0.9.0;
abstract contract contract_example { function getStr(
) public virtual returns (string memory);
uint private num1; }
uint public num2;
string internal str; contract derived_contract is contract_example{
constructor(){
num2 = 10; function setStr(
} string memory _str) public override{
str = _str;
function increment( }
uint data1) private pure returns(
uint) { function getStr(
return data1 + 1; ) public view override returns (
} string memory){
return str;
function updateValue( }
uint data1) public { }
num1 = data1;
} contract D {
function readData(
function getValue( ) public returns(
) public view returns( string memory, uint) {
uint) { contract_example c = new derived_contract();
return num1; c.setStr(“Manipal University");
} c.updateValue(16);
return (c.getStr(), c.getValue());
function setStr( }
string memory _str) public virtual; }
Inheritance
is one of the most important features of the object-oriented programming language. It is a way of
extending the functionality of a program, used to separate the code, reduces the dependency,
and increases the re-usability of the existing code.

Solidity supports inheritance between smart contracts, where multiple contracts can be inherited
into a single contract.

The contract from which other contracts inherit features is known as a base contract, while the
contract which inherits the features is called a derived contract.

Simply, they are referred to as parent-child contracts.

The scope of inheritance in Solidity is limited to public and internal modifiers only.
Some of the key highlights of Solidity are:

•A derived contract can access all non-private members including state variables and
internal methods. But using this is not allowed.

•Function overriding is allowed provided function signature remains the same. In case
of the difference of output parameters, the compilation will fail.

•We can call a super contract’s function using a super keyword or using a super
contract name.

•In the case of multiple inheritances, function calls using super gives preference to
most derived contracts.
pragma solidity >=0.4.22 <0.6.0;

contract parent{
1. Single Inheritance uint internal sum;

In Single or single level inheritance function setValue() external {


uint a = 10;
the functions and variables of one uint b = 20;
base contract are inherited to only sum = a + b;
one derived contract. }
}

contract child is parent{

function getValue(
) external view returns(uint) {
return sum;
}
}

contract caller {

child cc = new child();

function testInheritance(
) public returns (uint) {
cc.setValue();
return cc.getValue();
}
}
pragma solidity >=0.4.22 <0.6.0;
2. Multi-level Inheritance
It is very similar to single inheritance, but the contract A {
difference is that it has levels of the relationship
between the parent and the child. The child string internal x;
contract derived from a parent also acts as a string a = “Life" ;
parent for the contract which is derived from it. string b = "For";

contract C is B { function getA() external{


x = string(abi.encodePacked(a, b));
function getC() external view returns( }
string memory){ }
return y;
} contract B is A {
}
contract caller { string public y;
C cc = new C(); string c = “Life";
function testInheritance(
) public returns ( function getB() external payable returns(
string memory) { string memory){
cc.getA(); y = string(abi.encodePacked(x, c));
cc.getB(); }
return cc.getC(); }
}
}
pragma solidity >=0.4.22 <0.6.0;

3. Hierarchical Inheritance contract A {


In Hierarchical inheritance, a parent contract has
more than one child contracts. It is mostly used string internal x;
when a common functionality is to be used in function getA() external {
different places. x = “Life For Lives";
}
uint internal sum;
contract caller {
function setA() external {
B contractB = new B(); uint a = 10;
C contractC = new C(); uint b = 20;
sum = a + b;
function testInheritance( }
}
) public returns (
contract B is A {
string memory, uint) {
function getAstr(
return ( ) external view returns(string memory){
contractB.getAstr(), return x;
contractC.getAValue()); }
}
} }

contract C is A {

function getAValue(
) external view returns(uint){
return sum;
}
}
pragma solidity >=0.4.22 <0.6.0;

4. Multiple Inheritance contract A {


In Multiple Inheritance, a single contract
string internal x;
can be inherited from many contracts. A
function setA() external {
parent contract can have more than one x = “LifeForLives";
child while a child contract can have more }
than one parent. }

contract caller { contract B {


C contractC = new C(); uint internal pow;
function setB() external {
function testInheritance( uint a = 2;
uint b = 20;
) public returns(string memory, uint) {
pow = a ** b;
contractC.setA();
contractC.setB(); }
return ( }
contractC.getStr(), contract C is A, B {
contractC.getPow());
} function getStr(
} ) external returns(string memory) {
return x;
}

function getPow(
) external returns(uint) {
return pow;
}
}
Solidity – Constructors
A constructor is a special method in any object-oriented programming language which gets
called whenever an object of a class is initialized.

It is totally different in case of Solidity, Solidity provides a constructor declaration inside the
smart contract and it invokes only once when the contract is deployed and is used to initialize
the contract state.

A default constructor is created by the compiler if there is no explicitly defined constructor.

Creating a constructor

A Constructor is defined using a constructor keyword without any function name followed by
an access modifier.

It’s an optional function which initializes state variables of the contract.

A constructor can be either internal or public, an internal constructor marks contract as


abstract.
constructor() <Access Modifier> { }
pragma solidity ^0.5.0;

contract constructorExample
{

string str;

constructor() public
{
str = “I am
Indian";
}

function getValue(
) public view returns (
string memory) {
return str;
}
}
Constructor in Inheritance

In case if a constructor is not defined then the default constructor is called, but if the
constructor is defined in a parent contract and having some arguments then the child
contract should also provide the required parameters to the constructor.

If the child contract is not passing any parameter to the parent’s constructor the child
contract will become an abstract contract.

There are two ways of calling a parent contract’s constructor:

1. Direct Initialization: In the below example, the direct initialization method is used to
initialize the constructor of the parent class.
pragma solidity ^0.5.0;

contract Base {
uint data;
constructor(uint _data) public {
data = _data;
}
function Print(
) public returns(string memory){
return "Direct Initialization";
}

}
contract Derived is Base(2){

constructor() public {}

function getData(
) external returns(uint){
uint result = data ** 2;
return result;
}
}

contract caller{
Derived c = new Derived();
function getResult() public returns(uint){
c.Print();
return c.getData();
}
}
pragma solidity ^0.5.0;
2. Indirect Initialization: In the below example, contract Base {
the indirect initialization string str;
constructor(
string memory _str) public {
using Base(string(abi.encodePacked(_info, _info))) str = _str;
}
is done to initialize the constructor of the base function Print(
class. ) public returns(string memory){
return "Indirect Initialization";
}
}

contract Derived is Base {


constructor(
string memory _info) Base(
string(abi.encodePacked(
_info, _info))) public {}

function getStr(
) public view returns(string memory){
return str;
}
}
contract caller {
Derived c
= new Derived(“Jaipur");

function getResult() public view{


c.Print();
c.getStr();
}
}
Need of Constructors
pragma solidity ^0.5.0;
Constructors are very useful in a smart contract, a
contract constructorExample {
parameter value can be defined at the run time
and can also restrict the method call. Constructor string str;
overloading is not supported in Solidity, it only address private owner
allows one constructor at a time. =
0x62Ab98A0efB752C48bd82836D0b4335018B9B97e;

constructor(string memory string)


public {
if(msg.sender == owner){
str = string;
}
}

function getValue() public view


returns (
string memory) {
return str;
}
}
Solidity – Abstract Contract

Abstract contracts are contracts that have at least one function without its implementation
or in the case when you don’t provide arguments for all of the base contract constructors.

Also in the case when we don’t intend to create a contract directly we can consider the
contract to be abstract.

An instance of an abstract cannot be created.

Abstract contracts are used as base contracts so that the child contract can inherit and utilize
its functions.

The abstract contract defines the structure of the contract and any derived contract inherited
from it should provide an implementation for the incomplete functions, and if the derived
contract is also not implementing the incomplete functions then that derived contract will also
be marked as abstract.

An abstract contract is declared using the abstract keyword.


pragma solidity ^0.8.17;
abstract contract AbstractContract {
function getStr(
string memory _strIn) public view virtual returns(
string memory);
contract Call{
function setValue(uint _in1, uint _in2) public
virtual;
AbstractContract abs; function add() public virtual returns(uint);
}

constructor(){ contract DerivedContract is AbstractContract{


abs = new DerivedContract(); uint private num1;
} uint private num2;

function getValues(
) public returns (string memory,uint) function getStr(
{ string memory _strIn) public pure override returns(
abs.setValue(10, 16); string memory){
return (abs.getStr(“MUJ return _strIn;
}
Jaipur"),abs.add());
}
function setValue(
} uint _in1, uint _in2) public override{
num1 = _in1;
num2 = _in2;
}
function add() public view override returns(uint){
return (num2 + num1);
}
}
Deploy the Smart Contract: After successful compilation of the smart contract
select the Call contract before deploying it.
Solidity – Basics of Interface

Interfaces are the same as abstract contracts created by using an interface keyword, also known
as a pure abstract contract.

Interfaces do not have any definition or any state variables, constructors, or any function with
implementation, they only contain function declarations i.e. functions in interfaces do not have
any statements.

Functions of Interface can be only of type external.

They can inherit from other interfaces, but they can’t inherit from other contracts.

An interface can have enum, structs which can be accessed using interface name dot notation.
pragma solidity >=0.8.6 <0.9.0;

interface InterfaceExample{

function getStr(
) external view returns(string memory);

function setValue(uint _num1, uint _num2)


external;

function add(
) external view returns(uint);
}
pragma solidity >=0.8.6 <0.9.0;
contract call{

import "./InterfaceExample.sol"; InterfaceExample obj;


contract MyContract is InterfaceExample{
constructor(){
uint private num1; obj = new MyContract();
uint private num2; }

function getStr() public view virtual override function getValue(


returns(string memory){ ) public returns(string memory,uint){
return “Interface Example Working"; obj.setValue(10, 16);
} return (obj.getStr(),obj.add());
}
function setValue(
}
uint _num1, uint _num2) public virtual override{
num1 = _num1;
num2 = _num2;
}

function add(
) public view virtual override returns(uint){
return num1 + num2;
}
}
Libraries in solidity are similar to contracts that contain reusable codes. A library has
functions that can be called by other contracts.

Deploying a common code by creating a library reduces the gas cost. Functions of the library
can be called directly when they do not modify the state variables i.e. only pure and view
functions can be called from outside of the library. It cannot be destroyed because it is
assumed as stateless.

The library does not have state variables, it cannot inherit any element and cannot be
inherited.

Creating Library

A library contract is defined by using the library keyword instead of a general contract.
Libraries do not have any storage thus it cannot hold state variables, fallback or payable
functions also cannot be created inside the library as it cannot store ethers.

Libraries are not for changing the state of the contract, it can only be used for performing
basic operations based on inputs and outputs.

However, it can implement some data types like struct and enums which are user-defined,
and constant variables that are stored in a stack of Ethereum, not in storage.
pragma solidity ^0.5.0;

library libraryExample {

struct Constants {
uint Pi; uint EulerNb;
uint PythagoraConst;
uint TheodorusConst; }
}
Deploying Library Using ‘For’ Keyword

A library can be defined on the same contract as well as it can be


imported from outside by using the import statements.

Example:

import <libraryName> from “./library-file.sol”;

A single file can contain multiple libraries that can be specified using
curly braces in the import statement separated by a comma. A library
can be accessed within the smart contract by using ‘for’ keyword.

Syntax:
<libraryName> for <dataType>

The above statement can be used to attach library functions to any


type. libraryName is the name of the desired library to
import, dataType is the variable type for which we want to access the
library. All members of the library can also be used by the wildcard
operator(*).
pragma solidity ^0.5.0;

library LibExample {

function pow(
uint a, uint b) public view returns (
uint, address) {
return (a ** b, address(this));
}
}

contract LibraryExample {

using LibExample for uint;


address owner = address(this);

function getPow(
uint num1, uint num2) public view returns (
uint, address) {
return num1.pow(num2);
}
}
pragma solidity ^0.5.0;

Deploying Library library libraryExample {


Without using For
struct strings {
Keyword string str1 ;
Example: In the below string str2 ;
example, the contract string str3 ;
}
libExample is created to
demonstrate how to deploy a function concatenate(
library without using the ‘For’ string memory _In1, string memory _In2)
keyword. public view returns(
string memory){
return string(
abi.encodePacked(_In1, _In2));
}
}

contract libExample{
libraryExample.strings data
= libraryExample.strings("Manipal", "University", "Jaipur

function getResult(
) public view returns(string memory){
string memory result
= libraryExample.concatenate(data.str1, data.str2);
result = libraryExample.concatenate(result, data.str3);
return result;
}
}
Inbuilt libraries

Solidity has some inbuilt libraries for the ease of the users. Some of the libraries are listed
below :

1.Modular network: This includes many modular libraries that are very useful for
implementation like ArrayUtils, Token, CrowdSale, Vesting, StringUtils, LinkedList, Wallet, etc.

2.OpenZeppelin: other supporting libraries are Roles, MerkleProof, ECDSA, Math, Address,
SafeERC20, ERC165Checker, SafeMath, Arrays, etc which protects from overflow.

3.Dapp-bin: Created by Ethereum includes interesting and useful libraries like


DoublyLinkedList, StringUtils, IterableMapping, etc.
What are Events in Solidity?
Solidity Events are the same as events in any other programming language.

An event is an inheritable member of the contract, which stores the arguments passed in the
transaction logs when emitted.

Generally, events are used to inform the calling application about the current state of the
contract, with the help of the logging facility of EVM.

Events notify the applications about the change made to the contracts and applications
which can be used to execute the dependent logic.
Creating an event

Events are defined within the contracts as global and called within their functions.

Events are declared by using the event keyword, followed by an identifier and the
parameter list, and ends with a semicolon.

The parameter values are used to log the information or for executing the conditional
logic. Its information and values are saved as part of the transactions inside the block.

There is no need of providing variables, only datatypes are sufficient. An event can be
called from any method by using its name and passing the required parameters.
pragma solidity ^0.4.21;

contract eventExample {

uint256 public value = 0;

event Increment(address owner);

function getValue(uint _a, uint _b)


public {
emit Increment(msg.sender);
value = _a + _b;
}
}
Result in the console:

logs [
{
"from": "0xd9145CCE52D386f254917e481eB44e9943F39138",
"topic":
"0xfc3a67c9f0b5967ae4041ed898b05ec1fa49d2a3c22336247201d71be6f97120",
"event": "Increment",
"args": {
"0": "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4",
"owner": "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4"
}
}
]
IMP: We can add atmost 3 indexes in one
event.

Index in events: We can also add an index to our event. On adding the different fields to our
event, we can add an index to them it helps to access them later but of course, it’s going to
cost some more gas!
Output in the console: adding the output in
the console
pragma solidity >=0.7.0
logs [
<0.9.0;
{
"from": "0xcD6a42782d230D7c13A74ddec5dD140e55499Df9",
"topic": contract IndexEvents {
"0xa6b5ddd331f9dc412a8c258207b1c66f53c1740c72628d9913aafcb6b28d
8f73", event NewTrade(
"event": "NewTrade", uint256 indexed date,
"args": { address from,
"0": "1655406115", address indexed to,
"1": "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4", uint256 indexed
"2": "0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2", amount
"3": "1234", );
"date": "1655406115",
"from": function trade(address
to, uint256 amount) external
"0x5B38Da6a701c568545dCfcB03FcB875f56beddC4",
{
"to": "0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2",
emit
"amount": "1234" NewTrade(block.timestamp,
} msg.sender, to,amount);
} }
] }
Solidity – Error Handling

Solidity has many functions for error handling.

Errors can occur at compile time or runtime.

Solidity is compiled to byte code and there a syntax error check happens at compile-time, while
runtime errors are difficult to catch and occurs mainly while executing the contracts.

Some of the runtime errors are out-of-gas error, data type overflow error, divide by zero error,
array-out-of-index error, etc.

Until version 4.10 a single throw statement was there in solidity to handle errors, so to handle
errors multiple if…else statements, one has to implement for checking the values and throw
errors which consume more gas.

After version 4.10 new error handling construct assert, require, revert statements were
introduced and the throw was made absolute.
Require Statements

The ‘require’ statements declare prerequisites for running the function i.e. it declares the
constraints which should be satisfied before executing the code.

It accepts a single argument and returns a boolean value after evaluation, it also has a custom
string message option. If false then exception is raised and execution is terminated.

The unused gas is returned back to the caller and the state is reversed to its original state.
Following are some cases when require type of exception is triggered :

•When require() is called with the arguments which result as false.

•When a function called by a message does not end properly.

•When a contract is created using the new keyword and the process does not end properly.

•When a codeless contract is targeted to an external function.

•When ethers are sent to the contract using the public getter method.

•When .transfer() method fails.


• When an assert is called with a condition that results in false.
• When a zero-initialized variable of a function is called.
• When a large or a negative value is converted to an enum.
• When a value is divided or modulo by zero.
• When accessing an array in an index which is too big or negative.
pragma solidity ^0.5.0;

contract requireStatement {

function checkInput(uint _input)


public view returns(string memory){
require(_input >= 0, "invalid uint8");
require(_input <= 255, "invalid
uint8");

return "Input is Uint8";


}

function Odd(uint _input) public view


returns(bool){
require(_input % 2 != 0);
return true;
}
}
Assert Statement

Its syntax is similar to the require statement. It returns a boolean value after the evaluation of
the condition.

Based on the return value either the program will continue its execution or it will throw an
exception.

Instead of returning the unused gas, the assert statement consumes the entire gas supply and
the state is then reversed to the original state.

Assert is used to check the current state and function conditions before the execution of the
contract.

Below are some cases with assert type exceptions :

•When an assert is called with a condition that results in false.


•When a zero-initialized variable of a function is called.
•When a large or a negative value is converted to an enum.
•When a value is divided or modulo by zero.
•When accessing an array in an index which is too big or negative.
pragma solidity ^0.5.0;

contract assertStatement {

bool result;

function checkOverflow(uint _num1, uint _num2)


public {
uint sum = _num1 + _num2;
assert(sum<=255);
result = true;
}

function getResult() public view returns(string


memory){
if(result == true){
return "No Overflow";
}
else{
return "Overflow exist";
}
}
}
Revert Statement

This statement is similar to the require statement. It does not evaluate any condition and does
not depends on any state or statement.

It is used to generate exceptions, display errors, and revert the function call.

This statement contains a string message which indicates the issue related to the information of
the exception.

Calling a revert statement implies an exception is thrown, the unused gas is returned and the
state reverts to its original state.

Revert is used to handle the same exception types as require handles, but with little bit more
complex logic.
pragma solidity ^0.5.0;

contract revertStatement {

function checkOverflow(uint _num1, uint _num2)


public view returns(string memory, uint){
uint sum = _num1 + _num2;
if(sum < 0 || sum > 255){
revert(" Overflow Exist");
}
else{
return ("No Overflow", sum);
}

}
Custom Error

To define the custom error in the smart contract by using the “Error statement” .

Error statement is used either inside the smart contract or outside the smart contract along
with revert statement.

The main purpose of using custom error in the smart contract is to save gas.
pragma solidity >=0.4.22 <0.9.0;
contract CustomError {
mapping(address => uint) public bal;
function deposit() public payable {
bal[msg.sender] += msg.value;
}
error LackOfFunds(uint withdrawAmt, uint availableAmt);

//custom error generates if withdraw amount is greater than owner address


amount
function checkCustomError(address _receiver,uint _withdrawAmt) public {
if (bal[msg.sender]< _withdrawAmt) {
revert LackOfFunds({withdrawAmt: _withdrawAmt, availableAmt:
bal[msg.sender]});
}
bal[msg.sender] -= _withdrawAmt;
bal[_receiver]+=_withdrawAmt;
}
}
transact to CustomError.checkCustomError errored: VM error: revert.
revert
The transaction has been reverted to the initial state.
Error provided by the contract:
LackOfFunds
Parameters:
{
“withdrawAmt”: {
“value”: “200”
},
“availableAmt”: {
“value”: “100”
}
}
Debug the transaction to get more information.

You might also like