Quick Guide To Solidity Contracts

In this article, we will explore Solidity contracts, including their structure, data types, functions, and modifiers.

We will also discuss best practices for writing secure and efficient Solidity code and introduce some popular tools and frameworks for Solidity development.



Solidity Contracts

Solidity contracts encapsulate data and functions and represent objects or entities in the blockchain network.

There are several properties of Solidity contracts that make them unique from traditional software programs:

 

PropertiesOverview
AddressEach Solidity contract has its own blockchain address. An address is used to identify a contract on the network and interact with it.
State VariablesUsing state variables in Solidity, contracts can store data on the blockchain. There are various types of state variables in a contract, including integers, booleans, strings, arrays, and more. State variables are declared at the top level of the contract.
FunctionsAn external account or another contract can call the functions defined in Solidity contracts. A function modifies the state variables of a contract, performs calculations, and interacts with other contracts on the network.
EventsIn contracts, events can be generated to notify external accounts or applications about important state changes. Typically, events are used for logging purposes or to initiate off-chain processes.
ModifierA modifier restricts access to certain functions or operations within a Solidity contract. The purpose of these functions is to enforce permissions, validate inputs, and ensure that certain conditions are met before executing them.
InheritanceInheritance is a key feature of Solidity contracts, which allows developers to reuse code and functionality across multiple contracts by inheriting from one another.

 


Visibility Quantifiers

A visibility quantifier controls the accessibility of functions and state variables within a Solidity contract.

Solidity provides four visibility quantifiers:

 

QuantifiersOverview
PublicPublic variables and functions can be invoked from anywhere, within or outside the contract.
PrivatePrivate functions and state variables can only be accessed within a contract they are declared in.
InternalInternally accessible functions or variables are only accessible from within the contract or from its descendants.
ExternalExternal functions cannot be called from within a contract, only from outside. In addition to creating interfaces for interacting with other contracts, external functions also allow public access to certain features.

 

Note: Solidity defaults to internal visibility for functions and state variables.

Public Quantifiers

The public state variables and functions can be invoked from the parent contact (where it is created in) or from any other contract.

The following example shows the working of public quantifiers:

Example: 

pragma solidity ^0.8.0;// This is the Parent Method which contains all the arithmetic operations of solidity programmingcontract SolidityTest {uint public value=32;function add(uint mrx,uint ample) public pure returns(uint){return mrx+ample; }function subtract(uint mrx,uint ample) public pure returns(uint){return mrx-ample; } function multiply(uint mrx,uint ample) public pure returns(uint){return mrx*ample; } function modulus(uint mrx,uint ample) public pure returns(uint){return mrx%ample; } }// Here we have created another contract named as SolidityTest1 which is inherited from the parent contract SolidityTest //// It have the direct access to the public variables and functions in the parent contract //contract SolidityTest1 is SolidityTest{ function obtain_Sum() public pure returns(uint){return add(2,5); }function obtain_Difference() public pure returns(uint){return subtract(5,1); }function obtain_Product() public pure returns(uint){return multiply(3,4); }function obtain_Modulus() public pure returns(uint){return modulus(6,5); }function obtain_Value() public view returns(uint){return value; }}// This is an external contract but it has access to the public function and variables by creating an object of the parent contact or the inherited contract inside itcontract SolidityTest2{SolidityTest obj=new SolidityTest();function get_Add() public view returns(uint){ return obj.multiply(2,4); }function get_Sub() public view returns(uint){ return obj.subtract(4,1); }function get_Multiply() public view returns(uint){ return obj.multiply(5,2); }function get_Modulus() public view returns(uint){ return obj.modulus(8,4); }function get_Value() public view returns(uint){ return obj.value(); }}
<div class="spinner-border" role="status"><span class="sr-only">Loading...</span></div>

Private Quantifiers

The user has the access of private state variables and functions restricted to the contract they are initialized in.

The given example illustrates the working of Private state variables and functions:

Example: 

pragma solidity ^0.8.0;// This is the Parent Method which contains all the private arithmetic operations of solidity programmingcontract SolidityTest {uint private value=13;function add(uint mrx,uint ample) private pure returns(uint){return mrx+ample; }function subtract(uint mrx,uint ample) private pure returns(uint){return mrx-ample; } function multiply(uint mrx,uint ample) private pure returns(uint){return mrx*ample; } function modulus(uint mrx,uint ample) private pure returns(uint){return mrx%ample; } }// Here we have created another contract named as SolidityTest1 which is inherited from the parent contract SolidityTest //// It doesnot have an access to the private variables and functions we constructed in the parent contract (SolidityTest) //contract SolidityTest1 is SolidityTest{ function obtain_Sum() public pure returns(uint){return add(2,5); }function obtain_Difference() public pure returns(uint){return subtract(5,1); }function obtain_Product() public pure returns(uint){return multiply(3,4); }function obtain_Modulus() public pure returns(uint){return modulus(6,5); }function obtain_Value() public view returns(uint){return value; }}// This is an external contract having the object of the parent class (SolidityTest) inside it but still can not access the private functions and variables of the contract SolidityTestcontract SolidityTest2{SolidityTest obj=new SolidityTest();function get_Add() public view returns(uint){ return obj.multiply(2,4); }function get_Sub() public view returns(uint){ return obj.subtract(4,1); }function get_Multiply() public view returns(uint){ return obj.multiply(5,2); }function get_Modulus() public view returns(uint){ return obj.modulus(8,4); }function get_Value() public view returns(uint){ return obj.value(); }}
<div class="spinner-border" role="status"><span class="sr-only">Loading...</span></div>
Note: The execution of this code will result in an error, this is because the private variables and functions are inaccessible outside the contract they were created in.

Internal Quantifiers

The internal functions and state variables are accessible from the parent class as well as from the inherited contract but not from the external contracts.

The following code illustrates the working of the Internal quantifier:

Example: 

pragma solidity ^0.8.0;// This is the Parent Method which contains all the internal functions to performs several arithmetic operations of solidity programmingcontract SolidityTest {uint internal value=13;function add(uint mrx,uint ample) internal pure returns(uint){return mrx+ample; }function subtract(uint mrx,uint ample) internal pure returns(uint){return mrx-ample; } function multiply(uint mrx,uint ample) internal pure returns(uint){return mrx*ample; } function modulus(uint mrx,uint ample) internal pure returns(uint){return mrx%ample; } }// Here we have created another contract named as SolidityTest1 which is inherited from the parent contract SolidityTest //// It have an access to the internal variables and functions we constructed in the parent contract (SolidityTest) //contract SolidityTest1 is SolidityTest{ function obtain_Sum() public pure returns(uint){return add(2,5); }function obtain_Difference() public pure returns(uint){return subtract(5,1); }function obtain_Product() public pure returns(uint){return multiply(3,4); }function obtain_Modulus() public pure returns(uint){return modulus(6,5); }function obtain_Value() public view returns(uint){return value; }}// This is an external contract having the object of the parent class (SolidityTest) inside it but still can not access the internal functions and variables of the contract SolidityTest as the internal variables and functions are restricted to the parent contract or its inherited child contracts only contract SolidityTest2{SolidityTest obj=new SolidityTest();function get_Add() public view returns(uint){ return obj.multiply(2,4); }function get_Sub() public view returns(uint){ return obj.subtract(4,1); }function get_Multiply() public view returns(uint){ return obj.multiply(5,2); }function get_Modulus() public view returns(uint){ return obj.modulus(8,4); }function get_Value() public view returns(uint){ return obj.value(); }}
<div class="spinner-border" role="status"><span class="sr-only">Loading...</span></div>

External Quantifiers

The external keyword restricts the function from being accessed in the parent contract (where it was initialized) .

There is no way to make the state variables as external.

If we want to access the external functions inside the parent contract we can use the keyword this to fulfill our requirement.

The example below shows the calling of external functions and its exceptions:

Example: 

pragma solidity ^0.8.0;// This is the Parent Method which contains all the external functions to performs several arithmetic operations of solidity programmingcontract SolidityTest {// uint external value=4; // its is not possible to assign the external quantifier to a variable, hence it generates an errorfunction add(uint mrx,uint ample) external pure returns (uint){return mrx+ample; }function subtract(uint mrx,uint ample) external pure returns (uint) { return mrx-ample; }function multiply(uint mrx,uint ample) external pure returns (uint) {return mrx*ample; } function modulus(uint mrx,uint ample) external pure returns (uint){return mrx%ample; } }// Here we have created another contract named as SolidityTest1 which is inherited from the parent contract SolidityTest //// It lacks an access to the external variables and functions we constructed in the parent contract (SolidityTest) only the external contracts can access it//contract SolidityTest1 is SolidityTest{ function obtain_Sum() public pure returns(uint){return add(2,5); }function obtain_Difference() public pure returns(uint){return subtract(5,1); }function obtain_Product() public pure returns(uint){return multiply(3,4); }function obtain_Modulus() public pure returns(uint){return modulus(6,5); }function obtain_Value() public view returns(uint){return value; }}// This is an external contract having the object of the parent class (SolidityTest) only it can access the external functions and variables from the parent contract SolidityTest contract SolidityTest2{SolidityTest obj=new SolidityTest();function get_Add() public view returns(uint){ return obj.multiply(2,4); }function get_Sub() public view returns(uint){ return obj.subtract(4,1); }function get_Multiply() public view returns(uint){ return obj.multiply(5,2); }function get_Modulus() public view returns(uint){ return obj.modulus(8,4); }}
<div class="spinner-border" role="status"><span class="sr-only">Loading...</span></div>
If you want the inherited classes to use the external functions from the parent class, this could be done by using the this keyword as:

Example: 

pragma solidity ^0.8.0;// This is the Parent Method which contains all the external functions to performs several arithmetic operations of solidity programmingcontract SolidityTest {// uint external value=4; // its is not possible to assign the external quantifier to a variable, hence it generates an errorfunction add(uint mrx,uint ample) external pure returns (uint){return mrx+ample; }function subtract(uint mrx,uint ample) external pure returns (uint) { return mrx-ample; }function multiply(uint mrx,uint ample) external pure returns (uint) {return mrx*ample; } function modulus(uint mrx,uint ample) external pure returns (uint){return mrx%ample; } }// Here we have created another contract named as SolidityTest1 which is inherited from the parent contract SolidityTest //// After using the (this) keyword the inherited class from the parent contract can now have an access to the external variables and functions we constructed in the parent contract (SolidityTest) only the external contracts can access it//contract SolidityTest1 is SolidityTest{ function obtain_Sum() public view returns(uint){return this.add(2,5); }function obtain_Difference() public view returns(uint){return this.subtract(5,1); }function obtain_Product() public view returns(uint){return this.multiply(3,4); }function obtain_Modulus() public view returns(uint){return this.modulus(6,5); }}// This is an external contract having the object of the parent class (SolidityTest) only it can access the external functions and variables from the parent contract SolidityTest contract SolidityTest2{SolidityTest obj=new SolidityTest();function get_Add() public view returns(uint){ return obj.multiply(2,4); }function get_Sub() public view returns(uint){ return obj.subtract(4,1); }function get_Multiply() public view returns(uint){ return obj.multiply(5,2); }function get_Modulus() public view returns(uint){ return obj.modulus(8,4); }}
<div class="spinner-border" role="status"><span class="sr-only">Loading...</span></div>

Importance of Solidity Visibility Quantifiers

A solidity visibility quantifier’s importance lies in their ability to help you create smart contracts that are secure, modular, and maintainable.

When you choose the right quantifier for each function and variable, your contracts can be accessed only by the necessary parties.

By doing so, you will minimize the risk of vulnerabilities and attacks, as well as improve the readability and structure of your code.

It is crucial, for example, to declare a function private in order to prevent any other contracts or external entities from gaining access to the logic stored within that function, thus reducing the potential for unauthorized manipulation or exploitation.

Additionally, declaring a function external can be beneficial in optimizing gas usage because only outside calls will be allowed to invoke the function. In this way, the need for unnecessary state changes is eliminated.

Solidity visibility quantifiers can help you write more modular and maintainable code. Quantifiers enables you and other developers to better understand the purpose and functionality of a given contract by indicating a function’s intended use and accessibility.

This will facilitate the development of smart contracts that are more complex and interoperable.

We value your feedback.
+1
0
+1
0
+1
0
+1
0
+1
0
+1
0
+1
0

Subscribe To Our Newsletter
Enter your email to receive a weekly round-up of our best posts. Learn more!
icon

Leave a Reply

Your email address will not be published. Required fields are marked *